diff --git a/.eslintrc.json b/.eslintrc.json index bc2be3c66a782..5144282ae299b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -22,14 +22,53 @@ "@typescript-eslint/naming-convention": [ "error", - { "selector": "typeLike", "format": ["PascalCase"], "filter": { "regex": "^(__String|[A-Za-z]+_[A-Za-z]+)$", "match": false } }, - { "selector": "interface", "format": ["PascalCase"], "custom": { "regex": "^I[A-Z]", "match": false }, "filter": { "regex": "^I(Arguments|TextWriter|O([A-Z][a-z]+[A-Za-z]*)?)$", "match": false } }, - { "selector": "variable", "format": ["camelCase", "PascalCase", "UPPER_CASE"], "leadingUnderscore": "allow", "filter": { "regex": "^(_{1,2}filename|_{1,2}dirname|_+|[A-Za-z]+_[A-Za-z]+)$", "match": false } }, - { "selector": "function", "format": ["camelCase", "PascalCase"], "leadingUnderscore": "allow", "filter": { "regex": "^[A-Za-z]+_[A-Za-z]+$", "match": false } }, - { "selector": "parameter", "format": ["camelCase"], "leadingUnderscore": "allow", "filter": { "regex": "^(_+|[A-Za-z]+_[A-Z][a-z]+)$", "match": false } }, - { "selector": "method", "format": ["camelCase", "PascalCase"], "leadingUnderscore": "allow", "filter": { "regex": "^([0-9]+|[A-Za-z]+_[A-Za-z]+)$", "match": false } }, - { "selector": "memberLike", "format": ["camelCase"], "leadingUnderscore": "allow", "filter": { "regex": "^([0-9]+|[A-Za-z]+_[A-Za-z]+)$", "match": false } }, - { "selector": "enumMember", "format": ["camelCase", "PascalCase"], "leadingUnderscore": "allow", "filter": { "regex": "^[A-Za-z]+_[A-Za-z]+$", "match": false } }, + { + "selector": "typeLike", + "format": ["PascalCase"], + "filter": { "regex": "^(__String|[A-Za-z]+_[A-Za-z]+)$", "match": false } + }, + { + "selector": "interface", + "format": ["PascalCase"], + "custom": { "regex": "^I[A-Z]", "match": false }, + "filter": { "regex": "^I(Arguments|TextWriter|O([A-Z][a-z]+[A-Za-z]*)?)$", "match": false } + }, + { + "selector": "variable", + "format": ["camelCase", "PascalCase", "UPPER_CASE"], + "leadingUnderscore": "allow", + "filter": { "regex": "^(_{1,2}filename|_{1,2}dirname|_+|[A-Za-z]+_[A-Za-z]+)$", "match": false } + }, + { + "selector": "function", + "format": ["camelCase", "PascalCase"], + "leadingUnderscore": "allow", + "filter": { "regex": "^[A-Za-z]+_[A-Za-z]+$", "match": false } + }, + { + "selector": "parameter", + "format": ["camelCase"], + "leadingUnderscore": "allow", + "filter": { "regex": "^(_+|[A-Za-z]+_[A-Z][a-z]+)$", "match": false } + }, + { + "selector": "method", + "format": ["camelCase", "PascalCase"], + "leadingUnderscore": "allow", + "filter": { "regex": "^([0-9]+|[A-Za-z]+_[A-Za-z]+)$", "match": false } + }, + { + "selector": "memberLike", + "format": ["camelCase"], + "leadingUnderscore": "allow", + "filter": { "regex": "^([0-9]+|[A-Za-z]+_[A-Za-z]+)$", "match": false } + }, + { + "selector": "enumMember", + "format": ["camelCase", "PascalCase"], + "leadingUnderscore": "allow", + "filter": { "regex": "^[A-Za-z]+_[A-Za-z]+$", "match": false } + }, { "selector": "property", "format": null } ], @@ -87,7 +126,15 @@ "no-new-func": "error", "no-new-wrappers": "error", "no-return-await": "error", - "no-restricted-globals": ["error", { "name": "setTimeout" }, { "name": "clearTimeout" }, { "name": "setInterval" }, { "name": "clearInterval" }, { "name": "setImmediate" }, { "name": "clearImmediate" }], + "no-restricted-globals": [ + "error", + { "name": "setTimeout" }, + { "name": "clearTimeout" }, + { "name": "setInterval" }, + { "name": "clearInterval" }, + { "name": "setImmediate" }, + { "name": "clearImmediate" } + ], "no-sparse-arrays": "error", "no-template-curly-in-string": "error", "no-throw-literal": "error", @@ -121,7 +168,14 @@ "files": ["*.mjs", "*.mts"], "rules": { // These globals don't exist outside of CJS files. - "no-restricted-globals": ["error", { "name": "__filename" }, { "name": "__dirname" }, { "name": "require" }, { "name": "module" }, { "name": "exports" }] + "no-restricted-globals": [ + "error", + { "name": "__filename" }, + { "name": "__dirname" }, + { "name": "require" }, + { "name": "module" }, + { "name": "exports" } + ] } } ] diff --git a/Gulpfile.mjs b/Gulpfile.mjs index 612b6dc9351f1..43c03833f2386 100644 --- a/Gulpfile.mjs +++ b/Gulpfile.mjs @@ -12,7 +12,13 @@ import gulp from "gulp"; import { append, transform } from "gulp-insert"; import { prependFile } from "./scripts/build/prepend.mjs"; import { exec, readJson, needsUpdate, getDiffTool, getDirSize, rm } from "./scripts/build/utils.mjs"; -import { runConsoleTests, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } from "./scripts/build/tests.mjs"; +import { + runConsoleTests, + refBaseline, + localBaseline, + refRwcBaseline, + localRwcBaseline, +} from "./scripts/build/tests.mjs"; import { buildProject, cleanProject, watchProject } from "./scripts/build/projects.mjs"; import cmdLineOptions from "./scripts/build/options.mjs"; @@ -88,7 +94,12 @@ const localizationTargets = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt const localize = async () => { if (needsUpdate(diagnosticMessagesGeneratedJson, generatedLCGFile)) { - return exec(process.execPath, ["scripts/generateLocalizedDiagnosticMessages.mjs", "src/loc/lcl", "built/local", diagnosticMessagesGeneratedJson], { ignoreExitCode: true }); + return exec(process.execPath, [ + "scripts/generateLocalizedDiagnosticMessages.mjs", + "src/loc/lcl", + "built/local", + diagnosticMessagesGeneratedJson, + ], { ignoreExitCode: true }); } }; @@ -137,7 +148,9 @@ const buildServices = (() => { src("built/local/typescriptServices.out.d.ts") .pipe(newer("built/local/typescriptServices.d.ts")) .pipe(prependFile(copyright)) - .pipe(transform(content => content.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, "$1$2enum $3 {$4"))) + .pipe( + transform(content => content.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, "$1$2enum $3 {$4")), + ) .pipe(rename("typescriptServices.d.ts")) .pipe(dest("built/local")); @@ -162,7 +175,9 @@ const buildServices = (() => { const createTypescriptStandaloneDts = () => src("built/local/typescriptServices.d.ts") .pipe(newer("built/local/typescript_standalone.d.ts")) - .pipe(transform(content => content.replace(/declare (namespace|module) ts/g, 'declare module "typescript"'))) + .pipe( + transform(content => content.replace(/declare (namespace|module) ts/g, 'declare module "typescript"')), + ) .pipe(rename("typescript_standalone.d.ts")) .pipe(dest("built/local")); @@ -276,7 +291,9 @@ const buildLssl = (() => { src("built/local/tsserverlibrary.out.d.ts") .pipe(newer("built/local/tsserverlibrary.d.ts")) .pipe(prependFile(copyright)) - .pipe(transform(content => content.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, "$1$2enum $3 {$4"))) + .pipe( + transform(content => content.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, "$1$2enum $3 {$4")), + ) .pipe(append("\nexport = ts;\nexport as namespace ts;")) .pipe(rename("tsserverlibrary.d.ts")) .pipe(dest("built/local")); @@ -344,7 +361,13 @@ task("clean-tests").description = "Cleans the outputs for the test infrastructur const watchTests = () => watchProject("src/testRunner", cmdLineOptions); -const runEslintRulesTests = () => runConsoleTests("scripts/eslint/tests", "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ false); +const runEslintRulesTests = () => + runConsoleTests( + "scripts/eslint/tests", + "mocha-fivemat-progress-reporter", + /*runInParallel*/ false, + /*watchMode*/ false, + ); task("run-eslint-rules-tests", runEslintRulesTests); task("run-eslint-rules-tests").description = "Runs the eslint rule tests"; @@ -409,7 +432,13 @@ const copyBuiltLocalDiagnosticMessages = () => const cleanBuiltLocalDiagnosticMessages = () => del(builtLocalDiagnosticMessagesGeneratedJson); cleanTasks.push(cleanBuiltLocalDiagnosticMessages); -const buildOtherOutputs = parallel(buildCancellationToken, buildTypingsInstaller, buildWatchGuard, generateTypesMap, copyBuiltLocalDiagnosticMessages); +const buildOtherOutputs = parallel( + buildCancellationToken, + buildTypingsInstaller, + buildWatchGuard, + generateTypesMap, + copyBuiltLocalDiagnosticMessages, +); task("other-outputs", series(preBuild, buildOtherOutputs)); task("other-outputs").description = "Builds miscelaneous scripts and documents distributed with the LKG"; @@ -419,7 +448,10 @@ task("local").flags = { " --built": "Compile using the built version of the compiler.", }; -task("watch-local", series(preBuild, parallel(watchLib, watchDiagnostics, watchTsc, watchServices, watchServer, watchLssl))); +task( + "watch-local", + series(preBuild, parallel(watchLib, watchDiagnostics, watchTsc, watchServices, watchServer, watchLssl)), +); task("watch-local").description = "Watches for changes to projects in src/ (but does not execute tests)."; task("watch-local").flags = { " --built": "Compile using the built version of the compiler.", @@ -428,7 +460,13 @@ task("watch-local").flags = { const preTest = parallel(buildTsc, buildTests, buildServices, buildLssl); preTest.displayName = "preTest"; -const runTests = () => runConsoleTests("built/local/run.js", "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ false); +const runTests = () => + runConsoleTests( + "built/local/run.js", + "mocha-fivemat-progress-reporter", + /*runInParallel*/ false, + /*watchMode*/ false, + ); task("runtests", series(preBuild, preTest, runTests)); task("runtests").description = "Runs the tests using the built run.js file."; task("runtests").flags = { @@ -439,7 +477,8 @@ task("runtests").flags = { " --keepFailed": "Keep tests in .failed-tests even if they pass", " --light": "Run tests in light mode (fewer verifications, but tests run faster)", " --dirty": "Run tests without first cleaning test output directories", - " --stackTraceLimit=": "Sets the maximum number of stack frames to display. Use 'full' to show all frames.", + " --stackTraceLimit=": + "Sets the maximum number of stack frames to display. Use 'full' to show all frames.", " --no-color": "Disables color", " --timeout=": "Overrides the default test timeout.", " --built": "Compile using the built version of the compiler.", @@ -447,14 +486,16 @@ task("runtests").flags = { " --shardId": "1-based ID of this shard (default: 1)", }; -const runTestsParallel = () => runConsoleTests("built/local/run.js", "min", /*runInParallel*/ cmdLineOptions.workers > 1, /*watchMode*/ false); +const runTestsParallel = () => + runConsoleTests("built/local/run.js", "min", /*runInParallel*/ cmdLineOptions.workers > 1, /*watchMode*/ false); task("runtests-parallel", series(preBuild, preTest, runTestsParallel)); task("runtests-parallel").description = "Runs all the tests in parallel using the built run.js file."; task("runtests-parallel").flags = { " --light": "Run tests in light mode (fewer verifications, but tests run faster).", " --keepFailed": "Keep tests in .failed-tests even if they pass.", " --dirty": "Run tests without first cleaning test output directories.", - " --stackTraceLimit=": "Sets the maximum number of stack frames to display. Use 'full' to show all frames.", + " --stackTraceLimit=": + "Sets the maximum number of stack frames to display. Use 'full' to show all frames.", " --workers=": "The number of parallel workers to use.", " --timeout=": "Overrides the default test timeout.", " --built": "Compile using the built version of the compiler.", @@ -463,13 +504,19 @@ task("runtests-parallel").flags = { }; task("test-browser-integration", () => exec(process.execPath, ["scripts/browserIntegrationTest.mjs"])); -task("test-browser-integration").description = "Runs scripts/browserIntegrationTest.mjs which tests that typescript.js loads in a browser"; +task("test-browser-integration").description = + "Runs scripts/browserIntegrationTest.mjs which tests that typescript.js loads in a browser"; task("diff", () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true, waitForExit: false })); -task("diff").description = "Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable"; +task("diff").description = + "Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable"; -task("diff-rwc", () => exec(getDiffTool(), [refRwcBaseline, localRwcBaseline], { ignoreExitCode: true, waitForExit: false })); -task("diff-rwc").description = "Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable"; +task( + "diff-rwc", + () => exec(getDiffTool(), [refRwcBaseline, localRwcBaseline], { ignoreExitCode: true, waitForExit: false }), +); +task("diff-rwc").description = + "Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable"; /** * @param {string} localBaseline Path to the local copy of the baselines @@ -485,10 +532,12 @@ const baselineAccept = (localBaseline, refBaseline) => .pipe(rm(refBaseline)), ); task("baseline-accept", () => baselineAccept(localBaseline, refBaseline)); -task("baseline-accept").description = "Makes the most recent test results the new baseline, overwriting the old baseline"; +task("baseline-accept").description = + "Makes the most recent test results the new baseline, overwriting the old baseline"; task("baseline-accept-rwc", () => baselineAccept(localRwcBaseline, refRwcBaseline)); -task("baseline-accept-rwc").description = "Makes the most recent rwc test results the new baseline, overwriting the old baseline"; +task("baseline-accept-rwc").description = + "Makes the most recent rwc test results the new baseline, overwriting the old baseline"; // TODO(rbuckton): Determine if we still need this task. Depending on a relative // path here seems like a bad idea. @@ -499,9 +548,11 @@ task("update-sublime", updateSublime); task("update-sublime").description = "Updates the sublime plugin's tsserver"; // TODO(rbuckton): Should the path to DefinitelyTyped be configurable via an environment variable? -const importDefinitelyTypedTests = () => exec(process.execPath, ["scripts/importDefinitelyTypedTests.mjs", "./", "../DefinitelyTyped"]); +const importDefinitelyTypedTests = () => + exec(process.execPath, ["scripts/importDefinitelyTypedTests.mjs", "./", "../DefinitelyTyped"]); task("importDefinitelyTypedTests", importDefinitelyTypedTests); -task("importDefinitelyTypedTests").description = "Runs the importDefinitelyTypedTests script to copy DT's tests to the TS-internal RWC tests"; +task("importDefinitelyTypedTests").description = + "Runs the importDefinitelyTypedTests script to copy DT's tests to the TS-internal RWC tests"; const buildReleaseTsc = () => buildProject("src/tsc/tsconfig.release.json"); const cleanReleaseTsc = () => cleanProject("src/tsc/tsconfig.release.json"); @@ -527,7 +578,10 @@ const produceLKG = async () => { .concat(localizationTargets) .filter(f => !fs.existsSync(f)); if (missingFiles.length > 0) { - throw new Error("Cannot replace the LKG unless all built targets are present in directory 'built/local/'. The following files are missing:\n" + missingFiles.join("\n")); + throw new Error( + "Cannot replace the LKG unless all built targets are present in directory 'built/local/'. The following files are missing:\n" + + missingFiles.join("\n"), + ); } const sizeBefore = getDirSize("lib"); await exec(process.execPath, ["scripts/produceLKG.mjs"]); @@ -537,31 +591,59 @@ const produceLKG = async () => { } }; -task("LKG", series(lkgPreBuild, parallel(localize, buildTsc, buildServer, buildServices, buildLssl, buildOtherOutputs, buildReleaseTsc), produceLKG)); +task( + "LKG", + series( + lkgPreBuild, + parallel(localize, buildTsc, buildServer, buildServices, buildLssl, buildOtherOutputs, buildReleaseTsc), + produceLKG, + ), +); task("LKG").description = "Makes a new LKG out of the built js files"; task("LKG").flags = { " --built": "Compile using the built version of the compiler.", }; task("lkg", series("LKG")); -const generateSpec = () => exec("cscript", ["//nologo", "scripts/word2md.mjs", path.resolve("doc/TypeScript Language Specification - ARCHIVED.docx"), path.resolve("doc/spec-ARCHIVED.md")]); +const generateSpec = () => + exec("cscript", [ + "//nologo", + "scripts/word2md.mjs", + path.resolve("doc/TypeScript Language Specification - ARCHIVED.docx"), + path.resolve("doc/spec-ARCHIVED.md"), + ]); task("generate-spec", generateSpec); task("generate-spec").description = "Generates a Markdown version of the Language Specification"; task("clean", series(parallel(cleanTasks), cleanBuilt)); task("clean").description = "Cleans build outputs"; -const configureNightly = () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "dev", "package.json", "src/compiler/corePublic.ts"]); +const configureNightly = () => + exec(process.execPath, ["scripts/configurePrerelease.mjs", "dev", "package.json", "src/compiler/corePublic.ts"]); task("configure-nightly", series(buildScripts, configureNightly)); task("configure-nightly").description = "Runs scripts/configurePrerelease.ts to prepare a build for nightly publishing"; -const configureInsiders = () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "insiders", "package.json", "src/compiler/corePublic.ts"]); +const configureInsiders = () => + exec(process.execPath, [ + "scripts/configurePrerelease.mjs", + "insiders", + "package.json", + "src/compiler/corePublic.ts", + ]); task("configure-insiders", configureInsiders); -task("configure-insiders").description = "Runs scripts/configurePrerelease.mjs to prepare a build for insiders publishing"; - -const configureExperimental = () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "experimental", "package.json", "src/compiler/corePublic.ts"]); +task("configure-insiders").description = + "Runs scripts/configurePrerelease.mjs to prepare a build for insiders publishing"; + +const configureExperimental = () => + exec(process.execPath, [ + "scripts/configurePrerelease.mjs", + "experimental", + "package.json", + "src/compiler/corePublic.ts", + ]); task("configure-experimental", configureExperimental); -task("configure-experimental").description = "Runs scripts/configurePrerelease.mjs to prepare a build for experimental publishing"; +task("configure-experimental").description = + "Runs scripts/configurePrerelease.mjs to prepare a build for experimental publishing"; const publishNightly = () => exec("npm", ["publish", "--tag", "next"]); task("publish-nightly", series(task("clean"), task("LKG"), task("clean"), task("runtests-parallel"), publishNightly)); @@ -575,13 +657,25 @@ task("publish-nightly").description = "Runs `npm publish --tag next` to create a const watchRuntests = () => watch(["built/local/*.js", "tests/cases/**/*.ts", "tests/cases/**/tsconfig.json"], { delay: 5000 }, async () => { if (cmdLineOptions.tests || cmdLineOptions.failed) { - await runConsoleTests("built/local/run.js", "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ true); + await runConsoleTests( + "built/local/run.js", + "mocha-fivemat-progress-reporter", + /*runInParallel*/ false, + /*watchMode*/ true, + ); } else { await runConsoleTests("built/local/run.js", "min", /*runInParallel*/ true, /*watchMode*/ true); } }); -task("watch", series(preBuild, preTest, parallel(watchLib, watchDiagnostics, watchServices, watchLssl, watchTests, watchRuntests))); +task( + "watch", + series( + preBuild, + preTest, + parallel(watchLib, watchDiagnostics, watchServices, watchLssl, watchTests, watchRuntests), + ), +); task("watch").description = "Watches for changes and rebuilds and runs tests in parallel."; task("watch").flags = { "-t --tests=": "Pattern for tests to run. Forces tests to be run in a single worker.", @@ -590,7 +684,8 @@ task("watch").flags = { " --keepFailed": "Keep tests in .failed-tests even if they pass", " --light": "Run tests in light mode (fewer verifications, but tests run faster)", " --dirty": "Run tests without first cleaning test output directories", - " --stackTraceLimit=": "Sets the maximum number of stack frames to display. Use 'full' to show all frames.", + " --stackTraceLimit=": + "Sets the maximum number of stack frames to display. Use 'full' to show all frames.", " --no-color": "Disables color", " --timeout=": "Overrides the default test timeout.", " --workers=": "The number of parallel workers to use.", diff --git a/scripts/build/prepend.mjs b/scripts/build/prepend.mjs index f8d37da4e25ad..4b2b00ea70a17 100644 --- a/scripts/build/prepend.mjs +++ b/scripts/build/prepend.mjs @@ -14,14 +14,19 @@ export function prepend(data) { * @param {(error: Error | null, data?: any) => void} cb */ transform(input, _, cb) { - if (typeof input === "string" || Buffer.isBuffer(input)) return cb(new Error("Only Vinyl files are supported.")); + if (typeof input === "string" || Buffer.isBuffer(input)) { + return cb(new Error("Only Vinyl files are supported.")); + } if (!input.isBuffer()) return cb(new Error("Streams not supported.")); try { const output = input.clone(); const prependContent = typeof data === "function" ? data(input) : data; output.contents = Buffer.concat([Buffer.from(prependContent, "utf8"), input.contents]); if (input.sourceMap) { - if (typeof input.sourceMap === "string") input.sourceMap = /**@type {import("./sourcemaps.mjs").RawSourceMap}*/ (JSON.parse(input.sourceMap)); + if (typeof input.sourceMap === "string") { + input.sourceMap = + /**@type {import("./sourcemaps.mjs").RawSourceMap}*/ (JSON.parse(input.sourceMap)); + } const lineStarts = /**@type {*}*/ (ts).computeLineStarts(prependContent); let prependMappings = ""; for (let i = 1; i < lineStarts.length; i++) { @@ -55,7 +60,7 @@ export function prepend(data) { * @param {string | ((file: import("vinyl")) => string)} file */ export function prependFile(file) { - const data = typeof file === "string" ? fs.readFileSync(file, "utf8") : - (/** @type {import("vinyl")} */ vinyl) => fs.readFileSync(file(vinyl), "utf8"); + const data = typeof file === "string" ? fs.readFileSync(file, "utf8") + : (/** @type {import("vinyl")} */ vinyl) => fs.readFileSync(file(vinyl), "utf8"); return prepend(data); } diff --git a/scripts/build/projects.mjs b/scripts/build/projects.mjs index f1dd93db0fd59..34b0400a643fb 100644 --- a/scripts/build/projects.mjs +++ b/scripts/build/projects.mjs @@ -36,9 +36,14 @@ class ProjectQueue { } } -const execTsc = (/** @type {boolean} */ lkg, /** @type {string[]} */ ...args) => exec(process.execPath, [resolve(findUpRoot(), lkg ? "./lib/tsc" : "./built/local/tsc"), "-b", ...args], { hidePrompt: true }); +const execTsc = (/** @type {boolean} */ lkg, /** @type {string[]} */ ...args) => + exec(process.execPath, [resolve(findUpRoot(), lkg ? "./lib/tsc" : "./built/local/tsc"), "-b", ...args], { + hidePrompt: true, + }); -const projectBuilder = new ProjectQueue((projects, lkg, force) => execTsc(lkg, ...(force ? ["--force"] : []), ...projects)); +const projectBuilder = new ProjectQueue((projects, lkg, force) => + execTsc(lkg, ...(force ? ["--force"] : []), ...projects) +); /** * @param {string} project diff --git a/scripts/build/sourcemaps.mjs b/scripts/build/sourcemaps.mjs index 8d5a7422dce48..820835800d92a 100644 --- a/scripts/build/sourcemaps.mjs +++ b/scripts/build/sourcemaps.mjs @@ -10,13 +10,13 @@ function fail(message) { * @param {number} value */ function base64FormatEncode(value) { - return value < 0 ? fail("Invalid value") : - value < 26 ? 0x41 /*A*/ + value : - value < 52 ? 0x61 /*a*/ + value - 26 : - value < 62 ? 0x30 /*0*/ + value - 52 : - value === 62 ? 0x2B /*+*/ : - value === 63 ? 0x2F /*/*/ : - fail("Invalid value"); + return value < 0 ? fail("Invalid value") + : value < 26 ? 0x41 /*A*/ + value + : value < 52 ? 0x61 /*a*/ + value - 26 + : value < 62 ? 0x30 /*0*/ + value - 52 + : value === 62 ? 0x2B /*+*/ + : value === 63 ? 0x2F /*/*/ + : fail("Invalid value"); } /** diff --git a/scripts/build/tests.mjs b/scripts/build/tests.mjs index 11139cca9d41f..329eb6c0a2388 100644 --- a/scripts/build/tests.mjs +++ b/scripts/build/tests.mjs @@ -61,7 +61,18 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, _wa } if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed || shards || shardId) { - writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed, shards, shardId); + writeTestConfigFile( + tests, + runners, + light, + taskConfigsFolder, + workerCount, + stackTraceLimit, + testTimeout, + keepFailed, + shards, + shardId, + ); } const colors = cmdLineOptions.colors; @@ -171,7 +182,18 @@ export async function cleanTestDirs() { * @param {number | undefined} [shards] * @param {number | undefined} [shardId] */ -export function writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, timeout, keepFailed, shards, shardId) { +export function writeTestConfigFile( + tests, + runners, + light, + taskConfigsFolder, + workerCount, + stackTraceLimit, + timeout, + keepFailed, + shards, + shardId, +) { const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, runners: runners ? runners.split(",") : undefined, diff --git a/scripts/build/utils.mjs b/scripts/build/utils.mjs index 073ca55f579f7..ea9df06aa110f 100644 --- a/scripts/build/utils.mjs +++ b/scripts/build/utils.mjs @@ -225,10 +225,12 @@ export function rm(dest, opts) { */ write(file, _, cb) { if (failed) return; - if (typeof file === "string" || Buffer.isBuffer(file)) return cb(new Error("Only Vinyl files are supported.")); - const basePath = typeof dest === "string" ? path.resolve(cwd, dest) : - typeof dest === "function" ? path.resolve(cwd, dest(file)) : - file.base; + if (typeof file === "string" || Buffer.isBuffer(file)) { + return cb(new Error("Only Vinyl files are supported.")); + } + const basePath = typeof dest === "string" ? path.resolve(cwd, dest) + : typeof dest === "function" ? path.resolve(cwd, dest(file)) + : file.base; const filePath = path.resolve(basePath, file.relative); file.cwd = cwd; file.base = basePath; diff --git a/scripts/buildProtocol.mjs b/scripts/buildProtocol.mjs index 84ec220e4887c..a18a54e2bebc4 100644 --- a/scripts/buildProtocol.mjs +++ b/scripts/buildProtocol.mjs @@ -16,7 +16,8 @@ function endsWith(s, suffix) { * @returns {boolean} */ function isStringEnum(declaration) { - return !!declaration.members.length && declaration.members.every(m => !!m.initializer && m.initializer.kind === ts.SyntaxKind.StringLiteral); + return !!declaration.members.length + && declaration.members.every(m => !!m.initializer && m.initializer.kind === ts.SyntaxKind.StringLiteral); } class DeclarationsWalker { @@ -91,7 +92,9 @@ class DeclarationsWalker { if (declarations) { for (const decl of declarations) { const sourceFile = decl.getSourceFile(); - if (sourceFile === this.protocolFile || /lib(\..+)?\.d.ts/.test(path.basename(sourceFile.fileName))) { + if ( + sourceFile === this.protocolFile || /lib(\..+)?\.d.ts/.test(path.basename(sourceFile.fileName)) + ) { return; } if (ts.isEnumDeclaration(decl) && !isStringEnum(decl)) { @@ -125,7 +128,9 @@ class DeclarationsWalker { case ts.SyntaxKind.PropertySignature: case ts.SyntaxKind.Parameter: case ts.SyntaxKind.IndexSignature: - const parent = /** @type {ts.VariableDeclaration | ts.MethodDeclaration | ts.PropertyDeclaration | ts.ParameterDeclaration | ts.PropertySignature | ts.MethodSignature | ts.IndexSignatureDeclaration} */ (node.parent); + const parent = + /** @type {ts.VariableDeclaration | ts.MethodDeclaration | ts.PropertyDeclaration | ts.ParameterDeclaration | ts.PropertySignature | ts.MethodSignature | ts.IndexSignatureDeclaration} */ (node + .parent); if (parent.type === node) { this.processTypeOfNode(node); } @@ -134,7 +139,9 @@ class DeclarationsWalker { const heritageClauses = /** @type {ts.InterfaceDeclaration} */ (node.parent).heritageClauses; if (heritageClauses) { if (heritageClauses[0].token !== ts.SyntaxKind.ExtendsKeyword) { - throw new Error(`Unexpected kind of heritage clause: ${ts.SyntaxKind[heritageClauses[0].kind]}`); + throw new Error( + `Unexpected kind of heritage clause: ${ts.SyntaxKind[heritageClauses[0].kind]}`, + ); } for (const type of heritageClauses[0].types) { this.processTypeOfNode(type); @@ -172,14 +179,24 @@ class DeclarationsWalker { */ function writeProtocolFile(outputFile, protocolTs, typeScriptServicesDts) { /** @type {ts.CompilerOptions} */ - const options = { target: ts.ScriptTarget.ES5, declaration: true, noResolve: false, types: [], stripInternal: true }; + const options = { + target: ts.ScriptTarget.ES5, + declaration: true, + noResolve: false, + types: [], + stripInternal: true, + }; /** * 1st pass - generate a program from protocol.ts and typescriptservices.d.ts and emit core version of protocol.d.ts with all internal members stripped * @return text of protocol.d.t.s */ function getInitialDtsFileForProtocol() { - const program = ts.createProgram([protocolTs, typeScriptServicesDts, path.join(typeScriptServicesDts, "../lib.es5.d.ts")], options); + const program = ts.createProgram([ + protocolTs, + typeScriptServicesDts, + path.join(typeScriptServicesDts, "../lib.es5.d.ts"), + ], options); /** @type {string | undefined} */ let protocolDts; @@ -243,18 +260,28 @@ function writeProtocolFile(outputFile, protocolTs, typeScriptServicesDts) { // do sanity check and try to compile generated text as standalone program const sanityCheckProgram = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ false); - const diagnostics = [...sanityCheckProgram.getSyntacticDiagnostics(), ...sanityCheckProgram.getSemanticDiagnostics(), ...sanityCheckProgram.getGlobalDiagnostics()]; + const diagnostics = [ + ...sanityCheckProgram.getSyntacticDiagnostics(), + ...sanityCheckProgram.getSemanticDiagnostics(), + ...sanityCheckProgram.getGlobalDiagnostics(), + ]; ts.sys.writeFile(outputFile, protocolDts); if (diagnostics.length) { - const flattenedDiagnostics = diagnostics.map(d => `${ts.flattenDiagnosticMessageText(d.messageText, "\n")} at ${d.file ? d.file.fileName : ""} line ${d.start}`).join("\n"); + const flattenedDiagnostics = diagnostics.map(d => + `${ts.flattenDiagnosticMessageText(d.messageText, "\n")} at ${ + d.file ? d.file.fileName : "" + } line ${d.start}` + ).join("\n"); throw new Error(`Unexpected errors during sanity check: ${flattenedDiagnostics}`); } } if (process.argv.length < 5) { - console.log(`Expected 3 arguments: path to 'protocol.ts', path to 'typescriptservices.d.ts' and path to output file`); + console.log( + `Expected 3 arguments: path to 'protocol.ts', path to 'typescriptservices.d.ts' and path to output file`, + ); process.exit(1); } diff --git a/scripts/configurePrerelease.mjs b/scripts/configurePrerelease.mjs index 9c4b83ea8f508..9c9127e88b708 100644 --- a/scripts/configurePrerelease.mjs +++ b/scripts/configurePrerelease.mjs @@ -44,7 +44,8 @@ function main() { // Ensure we are actually changing something - the user probably wants to know that the update failed. if (tsFileContents === modifiedTsFileContents) { let err = `\n '${tsFilePath}' was not updated while configuring for a prerelease publish for '${tag}'.\n `; - err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`; + err += + `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`; throw new Error(err + "\n"); } @@ -67,19 +68,31 @@ function main() { function updateTsFile(tsFilePath, tsFileContents, majorMinor, patch, nightlyPatch) { const majorMinorRgx = /export const versionMajorMinor = "(\d+\.\d+)"/; const majorMinorMatch = majorMinorRgx.exec(tsFileContents); - assert(majorMinorMatch !== null, `The file '${tsFilePath}' seems to no longer have a string matching '${majorMinorRgx}'.`); + assert( + majorMinorMatch !== null, + `The file '${tsFilePath}' seems to no longer have a string matching '${majorMinorRgx}'.`, + ); const parsedMajorMinor = majorMinorMatch[1]; - assert(parsedMajorMinor === majorMinor, `versionMajorMinor does not match. ${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`); + assert( + parsedMajorMinor === majorMinor, + `versionMajorMinor does not match. ${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`, + ); const versionRgx = /export const version(?:: string)? = `\$\{versionMajorMinor\}\.(\d)(-\w+)?`;/; const patchMatch = versionRgx.exec(tsFileContents); - assert(patchMatch !== null, `The file '${tsFilePath}' seems to no longer have a string matching '${versionRgx.toString()}'.`); + assert( + patchMatch !== null, + `The file '${tsFilePath}' seems to no longer have a string matching '${versionRgx.toString()}'.`, + ); const parsedPatch = patchMatch[1]; if (parsedPatch !== patch) { throw new Error(`patch does not match. ${tsFilePath}: '${parsedPatch}; package.json: '${patch}'`); } - return tsFileContents.replace(versionRgx, `export const version: string = \`\${versionMajorMinor}.${nightlyPatch}\`;`); + return tsFileContents.replace( + versionRgx, + `export const version: string = \`\${versionMajorMinor}.${nightlyPatch}\`;`, + ); } /** diff --git a/scripts/eslint/rules/boolean-trivia.cjs b/scripts/eslint/rules/boolean-trivia.cjs index 614071891a83a..cfb3b3b4e0532 100644 --- a/scripts/eslint/rules/boolean-trivia.cjs +++ b/scripts/eslint/rules/boolean-trivia.cjs @@ -48,7 +48,8 @@ module.exports = createRule({ return true; } - return ["apply", "call", "equal", "fail", "isTrue", "output", "stringify", "push"].indexOf(methodName) >= 0; + return ["apply", "call", "equal", "fail", "isTrue", "output", "stringify", "push"].indexOf(methodName) + >= 0; } if (node.callee && node.callee.type === AST_NODE_TYPES.Identifier) { diff --git a/scripts/eslint/rules/debug-assert.cjs b/scripts/eslint/rules/debug-assert.cjs index c412fa45fac54..c5081cc65dbbb 100644 --- a/scripts/eslint/rules/debug-assert.cjs +++ b/scripts/eslint/rules/debug-assert.cjs @@ -10,7 +10,8 @@ module.exports = createRule({ }, messages: { secondArgumentDebugAssertError: `Second argument to 'Debug.assert' should be a string literal`, - thirdArgumentDebugAssertError: `Third argument to 'Debug.assert' should be a string literal or arrow function`, + thirdArgumentDebugAssertError: + `Third argument to 'Debug.assert' should be a string literal or arrow function`, }, schema: [], type: "problem", @@ -22,7 +23,8 @@ module.exports = createRule({ const isArrowFunction = node => node.type === AST_NODE_TYPES.ArrowFunctionExpression; /** @type {(node: TSESTree.Node) => boolean} */ const isStringLiteral = node => ( - (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") || node.type === AST_NODE_TYPES.TemplateLiteral + (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") + || node.type === AST_NODE_TYPES.TemplateLiteral ); /** @type {(node: TSESTree.MemberExpression) => boolean} */ diff --git a/scripts/eslint/rules/no-double-space.cjs b/scripts/eslint/rules/no-double-space.cjs index 5dd933803b105..9a3d1205663c8 100644 --- a/scripts/eslint/rules/no-double-space.cjs +++ b/scripts/eslint/rules/no-double-space.cjs @@ -23,15 +23,16 @@ module.exports = createRule({ /** @type {(node: TSESTree.Node | null) => boolean} */ const isStringLiteral = node => { return !!(node && ( - (node.type === AST_NODE_TYPES.TemplateElement) || - (node.type === AST_NODE_TYPES.TemplateLiteral && node.quasis) || - (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") + (node.type === AST_NODE_TYPES.TemplateElement) + || (node.type === AST_NODE_TYPES.TemplateLiteral && node.quasis) + || (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") )); }; /** @type {(node: TSESTree.Node | null) => boolean} */ const isRegexLiteral = node => { - return !!(node && node.type === AST_NODE_TYPES.Literal && Object.prototype.hasOwnProperty.call(node, "regex")); + return !!(node && node.type === AST_NODE_TYPES.Literal + && Object.prototype.hasOwnProperty.call(node, "regex")); }; /** @type {(node: TSESTree.Node) => void} */ @@ -62,7 +63,11 @@ module.exports = createRule({ return; } - context.report({ messageId: "noDoubleSpaceError", node, loc: { line: index + 1, column: doubleSpace.index + 1 } }); + context.report({ + messageId: "noDoubleSpaceError", + node, + loc: { line: index + 1, column: doubleSpace.index + 1 }, + }); }); }; diff --git a/scripts/eslint/rules/no-keywords.cjs b/scripts/eslint/rules/no-keywords.cjs index 6def4c45e9994..a441048845747 100644 --- a/scripts/eslint/rules/no-keywords.cjs +++ b/scripts/eslint/rules/no-keywords.cjs @@ -47,10 +47,10 @@ module.exports = createRule({ const checkProperties = node => { node.properties.forEach(property => { if ( - property && - property.type === AST_NODE_TYPES.Property && - property.key.type === AST_NODE_TYPES.Identifier && - isKeyword(property.key.name) + property + && property.type === AST_NODE_TYPES.Property + && property.key.type === AST_NODE_TYPES.Identifier + && isKeyword(property.key.name) ) { report(property.key); } @@ -61,9 +61,9 @@ module.exports = createRule({ const checkElements = node => { node.elements.forEach(element => { if ( - element && - element.type === AST_NODE_TYPES.Identifier && - isKeyword(element.name) + element + && element.type === AST_NODE_TYPES.Identifier + && isKeyword(element.name) ) { report(element); } @@ -78,9 +78,9 @@ module.exports = createRule({ node.params.forEach(param => { if ( - param && - param.type === AST_NODE_TYPES.Identifier && - isKeyword(param.name) + param + && param.type === AST_NODE_TYPES.Identifier + && isKeyword(param.name) ) { report(param); } @@ -98,8 +98,8 @@ module.exports = createRule({ } if ( - node.id.type === AST_NODE_TYPES.Identifier && - isKeyword(node.id.name) + node.id.type === AST_NODE_TYPES.Identifier + && isKeyword(node.id.name) ) { report(node.id); } diff --git a/scripts/eslint/rules/only-arrow-functions.cjs b/scripts/eslint/rules/only-arrow-functions.cjs index 4c76c76c76be0..f42ecc06647f9 100644 --- a/scripts/eslint/rules/only-arrow-functions.cjs +++ b/scripts/eslint/rules/only-arrow-functions.cjs @@ -29,7 +29,9 @@ module.exports = createRule({ create(context, [{ allowNamedFunctions, allowDeclarations }]) { /** @type {(node: TSESTree.FunctionDeclaration | TSESTree.FunctionExpression) => boolean} */ - const isThisParameter = node => !!node.params.length && !!node.params.find(param => param.type === AST_NODE_TYPES.Identifier && param.name === "this"); + const isThisParameter = node => + !!node.params.length + && !!node.params.find(param => param.type === AST_NODE_TYPES.Identifier && param.name === "this"); /** @type {(node: TSESTree.Node) => boolean} */ const isMethodType = node => { diff --git a/scripts/failed-tests.cjs b/scripts/failed-tests.cjs index cec61e8eb157c..7396364f4ca71 100644 --- a/scripts/failed-tests.cjs +++ b/scripts/failed-tests.cjs @@ -137,17 +137,23 @@ class FailedTestsReporter extends Mocha.reporters.Base { done(failures, fn) { assert(this.reporterOptions); assert(this.reporterOptions.file); - FailedTestsReporter.writeFailures(this.reporterOptions.file, this.passes, this.failures, this.reporterOptions.keepFailed || this.stats.tests === 0, err => { - const reporter = this.reporter; - if (reporter && reporter.done) { - reporter.done(failures, fn); - } - else if (fn) { - fn(failures); - } + FailedTestsReporter.writeFailures( + this.reporterOptions.file, + this.passes, + this.failures, + this.reporterOptions.keepFailed || this.stats.tests === 0, + err => { + const reporter = this.reporter; + if (reporter && reporter.done) { + reporter.done(failures, fn); + } + else if (fn) { + fn(failures); + } - if (err) console.error(err); - }); + if (err) console.error(err); + }, + ); } } diff --git a/scripts/generateLocalizedDiagnosticMessages.mjs b/scripts/generateLocalizedDiagnosticMessages.mjs index e34f9276e44f6..68b83f64af4a7 100644 --- a/scripts/generateLocalizedDiagnosticMessages.mjs +++ b/scripts/generateLocalizedDiagnosticMessages.mjs @@ -6,7 +6,9 @@ function main() { const args = process.argv.slice(2); if (args.length !== 3) { console.log("Usage:"); - console.log("\tnode generateLocalizedDiagnosticMessages.js "); + console.log( + "\tnode generateLocalizedDiagnosticMessages.js ", + ); return; } @@ -44,7 +46,10 @@ function main() { console.error(`Invalid output locale name for '${result.LCX.$.TgtCul}'.`); process.exit(1); } - writeFile(path.join(outputPath, outputDirectoryName, "diagnosticMessages.generated.json"), xmlObjectToString(result)); + writeFile( + path.join(outputPath, outputDirectoryName, "diagnosticMessages.generated.json"), + xmlObjectToString(result), + ); }); }); } diff --git a/scripts/importDefinitelyTypedTests.mjs b/scripts/importDefinitelyTypedTests.mjs index a48c597b87bb4..5c6fc975beeb7 100644 --- a/scripts/importDefinitelyTypedTests.mjs +++ b/scripts/importDefinitelyTypedTests.mjs @@ -15,7 +15,9 @@ function main() { throw new Error("Expected at least 2 argv elements."); } console.log("Usage:"); - console.log(` node ${path.relative(__dirname, progName)} [TypeScript Repo Root] [DefinitelyTyped Repo Root]`); + console.log( + ` node ${path.relative(__dirname, progName)} [TypeScript Repo Root] [DefinitelyTyped Repo Root]`, + ); return; } @@ -37,7 +39,8 @@ function main() { function filePathEndsWith(path, endingString) { const pathLen = path.length; const extLen = endingString.length; - return pathLen > extLen && path.substr(pathLen - extLen, extLen).toLocaleLowerCase() === endingString.toLocaleLowerCase(); + return pathLen > extLen + && path.substr(pathLen - extLen, extLen).toLocaleLowerCase() === endingString.toLocaleLowerCase(); } /** @@ -159,7 +162,9 @@ function importDefinitelyTypedTests(tscPath, rwcTestPath, definitelyTypedRoot) { const regexp = new RegExp(d + "(([-][0-9])|([\.]d[\.]ts))"); if (tsFiles.length > 1 && tsFiles.every(t => filePathEndsWith(t, ".d.ts") && regexp.test(t))) { for (const fileName of tsFiles) { - importDefinitelyTypedTest(tscPath, rwcTestPath, path.basename(fileName, ".d.ts"), [fileName], paramFile); + importDefinitelyTypedTest(tscPath, rwcTestPath, path.basename(fileName, ".d.ts"), [ + fileName, + ], paramFile); } } else { @@ -168,7 +173,9 @@ function importDefinitelyTypedTests(tscPath, rwcTestPath, definitelyTypedRoot) { } else { for (const fileName of tsFiles) { - importDefinitelyTypedTest(tscPath, rwcTestPath, path.basename(fileName, "-tests.ts"), [fileName], paramFile); + importDefinitelyTypedTest(tscPath, rwcTestPath, path.basename(fileName, "-tests.ts"), [ + fileName, + ], paramFile); } } }); diff --git a/scripts/open-cherry-pick-pr.mjs b/scripts/open-cherry-pick-pr.mjs index 24ca8a0f01054..2067e1db5c12a 100644 --- a/scripts/open-cherry-pick-pr.mjs +++ b/scripts/open-cherry-pick-pr.mjs @@ -31,9 +31,13 @@ async function main() { auth: process.argv[2], }); - const inputPR = (await gh.pulls.get({ pull_number: +process.env.SOURCE_ISSUE, owner: "microsoft", repo: "TypeScript" })).data; + const inputPR = + (await gh.pulls.get({ pull_number: +process.env.SOURCE_ISSUE, owner: "microsoft", repo: "TypeScript" })).data; let remoteName = "origin"; - if (inputPR.base.repo.git_url !== `git:github.com/microsoft/TypeScript` && inputPR.base.repo.git_url !== `git://github.com/microsoft/TypeScript`) { + if ( + inputPR.base.repo.git_url !== `git:github.com/microsoft/TypeScript` + && inputPR.base.repo.git_url !== `git://github.com/microsoft/TypeScript` + ) { runSequence([ ["git", ["remote", "add", "nonlocal", inputPR.base.repo.git_url.replace(/^git:(?:\/\/)?/, "https://")]], ]); @@ -85,11 +89,16 @@ ${logText.trim()}`; owner: "Microsoft", repo: "TypeScript", maintainer_can_modify: true, - title: `🤖 Pick PR #${process.env.SOURCE_ISSUE} (${inputPR.title.substring(0, 35)}${inputPR.title.length > 35 ? "..." : ""}) into ${process.env.TARGET_BRANCH}`, + title: `🤖 Pick PR #${process.env.SOURCE_ISSUE} (${inputPR.title.substring(0, 35)}${ + inputPR.title.length > 35 ? "..." : "" + }) into ${process.env.TARGET_BRANCH}`, head: `${userName}:${branchName}`, base: process.env.TARGET_BRANCH, - body: `This cherry-pick was triggered by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} -Please review the diff and merge if no changes are unexpected.${produceLKG ? ` An LKG update commit is included separately from the base change.` : ""} + body: + `This cherry-pick was triggered by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} +Please review the diff and merge if no changes are unexpected.${ + produceLKG ? ` An LKG update commit is included separately from the base change.` : "" + } You can view the cherry-pick log [here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary). cc ${reviewers.map(r => "@" + r).join(" ")}`, @@ -116,7 +125,8 @@ main().catch(async e => { issue_number: +process.env.SOURCE_ISSUE, owner: "Microsoft", repo: "TypeScript", - body: `Hey @${process.env.REQUESTING_USER}, I couldn't open a PR with the cherry-pick. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)). You may need to squash and pick this PR into ${process.env.TARGET_BRANCH} manually.`, + body: + `Hey @${process.env.REQUESTING_USER}, I couldn't open a PR with the cherry-pick. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)). You may need to squash and pick this PR into ${process.env.TARGET_BRANCH} manually.`, }); } }); diff --git a/scripts/open-user-pr.mjs b/scripts/open-user-pr.mjs index c65881210b36c..33d4083957261 100644 --- a/scripts/open-user-pr.mjs +++ b/scripts/open-user-pr.mjs @@ -2,10 +2,12 @@ import { Octokit } from "@octokit/rest"; import { runSequence } from "./run-sequence.mjs"; const userName = process.env.GH_USERNAME || "typescript-bot"; -const reviewers = process.env.REQUESTING_USER ? [process.env.REQUESTING_USER] : ["weswigham", "sandersn", "RyanCavanaugh"]; +const reviewers = process.env.REQUESTING_USER ? [process.env.REQUESTING_USER] + : ["weswigham", "sandersn", "RyanCavanaugh"]; const masterBranchname = `user-baseline-updates`; const targetBranch = process.env.TARGET_BRANCH || "main"; -const branchName = process.env.TARGET_FORK?.toLowerCase() === "microsoft" && (targetBranch === "main" || targetBranch === "refs/heads/main") +const branchName = process.env.TARGET_FORK?.toLowerCase() === "microsoft" + && (targetBranch === "main" || targetBranch === "refs/heads/main") ? masterBranchname : `user-update-${process.env.TARGET_FORK}-${process.env.TARGET_BRANCH ? "-" + process.env.TARGET_BRANCH : ""}`; const remoteUrl = `https://${process.argv[2]}@github.com/${userName}/TypeScript.git`; @@ -18,7 +20,11 @@ runSequence([ ["node", ["./node_modules/gulp/bin/gulp.js", "baseline-accept"]], // accept baselines ["git", ["checkout", "-b", branchName]], // create a branch ["git", ["add", "."]], // Add all changes - ["git", ["commit", "-m", `"Update user baselines${+(process.env.SOURCE_ISSUE ?? 0) === 33716 ? " +cc @sandersn" : ""}"`]], // Commit all changes (ping nathan if we would post to CI thread) + ["git", [ + "commit", + "-m", + `"Update user baselines${+(process.env.SOURCE_ISSUE ?? 0) === 33716 ? " +cc @sandersn" : ""}"`, + ]], // Commit all changes (ping nathan if we would post to CI thread) ["git", ["push", "--set-upstream", "fork", branchName, "-f"]], // push the branch ]); @@ -30,10 +36,15 @@ gh.pulls.create({ owner: prOwner, repo: "TypeScript", maintainer_can_modify: true, - title: `🤖 User test baselines have changed` + (process.env.TARGET_BRANCH ? ` for ${process.env.TARGET_BRANCH}` : ""), + title: `🤖 User test baselines have changed` + + (process.env.TARGET_BRANCH ? ` for ${process.env.TARGET_BRANCH}` : ""), head: `${userName}:${branchName}`, base: branchName === masterBranchname ? "main" : masterBranchname, - body: `${process.env.SOURCE_ISSUE ? `This test run was triggerd by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} ` + "\n" : ""}Please review the diff and merge if no changes are unexpected. + body: `${ + process.env.SOURCE_ISSUE + ? `This test run was triggerd by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} ` + + "\n" : "" + }Please review the diff and merge if no changes are unexpected. You can view the build log [here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary). cc ${reviewers.map(r => "@" + r).join(" ")}`, @@ -53,7 +64,8 @@ cc ${reviewers.map(r => "@" + r).join(" ")}`, issue_number: +process.env.SOURCE_ISSUE, owner: "microsoft", repo: "TypeScript", - body: `The user suite test run you requested has finished and _failed_. I've opened a [PR with the baseline diff from master](${r.data.html_url}).`, + body: + `The user suite test run you requested has finished and _failed_. I've opened a [PR with the baseline diff from master](${r.data.html_url}).`, }); } }).then(() => { diff --git a/scripts/perf-result-post.mjs b/scripts/perf-result-post.mjs index 050226b2041ce..ef0baf32884e7 100644 --- a/scripts/perf-result-post.mjs +++ b/scripts/perf-result-post.mjs @@ -30,7 +30,10 @@ async function main() { let benchmarkText = ""; if (includeArtifact === "--include-artifact") { // post a link to the benchmark file - const cli = new ado.WebApi("https://typescript.visualstudio.com/defaultcollection", ado.getHandlerFromToken("")); // Empty token, anon auth + const cli = new ado.WebApi( + "https://typescript.visualstudio.com/defaultcollection", + ado.getHandlerFromToken(""), + ); // Empty token, anon auth const build = await cli.getBuildApi(); const artifact = await build.getArtifact("typescript", +buildId, "benchmark"); assert(artifact.resource?.url); @@ -41,7 +44,8 @@ async function main() { if (/[\\/]linux\.benchmark$/.test(file.path)) { const benchmarkUrl = new URL(artifact.resource.url); benchmarkUrl.search = `artifactName=benchmark&fileId=${file.blob.id}&fileName=linux.benchmark`; - benchmarkText = `\n
Developer Information:

Download Benchmark

\n`; + benchmarkText = + `\n
Developer Information:

Download Benchmark

\n`; break; } } @@ -51,7 +55,8 @@ async function main() { issue_number: +source, owner: "Microsoft", repo: "TypeScript", - body: `@${requester}\nThe results of the perf run you requested are in!\n
Here they are:

\n${outputTableText}\n

${benchmarkText}
`, + body: + `@${requester}\nThe results of the perf run you requested are in!\n
Here they are:

\n${outputTableText}\n

${benchmarkText}
`, }); console.log(`Results posted!`); @@ -75,7 +80,8 @@ async function main() { issue_number: +source, owner: "Microsoft", repo: "TypeScript", - body: `Hey @${requester}, something went wrong when publishing results. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${buildId}&_a=summary)).`, + body: + `Hey @${requester}, something went wrong when publishing results. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${buildId}&_a=summary)).`, }); } } diff --git a/scripts/post-vsts-artifact-comment.mjs b/scripts/post-vsts-artifact-comment.mjs index 0508c1b3fc65e..1c4cf7ec06b9e 100644 --- a/scripts/post-vsts-artifact-comment.mjs +++ b/scripts/post-vsts-artifact-comment.mjs @@ -33,7 +33,8 @@ async function main() { issue_number: +process.env.SOURCE_ISSUE, owner: "Microsoft", repo: "TypeScript", - body: `Hey @${process.env.REQUESTING_USER}, I've packed this into [an installable tgz](${link}). You can install it for testing by referencing it in your \`package.json\` like so: + body: + `Hey @${process.env.REQUESTING_USER}, I've packed this into [an installable tgz](${link}). You can install it for testing by referencing it in your \`package.json\` like so: \`\`\` { "devDependencies": { @@ -47,7 +48,10 @@ and then running \`npm install\`. // Temporarily disable until we get access controls set up right // Send a ping to https://github.com/microsoft/typescript-make-monaco-builds#pull-request-builds - await gh.request("POST /repos/microsoft/typescript-make-monaco-builds/dispatches", { event_type: process.env.SOURCE_ISSUE, headers: { Accept: "application/vnd.github.everest-preview+json" } }); + await gh.request("POST /repos/microsoft/typescript-make-monaco-builds/dispatches", { + event_type: process.env.SOURCE_ISSUE, + headers: { Accept: "application/vnd.github.everest-preview+json" }, + }); } main().catch(async e => { @@ -61,7 +65,8 @@ main().catch(async e => { issue_number: +process.env.SOURCE_ISSUE, owner: "Microsoft", repo: "TypeScript", - body: `Hey @${process.env.REQUESTING_USER}, something went wrong when looking for the build artifact. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)).`, + body: + `Hey @${process.env.REQUESTING_USER}, something went wrong when looking for the build artifact. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)).`, }); } }); diff --git a/scripts/processDiagnosticMessages.mjs b/scripts/processDiagnosticMessages.mjs index 66cdbebae751e..78053b6c3bb14 100644 --- a/scripts/processDiagnosticMessages.mjs +++ b/scripts/processDiagnosticMessages.mjs @@ -47,7 +47,11 @@ function main() { const outputFilesDir = path.dirname(inputFilePath); const thisFilePathRel = path.relative(process.cwd(), outputFilesDir); - const infoFileOutput = buildInfoFileOutput(diagnosticMessages, `./${path.basename(inputFilePath)}`, thisFilePathRel); + const infoFileOutput = buildInfoFileOutput( + diagnosticMessages, + `./${path.basename(inputFilePath)}`, + thisFilePathRel, + ); checkForUniqueCodes(diagnosticMessages); writeFile("diagnosticInformationMap.generated.ts", infoFileOutput); @@ -76,22 +80,35 @@ function checkForUniqueCodes(diagnosticTable) { * @returns {string} */ function buildInfoFileOutput(messageTable, inputFilePathRel, thisFilePathRel) { - let result = "// \r\n" + - "// generated from '" + inputFilePathRel + "' in '" + thisFilePathRel.replace(/\\/g, "/") + "'\r\n" + - "/* @internal */\r\n" + - "namespace ts {\r\n" + - " function diag(code: number, category: DiagnosticCategory, key: string, message: string, reportsUnnecessary?: {}, elidedInCompatabilityPyramid?: boolean, reportsDeprecated?: {}): DiagnosticMessage {\r\n" + - " return { code, category, key, message, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated };\r\n" + - " }\r\n" + - " export const Diagnostics = {\r\n"; - messageTable.forEach(({ code, category, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated }, name) => { - const propName = convertPropertyName(name); - const argReportsUnnecessary = reportsUnnecessary ? `, /*reportsUnnecessary*/ ${reportsUnnecessary}` : ""; - const argElidedInCompatabilityPyramid = elidedInCompatabilityPyramid ? `${!reportsUnnecessary ? ", /*reportsUnnecessary*/ undefined" : ""}, /*elidedInCompatabilityPyramid*/ ${elidedInCompatabilityPyramid}` : ""; - const argReportsDeprecated = reportsDeprecated ? `${!argElidedInCompatabilityPyramid ? ", /*reportsUnnecessary*/ undefined, /*elidedInCompatabilityPyramid*/ undefined" : ""}, /*reportsDeprecated*/ ${reportsDeprecated}` : ""; - - result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}${argReportsUnnecessary}${argElidedInCompatabilityPyramid}${argReportsDeprecated}),\r\n`; - }); + let result = "// \r\n" + + "// generated from '" + inputFilePathRel + "' in '" + thisFilePathRel.replace(/\\/g, "/") + "'\r\n" + + "/* @internal */\r\n" + + "namespace ts {\r\n" + + " function diag(code: number, category: DiagnosticCategory, key: string, message: string, reportsUnnecessary?: {}, elidedInCompatabilityPyramid?: boolean, reportsDeprecated?: {}): DiagnosticMessage {\r\n" + + " return { code, category, key, message, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated };\r\n" + + " }\r\n" + + " export const Diagnostics = {\r\n"; + messageTable.forEach( + ({ code, category, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated }, name) => { + const propName = convertPropertyName(name); + const argReportsUnnecessary = reportsUnnecessary ? `, /*reportsUnnecessary*/ ${reportsUnnecessary}` : ""; + const argElidedInCompatabilityPyramid = elidedInCompatabilityPyramid + ? `${ + !reportsUnnecessary ? ", /*reportsUnnecessary*/ undefined" : "" + }, /*elidedInCompatabilityPyramid*/ ${elidedInCompatabilityPyramid}` : ""; + const argReportsDeprecated = reportsDeprecated + ? `${ + !argElidedInCompatabilityPyramid + ? ", /*reportsUnnecessary*/ undefined, /*elidedInCompatabilityPyramid*/ undefined" : "" + }, /*reportsDeprecated*/ ${reportsDeprecated}` : ""; + + result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${ + createKey(propName, code) + }", ${ + JSON.stringify(name) + }${argReportsUnnecessary}${argElidedInCompatabilityPyramid}${argReportsDeprecated}),\r\n`; + }, + ); result += " };\r\n}"; diff --git a/scripts/produceLKG.mjs b/scripts/produceLKG.mjs index 6861f4f7d64c3..26ae90e358e73 100644 --- a/scripts/produceLKG.mjs +++ b/scripts/produceLKG.mjs @@ -34,8 +34,8 @@ async function copyLocalizedDiagnostics() { for (const d of dir) { const fileName = path.join(source, d); if ( - fs.statSync(fileName).isDirectory() && - ignoredFolders.indexOf(d) < 0 + fs.statSync(fileName).isDirectory() + && ignoredFolders.indexOf(d) < 0 ) { await fs.copy(fileName, path.join(dest, d)); } diff --git a/scripts/regenerate-unicode-identifier-parts.mjs b/scripts/regenerate-unicode-identifier-parts.mjs index e993a40e7a8d9..a21b0bf848eea 100644 --- a/scripts/regenerate-unicode-identifier-parts.mjs +++ b/scripts/regenerate-unicode-identifier-parts.mjs @@ -2,7 +2,9 @@ const MAX_UNICODE_CODEPOINT = 0x10FFFF; /** @type {(c: string) => boolean} */ const isStart = c => /[\p{ID_Start}\u{2118}\u{212E}\u{309B}\u{309C}]/u.test(c); // Other_ID_Start explicitly included for back compat - see http://www.unicode.org/reports/tr31/#Introduction /** @type {(c: string) => boolean} */ -const isPart = c => /[\p{ID_Continue}\u{00B7}\u{0387}\u{19DA}\u{1369}\u{136A}\u{136B}\u{136C}\u{136D}\u{136E}\u{136F}\u{1370}\u{1371}]/u.test(c) || isStart(c); // Likewise for Other_ID_Continue +const isPart = c => + /[\p{ID_Continue}\u{00B7}\u{0387}\u{19DA}\u{1369}\u{136A}\u{136B}\u{136C}\u{136D}\u{136E}\u{136F}\u{1370}\u{1371}]/u + .test(c) || isStart(c); // Likewise for Other_ID_Continue const parts = []; let partsActive = false; let startsActive = false; diff --git a/scripts/run-sequence.mjs b/scripts/run-sequence.mjs index 910c9e5e5182d..96ccb1e220cb1 100644 --- a/scripts/run-sequence.mjs +++ b/scripts/run-sequence.mjs @@ -11,7 +11,13 @@ export function runSequence(tasks, opts = { timeout: 100000, shell: true }) { for (const task of tasks) { console.log(`${task[0]} ${task[1].join(" ")}`); const result = cp.spawnSync(task[0], task[1], opts); - if (result.status !== 0) throw new Error(`${task[0]} ${task[1].join(" ")} failed: ${result.stderr && "stderr: " + result.stderr.toString()}${result.stdout && "\nstdout: " + result.stdout.toString()}`); + if (result.status !== 0) { + throw new Error( + `${task[0]} ${task[1].join(" ")} failed: ${result.stderr && "stderr: " + result.stderr.toString()}${ + result.stdout && "\nstdout: " + result.stdout.toString() + }`, + ); + } console.log(result.stdout && result.stdout.toString()); lastResult = result; } diff --git a/scripts/types/ambient.d.ts b/scripts/types/ambient.d.ts index d1e885009a8bd..f46aaebc54cc8 100644 --- a/scripts/types/ambient.d.ts +++ b/scripts/types/ambient.d.ts @@ -4,7 +4,9 @@ declare module "gulp-insert" { export function append(text: string | Buffer): NodeJS.ReadWriteStream; export function prepend(text: string | Buffer): NodeJS.ReadWriteStream; export function wrap(text: string | Buffer, tail: string | Buffer): NodeJS.ReadWriteStream; - export function transform(cb: (contents: string, file: { path: string; relative: string; }) => string): NodeJS.ReadWriteStream; // file is a vinyl file + export function transform( + cb: (contents: string, file: { path: string; relative: string; }) => string, + ): NodeJS.ReadWriteStream; // file is a vinyl file } declare module "sorcery"; diff --git a/scripts/update-experimental-branches.mjs b/scripts/update-experimental-branches.mjs index cf32673880c02..8a12b7a66e0e0 100644 --- a/scripts/update-experimental-branches.mjs +++ b/scripts/update-experimental-branches.mjs @@ -49,7 +49,8 @@ async function main() { owner: "Microsoft", repo: "TypeScript", issue_number: num, - body: `This PR is configured as an experiment, and currently has rebase conflicts with main - please rebase onto main and fix the conflicts.`, + body: + `This PR is configured as an experiment, and currently has rebase conflicts with main - please rebase onto main and fix the conflicts.`, }); } throw new Error(`Rebase conflict detected in PR ${num} with main`); // A PR is currently in conflict, give up diff --git a/scripts/word2md.mjs b/scripts/word2md.mjs index 2456d09413d19..4640957b4c71a 100644 --- a/scripts/word2md.mjs +++ b/scripts/word2md.mjs @@ -109,7 +109,19 @@ function convertDocumentToMarkdown(doc) { const replace = find.replacement; replace.clearFormatting(); setProperties(replace, replaceOptions); - find.execute(findText, /* matchCase */ false, /* matchWholeWord */ false, /* matchWildcards */ false, /* matchSoundsLike */ false, /* matchAllWordForms */ false, /* forward */ true, 0, /* format */ true, replaceText, 2); + find.execute( + findText, + /* matchCase */ false, + /* matchWholeWord */ false, + /* matchWildcards */ false, + /* matchSoundsLike */ false, + /* matchAllWordForms */ false, + /* forward */ true, + 0, + /* format */ true, + replaceText, + 2, + ); } function fixHyperlinks() { @@ -224,7 +236,10 @@ function convertDocumentToMarkdown(doc) { break; case "Grammar": - write("  " + text.replace(/\s\s\s/g, " ").replace(/\x0B/g, " \n   ") + "\n\n"); + write( + "  " + text.replace(/\s\s\s/g, " ").replace(/\x0B/g, " \n   ") + + "\n\n", + ); break; case "Code": @@ -261,7 +276,10 @@ function convertDocumentToMarkdown(doc) { case "TOC": const strings = text.split("\t"); - write(" ".substr(0, level * 2 - 2) + "* [" + strings[0] + " " + strings[1] + "](#" + strings[0] + ")\n"); + write( + " ".substr(0, level * 2 - 2) + "* [" + strings[0] + " " + strings[1] + "](#" + strings[0] + + ")\n", + ); break; } diff --git a/src/cancellationToken/cancellationToken.ts b/src/cancellationToken/cancellationToken.ts index b458b683fa7e0..e0352514a0e10 100644 --- a/src/cancellationToken/cancellationToken.ts +++ b/src/cancellationToken/cancellationToken.ts @@ -42,7 +42,9 @@ function createCancellationToken(args: string[]): ServerCancellationToken { if (cancellationPipeName.charAt(cancellationPipeName.length - 1) === "*") { const namePrefix = cancellationPipeName.slice(0, -1); if (namePrefix.length === 0 || namePrefix.indexOf("*") >= 0) { - throw new Error("Invalid name for template cancellation pipe: it should have length greater than 2 characters and contain only one '*'."); + throw new Error( + "Invalid name for template cancellation pipe: it should have length greater than 2 characters and contain only one '*'.", + ); } let perRequestPipeName: string | undefined; let currentRequestId: number; diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 939ed510c74ce..d7f35f9174fd4 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -14,7 +14,10 @@ namespace ts { referenced: boolean; } - export function getModuleInstanceState(node: ModuleDeclaration, visited?: ESMap): ModuleInstanceState { + export function getModuleInstanceState( + node: ModuleDeclaration, + visited?: ESMap, + ): ModuleInstanceState { if (node.body && !node.body.parent) { // getModuleInstanceStateForAliasTarget needs to walk up the parent chain, so parent pointers must be set on this tree already setParent(node.body, node); @@ -34,7 +37,10 @@ namespace ts { return result; } - function getModuleInstanceStateWorker(node: Node, visited: ESMap): ModuleInstanceState { + function getModuleInstanceStateWorker( + node: Node, + visited: ESMap, + ): ModuleInstanceState { // A module is uninstantiated if it contains only switch (node.kind) { // 1. interface declarations, type alias declarations @@ -57,7 +63,10 @@ namespace ts { // 4. Export alias declarations pointing at only uninstantiated modules or things uninstantiated modules contain case SyntaxKind.ExportDeclaration: const exportDeclaration = node as ExportDeclaration; - if (!exportDeclaration.moduleSpecifier && exportDeclaration.exportClause && exportDeclaration.exportClause.kind === SyntaxKind.NamedExports) { + if ( + !exportDeclaration.moduleSpecifier && exportDeclaration.exportClause + && exportDeclaration.exportClause.kind === SyntaxKind.NamedExports + ) { let state = ModuleInstanceState.NonInstantiated; for (const specifier of exportDeclaration.exportClause.elements) { const specifierState = getModuleInstanceStateForAliasTarget(specifier, visited); @@ -106,7 +115,10 @@ namespace ts { return ModuleInstanceState.Instantiated; } - function getModuleInstanceStateForAliasTarget(specifier: ExportSpecifier, visited: ESMap) { + function getModuleInstanceStateForAliasTarget( + specifier: ExportSpecifier, + visited: ESMap, + ) { const name = specifier.propertyName || specifier.name; let p: Node | undefined = specifier.parent; while (p) { @@ -231,8 +243,21 @@ namespace ts { * If so, the node _must_ be in the current file (as that's the only way anything could have traversed to it to yield it as the error node) * This version of `createDiagnosticForNode` uses the binder's context to account for this, and always yields correct diagnostics even in these situations. */ - function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation { - return createDiagnosticForNodeInSourceFile(getSourceFileOfNode(node) || file, node, message, arg0, arg1, arg2); + function createDiagnosticForNode( + node: Node, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + ): DiagnosticWithLocation { + return createDiagnosticForNodeInSourceFile( + getSourceFileOfNode(node) || file, + node, + message, + arg0, + arg1, + arg2, + ); } function bindSourceFile(f: SourceFile, opts: CompilerOptions) { @@ -304,16 +329,26 @@ namespace ts { node.symbol = symbol; symbol.declarations = appendIfUnique(symbol.declarations, node); - if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.Module | SymbolFlags.Variable) && !symbol.exports) { + if ( + symbolFlags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.Module | SymbolFlags.Variable) + && !symbol.exports + ) { symbol.exports = createSymbolTable(); } - if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && !symbol.members) { + if ( + symbolFlags + & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) + && !symbol.members + ) { symbol.members = createSymbolTable(); } // On merge of const enum module with class or function, reset const enum only flag (namespaces will already recalculate) - if (symbol.constEnumOnlyModule && (symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum))) { + if ( + symbol.constEnumOnlyModule + && (symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum)) + ) { symbol.constEnumOnlyModule = false; } @@ -326,14 +361,16 @@ namespace ts { // unless it is a well known Symbol. function getDeclarationName(node: Declaration): __String | undefined { if (node.kind === SyntaxKind.ExportAssignment) { - return (node as ExportAssignment).isExportEquals ? InternalSymbolName.ExportEquals : InternalSymbolName.Default; + return (node as ExportAssignment).isExportEquals ? InternalSymbolName.ExportEquals + : InternalSymbolName.Default; } const name = getNameOfDeclaration(node); if (name) { if (isAmbientModule(node)) { const moduleName = getTextOfIdentifierOrLiteral(name as Identifier | StringLiteral); - return (isGlobalScopeAugmentation(node as ModuleDeclaration) ? "__global" : `"${moduleName}"`) as __String; + return (isGlobalScopeAugmentation(node as ModuleDeclaration) ? "__global" + : `"${moduleName}"`) as __String; } if (name.kind === SyntaxKind.ComputedPropertyName) { const nameExpression = name.expression; @@ -379,7 +416,10 @@ namespace ts { // module.exports = ... return InternalSymbolName.ExportEquals; case SyntaxKind.BinaryExpression: - if (getAssignmentDeclarationKind(node as BinaryExpression) === AssignmentDeclarationKind.ModuleExports) { + if ( + getAssignmentDeclarationKind(node as BinaryExpression) + === AssignmentDeclarationKind.ModuleExports + ) { // module.exports = ... return InternalSymbolName.ExportEquals; } @@ -390,7 +430,11 @@ namespace ts { case SyntaxKind.Parameter: // Parameters with names are handled at the top of this function. Parameters // without names can only come from JSDocFunctionTypes. - Debug.assert(node.parent.kind === SyntaxKind.JSDocFunctionType, "Impossible parameter parent kind", () => `parent is: ${Debug.formatSyntaxKind(node.parent.kind)}, expected JSDocFunctionType`); + Debug.assert( + node.parent.kind === SyntaxKind.JSDocFunctionType, + "Impossible parameter parent kind", + () => `parent is: ${Debug.formatSyntaxKind(node.parent.kind)}, expected JSDocFunctionType`, + ); const functionType = node.parent as JSDocFunctionType; const index = functionType.parameters.indexOf(node as ParameterDeclaration); return "arg" + index as __String; @@ -398,7 +442,8 @@ namespace ts { } function getDisplayName(node: Declaration): string { - return isNamedDeclaration(node) ? declarationNameToString(node.name) : unescapeLeadingUnderscores(Debug.checkDefined(getDeclarationName(node))); + return isNamedDeclaration(node) ? declarationNameToString(node.name) + : unescapeLeadingUnderscores(Debug.checkDefined(getDeclarationName(node))); } /** @@ -409,10 +454,19 @@ namespace ts { * @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.) * @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations. */ - function declareSymbol(symbolTable: SymbolTable, parent: Symbol | undefined, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags, isReplaceableByMethod?: boolean, isComputedName?: boolean): Symbol { + function declareSymbol( + symbolTable: SymbolTable, + parent: Symbol | undefined, + node: Declaration, + includes: SymbolFlags, + excludes: SymbolFlags, + isReplaceableByMethod?: boolean, + isComputedName?: boolean, + ): Symbol { Debug.assert(isComputedName || !hasDynamicName(node)); - const isDefaultExport = hasSyntacticModifier(node, ModifierFlags.Default) || isExportSpecifier(node) && node.name.escapedText === "default"; + const isDefaultExport = hasSyntacticModifier(node, ModifierFlags.Default) + || isExportSpecifier(node) && node.name.escapedText === "default"; // The exported symbol for an export default function/class node is always named "default" const name = isComputedName ? InternalSymbolName.Computed @@ -480,7 +534,8 @@ namespace ts { let messageNeedsName = true; if (symbol.flags & SymbolFlags.Enum || includes & SymbolFlags.Enum) { - message = Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations; + message = + Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations; messageNeedsName = false; } @@ -500,8 +555,9 @@ namespace ts { // 1. multiple export default of class declaration or function declaration by checking NodeFlags.Default // 2. multiple export default of export assignment. This one doesn't have NodeFlags.Default on (as export default doesn't considered as modifiers) if ( - symbol.declarations && symbol.declarations.length && - (node.kind === SyntaxKind.ExportAssignment && !(node as ExportAssignment).isExportEquals) + symbol.declarations && symbol.declarations.length + && (node.kind === SyntaxKind.ExportAssignment + && !(node as ExportAssignment).isExportEquals) ) { message = Diagnostics.A_module_cannot_have_multiple_default_exports; messageNeedsName = false; @@ -511,24 +567,52 @@ namespace ts { } const relatedInformation: DiagnosticRelatedInformation[] = []; - if (isTypeAliasDeclaration(node) && nodeIsMissing(node.type) && hasSyntacticModifier(node, ModifierFlags.Export) && symbol.flags & (SymbolFlags.Alias | SymbolFlags.Type | SymbolFlags.Namespace)) { + if ( + isTypeAliasDeclaration(node) && nodeIsMissing(node.type) + && hasSyntacticModifier(node, ModifierFlags.Export) + && symbol.flags & (SymbolFlags.Alias | SymbolFlags.Type | SymbolFlags.Namespace) + ) { // export type T; - may have meant export type { T }? - relatedInformation.push(createDiagnosticForNode(node, Diagnostics.Did_you_mean_0, `export type { ${unescapeLeadingUnderscores(node.name.escapedText)} }`)); + relatedInformation.push( + createDiagnosticForNode( + node, + Diagnostics.Did_you_mean_0, + `export type { ${unescapeLeadingUnderscores(node.name.escapedText)} }`, + ), + ); } const declarationName = getNameOfDeclaration(node) || node; forEach(symbol.declarations, (declaration, index) => { const decl = getNameOfDeclaration(declaration) || declaration; - const diag = createDiagnosticForNode(decl, message, messageNeedsName ? getDisplayName(declaration) : undefined); + const diag = createDiagnosticForNode( + decl, + message, + messageNeedsName ? getDisplayName(declaration) : undefined, + ); file.bindDiagnostics.push( - multipleDefaultExports ? addRelatedInfo(diag, createDiagnosticForNode(declarationName, index === 0 ? Diagnostics.Another_export_default_is_here : Diagnostics.and_here)) : diag, + multipleDefaultExports + ? addRelatedInfo( + diag, + createDiagnosticForNode( + declarationName, + index === 0 ? Diagnostics.Another_export_default_is_here + : Diagnostics.and_here, + ), + ) : diag, ); if (multipleDefaultExports) { - relatedInformation.push(createDiagnosticForNode(decl, Diagnostics.The_first_export_default_is_here)); + relatedInformation.push( + createDiagnosticForNode(decl, Diagnostics.The_first_export_default_is_here), + ); } }); - const diag = createDiagnosticForNode(declarationName, message, messageNeedsName ? getDisplayName(node) : undefined); + const diag = createDiagnosticForNode( + declarationName, + message, + messageNeedsName ? getDisplayName(node) : undefined, + ); file.bindDiagnostics.push(addRelatedInfo(diag, ...relatedInformation)); symbol = createSymbol(SymbolFlags.None, name); @@ -548,10 +632,20 @@ namespace ts { } function declareModuleMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { - const hasExportModifier = !!(getCombinedModifierFlags(node) & ModifierFlags.Export) || jsdocTreatAsExported(node); + const hasExportModifier = !!(getCombinedModifierFlags(node) & ModifierFlags.Export) + || jsdocTreatAsExported(node); if (symbolFlags & SymbolFlags.Alias) { - if (node.kind === SyntaxKind.ExportSpecifier || (node.kind === SyntaxKind.ImportEqualsDeclaration && hasExportModifier)) { - return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); + if ( + node.kind === SyntaxKind.ExportSpecifier + || (node.kind === SyntaxKind.ImportEqualsDeclaration && hasExportModifier) + ) { + return declareSymbol( + container.symbol.exports!, + container.symbol, + node, + symbolFlags, + symbolExcludes, + ); } else { return declareSymbol(container.locals!, /*parent*/ undefined, node, symbolFlags, symbolExcludes); @@ -575,12 +669,33 @@ namespace ts { // and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed. if (isJSDocTypeAlias(node)) Debug.assert(isInJSFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file. if (!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) { - if (!container.locals || (hasSyntacticModifier(node, ModifierFlags.Default) && !getDeclarationName(node))) { - return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default! + if ( + !container.locals + || (hasSyntacticModifier(node, ModifierFlags.Default) && !getDeclarationName(node)) + ) { + return declareSymbol( + container.symbol.exports!, + container.symbol, + node, + symbolFlags, + symbolExcludes, + ); // No local symbol for an unnamed default! } const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0; - const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes); - local.exportSymbol = declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); + const local = declareSymbol( + container.locals, + /*parent*/ undefined, + node, + exportKind, + symbolExcludes, + ); + local.exportSymbol = declareSymbol( + container.symbol.exports!, + container.symbol, + node, + symbolFlags, + symbolExcludes, + ); node.localSymbol = local; return local; } @@ -601,8 +716,12 @@ namespace ts { // 2. The thing a nameless typedef pulls its name from is implicitly a direct export (either by assignment or actual export flag). const declName = getNameOfDeclaration(node); if (!declName) return false; - if (isPropertyAccessEntityNameExpression(declName.parent) && isTopLevelNamespaceAssignment(declName.parent)) return true; - if (isDeclaration(declName.parent) && getCombinedModifierFlags(declName.parent) & ModifierFlags.Export) return true; + if ( + isPropertyAccessEntityNameExpression(declName.parent) && isTopLevelNamespaceAssignment(declName.parent) + ) return true; + if (isDeclaration(declName.parent) && getCombinedModifierFlags(declName.parent) & ModifierFlags.Export) { + return true; + } // This could potentially be simplified by having `delayedBindJSDocTypedefTag` pass in an override for `hasExportModifier`, since it should // already have calculated and branched on most of this. return false; @@ -658,22 +777,34 @@ namespace ts { const saveExceptionTarget = currentExceptionTarget; const saveActiveLabelList = activeLabelList; const saveHasExplicitReturn = hasExplicitReturn; - const isImmediatelyInvoked = (containerFlags & ContainerFlags.IsFunctionExpression && - !hasSyntacticModifier(node, ModifierFlags.Async) && - !(node as FunctionLikeDeclaration).asteriskToken && - !!getImmediatelyInvokedFunctionExpression(node)) || - node.kind === SyntaxKind.ClassStaticBlockDeclaration; + const isImmediatelyInvoked = (containerFlags & ContainerFlags.IsFunctionExpression + && !hasSyntacticModifier(node, ModifierFlags.Async) + && !(node as FunctionLikeDeclaration).asteriskToken + && !!getImmediatelyInvokedFunctionExpression(node)) + || node.kind === SyntaxKind.ClassStaticBlockDeclaration; // A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave // similarly to break statements that exit to a label just past the statement body. if (!isImmediatelyInvoked) { currentFlow = initFlowNode({ flags: FlowFlags.Start }); - if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor)) { - currentFlow.node = node as FunctionExpression | ArrowFunction | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration; + if ( + containerFlags + & (ContainerFlags.IsFunctionExpression + | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor) + ) { + currentFlow.node = node as + | FunctionExpression + | ArrowFunction + | MethodDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration; } } // We create a return control flow graph for IIFEs and constructors. For constructors // we use the return control flow graph in strict property initialization checks. - currentReturnTarget = isImmediatelyInvoked || node.kind === SyntaxKind.Constructor || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined; + currentReturnTarget = isImmediatelyInvoked || node.kind === SyntaxKind.Constructor + || (isInJSFile(node) + && (node.kind === SyntaxKind.FunctionDeclaration + || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined; currentExceptionTarget = undefined; currentBreakTarget = undefined; currentContinueTarget = undefined; @@ -682,7 +813,10 @@ namespace ts { bindChildren(node); // Reset all reachability check related flags on node (for incremental scenarios) node.flags &= ~NodeFlags.ReachabilityAndEmitFlags; - if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).body)) { + if ( + !(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike + && nodeIsPresent((node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).body) + ) { node.flags |= NodeFlags.HasImplicitReturn; if (hasExplicitReturn) node.flags |= NodeFlags.HasExplicitReturn; (node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).endFlowNode = currentFlow; @@ -695,7 +829,12 @@ namespace ts { if (currentReturnTarget) { addAntecedent(currentReturnTarget, currentFlow); currentFlow = finishFlowLabel(currentReturnTarget); - if (node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ClassStaticBlockDeclaration || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) { + if ( + node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ClassStaticBlockDeclaration + || (isInJSFile(node) + && (node.kind === SyntaxKind.FunctionDeclaration + || node.kind === SyntaxKind.FunctionExpression)) + ) { (node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).returnFlowNode = currentFlow; } } @@ -712,7 +851,8 @@ namespace ts { else if (containerFlags & ContainerFlags.IsInterface) { seenThisKeyword = false; bindChildren(node); - node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis; + node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis + : node.flags & ~NodeFlags.ContainsThis; } else { bindChildren(node); @@ -751,7 +891,10 @@ namespace ts { inAssignmentPattern = saveInAssignmentPattern; return; } - if (node.kind >= SyntaxKind.FirstStatement && node.kind <= SyntaxKind.LastStatement && !options.allowUnreachableCode) { + if ( + node.kind >= SyntaxKind.FirstStatement && node.kind <= SyntaxKind.LastStatement + && !options.allowUnreachableCode + ) { node.flowNode = currentFlow; } switch (node.kind) { @@ -885,7 +1028,8 @@ namespace ts { case SyntaxKind.BinaryExpression: return isNarrowingBinaryExpression(expr as BinaryExpression); case SyntaxKind.PrefixUnaryExpression: - return (expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken && isNarrowingExpression((expr as PrefixUnaryExpression).operand); + return (expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken + && isNarrowingExpression((expr as PrefixUnaryExpression).operand); case SyntaxKind.TypeOfExpression: return isNarrowingExpression((expr as TypeOfExpression).expression); } @@ -894,9 +1038,14 @@ namespace ts { function isNarrowableReference(expr: Expression): boolean { return isDottedName(expr) - || (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression) - || isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference(expr.right) - || isElementAccessExpression(expr) && (isStringOrNumericLiteralLike(expr.argumentExpression) || isEntityNameExpression(expr.argumentExpression)) && isNarrowableReference(expr.expression) + || (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) + && isNarrowableReference(expr.expression) + || isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken + && isNarrowableReference(expr.right) + || isElementAccessExpression(expr) + && (isStringOrNumericLiteralLike(expr.argumentExpression) + || isEntityNameExpression(expr.argumentExpression)) + && isNarrowableReference(expr.expression) || isAssignmentExpression(expr) && isNarrowableReference(expr.left); } @@ -913,8 +1062,8 @@ namespace ts { } } if ( - expr.expression.kind === SyntaxKind.PropertyAccessExpression && - containsNarrowableReference((expr.expression as PropertyAccessExpression).expression) + expr.expression.kind === SyntaxKind.PropertyAccessExpression + && containsNarrowableReference((expr.expression as PropertyAccessExpression).expression) ) { return true; } @@ -936,8 +1085,9 @@ namespace ts { case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: - return isNarrowableOperand(expr.left) || isNarrowableOperand(expr.right) || - isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right); + return isNarrowableOperand(expr.left) || isNarrowableOperand(expr.right) + || isNarrowingTypeofOperands(expr.right, expr.left) + || isNarrowingTypeofOperands(expr.left, expr.right); case SyntaxKind.InstanceOfKeyword: return isNarrowableOperand(expr.left); case SyntaxKind.InKeyword: @@ -987,7 +1137,11 @@ namespace ts { } } - function createFlowCondition(flags: FlowFlags, antecedent: FlowNode, expression: Expression | undefined): FlowNode { + function createFlowCondition( + flags: FlowFlags, + antecedent: FlowNode, + expression: Expression | undefined, + ): FlowNode { if (antecedent.flags & FlowFlags.Unreachable) { return antecedent; } @@ -995,9 +1149,9 @@ namespace ts { return flags & FlowFlags.TrueCondition ? antecedent : unreachableFlow; } if ( - (expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition || - expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) && - !isExpressionOfOptionalChainRoot(expression) && !isNullishCoalesce(expression.parent) + (expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition + || expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) + && !isExpressionOfOptionalChainRoot(expression) && !isNullishCoalesce(expression.parent) ) { return unreachableFlow; } @@ -1008,12 +1162,21 @@ namespace ts { return initFlowNode({ flags, antecedent, node: expression }); } - function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode { + function createFlowSwitchClause( + antecedent: FlowNode, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + ): FlowNode { setFlowNodeReferenced(antecedent); return initFlowNode({ flags: FlowFlags.SwitchClause, antecedent, switchStatement, clauseStart, clauseEnd }); } - function createFlowMutation(flags: FlowFlags, antecedent: FlowNode, node: Expression | VariableDeclaration | ArrayBindingElement): FlowNode { + function createFlowMutation( + flags: FlowFlags, + antecedent: FlowNode, + node: Expression | VariableDeclaration | ArrayBindingElement, + ): FlowNode { setFlowNodeReferenced(antecedent); const result = initFlowNode({ flags, antecedent, node }); if (currentExceptionTarget) { @@ -1057,14 +1220,17 @@ namespace ts { if (node.kind === SyntaxKind.ParenthesizedExpression) { node = (node as ParenthesizedExpression).expression; } - else if (node.kind === SyntaxKind.PrefixUnaryExpression && (node as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken) { + else if ( + node.kind === SyntaxKind.PrefixUnaryExpression + && (node as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken + ) { node = (node as PrefixUnaryExpression).operand; } else { return node.kind === SyntaxKind.BinaryExpression && ( - (node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || - (node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken || - (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken + (node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken + || (node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken + || (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken ); } } @@ -1077,17 +1243,22 @@ namespace ts { function isTopLevelLogicalExpression(node: Node): boolean { while ( - isParenthesizedExpression(node.parent) || - isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.ExclamationToken + isParenthesizedExpression(node.parent) + || isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.ExclamationToken ) { node = node.parent; } - return !isStatementCondition(node) && - !isLogicalExpression(node.parent) && - !(isOptionalChain(node.parent) && node.parent.expression === node); + return !isStatementCondition(node) + && !isLogicalExpression(node.parent) + && !(isOptionalChain(node.parent) && node.parent.expression === node); } - function doWithConditionalBranches(action: (value: T) => void, value: T, trueTarget: FlowLabel, falseTarget: FlowLabel) { + function doWithConditionalBranches( + action: (value: T) => void, + value: T, + trueTarget: FlowLabel, + falseTarget: FlowLabel, + ) { const savedTrueTarget = currentTrueTarget; const savedFalseTarget = currentFalseTarget; currentTrueTarget = trueTarget; @@ -1099,7 +1270,11 @@ namespace ts { function bindCondition(node: Expression | undefined, trueTarget: FlowLabel, falseTarget: FlowLabel) { doWithConditionalBranches(bind, node, trueTarget, falseTarget); - if (!node || !isLogicalAssignmentExpression(node) && !isLogicalExpression(node) && !(isOptionalChain(node) && isOutermostOptionalChain(node))) { + if ( + !node + || !isLogicalAssignmentExpression(node) && !isLogicalExpression(node) + && !(isOptionalChain(node) && isOutermostOptionalChain(node)) + ) { addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node)); addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node)); } @@ -1219,7 +1394,11 @@ namespace ts { return undefined; } - function bindBreakOrContinueFlow(node: BreakOrContinueStatement, breakTarget: FlowLabel | undefined, continueTarget: FlowLabel | undefined) { + function bindBreakOrContinueFlow( + node: BreakOrContinueStatement, + breakTarget: FlowLabel | undefined, + continueTarget: FlowLabel | undefined, + ) { const flowLabel = node.kind === SyntaxKind.BreakStatement ? breakTarget : continueTarget; if (flowLabel) { addAntecedent(flowLabel, currentFlow); @@ -1290,7 +1469,10 @@ namespace ts { // set of antecedents for the pre-finally label. As control flow analysis passes by a ReduceLabel // node, the pre-finally label is temporarily switched to the reduced antecedent set. const finallyLabel = createBranchLabel(); - finallyLabel.antecedents = concatenate(concatenate(normalExitLabel.antecedents, exceptionLabel.antecedents), returnLabel.antecedents); + finallyLabel.antecedents = concatenate( + concatenate(normalExitLabel.antecedents, exceptionLabel.antecedents), + returnLabel.antecedents, + ); currentFlow = finallyLabel; bind(node.finallyBlock); if (currentFlow.flags & FlowFlags.Unreachable) { @@ -1301,17 +1483,24 @@ namespace ts { // If we have an IIFE return target and return statements in the try or catch blocks, add a control // flow that goes back through the finally block and back through only the return statements. if (currentReturnTarget && returnLabel.antecedents) { - addAntecedent(currentReturnTarget, createReduceLabel(finallyLabel, returnLabel.antecedents, currentFlow)); + addAntecedent( + currentReturnTarget, + createReduceLabel(finallyLabel, returnLabel.antecedents, currentFlow), + ); } // If we have an outer exception target (i.e. a containing try-finally or try-catch-finally), add a // control flow that goes back through the finally blok and back through each possible exception source. if (currentExceptionTarget && exceptionLabel.antecedents) { - addAntecedent(currentExceptionTarget, createReduceLabel(finallyLabel, exceptionLabel.antecedents, currentFlow)); + addAntecedent( + currentExceptionTarget, + createReduceLabel(finallyLabel, exceptionLabel.antecedents, currentFlow), + ); } // If the end of the finally block is reachable, but the end of the try and catch blocks are not, // convert the current flow to unreachable. For example, 'try { return 1; } finally { ... }' should // result in an unreachable current control flow. - currentFlow = normalExitLabel.antecedents ? createReduceLabel(finallyLabel, normalExitLabel.antecedents, currentFlow) : unreachableFlow; + currentFlow = normalExitLabel.antecedents + ? createReduceLabel(finallyLabel, normalExitLabel.antecedents, currentFlow) : unreachableFlow; } } else { @@ -1352,13 +1541,20 @@ namespace ts { i++; } const preCaseLabel = createBranchLabel(); - addAntecedent(preCaseLabel, isNarrowingSwitch ? createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1) : preSwitchCaseFlow!); + addAntecedent( + preCaseLabel, + isNarrowingSwitch ? createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1) + : preSwitchCaseFlow!, + ); addAntecedent(preCaseLabel, fallthroughFlow); currentFlow = finishFlowLabel(preCaseLabel); const clause = clauses[i]; bind(clause); fallthroughFlow = currentFlow; - if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) { + if ( + !(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 + && options.noFallthroughCasesInSwitch + ) { clause.fallthroughFlowNode = currentFlow; } } @@ -1408,7 +1604,10 @@ namespace ts { } function bindDestructuringTargetFlow(node: Expression) { - if (node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { bindAssignmentTargetFlow((node as BinaryExpression).left); } else { @@ -1447,7 +1646,10 @@ namespace ts { function bindLogicalLikeExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) { const preRightLabel = createBranchLabel(); - if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === SyntaxKind.AmpersandAmpersandEqualsToken) { + if ( + node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken + || node.operatorToken.kind === SyntaxKind.AmpersandAmpersandEqualsToken + ) { bindCondition(node.left, preRightLabel, falseTarget); } else { @@ -1518,7 +1720,14 @@ namespace ts { parentStack: (Node | undefined)[]; } - return createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, /*foldState*/ undefined); + return createBinaryExpressionTrampoline( + onEnter, + onLeft, + onOperator, + onRight, + onExit, + /*foldState*/ undefined, + ); function onEnter(node: BinaryExpression, state: WorkArea | undefined) { if (state) { @@ -1547,10 +1756,10 @@ namespace ts { // For now, though, since the common cases are chained `+`, leaving it recursive is fine const operator = node.operatorToken.kind; if ( - operator === SyntaxKind.AmpersandAmpersandToken || - operator === SyntaxKind.BarBarToken || - operator === SyntaxKind.QuestionQuestionToken || - isLogicalOrCoalescingAssignmentOperator(operator) + operator === SyntaxKind.AmpersandAmpersandToken + || operator === SyntaxKind.BarBarToken + || operator === SyntaxKind.QuestionQuestionToken + || isLogicalOrCoalescingAssignmentOperator(operator) ) { if (isTopLevelLogicalExpression(node)) { const postExpressionLabel = createBranchLabel(); @@ -1596,7 +1805,9 @@ namespace ts { const operator = node.operatorToken.kind; if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) { bindAssignmentTargetFlow(node.left); - if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) { + if ( + operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression + ) { const elementAccess = node.left as ElementAccessExpression; if (isNarrowableOperand(elementAccess.expression)) { currentFlow = createFlowMutation(FlowFlags.ArrayMutation, currentFlow, node); @@ -1825,7 +2036,10 @@ namespace ts { } if (node.expression.kind === SyntaxKind.PropertyAccessExpression) { const propertyAccess = node.expression as PropertyAccessExpression; - if (isIdentifier(propertyAccess.name) && isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) { + if ( + isIdentifier(propertyAccess.name) && isNarrowableOperand(propertyAccess.expression) + && isPushOrUnshiftIdentifier(propertyAccess.name) + ) { currentFlow = createFlowMutation(FlowFlags.ArrayMutation, currentFlow, node); } } @@ -1852,13 +2066,16 @@ namespace ts { return ContainerFlags.IsContainer | ContainerFlags.HasLocals; case SyntaxKind.SourceFile: - return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals; + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer + | ContainerFlags.HasLocals; case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.MethodDeclaration: if (isObjectLiteralOrClassExpressionMethodOrAccessor(node)) { - return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor; + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer + | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike + | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor; } // falls through case SyntaxKind.Constructor: @@ -1871,11 +2088,13 @@ namespace ts { case SyntaxKind.ConstructSignature: case SyntaxKind.ConstructorType: case SyntaxKind.ClassStaticBlockDeclaration: - return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike; + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals + | ContainerFlags.IsFunctionLike; case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression; + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals + | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression; case SyntaxKind.ModuleBlock: return ContainerFlags.IsControlFlowContainer; @@ -1906,7 +2125,8 @@ namespace ts { // By not creating a new block-scoped-container here, we ensure that both 'var x' // and 'let x' go into the Function-container's locals, and we do get a collision // conflict. - return isFunctionLike(node.parent) || isClassStaticBlockDeclaration(node.parent) ? ContainerFlags.None : ContainerFlags.IsBlockScopedContainer; + return isFunctionLike(node.parent) || isClassStaticBlockDeclaration(node.parent) + ? ContainerFlags.None : ContainerFlags.IsBlockScopedContainer; } return ContainerFlags.None; @@ -1920,7 +2140,11 @@ namespace ts { lastContainer = next; } - function declareSymbolAndAddToSymbolTable(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol | undefined { + function declareSymbolAndAddToSymbolTable( + node: Declaration, + symbolFlags: SymbolFlags, + symbolExcludes: SymbolFlags, + ): Symbol | undefined { switch (container.kind) { // Modules, source files, and classes need specialized handling for how their // members are declared (for example, a member of a class will go into a specific @@ -1937,7 +2161,13 @@ namespace ts { return declareClassMember(node, symbolFlags, symbolExcludes); case SyntaxKind.EnumDeclaration: - return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); + return declareSymbol( + container.symbol.exports!, + container.symbol, + node, + symbolFlags, + symbolExcludes, + ); case SyntaxKind.TypeLiteral: case SyntaxKind.JSDocTypeLiteral: @@ -1949,7 +2179,13 @@ namespace ts { // container, and are never in scope otherwise (even inside the body of the // object / type / interface declaring them). An exception is type parameters, // which are in scope without qualification (similar to 'locals'). - return declareSymbol(container.symbol.members!, container.symbol, node, symbolFlags, symbolExcludes); + return declareSymbol( + container.symbol.members!, + container.symbol, + node, + symbolFlags, + symbolExcludes, + ); case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: @@ -2013,7 +2249,11 @@ namespace ts { setExportContextFlag(node); if (isAmbientModule(node)) { if (hasSyntacticModifier(node, ModifierFlags.Export)) { - errorOnFirstToken(node, Diagnostics.export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible); + errorOnFirstToken( + node, + Diagnostics + .export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible, + ); } if (isModuleAugmentationExternal(node)) { declareModuleSymbol(node); @@ -2024,12 +2264,23 @@ namespace ts { const { text } = node.name; pattern = tryParsePattern(text); if (pattern === undefined) { - errorOnFirstToken(node.name, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, text); + errorOnFirstToken( + node.name, + Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, + text, + ); } } - const symbol = declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes)!; - file.patternAmbientModules = append(file.patternAmbientModules, pattern && !isString(pattern) ? { pattern, symbol } : undefined); + const symbol = declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.ValueModule, + SymbolFlags.ValueModuleExcludes, + )!; + file.patternAmbientModules = append( + file.patternAmbientModules, + pattern && !isString(pattern) ? { pattern, symbol } : undefined, + ); } } else { @@ -2037,7 +2288,8 @@ namespace ts { if (state !== ModuleInstanceState.NonInstantiated) { const { symbol } = node; // if module was already merged with some function, class or non-const enum, treat it as non-const-enum-only - symbol.constEnumOnlyModule = (!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum))) + symbol.constEnumOnlyModule = + (!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum))) // Current must be `const enum` only && state === ModuleInstanceState.ConstEnumOnly // Can't have been set to 'false' in a previous merged symbol. ('undefined' OK) @@ -2049,7 +2301,11 @@ namespace ts { function declareModuleSymbol(node: ModuleDeclaration): ModuleInstanceState { const state = getModuleInstanceState(node); const instantiated = state !== ModuleInstanceState.NonInstantiated; - declareSymbolAndAddToSymbolTable(node, instantiated ? SymbolFlags.ValueModule : SymbolFlags.NamespaceModule, instantiated ? SymbolFlags.ValueModuleExcludes : SymbolFlags.NamespaceModuleExcludes); + declareSymbolAndAddToSymbolTable( + node, + instantiated ? SymbolFlags.ValueModule : SymbolFlags.NamespaceModule, + instantiated ? SymbolFlags.ValueModuleExcludes : SymbolFlags.NamespaceModuleExcludes, + ); return state; } @@ -2121,17 +2377,30 @@ namespace ts { const saveCurrentFlow = currentFlow; for (const typeAlias of delayedTypeAliases) { const host = typeAlias.parent.parent; - container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) || file; + container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) + || file; blockScopeContainer = getEnclosingBlockScopeContainer(host) || file; currentFlow = initFlowNode({ flags: FlowFlags.Start }); parent = typeAlias; bind(typeAlias.typeExpression); const declName = getNameOfDeclaration(typeAlias); - if ((isJSDocEnumTag(typeAlias) || !typeAlias.fullName) && declName && isPropertyAccessEntityNameExpression(declName.parent)) { + if ( + (isJSDocEnumTag(typeAlias) || !typeAlias.fullName) && declName + && isPropertyAccessEntityNameExpression(declName.parent) + ) { // typedef anchored to an A.B.C assignment - we need to bind into B's namespace under name C const isTopLevel = isTopLevelNamespaceAssignment(declName.parent); if (isTopLevel) { - bindPotentiallyMissingNamespaces(file.symbol, declName.parent, isTopLevel, !!findAncestor(declName, d => isPropertyAccessExpression(d) && d.name.escapedText === "prototype"), /*containerIsClass*/ false); + bindPotentiallyMissingNamespaces( + file.symbol, + declName.parent, + isTopLevel, + !!findAncestor( + declName, + d => isPropertyAccessExpression(d) && d.name.escapedText === "prototype", + ), + /*containerIsClass*/ false, + ); const oldContainer = container; switch (getAssignmentDeclarationPropertyAccessKind(declName.parent)) { case AssignmentDeclarationKind.ExportsProperty: @@ -2151,11 +2420,14 @@ namespace ts { break; case AssignmentDeclarationKind.Property: container = isExportsOrModuleExportsOrAlias(file, declName.parent.expression) ? file - : isPropertyAccessExpression(declName.parent.expression) ? declName.parent.expression.name + : isPropertyAccessExpression(declName.parent.expression) + ? declName.parent.expression.name : declName.parent.expression; break; case AssignmentDeclarationKind.None: - return Debug.fail("Shouldn't have detected typedef or enum on non-assignment declaration"); + return Debug.fail( + "Shouldn't have detected typedef or enum on non-assignment declaration", + ); } if (container) { declareModuleMember(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); @@ -2163,7 +2435,10 @@ namespace ts { container = oldContainer; } } - else if (isJSDocEnumTag(typeAlias) || !typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) { + else if ( + isJSDocEnumTag(typeAlias) || !typeAlias.fullName + || typeAlias.fullName.kind === SyntaxKind.Identifier + ) { parent = typeAlias.parent; bindBlockScopedDeclaration(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); } @@ -2184,29 +2459,53 @@ namespace ts { function checkContextualIdentifier(node: Identifier) { // Report error only if there are no parse errors in file if ( - !file.parseDiagnostics.length && - !(node.flags & NodeFlags.Ambient) && - !(node.flags & NodeFlags.JSDoc) && - !isIdentifierName(node) + !file.parseDiagnostics.length + && !(node.flags & NodeFlags.Ambient) + && !(node.flags & NodeFlags.JSDoc) + && !isIdentifierName(node) ) { // strict mode identifiers if ( - inStrictMode && - node.originalKeywordKind! >= SyntaxKind.FirstFutureReservedWord && - node.originalKeywordKind! <= SyntaxKind.LastFutureReservedWord + inStrictMode + && node.originalKeywordKind! >= SyntaxKind.FirstFutureReservedWord + && node.originalKeywordKind! <= SyntaxKind.LastFutureReservedWord ) { - file.bindDiagnostics.push(createDiagnosticForNode(node, getStrictModeIdentifierMessage(node), declarationNameToString(node))); + file.bindDiagnostics.push( + createDiagnosticForNode( + node, + getStrictModeIdentifierMessage(node), + declarationNameToString(node), + ), + ); } else if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) { if (isExternalModule(file) && isInTopLevelContext(node)) { - file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module, declarationNameToString(node))); + file.bindDiagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module, + declarationNameToString(node), + ), + ); } else if (node.flags & NodeFlags.AwaitContext) { - file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, declarationNameToString(node))); + file.bindDiagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, + declarationNameToString(node), + ), + ); } } else if (node.originalKeywordKind === SyntaxKind.YieldKeyword && node.flags & NodeFlags.YieldContext) { - file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, declarationNameToString(node))); + file.bindDiagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, + declarationNameToString(node), + ), + ); } } } @@ -2215,11 +2514,13 @@ namespace ts { // Provide specialized messages to help the user understand why we think they're in // strict mode. if (getContainingClass(node)) { - return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode; + return Diagnostics + .Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode; } if (file.externalModuleIndicator) { - return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode; + return Diagnostics + .Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode; } return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode; @@ -2231,7 +2532,13 @@ namespace ts { if (node.escapedText === "#constructor") { // Report error only if there are no parse errors in file if (!file.parseDiagnostics.length) { - file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.constructor_is_a_reserved_word, declarationNameToString(node))); + file.bindDiagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.constructor_is_a_reserved_word, + declarationNameToString(node), + ), + ); } } } @@ -2258,7 +2565,14 @@ namespace ts { // When a delete operator occurs within strict mode code, a SyntaxError is thrown if its // UnaryExpression is a direct reference to a variable, function argument, or function name const span = getErrorSpanForNode(file, node.expression); - file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode)); + file.bindDiagnostics.push( + createFileDiagnostic( + file, + span.start, + span.length, + Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode, + ), + ); } } @@ -2273,7 +2587,15 @@ namespace ts { // We check first if the name is inside class declaration or class expression; if so give explicit message // otherwise report generic error message. const span = getErrorSpanForNode(file, name); - file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, getStrictModeEvalOrArgumentsMessage(contextNode), idText(identifier))); + file.bindDiagnostics.push( + createFileDiagnostic( + file, + span.start, + span.length, + getStrictModeEvalOrArgumentsMessage(contextNode), + idText(identifier), + ), + ); } } } @@ -2282,7 +2604,8 @@ namespace ts { // Provide specialized messages to help the user understand why we think they're in // strict mode. if (getContainingClass(node)) { - return Diagnostics.Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode; + return Diagnostics + .Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode; } if (file.externalModuleIndicator) { @@ -2303,35 +2626,47 @@ namespace ts { // Provide specialized messages to help the user understand why we think they're in // strict mode. if (getContainingClass(node)) { - return Diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Class_definitions_are_automatically_in_strict_mode; + return Diagnostics + .Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Class_definitions_are_automatically_in_strict_mode; } if (file.externalModuleIndicator) { - return Diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Modules_are_automatically_in_strict_mode; + return Diagnostics + .Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Modules_are_automatically_in_strict_mode; } - return Diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5; + return Diagnostics + .Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5; } function checkStrictModeFunctionDeclaration(node: FunctionDeclaration) { if (languageVersion < ScriptTarget.ES2015) { // Report error if function is not top level function declaration if ( - blockScopeContainer.kind !== SyntaxKind.SourceFile && - blockScopeContainer.kind !== SyntaxKind.ModuleDeclaration && - !isFunctionLikeOrClassStaticBlockDeclaration(blockScopeContainer) + blockScopeContainer.kind !== SyntaxKind.SourceFile + && blockScopeContainer.kind !== SyntaxKind.ModuleDeclaration + && !isFunctionLikeOrClassStaticBlockDeclaration(blockScopeContainer) ) { // We check first if the name is inside class declaration or class expression; if so give explicit message // otherwise report generic error message. const errorSpan = getErrorSpanForNode(file, node); - file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length, getStrictModeBlockScopeFunctionDeclarationMessage(node))); + file.bindDiagnostics.push( + createFileDiagnostic( + file, + errorSpan.start, + errorSpan.length, + getStrictModeBlockScopeFunctionDeclarationMessage(node), + ), + ); } } } function checkStrictModeNumericLiteral(node: NumericLiteral) { if (languageVersion < ScriptTarget.ES5 && inStrictMode && node.numericLiteralFlags & TokenFlags.Octal) { - file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode)); + file.bindDiagnostics.push( + createDiagnosticForNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode), + ); } } @@ -2379,8 +2714,17 @@ namespace ts { errorOrSuggestionOnRange(isError, node, node, message); } - function errorOrSuggestionOnRange(isError: boolean, startNode: Node, endNode: Node, message: DiagnosticMessage): void { - addErrorOrSuggestionDiagnostic(isError, { pos: getTokenPosOfNode(startNode, file), end: endNode.end }, message); + function errorOrSuggestionOnRange( + isError: boolean, + startNode: Node, + endNode: Node, + message: DiagnosticMessage, + ): void { + addErrorOrSuggestionDiagnostic( + isError, + { pos: getTokenPosOfNode(startNode, file), end: endNode.end }, + message, + ); } function addErrorOrSuggestionDiagnostic(isError: boolean, range: TextRange, message: DiagnosticMessage): void { @@ -2389,7 +2733,10 @@ namespace ts { file.bindDiagnostics.push(diag); } else { - file.bindSuggestionDiagnostics = append(file.bindSuggestionDiagnostics, { ...diag, category: DiagnosticCategory.Suggestion }); + file.bindSuggestionDiagnostics = append(file.bindSuggestionDiagnostics, { + ...diag, + category: DiagnosticCategory.Suggestion, + }); } } @@ -2500,7 +2847,11 @@ namespace ts { while (parentNode && !isJSDocTypeAlias(parentNode)) { parentNode = parentNode.parent; } - bindBlockScopedDeclaration(parentNode as Declaration, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); + bindBlockScopedDeclaration( + parentNode as Declaration, + SymbolFlags.TypeAlias, + SymbolFlags.TypeAliasExcludes, + ); break; } // falls through @@ -2530,12 +2881,18 @@ namespace ts { bindSpecialPropertyDeclaration(expr); } if ( - isInJSFile(expr) && - file.commonJsModuleIndicator && - isModuleExportsAccessExpression(expr) && - !lookupSymbolForName(blockScopeContainer, "module" as __String) + isInJSFile(expr) + && file.commonJsModuleIndicator + && isModuleExportsAccessExpression(expr) + && !lookupSymbolForName(blockScopeContainer, "module" as __String) ) { - declareSymbol(file.locals!, /*parent*/ undefined, expr.expression, SymbolFlags.FunctionScopedVariable | SymbolFlags.ModuleExports, SymbolFlags.FunctionScopedVariableExcludes); + declareSymbol( + file.locals!, + /*parent*/ undefined, + expr.expression, + SymbolFlags.FunctionScopedVariable | SymbolFlags.ModuleExports, + SymbolFlags.FunctionScopedVariableExcludes, + ); } break; case SyntaxKind.BinaryExpression: @@ -2548,7 +2905,10 @@ namespace ts { bindModuleExportsAssignment(node as BindablePropertyAssignmentExpression); break; case AssignmentDeclarationKind.PrototypeProperty: - bindPrototypePropertyAssignment((node as BindableStaticPropertyAssignmentExpression).left, node); + bindPrototypePropertyAssignment( + (node as BindableStaticPropertyAssignmentExpression).left, + node, + ); break; case AssignmentDeclarationKind.Prototype: bindPrototypeAssignment(node as BindableStaticPropertyAssignmentExpression); @@ -2607,29 +2967,58 @@ namespace ts { return bindPropertyWorker(node as PropertyDeclaration | PropertySignature); case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.Property, + SymbolFlags.PropertyExcludes, + ); case SyntaxKind.EnumMember: - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.EnumMember, + SymbolFlags.EnumMemberExcludes, + ); case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: case SyntaxKind.IndexSignature: - return declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Signature, SymbolFlags.None); + return declareSymbolAndAddToSymbolTable( + node as Declaration, + SymbolFlags.Signature, + SymbolFlags.None, + ); case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: // If this is an ObjectLiteralExpression method, then it sits in the same space // as other properties in the object literal. So we use SymbolFlags.PropertyExcludes // so that it will conflict with any other object literal members with the same // name. - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.Method | ((node as MethodDeclaration).questionToken ? SymbolFlags.Optional : SymbolFlags.None), isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.Method + | ((node as MethodDeclaration).questionToken ? SymbolFlags.Optional : SymbolFlags.None), + isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes, + ); case SyntaxKind.FunctionDeclaration: return bindFunctionDeclaration(node as FunctionDeclaration); case SyntaxKind.Constructor: - return declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Constructor, /*symbolExcludes:*/ SymbolFlags.None); + return declareSymbolAndAddToSymbolTable( + node as Declaration, + SymbolFlags.Constructor, + /*symbolExcludes:*/ SymbolFlags.None, + ); case SyntaxKind.GetAccessor: - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.GetAccessor, + SymbolFlags.GetAccessorExcludes, + ); case SyntaxKind.SetAccessor: - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.SetAccessor, + SymbolFlags.SetAccessorExcludes, + ); case SyntaxKind.FunctionType: case SyntaxKind.JSDocFunctionType: case SyntaxKind.JSDocSignature: @@ -2673,9 +3062,17 @@ namespace ts { inStrictMode = true; return bindClassLikeDeclaration(node as ClassLikeDeclaration); case SyntaxKind.InterfaceDeclaration: - return bindBlockScopedDeclaration(node as Declaration, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes); + return bindBlockScopedDeclaration( + node as Declaration, + SymbolFlags.Interface, + SymbolFlags.InterfaceExcludes, + ); case SyntaxKind.TypeAliasDeclaration: - return bindBlockScopedDeclaration(node as Declaration, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); + return bindBlockScopedDeclaration( + node as Declaration, + SymbolFlags.TypeAlias, + SymbolFlags.TypeAliasExcludes, + ); case SyntaxKind.EnumDeclaration: return bindEnumDeclaration(node as EnumDeclaration); case SyntaxKind.ModuleDeclaration: @@ -2691,7 +3088,11 @@ namespace ts { case SyntaxKind.NamespaceImport: case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: - return declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Alias, SymbolFlags.AliasExcludes); + return declareSymbolAndAddToSymbolTable( + node as Declaration, + SymbolFlags.Alias, + SymbolFlags.AliasExcludes, + ); case SyntaxKind.NamespaceExportDeclaration: return bindNamespaceExportDeclaration(node as NamespaceExportDeclaration); case SyntaxKind.ImportClause: @@ -2721,14 +3122,18 @@ namespace ts { // falls through case SyntaxKind.JSDocPropertyTag: const propTag = node as JSDocPropertyLikeTag; - const flags = propTag.isBracketed || propTag.typeExpression && propTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType ? - SymbolFlags.Property | SymbolFlags.Optional : - SymbolFlags.Property; + const flags = propTag.isBracketed + || propTag.typeExpression + && propTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType + ? SymbolFlags.Property | SymbolFlags.Optional + : SymbolFlags.Property; return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes); case SyntaxKind.JSDocTypedefTag: case SyntaxKind.JSDocCallbackTag: case SyntaxKind.JSDocEnumTag: - return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag); + return (delayedTypeAliases || (delayedTypeAliases = [])).push( + node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag, + ); } } @@ -2736,7 +3141,11 @@ namespace ts { const isAutoAccessor = isAutoAccessorPropertyDeclaration(node); const includes = isAutoAccessor ? SymbolFlags.Accessor : SymbolFlags.Property; const excludes = isAutoAccessor ? SymbolFlags.AccessorExcludes : SymbolFlags.PropertyExcludes; - return bindPropertyOrMethodOrAccessor(node, includes | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), excludes); + return bindPropertyOrMethodOrAccessor( + node, + includes | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), + excludes, + ); } function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral) { @@ -2758,7 +3167,11 @@ namespace ts { } function bindSourceFileAsExternalModule() { - bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"` as __String); + bindAnonymousDeclaration( + file, + SymbolFlags.ValueModule, + `"${removeFileExtension(file.fileName)}"` as __String, + ); } function bindExportAssignment(node: ExportAssignment) { @@ -2789,14 +3202,21 @@ namespace ts { } const diag = !isSourceFile(node.parent) ? Diagnostics.Global_module_exports_may_only_appear_at_top_level : !isExternalModule(node.parent) ? Diagnostics.Global_module_exports_may_only_appear_in_module_files - : !node.parent.isDeclarationFile ? Diagnostics.Global_module_exports_may_only_appear_in_declaration_files + : !node.parent.isDeclarationFile + ? Diagnostics.Global_module_exports_may_only_appear_in_declaration_files : undefined; if (diag) { file.bindDiagnostics.push(createDiagnosticForNode(node, diag)); } else { file.symbol.globalExports = file.symbol.globalExports || createSymbolTable(); - declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes); + declareSymbol( + file.symbol.globalExports, + file.symbol, + node, + SymbolFlags.Alias, + SymbolFlags.AliasExcludes, + ); } } @@ -2807,13 +3227,25 @@ namespace ts { } else if (!node.exportClause) { // All export * declarations are collected in an __export symbol - declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.ExportStar, SymbolFlags.None); + declareSymbol( + container.symbol.exports, + container.symbol, + node, + SymbolFlags.ExportStar, + SymbolFlags.None, + ); } else if (isNamespaceExport(node.exportClause)) { // declareSymbol walks up parents to find name text, parent _must_ be set // but won't be set by the normal binder walk until `bindChildren` later on. setParent(node.exportClause, node); - declareSymbol(container.symbol.exports, container.symbol, node.exportClause, SymbolFlags.Alias, SymbolFlags.AliasExcludes); + declareSymbol( + container.symbol.exports, + container.symbol, + node.exportClause, + SymbolFlags.Alias, + SymbolFlags.AliasExcludes, + ); } } @@ -2865,7 +3297,9 @@ namespace ts { return symbol; }); if (symbol) { - const isAlias = isAliasableExpression(node.right) && (isExportsIdentifier(node.left.expression) || isModuleExportsAccessExpression(node.left.expression)); + const isAlias = isAliasableExpression(node.right) + && (isExportsIdentifier(node.left.expression) + || isModuleExportsAccessExpression(node.left.expression)); const flags = isAlias ? SymbolFlags.Alias : SymbolFlags.Property | SymbolFlags.ExportValue; setParent(node.left, node); declareSymbol(symbol.exports!, symbol, node.left, flags, SymbolFlags.None); @@ -2881,11 +3315,17 @@ namespace ts { return; } const assignedExpression = getRightMostAssignedExpression(node.right); - if (isEmptyObjectLiteral(assignedExpression) || container === file && isExportsOrModuleExportsOrAlias(file, assignedExpression)) { + if ( + isEmptyObjectLiteral(assignedExpression) + || container === file && isExportsOrModuleExportsOrAlias(file, assignedExpression) + ) { return; } - if (isObjectLiteralExpression(assignedExpression) && every(assignedExpression.properties, isShorthandPropertyAssignment)) { + if ( + isObjectLiteralExpression(assignedExpression) + && every(assignedExpression.properties, isShorthandPropertyAssignment) + ) { forEach(assignedExpression.properties, bindExportAssignedObjectMemberAlias); return; } @@ -2894,18 +3334,33 @@ namespace ts { const flags = exportAssignmentIsAlias(node) ? SymbolFlags.Alias // An export= with an EntityNameExpression or a ClassExpression exports all meanings of that identifier or class : SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule; - const symbol = declareSymbol(file.symbol.exports!, file.symbol, node, flags | SymbolFlags.Assignment, SymbolFlags.None); + const symbol = declareSymbol( + file.symbol.exports!, + file.symbol, + node, + flags | SymbolFlags.Assignment, + SymbolFlags.None, + ); setValueDeclaration(symbol, node); } function bindExportAssignedObjectMemberAlias(node: ShorthandPropertyAssignment) { - declareSymbol(file.symbol.exports!, file.symbol, node, SymbolFlags.Alias | SymbolFlags.Assignment, SymbolFlags.None); - } - - function bindThisPropertyAssignment(node: BindablePropertyAssignmentExpression | PropertyAccessExpression | LiteralLikeElementAccessExpression) { + declareSymbol( + file.symbol.exports!, + file.symbol, + node, + SymbolFlags.Alias | SymbolFlags.Assignment, + SymbolFlags.None, + ); + } + + function bindThisPropertyAssignment( + node: BindablePropertyAssignmentExpression | PropertyAccessExpression | LiteralLikeElementAccessExpression, + ) { Debug.assert(isInJSFile(node)); // private identifiers *must* be declared (even in JS files) - const hasPrivateIdentifier = (isBinaryExpression(node) && isPropertyAccessExpression(node.left) && isPrivateIdentifier(node.left.name)) + const hasPrivateIdentifier = (isBinaryExpression(node) && isPropertyAccessExpression(node.left) + && isPrivateIdentifier(node.left.name)) || (isPropertyAccessExpression(node) && isPrivateIdentifier(node.name)); if (hasPrivateIdentifier) { return; @@ -2916,10 +3371,16 @@ namespace ts { case SyntaxKind.FunctionExpression: let constructorSymbol: Symbol | undefined = thisContainer.symbol; // For `f.prototype.m = function() { this.x = 0; }`, `this.x = 0` should modify `f`'s members, not the function expression. - if (isBinaryExpression(thisContainer.parent) && thisContainer.parent.operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + isBinaryExpression(thisContainer.parent) + && thisContainer.parent.operatorToken.kind === SyntaxKind.EqualsToken + ) { const l = thisContainer.parent.left; if (isBindableStaticAccessExpression(l) && isPrototypeAccess(l.expression)) { - constructorSymbol = lookupSymbolForPropertyAccess(l.expression.expression, thisParentContainer); + constructorSymbol = lookupSymbolForPropertyAccess( + l.expression.expression, + thisParentContainer, + ); } } @@ -2928,12 +3389,26 @@ namespace ts { constructorSymbol.members = constructorSymbol.members || createSymbolTable(); // It's acceptable for multiple 'this' assignments of the same identifier to occur if (hasDynamicName(node)) { - bindDynamicallyNamedThisPropertyAssignment(node, constructorSymbol, constructorSymbol.members); + bindDynamicallyNamedThisPropertyAssignment( + node, + constructorSymbol, + constructorSymbol.members, + ); } else { - declareSymbol(constructorSymbol.members, constructorSymbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property); + declareSymbol( + constructorSymbol.members, + constructorSymbol, + node, + SymbolFlags.Property | SymbolFlags.Assignment, + SymbolFlags.PropertyExcludes & ~SymbolFlags.Property, + ); } - addDeclarationToSymbol(constructorSymbol, constructorSymbol.valueDeclaration, SymbolFlags.Class); + addDeclarationToSymbol( + constructorSymbol, + constructorSymbol.valueDeclaration, + SymbolFlags.Class, + ); } break; @@ -2946,12 +3421,20 @@ namespace ts { // this.foo assignment in a JavaScript class // Bind this property to the containing class const containingClass = thisContainer.parent; - const symbolTable = isStatic(thisContainer) ? containingClass.symbol.exports! : containingClass.symbol.members!; + const symbolTable = isStatic(thisContainer) ? containingClass.symbol.exports! + : containingClass.symbol.members!; if (hasDynamicName(node)) { bindDynamicallyNamedThisPropertyAssignment(node, containingClass.symbol, symbolTable); } else { - declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.None, /*isReplaceableByMethod*/ true); + declareSymbol( + symbolTable, + containingClass.symbol, + node, + SymbolFlags.Property | SymbolFlags.Assignment, + SymbolFlags.None, + /*isReplaceableByMethod*/ true, + ); } break; case SyntaxKind.SourceFile: @@ -2960,10 +3443,20 @@ namespace ts { break; } else if ((thisContainer as SourceFile).commonJsModuleIndicator) { - declareSymbol(thisContainer.symbol.exports!, thisContainer.symbol, node, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None); + declareSymbol( + thisContainer.symbol.exports!, + thisContainer.symbol, + node, + SymbolFlags.Property | SymbolFlags.ExportValue, + SymbolFlags.None, + ); } else { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes); + declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.FunctionScopedVariable, + SymbolFlags.FunctionScopedVariableExcludes, + ); } break; @@ -2972,14 +3465,32 @@ namespace ts { } } - function bindDynamicallyNamedThisPropertyAssignment(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol, symbolTable: SymbolTable) { - declareSymbol(symbolTable, symbol, node, SymbolFlags.Property, SymbolFlags.None, /*isReplaceableByMethod*/ true, /*isComputedName*/ true); + function bindDynamicallyNamedThisPropertyAssignment( + node: BinaryExpression | DynamicNamedDeclaration, + symbol: Symbol, + symbolTable: SymbolTable, + ) { + declareSymbol( + symbolTable, + symbol, + node, + SymbolFlags.Property, + SymbolFlags.None, + /*isReplaceableByMethod*/ true, + /*isComputedName*/ true, + ); addLateBoundAssignmentDeclarationToSymbol(node, symbol); } - function addLateBoundAssignmentDeclarationToSymbol(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol | undefined) { + function addLateBoundAssignmentDeclarationToSymbol( + node: BinaryExpression | DynamicNamedDeclaration, + symbol: Symbol | undefined, + ) { if (symbol) { - (symbol.assignmentDeclarationMembers || (symbol.assignmentDeclarationMembers = new Map())).set(getNodeId(node), node); + (symbol.assignmentDeclarationMembers || (symbol.assignmentDeclarationMembers = new Map())).set( + getNodeId(node), + node, + ); } } @@ -3001,11 +3512,18 @@ namespace ts { function bindPrototypeAssignment(node: BindableStaticPropertyAssignmentExpression) { setParent(node.left, node); setParent(node.right, node); - bindPropertyAssignment(node.left.expression, node.left, /*isPrototypeProperty*/ false, /*containerIsClass*/ true); + bindPropertyAssignment( + node.left.expression, + node.left, + /*isPrototypeProperty*/ false, + /*containerIsClass*/ true, + ); } function bindObjectDefinePrototypeProperty(node: BindableObjectDefinePropertyCall) { - const namespaceSymbol = lookupSymbolForPropertyAccess((node.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression); + const namespaceSymbol = lookupSymbolForPropertyAccess( + (node.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression, + ); if (namespaceSymbol && namespaceSymbol.valueDeclaration) { // Ensure the namespace symbol becomes class-like addDeclarationToSymbol(namespaceSymbol, namespaceSymbol.valueDeclaration, SymbolFlags.Class); @@ -3034,32 +3552,55 @@ namespace ts { function bindObjectDefinePropertyAssignment(node: BindableObjectDefinePropertyCall) { let namespaceSymbol = lookupSymbolForPropertyAccess(node.arguments[0]); const isToplevel = node.parent.parent.kind === SyntaxKind.SourceFile; - namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, node.arguments[0], isToplevel, /*isPrototypeProperty*/ false, /*containerIsClass*/ false); + namespaceSymbol = bindPotentiallyMissingNamespaces( + namespaceSymbol, + node.arguments[0], + isToplevel, + /*isPrototypeProperty*/ false, + /*containerIsClass*/ false, + ); bindPotentiallyNewExpandoMemberToNamespace(node, namespaceSymbol, /*isPrototypeProperty*/ false); } function bindSpecialPropertyAssignment(node: BindablePropertyAssignmentExpression) { // Class declarations in Typescript do not allow property declarations - const parentSymbol = lookupSymbolForPropertyAccess(node.left.expression, container) || lookupSymbolForPropertyAccess(node.left.expression, blockScopeContainer); + const parentSymbol = lookupSymbolForPropertyAccess(node.left.expression, container) + || lookupSymbolForPropertyAccess(node.left.expression, blockScopeContainer); if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) { return; } const rootExpr = getLeftmostAccessExpression(node.left); - if (isIdentifier(rootExpr) && lookupSymbolForName(container, rootExpr.escapedText)?.flags! & SymbolFlags.Alias) { + if ( + isIdentifier(rootExpr) + && lookupSymbolForName(container, rootExpr.escapedText)?.flags! & SymbolFlags.Alias + ) { return; } // Fix up parent pointers since we're going to use these nodes before we bind into them setParent(node.left, node); setParent(node.right, node); - if (isIdentifier(node.left.expression) && container === file && isExportsOrModuleExportsOrAlias(file, node.left.expression)) { + if ( + isIdentifier(node.left.expression) && container === file + && isExportsOrModuleExportsOrAlias(file, node.left.expression) + ) { // This can be an alias for the 'exports' or 'module.exports' names, e.g. // var util = module.exports; // util.property = function ... bindExportsPropertyAssignment(node as BindableStaticPropertyAssignmentExpression); } else if (hasDynamicName(node)) { - bindAnonymousDeclaration(node, SymbolFlags.Property | SymbolFlags.Assignment, InternalSymbolName.Computed); - const sym = bindPotentiallyMissingNamespaces(parentSymbol, node.left.expression, isTopLevelNamespaceAssignment(node.left), /*isPrototype*/ false, /*containerIsClass*/ false); + bindAnonymousDeclaration( + node, + SymbolFlags.Property | SymbolFlags.Assignment, + InternalSymbolName.Computed, + ); + const sym = bindPotentiallyMissingNamespaces( + parentSymbol, + node.left.expression, + isTopLevelNamespaceAssignment(node.left), + /*isPrototype*/ false, + /*containerIsClass*/ false, + ); addLateBoundAssignmentDeclarationToSymbol(node, sym); } else { @@ -3077,7 +3618,13 @@ namespace ts { bindPropertyAssignment(node.expression, node, /*isPrototypeProperty*/ false, /*containerIsClass*/ false); } - function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: BindableStaticNameExpression, isToplevel: boolean, isPrototypeProperty: boolean, containerIsClass: boolean) { + function bindPotentiallyMissingNamespaces( + namespaceSymbol: Symbol | undefined, + entityName: BindableStaticNameExpression, + isToplevel: boolean, + isPrototypeProperty: boolean, + containerIsClass: boolean, + ) { if (namespaceSymbol?.flags! & SymbolFlags.Alias) { return namespaceSymbol; } @@ -3091,8 +3638,8 @@ namespace ts { return symbol; } else { - const table = parent ? parent.exports! : - file.jsGlobalAugmentations || (file.jsGlobalAugmentations = createSymbolTable()); + const table = parent ? parent.exports! + : file.jsGlobalAugmentations || (file.jsGlobalAugmentations = createSymbolTable()); return declareSymbol(table, parent, id, flags, excludeFlags); } }); @@ -3103,15 +3650,19 @@ namespace ts { return namespaceSymbol; } - function bindPotentiallyNewExpandoMemberToNamespace(declaration: BindableStaticAccessExpression | CallExpression, namespaceSymbol: Symbol | undefined, isPrototypeProperty: boolean) { + function bindPotentiallyNewExpandoMemberToNamespace( + declaration: BindableStaticAccessExpression | CallExpression, + namespaceSymbol: Symbol | undefined, + isPrototypeProperty: boolean, + ) { if (!namespaceSymbol || !isExpandoSymbol(namespaceSymbol)) { return; } // Set up the members collection if it doesn't exist already - const symbolTable = isPrototypeProperty ? - (namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) : - (namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable())); + const symbolTable = isPrototypeProperty + ? (namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) + : (namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable())); let includes = SymbolFlags.None; let excludes = SymbolFlags.None; @@ -3149,7 +3700,13 @@ namespace ts { excludes = SymbolFlags.PropertyExcludes; } - declareSymbol(symbolTable, namespaceSymbol, declaration, includes | SymbolFlags.Assignment, excludes & ~SymbolFlags.Assignment); + declareSymbol( + symbolTable, + namespaceSymbol, + declaration, + includes | SymbolFlags.Assignment, + excludes & ~SymbolFlags.Assignment, + ); } function isTopLevelNamespaceAssignment(propertyAccess: BindableAccessExpression) { @@ -3158,10 +3715,22 @@ namespace ts { : propertyAccess.parent.parent.kind === SyntaxKind.SourceFile; } - function bindPropertyAssignment(name: BindableStaticNameExpression, propertyAccess: BindableStaticAccessExpression, isPrototypeProperty: boolean, containerIsClass: boolean) { - let namespaceSymbol = lookupSymbolForPropertyAccess(name, container) || lookupSymbolForPropertyAccess(name, blockScopeContainer); + function bindPropertyAssignment( + name: BindableStaticNameExpression, + propertyAccess: BindableStaticAccessExpression, + isPrototypeProperty: boolean, + containerIsClass: boolean, + ) { + let namespaceSymbol = lookupSymbolForPropertyAccess(name, container) + || lookupSymbolForPropertyAccess(name, blockScopeContainer); const isToplevel = isTopLevelNamespaceAssignment(propertyAccess); - namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, propertyAccess.expression, isToplevel, isPrototypeProperty, containerIsClass); + namespaceSymbol = bindPotentiallyMissingNamespaces( + namespaceSymbol, + propertyAccess.expression, + isToplevel, + isPrototypeProperty, + containerIsClass, + ); bindPotentiallyNewExpandoMemberToNamespace(propertyAccess, namespaceSymbol, isPrototypeProperty); } @@ -3183,15 +3752,22 @@ namespace ts { if (node && isCallExpression(node)) { return !!getAssignedExpandoInitializer(node); } - let init = !node ? undefined : - isVariableDeclaration(node) ? node.initializer : - isBinaryExpression(node) ? node.right : - isPropertyAccessExpression(node) && isBinaryExpression(node.parent) ? node.parent.right : - undefined; + let init = !node ? undefined + : isVariableDeclaration(node) ? node.initializer + : isBinaryExpression(node) ? node.right + : isPropertyAccessExpression(node) && isBinaryExpression(node.parent) ? node.parent.right + : undefined; init = init && getRightMostAssignedExpression(init); if (init) { - const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node!) ? node.name : isBinaryExpression(node!) ? node.left : node!); - return !!getExpandoInitializer(isBinaryExpression(init) && (init.operatorToken.kind === SyntaxKind.BarBarToken || init.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? init.right : init, isPrototypeAssignment); + const isPrototypeAssignment = isPrototypeAccess( + isVariableDeclaration(node!) ? node.name : isBinaryExpression(node!) ? node.left : node!, + ); + return !!getExpandoInitializer( + isBinaryExpression(init) + && (init.operatorToken.kind === SyntaxKind.BarBarToken + || init.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? init.right : init, + isPrototypeAssignment, + ); } return false; } @@ -3203,7 +3779,10 @@ namespace ts { return expr.parent; } - function lookupSymbolForPropertyAccess(node: BindableStaticNameExpression, lookupContainer: Node = container): Symbol | undefined { + function lookupSymbolForPropertyAccess( + node: BindableStaticNameExpression, + lookupContainer: Node = container, + ): Symbol | undefined { if (isIdentifier(node)) { return lookupSymbolForName(lookupContainer, node.escapedText); } @@ -3213,7 +3792,11 @@ namespace ts { } } - function forEachIdentifierInEntityName(e: BindableStaticNameExpression, parent: Symbol | undefined, action: (e: Declaration, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined { + function forEachIdentifierInEntityName( + e: BindableStaticNameExpression, + parent: Symbol | undefined, + action: (e: Declaration, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined, + ): Symbol | undefined { if (isExportsOrModuleExportsOrAlias(file, e)) { return file.symbol; } @@ -3269,7 +3852,13 @@ namespace ts { if (node.name) { setParent(node.name, node); } - file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations![0], Diagnostics.Duplicate_identifier_0, symbolName(prototypeSymbol))); + file.bindDiagnostics.push( + createDiagnosticForNode( + symbolExport.declarations![0], + Diagnostics.Duplicate_identifier_0, + symbolName(prototypeSymbol), + ), + ); } symbol.exports!.set(prototypeSymbol.escapedName, prototypeSymbol); prototypeSymbol.parent = symbol; @@ -3289,15 +3878,19 @@ namespace ts { if (!isBindingPattern(node.name)) { const possibleVariableDecl = node.kind === SyntaxKind.VariableDeclaration ? node : node.parent.parent; if ( - isInJSFile(node) && - isVariableDeclarationInitializedToBareOrAccessedRequire(possibleVariableDecl) && - !getJSDocTypeTag(node) && - !(getCombinedModifierFlags(node) & ModifierFlags.Export) + isInJSFile(node) + && isVariableDeclarationInitializedToBareOrAccessedRequire(possibleVariableDecl) + && !getJSDocTypeTag(node) + && !(getCombinedModifierFlags(node) & ModifierFlags.Export) ) { declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Alias, SymbolFlags.AliasExcludes); } else if (isBlockOrCatchScoped(node)) { - bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes); + bindBlockScopedDeclaration( + node, + SymbolFlags.BlockScopedVariable, + SymbolFlags.BlockScopedVariableExcludes, + ); } else if (isParameterDeclaration(node)) { // It is safe to walk up parent chain to find whether the node is a destructuring parameter declaration @@ -3309,10 +3902,18 @@ namespace ts { // function foo([a,a]) {} // Duplicate Identifier error // function bar(a,a) {} // Duplicate Identifier error, parameter declaration in this case is handled in bindParameter // // which correctly set excluded symbols - declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes); + declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.FunctionScopedVariable, + SymbolFlags.ParameterExcludes, + ); } else { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes); + declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.FunctionScopedVariable, + SymbolFlags.FunctionScopedVariableExcludes, + ); } } } @@ -3328,17 +3929,34 @@ namespace ts { } if (isBindingPattern(node.name)) { - bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, "__" + (node as ParameterDeclaration).parent.parameters.indexOf(node as ParameterDeclaration) as __String); + bindAnonymousDeclaration( + node, + SymbolFlags.FunctionScopedVariable, + "__" + + (node as ParameterDeclaration).parent.parameters.indexOf( + node as ParameterDeclaration, + ) as __String, + ); } else { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes); + declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.FunctionScopedVariable, + SymbolFlags.ParameterExcludes, + ); } // If this is a property-parameter, then also declare the property symbol into the // containing class. if (isParameterPropertyDeclaration(node, node.parent)) { const classDeclaration = node.parent.parent; - declareSymbol(classDeclaration.symbol.members!, classDeclaration.symbol, node, SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes); + declareSymbol( + classDeclaration.symbol.members!, + classDeclaration.symbol, + node, + SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), + SymbolFlags.PropertyExcludes, + ); } } @@ -3373,7 +3991,11 @@ namespace ts { return bindAnonymousDeclaration(node, SymbolFlags.Function, bindingName); } - function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) { + function bindPropertyOrMethodOrAccessor( + node: Declaration, + symbolFlags: SymbolFlags, + symbolExcludes: SymbolFlags, + ) { if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient) && isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } @@ -3388,7 +4010,10 @@ namespace ts { } function getInferTypeContainer(node: Node): ConditionalTypeNode | undefined { - const extendsType = findAncestor(node, n => n.parent && isConditionalTypeNode(n.parent) && n.parent.extendsType === n); + const extendsType = findAncestor( + node, + n => n.parent && isConditionalTypeNode(n.parent) && n.parent.extendsType === n, + ); return extendsType && extendsType.parent as ConditionalTypeNode; } @@ -3399,10 +4024,20 @@ namespace ts { if (!container.locals) { container.locals = createSymbolTable(); } - declareSymbol(container.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); + declareSymbol( + container.locals, + /*parent*/ undefined, + node, + SymbolFlags.TypeParameter, + SymbolFlags.TypeParameterExcludes, + ); } else { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); + declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.TypeParameter, + SymbolFlags.TypeParameterExcludes, + ); } } else if (node.parent.kind === SyntaxKind.InferType) { @@ -3411,7 +4046,13 @@ namespace ts { if (!container.locals) { container.locals = createSymbolTable(); } - declareSymbol(container.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); + declareSymbol( + container.locals, + /*parent*/ undefined, + node, + SymbolFlags.TypeParameter, + SymbolFlags.TypeParameterExcludes, + ); } else { bindAnonymousDeclaration(node, SymbolFlags.TypeParameter, getDeclarationName(node)!); // TODO: GH#18217 @@ -3426,7 +4067,8 @@ namespace ts { function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean { const instanceState = getModuleInstanceState(node); - return instanceState === ModuleInstanceState.Instantiated || (instanceState === ModuleInstanceState.ConstEnumOnly && shouldPreserveConstEnums(options)); + return instanceState === ModuleInstanceState.Instantiated + || (instanceState === ModuleInstanceState.ConstEnumOnly && shouldPreserveConstEnums(options)); } function checkUnreachable(node: Node): boolean { @@ -3436,11 +4078,12 @@ namespace ts { if (currentFlow === unreachableFlow) { const reportError = // report error on all statements except empty ones - (isStatementButNotDeclaration(node) && node.kind !== SyntaxKind.EmptyStatement) || + (isStatementButNotDeclaration(node) && node.kind !== SyntaxKind.EmptyStatement) // report error on class declarations - node.kind === SyntaxKind.ClassDeclaration || + || node.kind === SyntaxKind.ClassDeclaration // report error on instantiated modules or const-enums only modules if preserveConstEnums is set - (node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(node as ModuleDeclaration)); + || (node.kind === SyntaxKind.ModuleDeclaration + && shouldReportErrorOnModuleDeclaration(node as ModuleDeclaration)); if (reportError) { currentFlow = reportedUnreachableFlow; @@ -3455,15 +4098,19 @@ namespace ts { // - node is not block scoped variable statement and at least one variable declaration has initializer // Rationale: we don't want to report errors on non-initialized var's since they are hoisted // On the other side we do want to report errors on non-initialized 'lets' because of TDZ - const isError = unreachableCodeIsError(options) && - !(node.flags & NodeFlags.Ambient) && - ( - !isVariableStatement(node) || - !!(getCombinedNodeFlags(node.declarationList) & NodeFlags.BlockScoped) || - node.declarationList.declarations.some(d => !!d.initializer) + const isError = unreachableCodeIsError(options) + && !(node.flags & NodeFlags.Ambient) + && ( + !isVariableStatement(node) + || !!(getCombinedNodeFlags(node.declarationList) & NodeFlags.BlockScoped) + || node.declarationList.declarations.some(d => !!d.initializer) ); - eachUnreachableRange(node, (start, end) => errorOrSuggestionOnRange(isError, start, end, Diagnostics.Unreachable_code_detected)); + eachUnreachableRange( + node, + (start, end) => + errorOrSuggestionOnRange(isError, start, end, Diagnostics.Unreachable_code_detected), + ); } } } @@ -3484,9 +4131,10 @@ namespace ts { // As opposed to a pure declaration like an `interface` function isExecutableStatement(s: Statement): boolean { // Don't remove statements that can validly be used before they appear. - return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && !isEnumDeclaration(s) && + return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && !isEnumDeclaration(s) // `var x;` may declare a variable used above - !(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer)); + && !(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) + && s.declarationList.declarations.some(d => !d.initializer)); } function isPurelyTypeDeclaration(s: Statement): boolean { @@ -3515,7 +4163,10 @@ namespace ts { } else if (isIdentifier(node)) { const symbol = lookupSymbolForName(sourceFile, node.escapedText); - if (!!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && !!symbol.valueDeclaration.initializer) { + if ( + !!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) + && !!symbol.valueDeclaration.initializer + ) { const init = symbol.valueDeclaration.initializer; q.enqueue(init); if (isAssignmentExpression(init, /*excludeCompoundAssignment*/ true)) { diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 3345c08560ede..33b9c070ddd1e 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -148,16 +148,31 @@ namespace ts { > & { changedFilesSet: BuilderProgramState["changedFilesSet"] | undefined; }; - function hasSameKeys(map1: ReadonlyCollection | undefined, map2: ReadonlyCollection | undefined): boolean { + function hasSameKeys( + map1: ReadonlyCollection | undefined, + map2: ReadonlyCollection | undefined, + ): boolean { // Has same size and every key is present in both maps - return map1 === map2 || map1 !== undefined && map2 !== undefined && map1.size === map2.size && !forEachKey(map1, key => !map2.has(key)); + return map1 === map2 + || map1 !== undefined && map2 !== undefined && map1.size === map2.size + && !forEachKey(map1, key => !map2.has(key)); } /** * Create the state so that we can iterate on changedFiles/affected files */ - function createBuilderProgramState(newProgram: Program, getCanonicalFileName: GetCanonicalFileName, oldState: Readonly | undefined, disableUseFileVersionAsSignature: boolean | undefined): BuilderProgramState { - const state = BuilderState.create(newProgram, getCanonicalFileName, oldState, disableUseFileVersionAsSignature) as BuilderProgramState; + function createBuilderProgramState( + newProgram: Program, + getCanonicalFileName: GetCanonicalFileName, + oldState: Readonly | undefined, + disableUseFileVersionAsSignature: boolean | undefined, + ): BuilderProgramState { + const state = BuilderState.create( + newProgram, + getCanonicalFileName, + oldState, + disableUseFileVersionAsSignature, + ) as BuilderProgramState; state.program = newProgram; const compilerOptions = newProgram.getCompilerOptions(); state.compilerOptions = compilerOptions; @@ -166,7 +181,9 @@ namespace ts { if (!outFilePath) { state.semanticDiagnosticsPerFile = new Map(); } - else if (compilerOptions.composite && oldState?.outSignature && outFilePath === outFile(oldState?.compilerOptions)) { + else if ( + compilerOptions.composite && oldState?.outSignature && outFilePath === outFile(oldState?.compilerOptions) + ) { state.outSignature = oldState?.outSignature; } state.changedFilesSet = new Set(); @@ -174,24 +191,26 @@ namespace ts { const useOldState = BuilderState.canReuseOldState(state.referencedMap, oldState); const oldCompilerOptions = useOldState ? oldState!.compilerOptions : undefined; - const canCopySemanticDiagnostics = useOldState && oldState!.semanticDiagnosticsPerFile && !!state.semanticDiagnosticsPerFile && - !compilerOptionsAffectSemanticDiagnostics(compilerOptions, oldCompilerOptions!); + const canCopySemanticDiagnostics = useOldState && oldState!.semanticDiagnosticsPerFile + && !!state.semanticDiagnosticsPerFile + && !compilerOptionsAffectSemanticDiagnostics(compilerOptions, oldCompilerOptions!); // We can only reuse emit signatures (i.e. .d.ts signatures) if the .d.ts file is unchanged, // which will eg be depedent on change in options like declarationDir and outDir options are unchanged. // We need to look in oldState.compilerOptions, rather than oldCompilerOptions (i.e.we need to disregard useOldState) because // oldCompilerOptions can be undefined if there was change in say module from None to some other option // which would make useOldState as false since we can now use reference maps that are needed to track what to emit, what to check etc // but that option change does not affect d.ts file name so emitSignatures should still be reused. - const canCopyEmitSignatures = compilerOptions.composite && - oldState?.emitSignatures && - !outFilePath && - !compilerOptionsAffectDeclarationPath(compilerOptions, oldState.compilerOptions); + const canCopyEmitSignatures = compilerOptions.composite + && oldState?.emitSignatures + && !outFilePath + && !compilerOptionsAffectDeclarationPath(compilerOptions, oldState.compilerOptions); if (useOldState) { // Copy old state's changed files set oldState!.changedFilesSet?.forEach(value => state.changedFilesSet.add(value)); if (!outFilePath && oldState!.affectedFilesPendingEmit) { state.affectedFilesPendingEmit = oldState!.affectedFilesPendingEmit.slice(); - state.affectedFilesPendingEmitKind = oldState!.affectedFilesPendingEmitKind && new Map(oldState!.affectedFilesPendingEmitKind); + state.affectedFilesPendingEmitKind = oldState!.affectedFilesPendingEmitKind + && new Map(oldState!.affectedFilesPendingEmitKind); state.affectedFilesPendingEmitIndex = oldState!.affectedFilesPendingEmitIndex; state.seenAffectedFiles = new Set(); } @@ -200,25 +219,31 @@ namespace ts { // Update changed files and copy semantic diagnostics if we can const referencedMap = state.referencedMap; const oldReferencedMap = useOldState ? oldState!.referencedMap : undefined; - const copyDeclarationFileDiagnostics = canCopySemanticDiagnostics && !compilerOptions.skipLibCheck === !oldCompilerOptions!.skipLibCheck; - const copyLibFileDiagnostics = copyDeclarationFileDiagnostics && !compilerOptions.skipDefaultLibCheck === !oldCompilerOptions!.skipDefaultLibCheck; + const copyDeclarationFileDiagnostics = canCopySemanticDiagnostics + && !compilerOptions.skipLibCheck === !oldCompilerOptions!.skipLibCheck; + const copyLibFileDiagnostics = copyDeclarationFileDiagnostics + && !compilerOptions.skipDefaultLibCheck === !oldCompilerOptions!.skipDefaultLibCheck; state.fileInfos.forEach((info, sourceFilePath) => { let oldInfo: Readonly | undefined; let newReferences: ReadonlySet | undefined; // if not using old state, every file is changed if ( - !useOldState || + !useOldState // File wasn't present in old state - !(oldInfo = oldState!.fileInfos.get(sourceFilePath)) || + || !(oldInfo = oldState!.fileInfos.get(sourceFilePath)) // versions dont match - oldInfo.version !== info.version || + || oldInfo.version !== info.version // Implied formats dont match - oldInfo.impliedFormat !== info.impliedFormat || + || oldInfo.impliedFormat !== info.impliedFormat // Referenced files changed - !hasSameKeys(newReferences = referencedMap && referencedMap.getValues(sourceFilePath), oldReferencedMap && oldReferencedMap.getValues(sourceFilePath)) || + || !hasSameKeys( + newReferences = referencedMap && referencedMap.getValues(sourceFilePath), + oldReferencedMap && oldReferencedMap.getValues(sourceFilePath), + ) // Referenced file was deleted in the new program - newReferences && forEachKey(newReferences, path => !state.fileInfos.has(path) && oldState!.fileInfos.has(path)) + || newReferences + && forEachKey(newReferences, path => !state.fileInfos.has(path) && oldState!.fileInfos.has(path)) ) { // Register file as changed file and do not copy semantic diagnostics, since all changed files need to be re-evaluated state.changedFilesSet.add(sourceFilePath); @@ -232,7 +257,15 @@ namespace ts { // Unchanged file copy diagnostics const diagnostics = oldState!.semanticDiagnosticsPerFile!.get(sourceFilePath); if (diagnostics) { - state.semanticDiagnosticsPerFile!.set(sourceFilePath, oldState!.hasReusableDiagnostic ? convertToDiagnostics(diagnostics as readonly ReusableDiagnostic[], newProgram, getCanonicalFileName) : diagnostics as readonly Diagnostic[]); + state.semanticDiagnosticsPerFile!.set( + sourceFilePath, + oldState!.hasReusableDiagnostic + ? convertToDiagnostics( + diagnostics as readonly ReusableDiagnostic[], + newProgram, + getCanonicalFileName, + ) : diagnostics as readonly Diagnostic[], + ); if (!state.semanticDiagnosticsFromOldState) { state.semanticDiagnosticsFromOldState = new Set(); } @@ -246,24 +279,42 @@ namespace ts { }); // If the global file is removed, add all files as changed - if (useOldState && forEachEntry(oldState!.fileInfos, (info, sourceFilePath) => info.affectsGlobalScope && !state.fileInfos.has(sourceFilePath))) { + if ( + useOldState + && forEachEntry( + oldState!.fileInfos, + (info, sourceFilePath) => info.affectsGlobalScope && !state.fileInfos.has(sourceFilePath), + ) + ) { BuilderState.getAllFilesExcludingDefaultLibraryFile(state, newProgram, /*firstSourceFile*/ undefined) .forEach(file => state.changedFilesSet.add(file.resolvedPath)); } else if (oldCompilerOptions && !outFilePath && compilerOptionsAffectEmit(compilerOptions, oldCompilerOptions)) { // Add all files to affectedFilesPendingEmit since emit changed - newProgram.getSourceFiles().forEach(f => addToAffectedFilesPendingEmit(state, f.resolvedPath, BuilderFileEmit.Full)); + newProgram.getSourceFiles().forEach(f => + addToAffectedFilesPendingEmit(state, f.resolvedPath, BuilderFileEmit.Full) + ); Debug.assert(!state.seenAffectedFiles || !state.seenAffectedFiles.size); state.seenAffectedFiles = state.seenAffectedFiles || new Set(); } // Since old states change files set is copied, any additional change means we would need to emit build info - state.buildInfoEmitPending = !useOldState || state.changedFilesSet.size !== (oldState!.changedFilesSet?.size || 0); + state.buildInfoEmitPending = !useOldState + || state.changedFilesSet.size !== (oldState!.changedFilesSet?.size || 0); return state; } - function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], newProgram: Program, getCanonicalFileName: GetCanonicalFileName): readonly Diagnostic[] { + function convertToDiagnostics( + diagnostics: readonly ReusableDiagnostic[], + newProgram: Program, + getCanonicalFileName: GetCanonicalFileName, + ): readonly Diagnostic[] { if (!diagnostics.length) return emptyArray; - const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(newProgram.getCompilerOptions())!, newProgram.getCurrentDirectory())); + const buildInfoDirectory = getDirectoryPath( + getNormalizedAbsolutePath( + getTsBuildInfoEmitOutputFilePath(newProgram.getCompilerOptions())!, + newProgram.getCurrentDirectory(), + ), + ); return diagnostics.map(diagnostic => { const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, newProgram, toPath); result.reportsUnnecessary = diagnostic.reportsUnnecessary; @@ -271,11 +322,11 @@ namespace ts { result.source = diagnostic.source; result.skippedOn = diagnostic.skippedOn; const { relatedInformation } = diagnostic; - result.relatedInformation = relatedInformation ? - relatedInformation.length ? - relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, newProgram, toPath)) : - [] : - undefined; + result.relatedInformation = relatedInformation + ? relatedInformation.length + ? relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, newProgram, toPath)) + : [] + : undefined; return result; }); @@ -284,7 +335,11 @@ namespace ts { } } - function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program, toPath: (path: string) => Path): DiagnosticRelatedInformation { + function convertToDiagnosticRelatedInformation( + diagnostic: ReusableDiagnosticRelatedInformation, + newProgram: Program, + toPath: (path: string) => Path, + ): DiagnosticRelatedInformation { const { file } = diagnostic; return { ...diagnostic, @@ -306,7 +361,8 @@ namespace ts { Debug.assert(!state.changedFilesSet.size || outFilePath); return { affectedFilesPendingEmit: state.affectedFilesPendingEmit && state.affectedFilesPendingEmit.slice(), - affectedFilesPendingEmitKind: state.affectedFilesPendingEmitKind && new Map(state.affectedFilesPendingEmitKind), + affectedFilesPendingEmitKind: state.affectedFilesPendingEmitKind + && new Map(state.affectedFilesPendingEmitKind), affectedFilesPendingEmitIndex: state.affectedFilesPendingEmitIndex, seenEmittedFiles: state.seenEmittedFiles && new Map(state.seenEmittedFiles), programEmitComplete: state.programEmitComplete, @@ -335,7 +391,10 @@ namespace ts { * Verifies that source file is ok to be used in calls that arent handled by next */ function assertSourceFileOkWithoutNextAffectedCall(state: BuilderProgramState, sourceFile: SourceFile | undefined) { - Debug.assert(!sourceFile || !state.affectedFiles || state.affectedFiles[state.affectedFilesIndex! - 1] !== sourceFile || !state.semanticDiagnosticsPerFile!.has(sourceFile.resolvedPath)); + Debug.assert( + !sourceFile || !state.affectedFiles || state.affectedFiles[state.affectedFilesIndex! - 1] !== sourceFile + || !state.semanticDiagnosticsPerFile!.has(sourceFile.resolvedPath), + ); } /** @@ -431,7 +490,9 @@ namespace ts { const affectedFile = Debug.checkDefined(state.program).getSourceFileByPath(affectedFilesPendingEmit[i]); if (affectedFile) { const seenKind = seenEmittedFiles.get(affectedFile.resolvedPath); - const emitKind = Debug.checkDefined(Debug.checkDefined(state.affectedFilesPendingEmitKind).get(affectedFile.resolvedPath)); + const emitKind = Debug.checkDefined( + Debug.checkDefined(state.affectedFilesPendingEmitKind).get(affectedFile.resolvedPath), + ); if (seenKind === undefined || seenKind < emitKind) { // emit this file state.affectedFilesPendingEmitIndex = i; @@ -450,9 +511,9 @@ namespace ts { const program = Debug.checkDefined(state.program); const options = program.getCompilerOptions(); forEach(program.getSourceFiles(), f => - program.isSourceFileDefaultLibrary(f) && - !skipTypeChecking(f, options, program) && - removeSemanticDiagnosticsOf(state, f.resolvedPath)); + program.isSourceFileDefaultLibrary(f) + && !skipTypeChecking(f, options, program) + && removeSemanticDiagnosticsOf(state, f.resolvedPath)); } } @@ -607,8 +668,24 @@ namespace ts { const currentPath = queue.pop()!; if (!seenFileNamesMap.has(currentPath)) { seenFileNamesMap.set(currentPath, true); - if (handleDtsMayChangeOfGlobalScope(state, currentPath, cancellationToken, computeHash, getCanonicalFileName, host)) return; - handleDtsMayChangeOf(state, currentPath, cancellationToken, computeHash, getCanonicalFileName, host); + if ( + handleDtsMayChangeOfGlobalScope( + state, + currentPath, + cancellationToken, + computeHash, + getCanonicalFileName, + host, + ) + ) return; + handleDtsMayChangeOf( + state, + currentPath, + cancellationToken, + computeHash, + getCanonicalFileName, + host, + ); if (isChangedSignature(state, currentPath)) { const currentSourceFile = Debug.checkDefined(state.program).getSourceFileByPath(currentPath)!; queue.push(...BuilderState.getReferencedByPaths(state, currentSourceFile.resolvedPath)); @@ -621,7 +698,16 @@ namespace ts { // Go through exported modules from cache first // If exported modules has path, all files referencing file exported from are affected state.exportedModulesMap.getKeys(affectedFile.resolvedPath)?.forEach(exportedFromPath => { - if (handleDtsMayChangeOfGlobalScope(state, exportedFromPath, cancellationToken, computeHash, getCanonicalFileName, host)) return true; + if ( + handleDtsMayChangeOfGlobalScope( + state, + exportedFromPath, + cancellationToken, + computeHash, + getCanonicalFileName, + host, + ) + ) return true; const references = state.referencedMap!.getKeys(exportedFromPath); return references && forEachKey(references, filePath => handleDtsMayChangeOfFileAndExportsOfFile( @@ -651,7 +737,9 @@ namespace ts { ): boolean | undefined { if (!tryAddToSet(seenFileAndExportsOfFile, filePath)) return undefined; - if (handleDtsMayChangeOfGlobalScope(state, filePath, cancellationToken, computeHash, getCanonicalFileName, host)) return true; + if ( + handleDtsMayChangeOfGlobalScope(state, filePath, cancellationToken, computeHash, getCanonicalFileName, host) + ) return true; handleDtsMayChangeOf(state, filePath, cancellationToken, computeHash, getCanonicalFileName, host); // If exported modules has path, all files referencing file exported from are affected @@ -669,8 +757,8 @@ namespace ts { // Remove diagnostics of files that import this file (without going to exports of referencing files) state.referencedMap!.getKeys(filePath)?.forEach(referencingFilePath => - !seenFileAndExportsOfFile.has(referencingFilePath) && // Not already removed diagnostic file - handleDtsMayChangeOf( // Dont add to seen since this is not yet done with the export removal + !seenFileAndExportsOfFile.has(referencingFilePath) // Not already removed diagnostic file + && handleDtsMayChangeOf( // Dont add to seen since this is not yet done with the export removal state, referencingFilePath, cancellationToken, @@ -705,7 +793,10 @@ namespace ts { // Change in changeSet/affectedFilesPendingEmit, buildInfo needs to be emitted state.buildInfoEmitPending = true; if (emitKind !== undefined) { - (state.seenEmittedFiles || (state.seenEmittedFiles = new Map())).set((affected as SourceFile).resolvedPath, emitKind); + (state.seenEmittedFiles || (state.seenEmittedFiles = new Map())).set( + (affected as SourceFile).resolvedPath, + emitKind, + ); } if (isPendingEmit) { state.affectedFilesPendingEmitIndex!++; @@ -719,7 +810,11 @@ namespace ts { /** * Returns the result with affected file */ - function toAffectedFileResult(state: BuilderProgramState, result: T, affected: SourceFile | Program): AffectedFileResult { + function toAffectedFileResult( + state: BuilderProgramState, + result: T, + affected: SourceFile | Program, + ): AffectedFileResult { doneWithAffectedFile(state, affected); return { result, affected }; } @@ -743,7 +838,11 @@ namespace ts { * Gets semantic diagnostics for the file which are * bindAndCheckDiagnostics (from cache) and program diagnostics */ - function getSemanticDiagnosticsOfFile(state: BuilderProgramState, sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { + function getSemanticDiagnosticsOfFile( + state: BuilderProgramState, + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[] { return concatenate( getBinderAndCheckerDiagnosticsOfFile(state, sourceFile, cancellationToken), Debug.checkDefined(state.program).getProgramDiagnostics(sourceFile), @@ -754,7 +853,11 @@ namespace ts { * Gets the binder and checker diagnostics either from cache if present, or otherwise from program and caches it * Note that it is assumed that when asked about binder and checker diagnostics, the file has been taken out of affected files/changed file set */ - function getBinderAndCheckerDiagnosticsOfFile(state: BuilderProgramState, sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { + function getBinderAndCheckerDiagnosticsOfFile( + state: BuilderProgramState, + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[] { const path = sourceFile.resolvedPath; if (state.semanticDiagnosticsPerFile) { const cachedDiagnostics = state.semanticDiagnosticsPerFile.get(path); @@ -774,9 +877,15 @@ namespace ts { export type ProgramBuildInfoFileId = number & { __programBuildInfoFileIdBrand: any; }; export type ProgramBuildInfoFileIdListId = number & { __programBuildInfoFileIdListIdBrand: any; }; - export type ProgramBuildInfoDiagnostic = ProgramBuildInfoFileId | [fileId: ProgramBuildInfoFileId, diagnostics: readonly ReusableDiagnostic[]]; + export type ProgramBuildInfoDiagnostic = ProgramBuildInfoFileId | [ + fileId: ProgramBuildInfoFileId, + diagnostics: readonly ReusableDiagnostic[], + ]; export type ProgramBuilderInfoFilePendingEmit = [fileId: ProgramBuildInfoFileId, emitKind: BuilderFileEmit]; - export type ProgramBuildInfoReferencedMap = [fileId: ProgramBuildInfoFileId, fileIdListId: ProgramBuildInfoFileIdListId][]; + export type ProgramBuildInfoReferencedMap = [ + fileId: ProgramBuildInfoFileId, + fileIdListId: ProgramBuildInfoFileIdListId, + ][]; export type ProgramBuildInfoBuilderStateFileInfo = Omit & { /** * Signature is @@ -790,7 +899,10 @@ namespace ts { * [fileId, signature] if different from file's signature * fileId if file wasnt emitted */ - export type ProgramBuildInfoEmitSignature = ProgramBuildInfoFileId | [fileId: ProgramBuildInfoFileId, signature: string]; + export type ProgramBuildInfoEmitSignature = ProgramBuildInfoFileId | [ + fileId: ProgramBuildInfoFileId, + signature: string, + ]; /** * ProgramBuildInfoFileInfo is string if FileInfo.version === FileInfo.signature && !FileInfo.affectsGlobalScope otherwise encoded FileInfo */ @@ -827,13 +939,19 @@ namespace ts { /** * Gets the program information to be emitted in buildInfo so that we can use it to create new program */ - function getProgramBuildInfo(state: BuilderProgramState, getCanonicalFileName: GetCanonicalFileName): ProgramBuildInfo | undefined { + function getProgramBuildInfo( + state: BuilderProgramState, + getCanonicalFileName: GetCanonicalFileName, + ): ProgramBuildInfo | undefined { const outFilePath = outFile(state.compilerOptions); if (outFilePath && !state.compilerOptions.composite) return; const currentDirectory = Debug.checkDefined(state.program).getCurrentDirectory(); - const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(state.compilerOptions)!, currentDirectory)); + const buildInfoDirectory = getDirectoryPath( + getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(state.compilerOptions)!, currentDirectory), + ); // Convert the file name to Path here if we set the fileName instead to optimize multiple d.ts file emits and having to compute Canonical path - const latestChangedDtsFile = state.latestChangedDtsFile ? relativeToBuildInfoEnsuringAbsolutePath(state.latestChangedDtsFile) : undefined; + const latestChangedDtsFile = state.latestChangedDtsFile + ? relativeToBuildInfoEnsuringAbsolutePath(state.latestChangedDtsFile) : undefined; if (outFilePath) { const fileNames: string[] = []; const fileInfos: string[] = []; @@ -873,20 +991,35 @@ namespace ts { } } } - return value.version === actualSignature ? - value.affectsGlobalScope || value.impliedFormat ? + return value.version === actualSignature + ? value.affectsGlobalScope || value.impliedFormat // If file version is same as signature, dont serialize signature - { version: value.version, signature: undefined, affectsGlobalScope: value.affectsGlobalScope, impliedFormat: value.impliedFormat } : + ? { + version: value.version, + signature: undefined, + affectsGlobalScope: value.affectsGlobalScope, + impliedFormat: value.impliedFormat, + } // If file info only contains version and signature and both are same we can just write string - value.version : - actualSignature !== undefined ? // If signature is not same as version, encode signature in the fileInfo - oldSignature === undefined ? + : value.version + : actualSignature !== undefined // If signature is not same as version, encode signature in the fileInfo + ? oldSignature === undefined // If we havent computed signature, use fileInfo as is - value : + ? value // Serialize fileInfo with new updated signature - { version: value.version, signature: actualSignature, affectsGlobalScope: value.affectsGlobalScope, impliedFormat: value.impliedFormat } : + : { + version: value.version, + signature: actualSignature, + affectsGlobalScope: value.affectsGlobalScope, + impliedFormat: value.impliedFormat, + } // Signature of the FileInfo is undefined, serialize it as false - { version: value.version, signature: false, affectsGlobalScope: value.affectsGlobalScope, impliedFormat: value.impliedFormat }; + : { + version: value.version, + signature: false, + affectsGlobalScope: value.affectsGlobalScope, + impliedFormat: value.impliedFormat, + }; }); let referencedMap: ProgramBuildInfoReferencedMap | undefined; @@ -899,13 +1032,20 @@ namespace ts { let exportedModulesMap: ProgramBuildInfoReferencedMap | undefined; if (state.exportedModulesMap) { - exportedModulesMap = mapDefined(arrayFrom(state.exportedModulesMap.keys()).sort(compareStringsCaseSensitive), key => { - const oldValue = state.oldExportedModulesMap?.get(key); - // Not in temporary cache, use existing value - if (oldValue === undefined) return [toFileId(key), toFileIdListId(state.exportedModulesMap!.getValues(key)!)]; - if (oldValue) return [toFileId(key), toFileIdListId(oldValue)]; - return undefined; - }); + exportedModulesMap = mapDefined( + arrayFrom(state.exportedModulesMap.keys()).sort(compareStringsCaseSensitive), + key => { + const oldValue = state.oldExportedModulesMap?.get(key); + // Not in temporary cache, use existing value + if (oldValue === undefined) { + return [toFileId(key), toFileIdListId(state.exportedModulesMap!.getValues(key)!)]; + } + if (oldValue) { + return [toFileId(key), toFileIdListId(oldValue)]; + } + return undefined; + }, + ); } let semanticDiagnosticsPerFile: ProgramBuildInfoDiagnostic[] | undefined; @@ -913,12 +1053,12 @@ namespace ts { for (const key of arrayFrom(state.semanticDiagnosticsPerFile.keys()).sort(compareStringsCaseSensitive)) { const value = state.semanticDiagnosticsPerFile.get(key)!; (semanticDiagnosticsPerFile ||= []).push( - value.length ? - [ + value.length + ? [ toFileId(key), convertToReusableDiagnostics(value, relativeToBuildInfo), - ] : - toFileId(key), + ] + : toFileId(key), ); } } @@ -926,9 +1066,16 @@ namespace ts { let affectedFilesPendingEmit: ProgramBuilderInfoFilePendingEmit[] | undefined; if (state.affectedFilesPendingEmit) { const seenFiles = new Set(); - for (const path of state.affectedFilesPendingEmit.slice(state.affectedFilesPendingEmitIndex).sort(compareStringsCaseSensitive)) { + for ( + const path of state.affectedFilesPendingEmit.slice(state.affectedFilesPendingEmitIndex).sort( + compareStringsCaseSensitive, + ) + ) { if (tryAddToSet(seenFiles, path)) { - (affectedFilesPendingEmit ||= []).push([toFileId(path), state.affectedFilesPendingEmitKind!.get(path)!]); + (affectedFilesPendingEmit ||= []).push([ + toFileId(path), + state.affectedFilesPendingEmitKind!.get(path)!, + ]); } } } @@ -960,7 +1107,9 @@ namespace ts { } function relativeToBuildInfo(path: string) { - return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory, path, getCanonicalFileName)); + return ensurePathIsNonModuleName( + getRelativePathFromDirectory(buildInfoDirectory, path, getCanonicalFileName), + ); } function toFileId(path: Path): ProgramBuildInfoFileId { @@ -978,7 +1127,10 @@ namespace ts { let fileIdListId = fileNamesToFileIdListId?.get(key); if (fileIdListId === undefined) { (fileIdsList ||= []).push(fileIds); - (fileNamesToFileIdListId ||= new Map()).set(key, fileIdListId = fileIdsList.length as ProgramBuildInfoFileIdListId); + (fileNamesToFileIdListId ||= new Map()).set( + key, + fileIdListId = fileIdsList.length as ProgramBuildInfoFileIdListId, + ); } return fileIdListId; } @@ -986,7 +1138,10 @@ namespace ts { /** * @param optionKey key of CommandLineOption to use to determine if the option should be serialized in tsbuildinfo */ - function convertToProgramBuildInfoCompilerOptions(options: CompilerOptions, optionKey: "affectsBundleEmitBuildInfo" | "affectsMultiFileEmitBuildInfo") { + function convertToProgramBuildInfoCompilerOptions( + options: CompilerOptions, + optionKey: "affectsBundleEmitBuildInfo" | "affectsMultiFileEmitBuildInfo", + ) { let result: CompilerOptions | undefined; const { optionsNameMap } = getOptionsNameMap(); for (const name of getOwnKeys(options).sort(compareStringsCaseSensitive)) { @@ -1003,7 +1158,11 @@ namespace ts { } } - function convertToReusableCompilerOptionValue(option: CommandLineOption | undefined, value: CompilerOptionsValue, relativeToBuildInfo: (path: string) => string) { + function convertToReusableCompilerOptionValue( + option: CommandLineOption | undefined, + value: CompilerOptionsValue, + relativeToBuildInfo: (path: string) => string, + ) { if (option) { if (option.type === "list") { const values = value as readonly (string | number)[]; @@ -1018,25 +1177,34 @@ namespace ts { return value; } - function convertToReusableDiagnostics(diagnostics: readonly Diagnostic[], relativeToBuildInfo: (path: string) => string): readonly ReusableDiagnostic[] { + function convertToReusableDiagnostics( + diagnostics: readonly Diagnostic[], + relativeToBuildInfo: (path: string) => string, + ): readonly ReusableDiagnostic[] { Debug.assert(!!diagnostics.length); return diagnostics.map(diagnostic => { - const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation(diagnostic, relativeToBuildInfo); + const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation( + diagnostic, + relativeToBuildInfo, + ); result.reportsUnnecessary = diagnostic.reportsUnnecessary; result.reportDeprecated = diagnostic.reportsDeprecated; result.source = diagnostic.source; result.skippedOn = diagnostic.skippedOn; const { relatedInformation } = diagnostic; - result.relatedInformation = relatedInformation ? - relatedInformation.length ? - relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r, relativeToBuildInfo)) : - [] : - undefined; + result.relatedInformation = relatedInformation + ? relatedInformation.length + ? relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r, relativeToBuildInfo)) + : [] + : undefined; return result; }); } - function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation, relativeToBuildInfo: (path: string) => string): ReusableDiagnosticRelatedInformation { + function convertToReusableDiagnosticRelatedInformation( + diagnostic: DiagnosticRelatedInformation, + relativeToBuildInfo: (path: string) => string, + ): ReusableDiagnosticRelatedInformation { const { file } = diagnostic; return { ...diagnostic, @@ -1056,7 +1224,14 @@ namespace ts { configFileParsingDiagnostics: readonly Diagnostic[]; } - export function getBuilderCreationParameters(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: BuilderProgram | CompilerHost, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderCreationParameters { + export function getBuilderCreationParameters( + newProgramOrRootNames: Program | readonly string[] | undefined, + hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, + oldProgramOrHost?: BuilderProgram | CompilerHost, + configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], + ): BuilderCreationParameters { let host: BuilderProgramHost; let newProgram: Program; let oldProgram: BuilderProgram; @@ -1085,7 +1260,12 @@ namespace ts { oldProgram = oldProgramOrHost as BuilderProgram; configFileParsingDiagnostics = configFileParsingDiagnosticsOrOldProgram as readonly Diagnostic[]; } - return { host, newProgram, oldProgram, configFileParsingDiagnostics: configFileParsingDiagnostics || emptyArray }; + return { + host, + newProgram, + oldProgram, + configFileParsingDiagnostics: configFileParsingDiagnostics || emptyArray, + }; } function getTextHandlingSourceMapForSignature(text: string, data: WriteFileCallbackData | undefined) { @@ -1102,37 +1282,67 @@ namespace ts { text = getTextHandlingSourceMapForSignature(text, data); let sourceFileDirectory: string | undefined; if (data?.diagnostics?.length) { - text += data.diagnostics.map(diagnostic => `${locationInfo(diagnostic)}${DiagnosticCategory[diagnostic.category]}${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText)}`).join("\n"); + text += data.diagnostics.map(diagnostic => + `${locationInfo(diagnostic)}${DiagnosticCategory[diagnostic.category]}${diagnostic.code}: ${ + flattenDiagnosticMessageText(diagnostic.messageText) + }` + ).join("\n"); } return (computeHash ?? generateDjb2Hash)(text); function flattenDiagnosticMessageText(diagnostic: string | DiagnosticMessageChain | undefined): string { - return isString(diagnostic) ? - diagnostic : - diagnostic === undefined ? - "" : - !diagnostic.next ? - diagnostic.messageText : - diagnostic.messageText + diagnostic.next.map(flattenDiagnosticMessageText).join("\n"); + return isString(diagnostic) + ? diagnostic + : diagnostic === undefined + ? "" + : !diagnostic.next + ? diagnostic.messageText + : diagnostic.messageText + diagnostic.next.map(flattenDiagnosticMessageText).join("\n"); } function locationInfo(diagnostic: DiagnosticWithLocation) { - if (diagnostic.file.resolvedPath === sourceFile.resolvedPath) return `(${diagnostic.start},${diagnostic.length})`; + if (diagnostic.file.resolvedPath === sourceFile.resolvedPath) { + return `(${diagnostic.start},${diagnostic.length})`; + } if (sourceFileDirectory === undefined) sourceFileDirectory = getDirectoryPath(sourceFile.resolvedPath); - return `${ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceFileDirectory, diagnostic.file.resolvedPath, getCanonicalFileName))}(${diagnostic.start},${diagnostic.length})`; + return `${ + ensurePathIsNonModuleName( + getRelativePathFromDirectory( + sourceFileDirectory, + diagnostic.file.resolvedPath, + getCanonicalFileName, + ), + ) + }(${diagnostic.start},${diagnostic.length})`; } } - export function computeSignature(text: string, computeHash: BuilderState.ComputeHash | undefined, data?: WriteFileCallbackData) { + export function computeSignature( + text: string, + computeHash: BuilderState.ComputeHash | undefined, + data?: WriteFileCallbackData, + ) { return (computeHash ?? generateDjb2Hash)(getTextHandlingSourceMapForSignature(text, data)); } - export function createBuilderProgram(kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): SemanticDiagnosticsBuilderProgram; - export function createBuilderProgram(kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): EmitAndSemanticDiagnosticsBuilderProgram; - export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, host, oldProgram, configFileParsingDiagnostics }: BuilderCreationParameters) { + export function createBuilderProgram( + kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram, + builderCreationParameters: BuilderCreationParameters, + ): SemanticDiagnosticsBuilderProgram; + export function createBuilderProgram( + kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, + builderCreationParameters: BuilderCreationParameters, + ): EmitAndSemanticDiagnosticsBuilderProgram; + export function createBuilderProgram( + kind: BuilderProgramKind, + { newProgram, host, oldProgram, configFileParsingDiagnostics }: BuilderCreationParameters, + ) { // Return same program if underlying program doesnt change let oldState = oldProgram && oldProgram.getState(); - if (oldState && newProgram === oldState.program && configFileParsingDiagnostics === newProgram.getConfigFileParsingDiagnostics()) { + if ( + oldState && newProgram === oldState.program + && configFileParsingDiagnostics === newProgram.getConfigFileParsingDiagnostics() + ) { newProgram = undefined!; // TODO: GH#18217 oldState = undefined; return oldProgram; @@ -1146,7 +1356,12 @@ namespace ts { * Computing hash to for signature verification */ const computeHash = maybeBind(host, host.createHash); - const state = createBuilderProgramState(newProgram, getCanonicalFileName, oldState, host.disableUseFileVersionAsSignature); + const state = createBuilderProgramState( + newProgram, + getCanonicalFileName, + oldState, + host.disableUseFileVersionAsSignature, + ); newProgram.getProgramBuildInfo = () => getProgramBuildInfo(state, getCanonicalFileName); // To ensure that we arent storing any references to old program or new program without state @@ -1160,16 +1375,19 @@ namespace ts { builderProgram.saveEmitState = () => backupBuilderProgramEmitState(state); builderProgram.restoreEmitState = saved => restoreBuilderProgramEmitState(state, saved); builderProgram.hasChangedEmitSignature = () => !!state.hasChangedEmitSignature; - builderProgram.getAllDependencies = sourceFile => BuilderState.getAllDependencies(state, Debug.checkDefined(state.program), sourceFile); + builderProgram.getAllDependencies = sourceFile => + BuilderState.getAllDependencies(state, Debug.checkDefined(state.program), sourceFile); builderProgram.getSemanticDiagnostics = getSemanticDiagnostics; builderProgram.emit = emit; builderProgram.releaseProgram = () => releaseCache(state); if (kind === BuilderProgramKind.SemanticDiagnosticsBuilderProgram) { - (builderProgram as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile; + (builderProgram as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = + getSemanticDiagnosticsOfNextAffectedFile; } else if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) { - (builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile; + (builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = + getSemanticDiagnosticsOfNextAffectedFile; (builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).emitNextAffectedFile = emitNextAffectedFile; builderProgram.emitBuildInfo = emitBuildInfo; } @@ -1181,7 +1399,10 @@ namespace ts { function emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult { if (state.buildInfoEmitPending) { - const result = Debug.checkDefined(state.program).emitBuildInfo(writeFile || maybeBind(host, host.writeFile), cancellationToken); + const result = Debug.checkDefined(state.program).emitBuildInfo( + writeFile || maybeBind(host, host.writeFile), + cancellationToken, + ); state.buildInfoEmitPending = false; return result; } @@ -1193,7 +1414,12 @@ namespace ts { * The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host * in that order would be used to write the files */ - function emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): AffectedFileResult { + function emitNextAffectedFile( + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): AffectedFileResult { let affected = getNextAffectedFile(state, cancellationToken, computeHash, getCanonicalFileName, host); let emitKind = BuilderFileEmit.Full; let isPendingEmitFile = false; @@ -1233,9 +1459,9 @@ namespace ts { // Otherwise just affected file Debug.checkDefined(state.program).emit( affected === state.program ? undefined : affected as SourceFile, - getEmitDeclarations(state.compilerOptions) ? - getWriteFileCallback(writeFile, customTransformers) : - writeFile || maybeBind(host, host.writeFile), + getEmitDeclarations(state.compilerOptions) + ? getWriteFileCallback(writeFile, customTransformers) + : writeFile || maybeBind(host, host.writeFile), cancellationToken, emitOnlyDtsFiles || emitKind === BuilderFileEmit.DtsOnly, customTransformers, @@ -1246,7 +1472,10 @@ namespace ts { ); } - function getWriteFileCallback(writeFile: WriteFileCallback | undefined, customTransformers: CustomTransformers | undefined): WriteFileCallback { + function getWriteFileCallback( + writeFile: WriteFileCallback | undefined, + customTransformers: CustomTransformers | undefined, + ): WriteFileCallback { return (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => { if (isDeclarationFileName(fileName)) { if (!outFile(state.compilerOptions)) { @@ -1266,12 +1495,25 @@ namespace ts { // With d.ts diagnostics they are also part of the signature so emitSignature will be different from it since its just hash of d.ts if (!data?.diagnostics?.length) emitSignature = signature; if (signature !== file.version) { // Update it - if (host.storeFilesChangingSignatureDuringEmit) (state.filesChangingSignature ??= new Set()).add(file.resolvedPath); - if (state.exportedModulesMap) BuilderState.updateExportedModules(state, file, file.exportedModulesFromDeclarationEmit); + if (host.storeFilesChangingSignatureDuringEmit) { + (state.filesChangingSignature ??= new Set()).add(file.resolvedPath); + } + if (state.exportedModulesMap) { + BuilderState.updateExportedModules( + state, + file, + file.exportedModulesFromDeclarationEmit, + ); + } if (state.affectedFiles) { // Keep old signature so we know what to undo if cancellation happens const existing = state.oldSignatures?.get(file.resolvedPath); - if (existing === undefined) (state.oldSignatures ??= new Map()).set(file.resolvedPath, info.signature || false); + if (existing === undefined) { + (state.oldSignatures ??= new Map()).set( + file.resolvedPath, + info.signature || false, + ); + } info.signature = signature; } else { @@ -1323,7 +1565,13 @@ namespace ts { * The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host * in that order would be used to write the files */ - function emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult { + function emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): EmitResult { if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) { assertSourceFileOkWithoutNextAffectedCall(state, targetSourceFile); } @@ -1340,7 +1588,14 @@ namespace ts { let emittedFiles: string[] = []; let affectedEmitResult: AffectedFileResult; - while (affectedEmitResult = emitNextAffectedFile(writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers)) { + while ( + affectedEmitResult = emitNextAffectedFile( + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers, + ) + ) { emitSkipped = emitSkipped || affectedEmitResult.result.emitSkipped; diagnostics = addRange(diagnostics, affectedEmitResult.result.diagnostics); emittedFiles = addRange(emittedFiles, affectedEmitResult.result.emittedFiles); @@ -1360,9 +1615,12 @@ namespace ts { if ( !emitOnlyDtsFiles // If we are doing complete emit, affected files pending emit can be cleared // If every file pending emit is pending on only dts emit - || every(state.affectedFilesPendingEmit, (path, index) => - index < state.affectedFilesPendingEmitIndex! || - state.affectedFilesPendingEmitKind!.get(path) === BuilderFileEmit.DtsOnly) + || every( + state.affectedFilesPendingEmit, + (path, index) => + index < state.affectedFilesPendingEmitIndex! + || state.affectedFilesPendingEmitKind!.get(path) === BuilderFileEmit.DtsOnly, + ) ) { clearAffectedFilesPendingEmit(state); } @@ -1370,9 +1628,9 @@ namespace ts { } return Debug.checkDefined(state.program).emit( targetSourceFile, - getEmitDeclarations(state.compilerOptions) ? - getWriteFileCallback(writeFile, customTransformers) : - writeFile || maybeBind(host, host.writeFile), + getEmitDeclarations(state.compilerOptions) + ? getWriteFileCallback(writeFile, customTransformers) + : writeFile || maybeBind(host, host.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers, @@ -1383,7 +1641,10 @@ namespace ts { * Return the semantic diagnostics for the next affected file or undefined if iteration is complete * If provided ignoreSourceFile would be called before getting the diagnostics and would ignore the sourceFile if the returned value was true */ - function getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult { + function getSemanticDiagnosticsOfNextAffectedFile( + cancellationToken?: CancellationToken, + ignoreSourceFile?: (sourceFile: SourceFile) => boolean, + ): AffectedFileResult { while (true) { const affected = getNextAffectedFile(state, cancellationToken, computeHash, getCanonicalFileName, host); if (!affected) { @@ -1401,7 +1662,10 @@ namespace ts { // Add file to affected file pending emit to handle for later emit time // Apart for emit builder do this for tsbuildinfo, do this for non emit builder when noEmit is set as tsbuildinfo is written and reused between emitters - if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram || state.compilerOptions.noEmit || state.compilerOptions.noEmitOnError) { + if ( + kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram || state.compilerOptions.noEmit + || state.compilerOptions.noEmitOnError + ) { addToAffectedFilesPendingEmit(state, (affected as SourceFile).resolvedPath, BuilderFileEmit.Full); } @@ -1428,7 +1692,10 @@ namespace ts { * In case of SemanticDiagnosticsBuilderProgram if the source file is not provided, * it will iterate through all the affected files, to ensure that cache stays valid and yet provide a way to get all semantic diagnostics */ - function getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { + function getSemanticDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[] { assertSourceFileOkWithoutNextAffectedCall(state, sourceFile); const compilerOptions = Debug.checkDefined(state.program).getCompilerOptions(); if (outFile(compilerOptions)) { @@ -1455,7 +1722,11 @@ namespace ts { } } - function addToAffectedFilesPendingEmit(state: BuilderProgramState, affectedFilePendingEmit: Path, kind: BuilderFileEmit) { + function addToAffectedFilesPendingEmit( + state: BuilderProgramState, + affectedFilePendingEmit: Path, + kind: BuilderFileEmit, + ) { if (!state.affectedFilesPendingEmit) state.affectedFilesPendingEmit = []; if (!state.affectedFilesPendingEmitKind) state.affectedFilesPendingEmitKind = new Map(); @@ -1473,25 +1744,38 @@ namespace ts { } export function toBuilderStateFileInfo(fileInfo: ProgramBuildInfoFileInfo): BuilderState.FileInfo { - return isString(fileInfo) ? - { version: fileInfo, signature: fileInfo, affectsGlobalScope: undefined, impliedFormat: undefined } : - isString(fileInfo.signature) ? - fileInfo as BuilderState.FileInfo : - { version: fileInfo.version, signature: fileInfo.signature === false ? undefined : fileInfo.version, affectsGlobalScope: fileInfo.affectsGlobalScope, impliedFormat: fileInfo.impliedFormat }; + return isString(fileInfo) + ? { version: fileInfo, signature: fileInfo, affectsGlobalScope: undefined, impliedFormat: undefined } + : isString(fileInfo.signature) + ? fileInfo as BuilderState.FileInfo + : { + version: fileInfo.version, + signature: fileInfo.signature === false ? undefined : fileInfo.version, + affectsGlobalScope: fileInfo.affectsGlobalScope, + impliedFormat: fileInfo.impliedFormat, + }; } - export function createBuilderProgramUsingProgramBuildInfo(program: ProgramBuildInfo, buildInfoPath: string, host: ReadBuildProgramHost): EmitAndSemanticDiagnosticsBuilderProgram { - const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory())); + export function createBuilderProgramUsingProgramBuildInfo( + program: ProgramBuildInfo, + buildInfoPath: string, + host: ReadBuildProgramHost, + ): EmitAndSemanticDiagnosticsBuilderProgram { + const buildInfoDirectory = getDirectoryPath( + getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory()), + ); const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames()); let state: ReusableBuilderProgramState; let filePaths: Path[] | undefined; let filePathsSetList: Set[] | undefined; - const latestChangedDtsFile = program.latestChangedDtsFile ? toAbsolutePath(program.latestChangedDtsFile) : undefined; + const latestChangedDtsFile = program.latestChangedDtsFile ? toAbsolutePath(program.latestChangedDtsFile) + : undefined; if (isProgramBundleEmitBuildInfo(program)) { state = { fileInfos: new Map(), - compilerOptions: program.options ? convertToOptionsWithAbsolutePaths(program.options, toAbsolutePath) : {}, + compilerOptions: program.options ? convertToOptionsWithAbsolutePaths(program.options, toAbsolutePath) + : {}, latestChangedDtsFile, outSignature: program.outSignature, }; @@ -1500,7 +1784,8 @@ namespace ts { filePaths = program.fileNames?.map(toPath); filePathsSetList = program.fileIdsList?.map(fileIds => new Set(fileIds.map(toFilePath))); const fileInfos = new Map(); - const emitSignatures = program.options?.composite && !outFile(program.options) ? new Map() : undefined; + const emitSignatures = program.options?.composite && !outFile(program.options) ? new Map() + : undefined; program.fileInfos.forEach((fileInfo, index) => { const path = toFilePath(index + 1 as ProgramBuildInfoFileId); const stateFileInfo = toBuilderStateFileInfo(fileInfo); @@ -1513,13 +1798,20 @@ namespace ts { }); state = { fileInfos, - compilerOptions: program.options ? convertToOptionsWithAbsolutePaths(program.options, toAbsolutePath) : {}, + compilerOptions: program.options ? convertToOptionsWithAbsolutePaths(program.options, toAbsolutePath) + : {}, referencedMap: toManyToManyPathMap(program.referencedMap), exportedModulesMap: toManyToManyPathMap(program.exportedModulesMap), - semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile && arrayToMap(program.semanticDiagnosticsPerFile, value => toFilePath(isNumber(value) ? value : value[0]), value => isNumber(value) ? emptyArray : value[1]), + semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile + && arrayToMap( + program.semanticDiagnosticsPerFile, + value => toFilePath(isNumber(value) ? value : value[0]), + value => isNumber(value) ? emptyArray : value[1], + ), hasReusableDiagnostic: true, affectedFilesPendingEmit: map(program.affectedFilesPendingEmit, value => toFilePath(value[0])), - affectedFilesPendingEmitKind: program.affectedFilesPendingEmit && arrayToMap(program.affectedFilesPendingEmit, value => toFilePath(value[0]), value => value[1]), + affectedFilesPendingEmitKind: program.affectedFilesPendingEmit + && arrayToMap(program.affectedFilesPendingEmit, value => toFilePath(value[0]), value => value[1]), affectedFilesPendingEmitIndex: program.affectedFilesPendingEmit && 0, changedFilesSet: new Set(map(program.changeFileSet, toFilePath)), latestChangedDtsFile, @@ -1569,7 +1861,9 @@ namespace ts { return filePathsSetList![fileIdsListId - 1]; } - function toManyToManyPathMap(referenceMap: ProgramBuildInfoReferencedMap | undefined): BuilderState.ManyToManyPathMap | undefined { + function toManyToManyPathMap( + referenceMap: ProgramBuildInfoReferencedMap | undefined, + ): BuilderState.ManyToManyPathMap | undefined { if (!referenceMap) { return undefined; } @@ -1585,7 +1879,9 @@ namespace ts { buildInfoPath: string, host: Pick, ): ESMap { - const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory())); + const buildInfoDirectory = getDirectoryPath( + getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory()), + ); const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames()); const fileInfos = new Map(); program.fileInfos.forEach((fileInfo, index) => { @@ -1596,7 +1892,10 @@ namespace ts { return fileInfos; } - export function createRedirectedBuilderProgram(getState: () => { program?: Program | undefined; compilerOptions: CompilerOptions; }, configFileParsingDiagnostics: readonly Diagnostic[]): BuilderProgram { + export function createRedirectedBuilderProgram( + getState: () => { program?: Program | undefined; compilerOptions: CompilerOptions; }, + configFileParsingDiagnostics: readonly Diagnostic[], + ): BuilderProgram { return { getState: notImplemented, saveEmitState: noop as BuilderProgram["saveEmitState"], @@ -1610,10 +1909,14 @@ namespace ts { getOptionsDiagnostics: cancellationToken => getProgram().getOptionsDiagnostics(cancellationToken), getGlobalDiagnostics: cancellationToken => getProgram().getGlobalDiagnostics(cancellationToken), getConfigFileParsingDiagnostics: () => configFileParsingDiagnostics, - getSyntacticDiagnostics: (sourceFile, cancellationToken) => getProgram().getSyntacticDiagnostics(sourceFile, cancellationToken), - getDeclarationDiagnostics: (sourceFile, cancellationToken) => getProgram().getDeclarationDiagnostics(sourceFile, cancellationToken), - getSemanticDiagnostics: (sourceFile, cancellationToken) => getProgram().getSemanticDiagnostics(sourceFile, cancellationToken), - emit: (sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers) => getProgram().emit(sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers), + getSyntacticDiagnostics: (sourceFile, cancellationToken) => + getProgram().getSyntacticDiagnostics(sourceFile, cancellationToken), + getDeclarationDiagnostics: (sourceFile, cancellationToken) => + getProgram().getDeclarationDiagnostics(sourceFile, cancellationToken), + getSemanticDiagnostics: (sourceFile, cancellationToken) => + getProgram().getSemanticDiagnostics(sourceFile, cancellationToken), + emit: (sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers) => + getProgram().emit(sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers), emitBuildInfo: (writeFile, cancellationToken) => getProgram().emitBuildInfo(writeFile, cancellationToken), getAllDependencies: notImplemented, getCurrentDirectory: () => getProgram().getCurrentDirectory(), diff --git a/src/compiler/builderPublic.ts b/src/compiler/builderPublic.ts index cc1a971753f3b..8ad5af1dcd044 100644 --- a/src/compiler/builderPublic.ts +++ b/src/compiler/builderPublic.ts @@ -89,7 +89,10 @@ namespace ts { /** * Get the declaration diagnostics, for all source files if source file is not supplied */ - getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; + getDeclarationDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; /** * Get all the dependencies of the file */ @@ -115,7 +118,13 @@ namespace ts { * The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host * in that order would be used to write the files */ - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult; + emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): EmitResult; /*@internal*/ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult; /** @@ -134,7 +143,10 @@ namespace ts { * Gets the semantic diagnostics from the program for the next affected file and caches it * Returns undefined if the iteration is complete */ - getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult; + getSemanticDiagnosticsOfNextAffectedFile( + cancellationToken?: CancellationToken, + ignoreSourceFile?: (sourceFile: SourceFile) => boolean, + ): AffectedFileResult; } /** @@ -147,35 +159,128 @@ namespace ts { * The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host * in that order would be used to write the files */ - emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): AffectedFileResult; + emitNextAffectedFile( + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): AffectedFileResult; } /** * Create the builder to manage semantic diagnostics and cache them */ - export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): SemanticDiagnosticsBuilderProgram; - export function createSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): SemanticDiagnosticsBuilderProgram; - export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) { - return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences)); + export function createSemanticDiagnosticsBuilderProgram( + newProgram: Program, + host: BuilderProgramHost, + oldProgram?: SemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + ): SemanticDiagnosticsBuilderProgram; + export function createSemanticDiagnosticsBuilderProgram( + rootNames: readonly string[] | undefined, + options: CompilerOptions | undefined, + host?: CompilerHost, + oldProgram?: SemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], + ): SemanticDiagnosticsBuilderProgram; + export function createSemanticDiagnosticsBuilderProgram( + newProgramOrRootNames: Program | readonly string[] | undefined, + hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, + oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, + configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | SemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], + ) { + return createBuilderProgram( + BuilderProgramKind.SemanticDiagnosticsBuilderProgram, + getBuilderCreationParameters( + newProgramOrRootNames, + hostOrOptions, + oldProgramOrHost, + configFileParsingDiagnosticsOrOldProgram, + configFileParsingDiagnostics, + projectReferences, + ), + ); } /** * Create the builder that can handle the changes in program and iterate through changed files * to emit the those files and manage semantic diagnostics cache as well */ - export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): EmitAndSemanticDiagnosticsBuilderProgram; - export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): EmitAndSemanticDiagnosticsBuilderProgram; - export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) { - return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences)); + export function createEmitAndSemanticDiagnosticsBuilderProgram( + newProgram: Program, + host: BuilderProgramHost, + oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + ): EmitAndSemanticDiagnosticsBuilderProgram; + export function createEmitAndSemanticDiagnosticsBuilderProgram( + rootNames: readonly string[] | undefined, + options: CompilerOptions | undefined, + host?: CompilerHost, + oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], + ): EmitAndSemanticDiagnosticsBuilderProgram; + export function createEmitAndSemanticDiagnosticsBuilderProgram( + newProgramOrRootNames: Program | readonly string[] | undefined, + hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, + oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, + configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | EmitAndSemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], + ) { + return createBuilderProgram( + BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, + getBuilderCreationParameters( + newProgramOrRootNames, + hostOrOptions, + oldProgramOrHost, + configFileParsingDiagnosticsOrOldProgram, + configFileParsingDiagnostics, + projectReferences, + ), + ); } /** * Creates a builder thats just abstraction over program and can be used with watch */ - export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): BuilderProgram; - export function createAbstractBuilder(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram; - export function createAbstractBuilder(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram { - const { newProgram, configFileParsingDiagnostics: newConfigFileParsingDiagnostics } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences); - return createRedirectedBuilderProgram(() => ({ program: newProgram, compilerOptions: newProgram.getCompilerOptions() }), newConfigFileParsingDiagnostics); + export function createAbstractBuilder( + newProgram: Program, + host: BuilderProgramHost, + oldProgram?: BuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + ): BuilderProgram; + export function createAbstractBuilder( + rootNames: readonly string[] | undefined, + options: CompilerOptions | undefined, + host?: CompilerHost, + oldProgram?: BuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], + ): BuilderProgram; + export function createAbstractBuilder( + newProgramOrRootNames: Program | readonly string[] | undefined, + hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, + oldProgramOrHost?: CompilerHost | BuilderProgram, + configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], + ): BuilderProgram { + const { newProgram, configFileParsingDiagnostics: newConfigFileParsingDiagnostics } = + getBuilderCreationParameters( + newProgramOrRootNames, + hostOrOptions, + oldProgramOrHost, + configFileParsingDiagnosticsOrOldProgram, + configFileParsingDiagnostics, + projectReferences, + ); + return createRedirectedBuilderProgram( + () => ({ program: newProgram, compilerOptions: newProgram.getCompilerOptions() }), + newConfigFileParsingDiagnostics, + ); } } diff --git a/src/compiler/builderState.ts b/src/compiler/builderState.ts index a83691c2a83ba..79bad4f33a83a 100644 --- a/src/compiler/builderState.ts +++ b/src/compiler/builderState.ts @@ -1,8 +1,22 @@ /*@internal*/ namespace ts { - export function getFileEmitOutput(program: Program, sourceFile: SourceFile, emitOnlyDtsFiles: boolean, cancellationToken?: CancellationToken, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitOutput { + export function getFileEmitOutput( + program: Program, + sourceFile: SourceFile, + emitOnlyDtsFiles: boolean, + cancellationToken?: CancellationToken, + customTransformers?: CustomTransformers, + forceDtsEmit?: boolean, + ): EmitOutput { const outputFiles: OutputFile[] = []; - const { emitSkipped, diagnostics } = program.emit(sourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers, forceDtsEmit); + const { emitSkipped, diagnostics } = program.emit( + sourceFile, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers, + forceDtsEmit, + ); return { outputFiles, emitSkipped, diagnostics }; function writeFile(fileName: string, text: string, writeByteOrderMark: boolean) { @@ -79,7 +93,11 @@ namespace ts { } export function createManyToManyPathMap(): ManyToManyPathMap { - function create(forward: ESMap>, reverse: ESMap>, deleted: Set | undefined): ManyToManyPathMap { + function create( + forward: ESMap>, + reverse: ESMap>, + deleted: Set | undefined, + ): ManyToManyPathMap { const map: ManyToManyPathMap = { getKeys: v => reverse.get(v), getValues: k => forward.get(k), @@ -159,7 +177,10 @@ namespace ts { /** * Get the module source file and all augmenting files from the import name node from file */ - function getReferencedFilesFromImportLiteral(checker: TypeChecker, importName: StringLiteralLike): Path[] | undefined { + function getReferencedFilesFromImportLiteral( + checker: TypeChecker, + importName: StringLiteralLike, + ): Path[] | undefined { const symbol = checker.getSymbolAtLocation(importName); return symbol && getReferencedFilesFromImportedModuleSymbol(symbol); } @@ -167,14 +188,27 @@ namespace ts { /** * Gets the path to reference file from file name, it could be resolvedPath if present otherwise path */ - function getReferencedFileFromFileName(program: Program, fileName: string, sourceFileDirectory: Path, getCanonicalFileName: GetCanonicalFileName): Path { - return toPath(program.getProjectReferenceRedirect(fileName) || fileName, sourceFileDirectory, getCanonicalFileName); + function getReferencedFileFromFileName( + program: Program, + fileName: string, + sourceFileDirectory: Path, + getCanonicalFileName: GetCanonicalFileName, + ): Path { + return toPath( + program.getProjectReferenceRedirect(fileName) || fileName, + sourceFileDirectory, + getCanonicalFileName, + ); } /** * Gets the referenced files for a file from the program with values for the keys as referenced file's path to be true */ - function getReferencedFiles(program: Program, sourceFile: SourceFile, getCanonicalFileName: GetCanonicalFileName): Set | undefined { + function getReferencedFiles( + program: Program, + sourceFile: SourceFile, + getCanonicalFileName: GetCanonicalFileName, + ): Set | undefined { let referencedFiles: Set | undefined; // We need to use a set here since the code can contain the same import twice, @@ -192,7 +226,12 @@ namespace ts { // Handle triple slash references if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) { for (const referencedFile of sourceFile.referencedFiles) { - const referencedPath = getReferencedFileFromFileName(program, referencedFile.fileName, sourceFileDirectory, getCanonicalFileName); + const referencedPath = getReferencedFileFromFileName( + program, + referencedFile.fileName, + sourceFileDirectory, + getCanonicalFileName, + ); addReferencedFile(referencedPath); } } @@ -205,7 +244,12 @@ namespace ts { } const fileName = resolvedTypeReferenceDirective.resolvedFileName!; // TODO: GH#18217 - const typeFilePath = getReferencedFileFromFileName(program, fileName, sourceFileDirectory, getCanonicalFileName); + const typeFilePath = getReferencedFileFromFileName( + program, + fileName, + sourceFileDirectory, + getCanonicalFileName, + ); addReferencedFile(typeFilePath); }); } @@ -240,8 +284,8 @@ namespace ts { for (const declaration of symbol.declarations) { const declarationSourceFile = getSourceFileOfNode(declaration); if ( - declarationSourceFile && - declarationSourceFile !== sourceFile + declarationSourceFile + && declarationSourceFile !== sourceFile ) { addReferencedFile(declarationSourceFile.resolvedPath); } @@ -256,16 +300,25 @@ namespace ts { /** * Returns true if oldState is reusable, that is the emitKind = module/non module has not changed */ - export function canReuseOldState(newReferencedMap: ReadonlyManyToManyPathMap | undefined, oldState: BuilderState | undefined) { + export function canReuseOldState( + newReferencedMap: ReadonlyManyToManyPathMap | undefined, + oldState: BuilderState | undefined, + ) { return oldState && !oldState.referencedMap === !newReferencedMap; } /** * Creates the state of file references and signature for the new program from oldState if it is safe */ - export function create(newProgram: Program, getCanonicalFileName: GetCanonicalFileName, oldState?: Readonly, disableUseFileVersionAsSignature?: boolean): BuilderState { + export function create( + newProgram: Program, + getCanonicalFileName: GetCanonicalFileName, + oldState?: Readonly, + disableUseFileVersionAsSignature?: boolean, + ): BuilderState { const fileInfos = new Map(); - const referencedMap = newProgram.getCompilerOptions().module !== ModuleKind.None ? createManyToManyPathMap() : undefined; + const referencedMap = newProgram.getCompilerOptions().module !== ModuleKind.None ? createManyToManyPathMap() + : undefined; const exportedModulesMap = referencedMap ? createManyToManyPathMap() : undefined; const useOldState = canReuseOldState(referencedMap, oldState); @@ -274,11 +327,15 @@ namespace ts { // Create the reference map, and set the file infos for (const sourceFile of newProgram.getSourceFiles()) { - const version = Debug.checkDefined(sourceFile.version, "Program intended to be used with Builder should have source files with versions set"); - const oldUncommittedSignature = useOldState ? oldState!.oldSignatures?.get(sourceFile.resolvedPath) : undefined; - const signature = oldUncommittedSignature === undefined ? - useOldState ? oldState!.fileInfos.get(sourceFile.resolvedPath)?.signature : undefined : - oldUncommittedSignature || undefined; + const version = Debug.checkDefined( + sourceFile.version, + "Program intended to be used with Builder should have source files with versions set", + ); + const oldUncommittedSignature = useOldState ? oldState!.oldSignatures?.get(sourceFile.resolvedPath) + : undefined; + const signature = oldUncommittedSignature === undefined + ? useOldState ? oldState!.fileInfos.get(sourceFile.resolvedPath)?.signature : undefined + : oldUncommittedSignature || undefined; if (referencedMap) { const newReferences = getReferencedFiles(newProgram, sourceFile, getCanonicalFileName); if (newReferences) { @@ -286,10 +343,12 @@ namespace ts { } // Copy old visible to outside files map if (useOldState) { - const oldUncommittedExportedModules = oldState!.oldExportedModulesMap?.get(sourceFile.resolvedPath); - const exportedModules = oldUncommittedExportedModules === undefined ? - oldState!.exportedModulesMap!.getValues(sourceFile.resolvedPath) : - oldUncommittedExportedModules || undefined; + const oldUncommittedExportedModules = oldState!.oldExportedModulesMap?.get( + sourceFile.resolvedPath, + ); + const exportedModules = oldUncommittedExportedModules === undefined + ? oldState!.exportedModulesMap!.getValues(sourceFile.resolvedPath) + : oldUncommittedExportedModules || undefined; if (exportedModules) { exportedModulesMap!.set(sourceFile.resolvedPath, exportedModules); } @@ -356,11 +415,28 @@ namespace ts { return emptyArray; } - if (!updateShapeSignature(state, programOfThisState, sourceFile, cancellationToken, computeHash, getCanonicalFileName)) { + if ( + !updateShapeSignature( + state, + programOfThisState, + sourceFile, + cancellationToken, + computeHash, + getCanonicalFileName, + ) + ) { return [sourceFile]; } - return (state.referencedMap ? getFilesAffectedByUpdatedShapeWhenModuleEmit : getFilesAffectedByUpdatedShapeWhenNonModuleEmit)(state, programOfThisState, sourceFile, cancellationToken, computeHash, getCanonicalFileName); + return (state.referencedMap ? getFilesAffectedByUpdatedShapeWhenModuleEmit + : getFilesAffectedByUpdatedShapeWhenNonModuleEmit)( + state, + programOfThisState, + sourceFile, + cancellationToken, + computeHash, + getCanonicalFileName, + ); } export function updateSignatureOfFile(state: BuilderState, signature: string | undefined, path: Path) { @@ -390,7 +466,10 @@ namespace ts { programOfThisState.emit( sourceFile, (fileName, text, _writeByteOrderMark, _onError, sourceFiles, data) => { - Debug.assert(isDeclarationFileName(fileName), `File extension for signature expected to be dts: Got:: ${fileName}`); + Debug.assert( + isDeclarationFileName(fileName), + `File extension for signature expected to be dts: Got:: ${fileName}`, + ); latestSignature = computeSignatureWithDiagnostics( sourceFile, text, @@ -399,7 +478,11 @@ namespace ts { data, ); if (latestSignature !== prevSignature) { - updateExportedModules(state, sourceFile, sourceFiles![0].exportedModulesFromDeclarationEmit); + updateExportedModules( + state, + sourceFile, + sourceFiles![0].exportedModulesFromDeclarationEmit, + ); } }, cancellationToken, @@ -412,9 +495,13 @@ namespace ts { if (latestSignature === undefined) { latestSignature = sourceFile.version; if (state.exportedModulesMap && latestSignature !== prevSignature) { - (state.oldExportedModulesMap ||= new Map()).set(sourceFile.resolvedPath, state.exportedModulesMap.getValues(sourceFile.resolvedPath) || false); + (state.oldExportedModulesMap ||= new Map()).set( + sourceFile.resolvedPath, + state.exportedModulesMap.getValues(sourceFile.resolvedPath) || false, + ); // All the references in this file are exported - const references = state.referencedMap ? state.referencedMap.getValues(sourceFile.resolvedPath) : undefined; + const references = state.referencedMap ? state.referencedMap.getValues(sourceFile.resolvedPath) + : undefined; if (references) { state.exportedModulesMap.set(sourceFile.resolvedPath, references); } @@ -432,16 +519,25 @@ namespace ts { /** * Coverts the declaration emit result into exported modules map */ - export function updateExportedModules(state: BuilderState, sourceFile: SourceFile, exportedModulesFromDeclarationEmit: ExportedModulesFromDeclarationEmit | undefined) { + export function updateExportedModules( + state: BuilderState, + sourceFile: SourceFile, + exportedModulesFromDeclarationEmit: ExportedModulesFromDeclarationEmit | undefined, + ) { if (!state.exportedModulesMap) return; - (state.oldExportedModulesMap ||= new Map()).set(sourceFile.resolvedPath, state.exportedModulesMap.getValues(sourceFile.resolvedPath) || false); + (state.oldExportedModulesMap ||= new Map()).set( + sourceFile.resolvedPath, + state.exportedModulesMap.getValues(sourceFile.resolvedPath) || false, + ); if (!exportedModulesFromDeclarationEmit) { state.exportedModulesMap.deleteKey(sourceFile.resolvedPath); return; } let exportedModules: Set | undefined; - exportedModulesFromDeclarationEmit.forEach(symbol => addExportedModule(getReferencedFilesFromImportedModuleSymbol(symbol))); + exportedModulesFromDeclarationEmit.forEach(symbol => + addExportedModule(getReferencedFilesFromImportedModuleSymbol(symbol)) + ); if (exportedModules) { state.exportedModulesMap.set(sourceFile.resolvedPath, exportedModules); } @@ -462,7 +558,11 @@ namespace ts { /** * Get all the dependencies of the sourceFile */ - export function getAllDependencies(state: BuilderState, programOfThisState: Program, sourceFile: SourceFile): readonly string[] { + export function getAllDependencies( + state: BuilderState, + programOfThisState: Program, + sourceFile: SourceFile, + ): readonly string[] { const compilerOptions = programOfThisState.getCompilerOptions(); // With --out or --outFile all outputs go into single file, all files depend on each other if (outFile(compilerOptions)) { @@ -491,7 +591,12 @@ namespace ts { } } - return arrayFrom(mapDefinedIterator(seenMap.keys(), path => programOfThisState.getSourceFileByPath(path)?.fileName ?? path)); + return arrayFrom( + mapDefinedIterator( + seenMap.keys(), + path => programOfThisState.getSourceFileByPath(path)?.fileName ?? path, + ), + ); } /** @@ -533,21 +638,29 @@ namespace ts { * they are global files as well as module */ function containsGlobalScopeAugmentation(sourceFile: SourceFile) { - return some(sourceFile.moduleAugmentations, augmentation => isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration)); + return some( + sourceFile.moduleAugmentations, + augmentation => isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration), + ); } /** * Return true if the file will invalidate all files because it affectes global scope */ function isFileAffectingGlobalScope(sourceFile: SourceFile) { - return containsGlobalScopeAugmentation(sourceFile) || - !isExternalOrCommonJsModule(sourceFile) && !isJsonSourceFile(sourceFile) && !containsOnlyAmbientModules(sourceFile); + return containsGlobalScopeAugmentation(sourceFile) + || !isExternalOrCommonJsModule(sourceFile) && !isJsonSourceFile(sourceFile) + && !containsOnlyAmbientModules(sourceFile); } /** * Gets all files of the program excluding the default library file */ - export function getAllFilesExcludingDefaultLibraryFile(state: BuilderState, programOfThisState: Program, firstSourceFile: SourceFile | undefined): readonly SourceFile[] { + export function getAllFilesExcludingDefaultLibraryFile( + state: BuilderState, + programOfThisState: Program, + firstSourceFile: SourceFile | undefined, + ): readonly SourceFile[] { // Use cached result if (state.allFilesExcludingDefaultLibraryFile) { return state.allFilesExcludingDefaultLibraryFile; @@ -573,7 +686,11 @@ namespace ts { /** * When program emits non modular code, gets the files affected by the sourceFile whose shape has changed */ - function getFilesAffectedByUpdatedShapeWhenNonModuleEmit(state: BuilderState, programOfThisState: Program, sourceFileWithUpdatedShape: SourceFile) { + function getFilesAffectedByUpdatedShapeWhenNonModuleEmit( + state: BuilderState, + programOfThisState: Program, + sourceFileWithUpdatedShape: SourceFile, + ) { const compilerOptions = programOfThisState.getCompilerOptions(); // If `--out` or `--outFile` is specified, any new emit will result in re-emitting the entire project, // so returning the file itself is good enough. @@ -616,7 +733,17 @@ namespace ts { if (!seenFileNamesMap.has(currentPath)) { const currentSourceFile = programOfThisState.getSourceFileByPath(currentPath)!; seenFileNamesMap.set(currentPath, currentSourceFile); - if (currentSourceFile && updateShapeSignature(state, programOfThisState, currentSourceFile, cancellationToken, computeHash, getCanonicalFileName)) { + if ( + currentSourceFile + && updateShapeSignature( + state, + programOfThisState, + currentSourceFile, + cancellationToken, + computeHash, + getCanonicalFileName, + ) + ) { queue.push(...getReferencedByPaths(state, currentSourceFile.resolvedPath)); } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6a568de6f63a4..9e25fd5780b0f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -93,7 +93,8 @@ namespace ts { // The following members encode facts about particular kinds of types for use in the getTypeFacts function. // The presence of a particular fact means that the given test is true for some (and possibly all) values // of that kind of type. - BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, + BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol + | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, BaseStringFacts = BaseStringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, StringStrictFacts = BaseStringStrictFacts | Truthy | Falsy, StringFacts = BaseStringFacts | Truthy, @@ -101,7 +102,8 @@ namespace ts { EmptyStringFacts = BaseStringFacts, NonEmptyStringStrictFacts = BaseStringStrictFacts | Truthy, NonEmptyStringFacts = BaseStringFacts | Truthy, - BaseNumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, + BaseNumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol + | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, BaseNumberFacts = BaseNumberStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, NumberStrictFacts = BaseNumberStrictFacts | Truthy | Falsy, NumberFacts = BaseNumberFacts | Truthy, @@ -109,7 +111,8 @@ namespace ts { ZeroNumberFacts = BaseNumberFacts, NonZeroNumberStrictFacts = BaseNumberStrictFacts | Truthy, NonZeroNumberFacts = BaseNumberFacts | Truthy, - BaseBigIntStrictFacts = TypeofEQBigInt | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, + BaseBigIntStrictFacts = TypeofEQBigInt | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol + | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, BaseBigIntFacts = BaseBigIntStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, BigIntStrictFacts = BaseBigIntStrictFacts | Truthy | Falsy, BigIntFacts = BaseBigIntFacts | Truthy, @@ -117,7 +120,8 @@ namespace ts { ZeroBigIntFacts = BaseBigIntFacts, NonZeroBigIntStrictFacts = BaseBigIntStrictFacts | Truthy, NonZeroBigIntFacts = BaseBigIntFacts | Truthy, - BaseBooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, + BaseBooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNESymbol + | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, BaseBooleanFacts = BaseBooleanStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, BooleanStrictFacts = BaseBooleanStrictFacts | Truthy | Falsy, BooleanFacts = BaseBooleanFacts | Truthy, @@ -125,19 +129,28 @@ namespace ts { FalseFacts = BaseBooleanFacts, TrueStrictFacts = BaseBooleanStrictFacts | Truthy, TrueFacts = BaseBooleanFacts | Truthy, - SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean + | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull + | Truthy, SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt + | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt + | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - VoidFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, - UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy | IsUndefined, - NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy | IsNull, + VoidFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject + | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, + UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol + | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy + | IsUndefined, + NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol + | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy | IsNull, EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull | IsUndefinedOrNull), EmptyObjectFacts = All & ~IsUndefinedOrNull, UnknownFacts = All & ~IsUndefinedOrNull, - AllTypeofNE = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined, + AllTypeofNE = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol + | TypeofNEObject | TypeofNEFunction | NEUndefined, // Masks OrFactsMask = TypeofEQFunction | TypeofNEObject, AndFactsMask = All & ~OrFactsMask, @@ -294,8 +307,8 @@ namespace ts { export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean) { const moduleState = getModuleInstanceState(node); - return moduleState === ModuleInstanceState.Instantiated || - (preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly); + return moduleState === ModuleInstanceState.Instantiated + || (preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly); } export function createTypeChecker(host: TypeCheckerHost): TypeChecker { @@ -309,7 +322,9 @@ namespace ts { if (!sf.resolvedModules) return; sf.resolvedModules.forEach(r => { - if (r && r.packageId) map.set(r.packageId.name, r.extension === Extension.Dts || !!map.get(r.packageId.name)); + if (r && r.packageId) { + map.set(r.packageId.name, r.extension === Extension.Dts || !!map.get(r.packageId.name)); + } }); }); return map; @@ -418,7 +433,11 @@ namespace ts { getTypeOfSymbol, getSymbolsOfParameterPropertyDeclaration: (parameterIn, parameterName) => { const parameter = getParseTreeNode(parameterIn, isParameter); - if (parameter === undefined) return Debug.fail("Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node."); + if (parameter === undefined) { + return Debug.fail( + "Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node.", + ); + } return getSymbolsOfParameterPropertyDeclaration(parameter, escapeLeadingUnderscores(parameterName)); }, getDeclaredTypeOfSymbol, @@ -431,14 +450,17 @@ namespace ts { } const propName = escapeLeadingUnderscores(name); const lexicallyScopedIdentifier = lookupSymbolForPrivateIdentifierDeclaration(propName, node); - return lexicallyScopedIdentifier ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedIdentifier) : undefined; + return lexicallyScopedIdentifier + ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedIdentifier) : undefined; }, getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)), - getIndexInfoOfType: (type, kind) => getIndexInfoOfType(type, kind === IndexKind.String ? stringType : numberType), + getIndexInfoOfType: (type, kind) => + getIndexInfoOfType(type, kind === IndexKind.String ? stringType : numberType), getIndexInfosOfType, getIndexInfosOfIndexSymbol, getSignaturesOfType, - getIndexTypeOfType: (type, kind) => getIndexTypeOfType(type, kind === IndexKind.String ? stringType : numberType), + getIndexTypeOfType: (type, kind) => + getIndexTypeOfType(type, kind === IndexKind.String ? stringType : numberType), getIndexType: type => getIndexType(type), getBaseTypes, getBaseTypeOfLiteralType, @@ -554,9 +576,18 @@ namespace ts { isContextSensitive, getTypeOfPropertyOfContextualType, getFullyQualifiedName, - getResolvedSignature: (node, candidatesOutArray, argumentCount) => getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.Normal), - getResolvedSignatureForStringLiteralCompletions: (call, editingArgument, candidatesOutArray) => getResolvedSignatureWorker(call, candidatesOutArray, /*argumentCount*/ undefined, CheckMode.IsForStringLiteralArgumentCompletions, editingArgument), - getResolvedSignatureForSignatureHelp: (node, candidatesOutArray, argumentCount) => getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.IsForSignatureHelp), + getResolvedSignature: (node, candidatesOutArray, argumentCount) => + getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.Normal), + getResolvedSignatureForStringLiteralCompletions: (call, editingArgument, candidatesOutArray) => + getResolvedSignatureWorker( + call, + candidatesOutArray, + /*argumentCount*/ undefined, + CheckMode.IsForStringLiteralArgumentCompletions, + editingArgument, + ), + getResolvedSignatureForSignatureHelp: (node, candidatesOutArray, argumentCount) => + getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.IsForSignatureHelp), getExpandedParameters, hasEffectiveRestParameter, containsArgumentsReference, @@ -604,8 +635,10 @@ namespace ts { const node = getParseTreeNode(nodeIn, isParameter); return node ? isOptionalParameter(node) : false; }, - tryGetMemberInModuleExports: (name, symbol) => tryGetMemberInModuleExports(escapeLeadingUnderscores(name), symbol), - tryGetMemberInModuleExportsAndProperties: (name, symbol) => tryGetMemberInModuleExportsAndProperties(escapeLeadingUnderscores(name), symbol), + tryGetMemberInModuleExports: (name, symbol) => + tryGetMemberInModuleExports(escapeLeadingUnderscores(name), symbol), + tryGetMemberInModuleExportsAndProperties: (name, symbol) => + tryGetMemberInModuleExportsAndProperties(escapeLeadingUnderscores(name), symbol), tryFindAmbientModule: moduleName => tryFindAmbientModule(moduleName, /*withAugmentations*/ true), tryFindAmbientModuleWithoutAugmentations: moduleName => { // we deliberately exclude augmentations @@ -651,26 +684,40 @@ namespace ts { getSuggestedSymbolForNonexistentProperty, getSuggestionForNonexistentProperty, getSuggestedSymbolForNonexistentJSXAttribute, - getSuggestedSymbolForNonexistentSymbol: (location, name, meaning) => getSuggestedSymbolForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), - getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), + getSuggestedSymbolForNonexistentSymbol: (location, name, meaning) => + getSuggestedSymbolForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), + getSuggestionForNonexistentSymbol: (location, name, meaning) => + getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), getSuggestedSymbolForNonexistentModule, getSuggestionForNonexistentExport, getSuggestedSymbolForNonexistentClassMember, getBaseConstraintOfType, - getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined, + getDefaultFromTypeParameter: type => + type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) + : undefined, resolveName(name, location, meaning, excludeGlobals) { - return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false, excludeGlobals); + return resolveName( + location, + escapeLeadingUnderscores(name), + meaning, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + excludeGlobals, + ); }, getJsxNamespace: n => unescapeLeadingUnderscores(getJsxNamespace(n)), getJsxFragmentFactory: n => { const jsxFragmentFactory = getJsxFragmentFactoryEntity(n); - return jsxFragmentFactory && unescapeLeadingUnderscores(getFirstIdentifier(jsxFragmentFactory).escapedText); + return jsxFragmentFactory + && unescapeLeadingUnderscores(getFirstIdentifier(jsxFragmentFactory).escapedText); }, getAccessibleSymbolChain, getTypePredicateOfSignature, resolveExternalModuleName: moduleSpecifierIn => { const moduleSpecifier = getParseTreeNode(moduleSpecifierIn, isExpression); - return moduleSpecifier && resolveExternalModuleName(moduleSpecifier, moduleSpecifier, /*ignoreErrors*/ true); + return moduleSpecifier + && resolveExternalModuleName(moduleSpecifier, moduleSpecifier, /*ignoreErrors*/ true); }, resolveExternalModuleSymbol, tryGetThisTypeAt: (nodeIn, includeGlobalThis, container) => { @@ -682,7 +729,8 @@ namespace ts { return node && getTypeArgumentConstraint(node); }, getSuggestionDiagnostics: (fileIn, ct) => { - const file = getParseTreeNode(fileIn, isSourceFile) || Debug.fail("Could not determine parsed source file."); + const file = getParseTreeNode(fileIn, isSourceFile) + || Debug.fail("Could not determine parsed source file."); if (skipTypeChecking(file, compilerOptions, host)) { return emptyArray; } @@ -700,8 +748,14 @@ namespace ts { diagnostics = addRange(diagnostics, suggestionDiagnostics.getDiagnostics(file.fileName)); checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(file), (containingNode, kind, diag) => { - if (!containsParseError(containingNode) && !unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient))) { - (diagnostics || (diagnostics = [])).push({ ...diag, category: DiagnosticCategory.Suggestion }); + if ( + !containsParseError(containingNode) + && !unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient)) + ) { + (diagnostics || (diagnostics = [])).push({ + ...diag, + category: DiagnosticCategory.Suggestion, + }); } }); @@ -755,12 +809,22 @@ namespace ts { return result; } - function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, checkMode: CheckMode, editingArgument?: Node): Signature | undefined { + function getResolvedSignatureWorker( + nodeIn: CallLikeExpression, + candidatesOutArray: Signature[] | undefined, + argumentCount: number | undefined, + checkMode: CheckMode, + editingArgument?: Node, + ): Signature | undefined { const node = getParseTreeNode(nodeIn, isCallLikeExpression); apparentArgumentCount = argumentCount; - const res = !node ? undefined : - editingArgument ? runWithInferenceBlockedFromSourceNode(editingArgument, () => getResolvedSignature(node, candidatesOutArray, checkMode)) : - getResolvedSignature(node, candidatesOutArray, checkMode); + const res = !node ? undefined + : editingArgument + ? runWithInferenceBlockedFromSourceNode( + editingArgument, + () => getResolvedSignature(node, candidatesOutArray, checkMode), + ) + : getResolvedSignature(node, candidatesOutArray, checkMode); apparentArgumentCount = undefined; return res; } @@ -797,11 +861,14 @@ namespace ts { const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); const nonNullUnknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined"); - const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType); + const undefinedWideningType = strictNullChecks ? undefinedType + : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType); const optionalType = createIntrinsicType(TypeFlags.Undefined, "undefined"); - const missingType = exactOptionalPropertyTypes ? createIntrinsicType(TypeFlags.Undefined, "undefined") : undefinedType; + const missingType = exactOptionalPropertyTypes ? createIntrinsicType(TypeFlags.Undefined, "undefined") + : undefinedType; const nullType = createIntrinsicType(TypeFlags.Null, "null"); - const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType); + const nullWideningType = strictNullChecks ? nullType + : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType); const stringType = createIntrinsicType(TypeFlags.String, "string"); const numberType = createIntrinsicType(TypeFlags.Number, "number"); const bigintType = createIntrinsicType(TypeFlags.BigInt, "bigint"); @@ -829,22 +896,44 @@ namespace ts { const stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]); const keyofConstraintType = keyofStringsOnly ? stringType : stringNumberSymbolType; const numberOrBigIntType = getUnionType([numberType, bigintType]); - const templateConstraintType = getUnionType([stringType, numberType, booleanType, bigintType, nullType, undefinedType]) as UnionType; + const templateConstraintType = getUnionType([ + stringType, + numberType, + booleanType, + bigintType, + nullType, + undefinedType, + ]) as UnionType; const numericStringType = getTemplateLiteralType(["", ""], [numberType]); // The `${number}` type - const restrictiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t, () => "(restrictive mapper)"); - const permissiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? wildcardType : t, () => "(permissive mapper)"); + const restrictiveMapper: TypeMapper = makeFunctionTypeMapper( + t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t, + () => "(restrictive mapper)", + ); + const permissiveMapper: TypeMapper = makeFunctionTypeMapper( + t => t.flags & TypeFlags.TypeParameter ? wildcardType : t, + () => "(permissive mapper)", + ); const uniqueLiteralType = createIntrinsicType(TypeFlags.Never, "never"); // `uniqueLiteralType` is a special `never` flagged by union reduction to behave as a literal - const uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t, () => "(unique literal mapper)"); // replace all type parameters with the unique literal type (disregarding constraints) + const uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper( + t => t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t, + () => "(unique literal mapper)", + ); // replace all type parameters with the unique literal type (disregarding constraints) let outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined; const reportUnreliableMapper = makeFunctionTypeMapper(t => { - if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) { + if ( + outofbandVarianceMarkerHandler + && (t === markerSuperType || t === markerSubType || t === markerOtherType) + ) { outofbandVarianceMarkerHandler(/*onlyUnreliable*/ true); } return t; }, () => "(unmeasurable reporter)"); const reportUnmeasurableMapper = makeFunctionTypeMapper(t => { - if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) { + if ( + outofbandVarianceMarkerHandler + && (t === markerSuperType || t === markerSubType || t === markerOtherType) + ) { outofbandVarianceMarkerHandler(/*onlyUnreliable*/ false); } return t; @@ -856,12 +945,25 @@ namespace ts { const emptyTypeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type); emptyTypeLiteralSymbol.members = createSymbolTable(); - const emptyTypeLiteralType = createAnonymousType(emptyTypeLiteralSymbol, emptySymbols, emptyArray, emptyArray, emptyArray); + const emptyTypeLiteralType = createAnonymousType( + emptyTypeLiteralSymbol, + emptySymbols, + emptyArray, + emptyArray, + emptyArray, + ); const unknownEmptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - const unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) : unknownType; - - const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray) as ObjectType as GenericType; + const unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) + : unknownType; + + const emptyGenericType = createAnonymousType( + undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray, + ) as ObjectType as GenericType; emptyGenericType.instantiations = new Map(); const anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); @@ -884,10 +986,46 @@ namespace ts { const noTypePredicate = createTypePredicate(TypePredicateKind.Identifier, "<>", 0, anyType); - const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, errorType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); + const anySignature = createSignature( + undefined, + undefined, + undefined, + emptyArray, + anyType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None, + ); + const unknownSignature = createSignature( + undefined, + undefined, + undefined, + emptyArray, + errorType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None, + ); + const resolvingSignature = createSignature( + undefined, + undefined, + undefined, + emptyArray, + anyType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None, + ); + const silentNeverSignature = createSignature( + undefined, + undefined, + undefined, + emptyArray, + silentNeverType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None, + ); const enumNumberIndexInfo = createIndexInfo(numberType, stringType, /*isReadonly*/ true); @@ -919,7 +1057,8 @@ namespace ts { resolveIterationType: getAwaitedType, mustHaveANextMethodDiagnostic: Diagnostics.An_async_iterator_must_have_a_next_method, mustBeAMethodDiagnostic: Diagnostics.The_0_property_of_an_async_iterator_must_be_a_method, - mustHaveAValueDiagnostic: Diagnostics.The_type_returned_by_the_0_method_of_an_async_iterator_must_be_a_promise_for_a_type_with_a_value_property, + mustHaveAValueDiagnostic: Diagnostics + .The_type_returned_by_the_0_method_of_an_async_iterator_must_be_a_promise_for_a_type_with_a_value_property, }; const syncIterationTypesResolver: IterationTypesResolver = { @@ -933,7 +1072,8 @@ namespace ts { resolveIterationType: (type, _errorNode) => type, mustHaveANextMethodDiagnostic: Diagnostics.An_iterator_must_have_a_next_method, mustBeAMethodDiagnostic: Diagnostics.The_0_property_of_an_iterator_must_be_a_method, - mustHaveAValueDiagnostic: Diagnostics.The_type_returned_by_the_0_method_of_an_iterator_must_have_a_value_property, + mustHaveAValueDiagnostic: + Diagnostics.The_type_returned_by_the_0_method_of_an_iterator_must_have_a_value_property, }; interface DuplicateInfoForSymbol { @@ -1105,10 +1245,14 @@ namespace ts { const jsxFragmentPragma = file.pragmas.get("jsxfrag"); if (jsxFragmentPragma) { const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma; - file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion); + file.localJsxFragmentFactory = parseIsolatedEntityName( + chosenPragma.arguments.factory, + languageVersion, + ); visitNode(file.localJsxFragmentFactory, markAsSynthetic); if (file.localJsxFragmentFactory) { - return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText; + return file.localJsxFragmentNamespace = + getFirstIdentifier(file.localJsxFragmentFactory).escapedText; } } const entity = getJsxFragmentFactoryEntity(location); @@ -1139,7 +1283,10 @@ namespace ts { } } if (!_jsxFactoryEntity) { - _jsxFactoryEntity = factory.createQualifiedName(factory.createIdentifier(unescapeLeadingUnderscores(_jsxNamespace)), "createElement"); + _jsxFactoryEntity = factory.createQualifiedName( + factory.createIdentifier(unescapeLeadingUnderscores(_jsxNamespace)), + "createElement", + ); } return _jsxNamespace; } @@ -1171,7 +1318,14 @@ namespace ts { return emitResolver; } - function lookupOrIssueError(location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { + function lookupOrIssueError( + location: Node | undefined, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): Diagnostic { const diagnostic = location ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createCompilerDiagnostic(message, arg0, arg1, arg2, arg3); @@ -1185,19 +1339,41 @@ namespace ts { } } - function errorSkippedOn(key: keyof CompilerOptions, location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { + function errorSkippedOn( + key: keyof CompilerOptions, + location: Node | undefined, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): Diagnostic { const diagnostic = error(location, message, arg0, arg1, arg2, arg3); diagnostic.skippedOn = key; return diagnostic; } - function createError(location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { + function createError( + location: Node | undefined, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): Diagnostic { return location ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createCompilerDiagnostic(message, arg0, arg1, arg2, arg3); } - function error(location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { + function error( + location: Node | undefined, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): Diagnostic { const diagnostic = createError(location, message, arg0, arg1, arg2, arg3); diagnostics.add(diagnostic); return diagnostic; @@ -1211,7 +1387,15 @@ namespace ts { suggestionDiagnostics.add({ ...diagnostic, category: DiagnosticCategory.Suggestion }); } } - function errorOrSuggestion(isError: boolean, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { + function errorOrSuggestion( + isError: boolean, + location: Node, + message: DiagnosticMessage | DiagnosticMessageChain, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): void { // Pseudo-synthesized input node if (location.pos < 0 || location.end < 0) { if (!isError) { @@ -1219,10 +1403,18 @@ namespace ts { } // Issue errors globally const file = getSourceFileOfNode(location); - addErrorOrSuggestion(isError, "message" in message ? createFileDiagnostic(file, 0, 0, message, arg0, arg1, arg2, arg3) : createDiagnosticForFileFromMessageChain(file, message)); // eslint-disable-line local/no-in-operator + addErrorOrSuggestion( + isError, + "message" in message ? createFileDiagnostic(file, 0, 0, message, arg0, arg1, arg2, arg3) + : createDiagnosticForFileFromMessageChain(file, message), + ); // eslint-disable-line local/no-in-operator return; } - addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message)); // eslint-disable-line local/no-in-operator + addErrorOrSuggestion( + isError, + "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) + : createDiagnosticForNodeFromMessageChain(location, message), + ); // eslint-disable-line local/no-in-operator } function errorAndMaybeSuggestAwait( @@ -1243,7 +1435,8 @@ namespace ts { } function addDeprecatedSuggestionWorker(declarations: Node | Node[], diagnostic: DiagnosticWithLocation) { - const deprecatedTag = Array.isArray(declarations) ? forEach(declarations, getJSDocDeprecatedTag) : getJSDocDeprecatedTag(declarations); + const deprecatedTag = Array.isArray(declarations) ? forEach(declarations, getJSDocDeprecatedTag) + : getJSDocDeprecatedTag(declarations); if (deprecatedTag) { addRelatedInfo( diagnostic, @@ -1264,9 +1457,19 @@ namespace ts { return addDeprecatedSuggestionWorker(declarations, diagnostic); } - function addDeprecatedSuggestionWithSignature(location: Node, declaration: Node, deprecatedEntity: string | undefined, signatureString: string) { + function addDeprecatedSuggestionWithSignature( + location: Node, + declaration: Node, + deprecatedEntity: string | undefined, + signatureString: string, + ) { const diagnostic = deprecatedEntity - ? createDiagnosticForNode(location, Diagnostics.The_signature_0_of_1_is_deprecated, signatureString, deprecatedEntity) + ? createDiagnosticForNode( + location, + Diagnostics.The_signature_0_of_1_is_deprecated, + signatureString, + deprecatedEntity, + ) : createDiagnosticForNode(location, Diagnostics._0_is_deprecated, signatureString); return addDeprecatedSuggestionWorker(declaration, diagnostic); } @@ -1325,8 +1528,8 @@ namespace ts { */ function mergeSymbol(target: Symbol, source: Symbol, unidirectional = false): Symbol { if ( - !(target.flags & getExcludedSymbolFlags(source.flags)) || - (source.flags | target.flags) & SymbolFlags.Assignment + !(target.flags & getExcludedSymbolFlags(source.flags)) + || (source.flags | target.flags) & SymbolFlags.Assignment ) { if (source === target) { // This can happen when an export assigned namespace exports something also erroneously exported at the top level @@ -1341,7 +1544,10 @@ namespace ts { target = cloneSymbol(resolvedTarget); } // Javascript static-property-assignment declarations always merge, even though they are also values - if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) { + if ( + source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule + && target.constEnumOnlyModule && !source.constEnumOnlyModule + ) { // reset flag when merging instantiated module into value module that has only const enums target.constEnumOnlyModule = false; } @@ -1369,15 +1575,18 @@ namespace ts { if (target !== globalThisSymbol) { error( source.declarations && getNameOfDeclaration(source.declarations[0]), - Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, + Diagnostics + .Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, symbolToString(target), ); } } else { // error const isEitherEnum = !!(target.flags & SymbolFlags.Enum || source.flags & SymbolFlags.Enum); - const isEitherBlockScoped = !!(target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable); - const message = isEitherEnum ? Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations + const isEitherBlockScoped = !!(target.flags & SymbolFlags.BlockScopedVariable + || source.flags & SymbolFlags.BlockScopedVariable); + const message = isEitherEnum + ? Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations : isEitherBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; const sourceSymbolFile = source.declarations && getSourceFileOfNode(source.declarations[0]); @@ -1388,11 +1597,27 @@ namespace ts { const symbolName = symbolToString(source); // Collect top-level duplicate identifier errors into one mapping, so we can then merge their diagnostics if there are a bunch - if (sourceSymbolFile && targetSymbolFile && amalgamatedDuplicates && !isEitherEnum && sourceSymbolFile !== targetSymbolFile) { - const firstFile = comparePaths(sourceSymbolFile.path, targetSymbolFile.path) === Comparison.LessThan ? sourceSymbolFile : targetSymbolFile; + if ( + sourceSymbolFile && targetSymbolFile && amalgamatedDuplicates && !isEitherEnum + && sourceSymbolFile !== targetSymbolFile + ) { + const firstFile = comparePaths(sourceSymbolFile.path, targetSymbolFile.path) === Comparison.LessThan + ? sourceSymbolFile : targetSymbolFile; const secondFile = firstFile === sourceSymbolFile ? targetSymbolFile : sourceSymbolFile; - const filesDuplicates = getOrUpdate(amalgamatedDuplicates, `${firstFile.path}|${secondFile.path}`, () => ({ firstFile, secondFile, conflictingSymbols: new Map() } as DuplicateInfoForFiles)); - const conflictingSymbolInfo = getOrUpdate(filesDuplicates.conflictingSymbols, symbolName, () => ({ isBlockScoped: isEitherBlockScoped, firstFileLocations: [], secondFileLocations: [] } as DuplicateInfoForSymbol)); + const filesDuplicates = getOrUpdate( + amalgamatedDuplicates, + `${firstFile.path}|${secondFile.path}`, + () => ({ firstFile, secondFile, conflictingSymbols: new Map() } as DuplicateInfoForFiles), + ); + const conflictingSymbolInfo = getOrUpdate( + filesDuplicates.conflictingSymbols, + symbolName, + () => ({ + isBlockScoped: isEitherBlockScoped, + firstFileLocations: [], + secondFileLocations: [], + } as DuplicateInfoForSymbol), + ); if (!isSourcePlainJs) addDuplicateLocations(conflictingSymbolInfo.firstFileLocations, source); if (!isTargetPlainJs) addDuplicateLocations(conflictingSymbolInfo.secondFileLocations, target); } @@ -1412,27 +1637,52 @@ namespace ts { } } - function addDuplicateDeclarationErrorsForSymbols(target: Symbol, message: DiagnosticMessage, symbolName: string, source: Symbol) { + function addDuplicateDeclarationErrorsForSymbols( + target: Symbol, + message: DiagnosticMessage, + symbolName: string, + source: Symbol, + ) { forEach(target.declarations, node => { addDuplicateDeclarationError(node, message, symbolName, source.declarations); }); } - function addDuplicateDeclarationError(node: Declaration, message: DiagnosticMessage, symbolName: string, relatedNodes: readonly Declaration[] | undefined) { - const errorNode = (getExpandoInitializer(node, /*isPrototypeAssignment*/ false) ? getNameOfExpando(node) : getNameOfDeclaration(node)) || node; + function addDuplicateDeclarationError( + node: Declaration, + message: DiagnosticMessage, + symbolName: string, + relatedNodes: readonly Declaration[] | undefined, + ) { + const errorNode = (getExpandoInitializer(node, /*isPrototypeAssignment*/ false) ? getNameOfExpando(node) + : getNameOfDeclaration(node)) || node; const err = lookupOrIssueError(errorNode, message, symbolName); for (const relatedNode of relatedNodes || emptyArray) { - const adjustedNode = (getExpandoInitializer(relatedNode, /*isPrototypeAssignment*/ false) ? getNameOfExpando(relatedNode) : getNameOfDeclaration(relatedNode)) || relatedNode; + const adjustedNode = + (getExpandoInitializer(relatedNode, /*isPrototypeAssignment*/ false) ? getNameOfExpando(relatedNode) + : getNameOfDeclaration(relatedNode)) || relatedNode; if (adjustedNode === errorNode) continue; err.relatedInformation = err.relatedInformation || []; - const leadingMessage = createDiagnosticForNode(adjustedNode, Diagnostics._0_was_also_declared_here, symbolName); + const leadingMessage = createDiagnosticForNode( + adjustedNode, + Diagnostics._0_was_also_declared_here, + symbolName, + ); const followOnMessage = createDiagnosticForNode(adjustedNode, Diagnostics.and_here); - if (length(err.relatedInformation) >= 5 || some(err.relatedInformation, r => compareDiagnostics(r, followOnMessage) === Comparison.EqualTo || compareDiagnostics(r, leadingMessage) === Comparison.EqualTo)) continue; + if ( + length(err.relatedInformation) >= 5 + || some(err.relatedInformation, r => + compareDiagnostics(r, followOnMessage) === Comparison.EqualTo + || compareDiagnostics(r, leadingMessage) === Comparison.EqualTo) + ) continue; addRelatedInfo(err, !length(err.relatedInformation) ? leadingMessage : followOnMessage); } } - function combineSymbolTables(first: SymbolTable | undefined, second: SymbolTable | undefined): SymbolTable | undefined { + function combineSymbolTables( + first: SymbolTable | undefined, + second: SymbolTable | undefined, + ): SymbolTable | undefined { if (!first?.size) return second; if (!second?.size) return first; const combined = createSymbolTable(); @@ -1444,7 +1694,11 @@ namespace ts { function mergeSymbolTable(target: SymbolTable, source: SymbolTable, unidirectional = false) { source.forEach((sourceSymbol, id) => { const targetSymbol = target.get(id); - target.set(id, targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) : getMergedSymbol(sourceSymbol)); + target.set( + id, + targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) + : getMergedSymbol(sourceSymbol), + ); }); } @@ -1467,7 +1721,12 @@ namespace ts { const moduleNotFoundError = !(moduleName.parent.parent.flags & NodeFlags.Ambient) ? Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found : undefined; - let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError, /*isForAugmentation*/ true); + let mainModule = resolveExternalModuleNameWorker( + moduleName, + moduleName, + moduleNotFoundError, + /*isForAugmentation*/ true, + ); if (!mainModule) { return; } @@ -1488,9 +1747,15 @@ namespace ts { patternAmbientModuleAugmentations.set((moduleName as StringLiteral).text, merged); } else { - if (mainModule.exports?.get(InternalSymbolName.ExportStar) && moduleAugmentation.symbol.exports?.size) { + if ( + mainModule.exports?.get(InternalSymbolName.ExportStar) + && moduleAugmentation.symbol.exports?.size + ) { // We may need to merge the module augmentation's exports into the target symbols of the resolved exports - const resolvedExports = getResolvedMembersOrExportsOfSymbol(mainModule, MembersOrExportsResolutionKind.resolvedExports); + const resolvedExports = getResolvedMembersOrExportsOfSymbol( + mainModule, + MembersOrExportsResolutionKind.resolvedExports, + ); for (const [key, value] of arrayFrom(moduleAugmentation.symbol.exports.entries())) { if (resolvedExports.has(key) && !mainModule.exports.has(key)) { mergeSymbol(resolvedExports.get(key)!, value); @@ -1502,7 +1767,11 @@ namespace ts { } else { // moduleName will be a StringLiteral since this is not `declare global`. - error(moduleName, Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, (moduleName as StringLiteral).text); + error( + moduleName, + Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, + (moduleName as StringLiteral).text, + ); } } } @@ -1512,7 +1781,10 @@ namespace ts { const targetSymbol = target.get(id); if (targetSymbol) { // Error on redeclarations - forEach(targetSymbol.declarations, addDeclarationDiagnostic(unescapeLeadingUnderscores(id), message)); + forEach( + targetSymbol.declarations, + addDeclarationDiagnostic(unescapeLeadingUnderscores(id), message), + ); } else { target.set(id, sourceSymbol); @@ -1543,7 +1815,10 @@ namespace ts { if (meaning) { const symbol = getMergedSymbol(symbols.get(name)); if (symbol) { - Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); + Debug.assert( + (getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, + "Should never get an instantiated symbol here.", + ); if (symbol.flags & meaning) { return symbol; } @@ -1565,18 +1840,27 @@ namespace ts { * @param parameterName a name of the parameter to get the symbols for. * @return a tuple of two symbols */ - function getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: __String): [Symbol, Symbol] { + function getSymbolsOfParameterPropertyDeclaration( + parameter: ParameterDeclaration, + parameterName: __String, + ): [Symbol, Symbol] { const constructorDeclaration = parameter.parent; const classDeclaration = parameter.parent.parent; const parameterSymbol = getSymbol(constructorDeclaration.locals!, parameterName, SymbolFlags.Value); - const propertySymbol = getSymbol(getMembersOfSymbol(classDeclaration.symbol), parameterName, SymbolFlags.Value); + const propertySymbol = getSymbol( + getMembersOfSymbol(classDeclaration.symbol), + parameterName, + SymbolFlags.Value, + ); if (parameterSymbol && propertySymbol) { return [parameterSymbol, propertySymbol]; } - return Debug.fail("There should exist two symbols, one as property declaration and one as parameter declaration"); + return Debug.fail( + "There should exist two symbols, one as property declaration and one as parameter declaration", + ); } function isBlockScopedNameDeclaredBeforeUse(declaration: Declaration, usage: Node): boolean { @@ -1585,10 +1869,10 @@ namespace ts { const declContainer = getEnclosingBlockScopeContainer(declaration); if (declarationFile !== useFile) { if ( - (moduleKind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) || - (!outFile(compilerOptions)) || - isInTypeQuery(usage) || - declaration.flags & NodeFlags.Ambient + (moduleKind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) + || (!outFile(compilerOptions)) + || isInTypeQuery(usage) + || declaration.flags & NodeFlags.Ambient ) { // nodes are in different files and order cannot be determined return true; @@ -1602,21 +1886,32 @@ namespace ts { return sourceFiles.indexOf(declarationFile) <= sourceFiles.indexOf(useFile); } - if (declaration.pos <= usage.pos && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer && !declaration.exclamationToken)) { + if ( + declaration.pos <= usage.pos + && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer + && !declaration.exclamationToken) + ) { // declaration is before usage if (declaration.kind === SyntaxKind.BindingElement) { // still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2]) const errorBindingElement = getAncestor(usage, SyntaxKind.BindingElement) as BindingElement; if (errorBindingElement) { - return findAncestor(errorBindingElement, isBindingElement) !== findAncestor(declaration, isBindingElement) || - declaration.pos < errorBindingElement.pos; + return findAncestor(errorBindingElement, isBindingElement) + !== findAncestor(declaration, isBindingElement) + || declaration.pos < errorBindingElement.pos; } // or it might be illegal if usage happens before parent variable is declared (eg var [a] = a) - return isBlockScopedNameDeclaredBeforeUse(getAncestor(declaration, SyntaxKind.VariableDeclaration) as Declaration, usage); + return isBlockScopedNameDeclaredBeforeUse( + getAncestor(declaration, SyntaxKind.VariableDeclaration) as Declaration, + usage, + ); } else if (declaration.kind === SyntaxKind.VariableDeclaration) { // still might be illegal if usage is in the initializer of the variable declaration (eg var a = a) - return !isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration as VariableDeclaration, usage); + return !isImmediatelyUsedInInitializerOfBlockScopedVariable( + declaration as VariableDeclaration, + usage, + ); } else if (isClassDeclaration(declaration)) { // still might be illegal if the usage is within a computed property name in the class (eg class A { static p = "a"; [A.p]() {} }) @@ -1624,7 +1919,11 @@ namespace ts { } else if (isPropertyDeclaration(declaration)) { // still might be illegal if a self-referencing property initializer (eg private x = this.x) - return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ false); + return !isPropertyImmediatelyReferencedWithinDeclaration( + declaration, + usage, + /*stopAtAnyPropertyDeclaration*/ false, + ); } else if (isParameterPropertyDeclaration(declaration, declaration.parent)) { // foo = this.bar is illegal in esnext+useDefineForClassFields when bar is a parameter property @@ -1645,7 +1944,11 @@ namespace ts { // or if usage is in a type context: // 1. inside a type query (typeof in type position) // 2. inside a jsdoc comment - if (usage.parent.kind === SyntaxKind.ExportSpecifier || (usage.parent.kind === SyntaxKind.ExportAssignment && (usage.parent as ExportAssignment).isExportEquals)) { + if ( + usage.parent.kind === SyntaxKind.ExportSpecifier + || (usage.parent.kind === SyntaxKind.ExportAssignment + && (usage.parent as ExportAssignment).isExportEquals) + ) { // export specifiers do not use the variable, they only make it available for use return true; } @@ -1661,9 +1964,14 @@ namespace ts { if ( getEmitScriptTarget(compilerOptions) === ScriptTarget.ESNext && useDefineForClassFields && getContainingClass(declaration) - && (isPropertyDeclaration(declaration) || isParameterPropertyDeclaration(declaration, declaration.parent)) + && (isPropertyDeclaration(declaration) + || isParameterPropertyDeclaration(declaration, declaration.parent)) ) { - return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ true); + return !isPropertyImmediatelyReferencedWithinDeclaration( + declaration, + usage, + /*stopAtAnyPropertyDeclaration*/ true, + ); } else { return true; @@ -1675,7 +1983,10 @@ namespace ts { return !!findAncestor(usage, node => isInterfaceDeclaration(node) || isTypeAliasDeclaration(node)); } - function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean { + function isImmediatelyUsedInInitializerOfBlockScopedVariable( + declaration: VariableDeclaration, + usage: Node, + ): boolean { switch (declaration.parent.parent.kind) { case SyntaxKind.VariableStatement: case SyntaxKind.ForStatement: @@ -1690,7 +2001,8 @@ namespace ts { // ForIn/ForOf case - use site should not be used in expression part const grandparent = declaration.parent.parent; - return isForInOrOfStatement(grandparent) && isSameScopeDescendentOf(usage, grandparent.expression, declContainer); + return isForInOrOfStatement(grandparent) + && isSameScopeDescendentOf(usage, grandparent.expression, declContainer); } function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node): boolean { @@ -1713,20 +2025,38 @@ namespace ts { if (declaration.kind === SyntaxKind.MethodDeclaration) { return true; } - if (isPropertyDeclaration(declaration) && getContainingClass(usage) === getContainingClass(declaration)) { + if ( + isPropertyDeclaration(declaration) + && getContainingClass(usage) === getContainingClass(declaration) + ) { const propName = declaration.name; if (isIdentifier(propName) || isPrivateIdentifier(propName)) { const type = getTypeOfSymbol(getSymbolOfNode(declaration)); - const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration); - if (isPropertyInitializedInStaticBlocks(propName, type, staticBlocks, declaration.parent.pos, current.pos)) { + const staticBlocks = filter( + declaration.parent.members, + isClassStaticBlockDeclaration, + ); + if ( + isPropertyInitializedInStaticBlocks( + propName, + type, + staticBlocks, + declaration.parent.pos, + current.pos, + ) + ) { return true; } } } } else { - const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !isStatic(declaration); - if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) { + const isDeclarationInstanceProperty = + declaration.kind === SyntaxKind.PropertyDeclaration && !isStatic(declaration); + if ( + !isDeclarationInstanceProperty + || getContainingClass(usage) !== getContainingClass(declaration) + ) { return true; } } @@ -1737,7 +2067,11 @@ namespace ts { } /** stopAtAnyPropertyDeclaration is used for detecting ES-standard class field use-before-def errors */ - function isPropertyImmediatelyReferencedWithinDeclaration(declaration: PropertyDeclaration | ParameterPropertyDeclaration, usage: Node, stopAtAnyPropertyDeclaration: boolean) { + function isPropertyImmediatelyReferencedWithinDeclaration( + declaration: PropertyDeclaration | ParameterPropertyDeclaration, + usage: Node, + stopAtAnyPropertyDeclaration: boolean, + ) { // always legal if usage is after declaration if (usage.end > declaration.end) { return false; @@ -1755,9 +2089,10 @@ namespace ts { return true; case SyntaxKind.PropertyDeclaration: // even when stopping at any property declaration, they need to come from the same class - return stopAtAnyPropertyDeclaration && - (isPropertyDeclaration(declaration) && node.parent === declaration.parent - || isParameterPropertyDeclaration(declaration, declaration.parent) && node.parent === declaration.parent.parent) + return stopAtAnyPropertyDeclaration + && (isPropertyDeclaration(declaration) && node.parent === declaration.parent + || isParameterPropertyDeclaration(declaration, declaration.parent) + && node.parent === declaration.parent.parent) ? "quit" : true; case SyntaxKind.Block: switch (node.parent.kind) { @@ -1795,7 +2130,8 @@ namespace ts { if (target >= ScriptTarget.ES2015) { const links = getNodeLinks(functionLocation); if (links.declarationRequiresScopeChange === undefined) { - links.declarationRequiresScopeChange = forEach(functionLocation.parameters, requiresScopeChange) || false; + links.declarationRequiresScopeChange = forEach(functionLocation.parameters, requiresScopeChange) + || false; } return !links.declarationRequiresScopeChange; } @@ -1819,7 +2155,9 @@ namespace ts { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.PropertyAssignment: - return requiresScopeChangeWorker((node as MethodDeclaration | AccessorDeclaration | PropertyAssignment).name); + return requiresScopeChangeWorker( + (node as MethodDeclaration | AccessorDeclaration | PropertyAssignment).name, + ); case SyntaxKind.PropertyDeclaration: // static properties in classes introduce temporary variables if (hasStaticModifier(node)) { @@ -1863,7 +2201,17 @@ namespace ts { excludeGlobals = false, getSpellingSuggestions = true, ): Symbol | undefined { - return resolveNameHelper(location, name, meaning, nameNotFoundMessage, nameArg, isUse, excludeGlobals, getSpellingSuggestions, getSymbol); + return resolveNameHelper( + location, + name, + meaning, + nameNotFoundMessage, + nameArg, + isUse, + excludeGlobals, + getSpellingSuggestions, + getSymbol, + ); } function resolveNameHelper( @@ -1882,7 +2230,10 @@ namespace ts { let lastLocation: Node | undefined; let lastSelfReferenceLocation: Node | undefined; let propertyWithInvalidInitializer: PropertyDeclaration | undefined; - let associatedDeclarationForContainingInitializerOrBindingName: ParameterDeclaration | BindingElement | undefined; + let associatedDeclarationForContainingInitializerOrBindingName: + | ParameterDeclaration + | BindingElement + | undefined; let withinDeferredContext = false; const errorLocation = location; let grandparent: Node; @@ -1899,7 +2250,10 @@ namespace ts { if (location.locals && !isGlobalSourceFile(location)) { if (result = lookup(location.locals, name, meaning)) { let useResult = true; - if (isFunctionLike(location) && lastLocation && lastLocation !== (location as FunctionLikeDeclaration).body) { + if ( + isFunctionLike(location) && lastLocation + && lastLocation !== (location as FunctionLikeDeclaration).body + ) { // symbol lookup restrictions for function-like declarations // - Type parameters of a function are in scope in the entire function declaration, including the parameter // list and return type. However, local types are only in scope in the function body. @@ -1909,11 +2263,11 @@ namespace ts { if (meaning & result.flags & SymbolFlags.Type && lastLocation.kind !== SyntaxKind.JSDoc) { useResult = result.flags & SymbolFlags.TypeParameter // type parameters are visible in parameter list, return type and type parameter list - ? lastLocation === (location as FunctionLikeDeclaration).type || - lastLocation.kind === SyntaxKind.Parameter || - lastLocation.kind === SyntaxKind.JSDocParameterTag || - lastLocation.kind === SyntaxKind.JSDocReturnTag || - lastLocation.kind === SyntaxKind.TypeParameter + ? lastLocation === (location as FunctionLikeDeclaration).type + || lastLocation.kind === SyntaxKind.Parameter + || lastLocation.kind === SyntaxKind.JSDocParameterTag + || lastLocation.kind === SyntaxKind.JSDocReturnTag + || lastLocation.kind === SyntaxKind.TypeParameter // local types not visible outside the function body : false; } @@ -1927,10 +2281,10 @@ namespace ts { // technically for parameter list case here we might mix parameters and variables declared in function, // however it is detected separately when checking initializers of parameters // to make sure that they reference no variables declared after them. - useResult = lastLocation.kind === SyntaxKind.Parameter || - ( - lastLocation === (location as FunctionLikeDeclaration).type && - !!findAncestor(result.valueDeclaration, isParameter) + useResult = lastLocation.kind === SyntaxKind.Parameter + || ( + lastLocation === (location as FunctionLikeDeclaration).type + && !!findAncestor(result.valueDeclaration, isParameter) ); } } @@ -1956,8 +2310,13 @@ namespace ts { isInExternalModule = true; // falls through case SyntaxKind.ModuleDeclaration: - const moduleExports = getSymbolOfNode(location as SourceFile | ModuleDeclaration)?.exports || emptySymbols; - if (location.kind === SyntaxKind.SourceFile || (isModuleDeclaration(location) && location.flags & NodeFlags.Ambient && !isGlobalScopeAugmentation(location))) { + const moduleExports = getSymbolOfNode(location as SourceFile | ModuleDeclaration)?.exports + || emptySymbols; + if ( + location.kind === SyntaxKind.SourceFile + || (isModuleDeclaration(location) && location.flags & NodeFlags.Ambient + && !isGlobalScopeAugmentation(location)) + ) { // It's an external module. First see if the module has an export default and if the local // name of that export default matches. if (result = moduleExports.get(InternalSymbolName.Default)) { @@ -1981,17 +2340,24 @@ namespace ts { // which is not the desired behavior. const moduleExport = moduleExports.get(name); if ( - moduleExport && - moduleExport.flags === SymbolFlags.Alias && - (getDeclarationOfKind(moduleExport, SyntaxKind.ExportSpecifier) || getDeclarationOfKind(moduleExport, SyntaxKind.NamespaceExport)) + moduleExport + && moduleExport.flags === SymbolFlags.Alias + && (getDeclarationOfKind(moduleExport, SyntaxKind.ExportSpecifier) + || getDeclarationOfKind(moduleExport, SyntaxKind.NamespaceExport)) ) { break; } } // ES6 exports are also visible locally (except for 'default'), but commonjs exports are not (except typedefs) - if (name !== InternalSymbolName.Default && (result = lookup(moduleExports, name, meaning & SymbolFlags.ModuleMember))) { - if (isSourceFile(location) && location.commonJsModuleIndicator && !result.declarations?.some(isJSDocTypeAlias)) { + if ( + name !== InternalSymbolName.Default + && (result = lookup(moduleExports, name, meaning & SymbolFlags.ModuleMember)) + ) { + if ( + isSourceFile(location) && location.commonJsModuleIndicator + && !result.declarations?.some(isJSDocTypeAlias) + ) { result = undefined; } else { @@ -2000,7 +2366,13 @@ namespace ts { } break; case SyntaxKind.EnumDeclaration: - if (result = lookup(getSymbolOfNode(location)?.exports || emptySymbols, name, meaning & SymbolFlags.EnumMember)) { + if ( + result = lookup( + getSymbolOfNode(location)?.exports || emptySymbols, + name, + meaning & SymbolFlags.EnumMember, + ) + ) { break loop; } break; @@ -2028,7 +2400,14 @@ namespace ts { // The below is used to lookup type parameters within a class or interface, as they are added to the class/interface locals // These can never be latebound, so the symbol's raw members are sufficient. `getMembersOfNode` cannot be used, as it would // trigger resolving late-bound names, which we may already be in the process of doing while we're here! - if (result = lookup(getSymbolOfNode(location as ClassLikeDeclaration | InterfaceDeclaration).members || emptySymbols, name, meaning & SymbolFlags.Type)) { + if ( + result = lookup( + getSymbolOfNode(location as ClassLikeDeclaration | InterfaceDeclaration).members + || emptySymbols, + name, + meaning & SymbolFlags.Type, + ) + ) { if (!isTypeParameterSymbolDeclaredInContainer(result, location)) { // ignore type parameters not declared in this container result = undefined; @@ -2039,7 +2418,10 @@ namespace ts { // The scope of a type parameter extends over the entire declaration with which the type // parameter list is associated, with the exception of static member declarations in classes. if (nameNotFoundMessage) { - error(errorLocation, Diagnostics.Static_members_cannot_reference_class_type_parameters); + error( + errorLocation, + Diagnostics.Static_members_cannot_reference_class_type_parameters, + ); } return undefined; } @@ -2055,11 +2437,24 @@ namespace ts { break; case SyntaxKind.ExpressionWithTypeArguments: // The type parameters of a class are not in scope in the base class expression. - if (lastLocation === (location as ExpressionWithTypeArguments).expression && (location.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword) { + if ( + lastLocation === (location as ExpressionWithTypeArguments).expression + && (location.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword + ) { const container = location.parent.parent; - if (isClassLike(container) && (result = lookup(getSymbolOfNode(container).members!, name, meaning & SymbolFlags.Type))) { + if ( + isClassLike(container) + && (result = lookup( + getSymbolOfNode(container).members!, + name, + meaning & SymbolFlags.Type, + )) + ) { if (nameNotFoundMessage) { - error(errorLocation, Diagnostics.Base_class_expressions_cannot_reference_class_type_parameters); + error( + errorLocation, + Diagnostics.Base_class_expressions_cannot_reference_class_type_parameters, + ); } return undefined; } @@ -2077,9 +2472,20 @@ namespace ts { grandparent = location.parent.parent; if (isClassLike(grandparent) || grandparent.kind === SyntaxKind.InterfaceDeclaration) { // A reference to this grandparent's type parameters would be an error - if (result = lookup(getSymbolOfNode(grandparent as ClassLikeDeclaration | InterfaceDeclaration).members!, name, meaning & SymbolFlags.Type)) { + if ( + result = lookup( + getSymbolOfNode(grandparent as ClassLikeDeclaration | InterfaceDeclaration) + .members!, + name, + meaning & SymbolFlags.Type, + ) + ) { if (nameNotFoundMessage) { - error(errorLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type); + error( + errorLocation, + Diagnostics + .A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type, + ); } return undefined; } @@ -2141,7 +2547,10 @@ namespace ts { // declare function y(x: T): any; // @param(1 as T) // <-- T should resolve to the type alias outside of class C // class C {} - if (location.parent && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration)) { + if ( + location.parent + && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration) + ) { location = location.parent; } break; @@ -2157,23 +2566,28 @@ namespace ts { case SyntaxKind.Parameter: if ( lastLocation && ( - lastLocation === (location as ParameterDeclaration).initializer || - lastLocation === (location as ParameterDeclaration).name && isBindingPattern(lastLocation) + lastLocation === (location as ParameterDeclaration).initializer + || lastLocation === (location as ParameterDeclaration).name + && isBindingPattern(lastLocation) ) ) { if (!associatedDeclarationForContainingInitializerOrBindingName) { - associatedDeclarationForContainingInitializerOrBindingName = location as ParameterDeclaration; + associatedDeclarationForContainingInitializerOrBindingName = + location as ParameterDeclaration; } } break; case SyntaxKind.BindingElement: if ( lastLocation && ( - lastLocation === (location as BindingElement).initializer || - lastLocation === (location as BindingElement).name && isBindingPattern(lastLocation) + lastLocation === (location as BindingElement).initializer + || lastLocation === (location as BindingElement).name && isBindingPattern(lastLocation) ) ) { - if (isParameterDeclaration(location as BindingElement) && !associatedDeclarationForContainingInitializerOrBindingName) { + if ( + isParameterDeclaration(location as BindingElement) + && !associatedDeclarationForContainingInitializerOrBindingName + ) { associatedDeclarationForContainingInitializerOrBindingName = location as BindingElement; } } @@ -2192,9 +2606,11 @@ namespace ts { lastSelfReferenceLocation = location; } lastLocation = location; - location = isJSDocTemplateTag(location) ? getEffectiveContainerForJSDocTemplateTag(location) || location.parent : - isJSDocParameterTag(location) || isJSDocReturnTag(location) ? getHostSignatureFromJSDoc(location) || location.parent : - location.parent; + location = isJSDocTemplateTag(location) + ? getEffectiveContainerForJSDocTemplateTag(location) || location.parent + : isJSDocParameterTag(location) || isJSDocReturnTag(location) + ? getHostSignatureFromJSDoc(location) || location.parent + : location.parent; } // We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`. @@ -2207,7 +2623,10 @@ namespace ts { if (!result) { if (lastLocation) { Debug.assert(lastLocation.kind === SyntaxKind.SourceFile); - if ((lastLocation as SourceFile).commonJsModuleIndicator && name === "exports" && meaning & lastLocation.symbol.flags) { + if ( + (lastLocation as SourceFile).commonJsModuleIndicator && name === "exports" + && meaning & lastLocation.symbol.flags + ) { return lastLocation.symbol; } } @@ -2228,15 +2647,24 @@ namespace ts { // 1. When result is undefined, after checking for a missing "this." // 2. When result is defined function checkAndReportErrorForInvalidInitializer() { - if (propertyWithInvalidInitializer && !(useDefineForClassFields && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022)) { + if ( + propertyWithInvalidInitializer + && !(useDefineForClassFields && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022) + ) { // We have a match, but the reference occurred within a property initializer and the identifier also binds // to a local variable in the constructor where the code will be emitted. Note that this is actually allowed // with ESNext+useDefineForClassFields because the scope semantics are different. error( errorLocation, - errorLocation && propertyWithInvalidInitializer.type && textRangeContainsPositionInclusive(propertyWithInvalidInitializer.type, errorLocation.pos) - ? Diagnostics.Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor - : Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, + errorLocation && propertyWithInvalidInitializer.type + && textRangeContainsPositionInclusive( + propertyWithInvalidInitializer.type, + errorLocation.pos, + ) + ? Diagnostics + .Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor + : Diagnostics + .Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, declarationNameToString(propertyWithInvalidInitializer.name), diagnosticName(nameArg!), ); @@ -2249,15 +2677,15 @@ namespace ts { if (nameNotFoundMessage) { addLazyDiagnostic(() => { if ( - !errorLocation || - !checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg!) && // TODO: GH#18217 - !checkAndReportErrorForInvalidInitializer() && - !checkAndReportErrorForExtendingInterface(errorLocation) && - !checkAndReportErrorForUsingTypeAsNamespace(errorLocation, name, meaning) && - !checkAndReportErrorForExportingPrimitiveType(errorLocation, name) && - !checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation, name, meaning) && - !checkAndReportErrorForUsingTypeAsValue(errorLocation, name, meaning) && - !checkAndReportErrorForUsingValueAsType(errorLocation, name, meaning) + !errorLocation + || !checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg!) // TODO: GH#18217 + && !checkAndReportErrorForInvalidInitializer() + && !checkAndReportErrorForExtendingInterface(errorLocation) + && !checkAndReportErrorForUsingTypeAsNamespace(errorLocation, name, meaning) + && !checkAndReportErrorForExportingPrimitiveType(errorLocation, name) + && !checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation, name, meaning) + && !checkAndReportErrorForUsingTypeAsValue(errorLocation, name, meaning) + && !checkAndReportErrorForUsingValueAsType(errorLocation, name, meaning) ) { let suggestion: Symbol | undefined; let suggestedLib: string | undefined; @@ -2271,22 +2699,39 @@ namespace ts { // then spelling suggestions if (!suggestedLib && getSpellingSuggestions && suggestionCount < maximumSuggestionCount) { suggestion = getSuggestedSymbolForNonexistentSymbol(originalLocation, name, meaning); - const isGlobalScopeAugmentationDeclaration = suggestion?.valueDeclaration && isAmbientModule(suggestion.valueDeclaration) && isGlobalScopeAugmentation(suggestion.valueDeclaration); + const isGlobalScopeAugmentationDeclaration = suggestion?.valueDeclaration + && isAmbientModule(suggestion.valueDeclaration) + && isGlobalScopeAugmentation(suggestion.valueDeclaration); if (isGlobalScopeAugmentationDeclaration) { suggestion = undefined; } if (suggestion) { const suggestionName = symbolToString(suggestion); - const isUncheckedJS = isUncheckedJSSuggestion(originalLocation, suggestion, /*excludeClasses*/ false); - const message = meaning === SymbolFlags.Namespace || nameArg && typeof nameArg !== "string" && nodeIsSynthesized(nameArg) ? Diagnostics.Cannot_find_namespace_0_Did_you_mean_1 + const isUncheckedJS = isUncheckedJSSuggestion( + originalLocation, + suggestion, + /*excludeClasses*/ false, + ); + const message = meaning === SymbolFlags.Namespace + || nameArg && typeof nameArg !== "string" && nodeIsSynthesized(nameArg) + ? Diagnostics.Cannot_find_namespace_0_Did_you_mean_1 : isUncheckedJS ? Diagnostics.Could_not_find_name_0_Did_you_mean_1 : Diagnostics.Cannot_find_name_0_Did_you_mean_1; - const diagnostic = createError(errorLocation, message, diagnosticName(nameArg!), suggestionName); + const diagnostic = createError( + errorLocation, + message, + diagnosticName(nameArg!), + suggestionName, + ); addErrorOrSuggestion(!isUncheckedJS, diagnostic); if (suggestion.valueDeclaration) { addRelatedInfo( diagnostic, - createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName), + createDiagnosticForNode( + suggestion.valueDeclaration, + Diagnostics._0_is_declared_here, + suggestionName, + ), ); } } @@ -2320,38 +2765,85 @@ namespace ts { // try to resolve name in /*1*/ which is used in variable position, // we want to check for block-scoped if ( - errorLocation && - (meaning & SymbolFlags.BlockScopedVariable || - ((meaning & SymbolFlags.Class || meaning & SymbolFlags.Enum) && (meaning & SymbolFlags.Value) === SymbolFlags.Value)) + errorLocation + && (meaning & SymbolFlags.BlockScopedVariable + || ((meaning & SymbolFlags.Class || meaning & SymbolFlags.Enum) + && (meaning & SymbolFlags.Value) === SymbolFlags.Value)) ) { const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result!); - if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable || exportOrLocalSymbol.flags & SymbolFlags.Class || exportOrLocalSymbol.flags & SymbolFlags.Enum) { + if ( + exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable + || exportOrLocalSymbol.flags & SymbolFlags.Class + || exportOrLocalSymbol.flags & SymbolFlags.Enum + ) { checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation); } } // If we're in an external module, we can't reference value symbols created from UMD export declarations - if (result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value && !(originalLocation!.flags & NodeFlags.JSDoc)) { + if ( + result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value + && !(originalLocation!.flags & NodeFlags.JSDoc) + ) { const merged = getMergedSymbol(result); - if (length(merged.declarations) && every(merged.declarations, d => isNamespaceExportDeclaration(d) || isSourceFile(d) && !!d.symbol.globalExports)) { - errorOrSuggestion(!compilerOptions.allowUmdGlobalAccess, errorLocation!, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, unescapeLeadingUnderscores(name)); + if ( + length(merged.declarations) + && every( + merged.declarations, + d => isNamespaceExportDeclaration(d) || isSourceFile(d) && !!d.symbol.globalExports, + ) + ) { + errorOrSuggestion( + !compilerOptions.allowUmdGlobalAccess, + errorLocation!, + Diagnostics + ._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, + unescapeLeadingUnderscores(name), + ); } } // If we're in a parameter initializer or binding name, we can't reference the values of the parameter whose initializer we're within or parameters to the right - if (result && associatedDeclarationForContainingInitializerOrBindingName && !withinDeferredContext && (meaning & SymbolFlags.Value) === SymbolFlags.Value) { + if ( + result && associatedDeclarationForContainingInitializerOrBindingName && !withinDeferredContext + && (meaning & SymbolFlags.Value) === SymbolFlags.Value + ) { const candidate = getMergedSymbol(getLateBoundSymbol(result)); - const root = (getRootDeclaration(associatedDeclarationForContainingInitializerOrBindingName) as ParameterDeclaration); + const root = (getRootDeclaration( + associatedDeclarationForContainingInitializerOrBindingName, + ) as ParameterDeclaration); // A parameter initializer or binding pattern initializer within a parameter cannot refer to itself if (candidate === getSymbolOfNode(associatedDeclarationForContainingInitializerOrBindingName)) { - error(errorLocation, Diagnostics.Parameter_0_cannot_reference_itself, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name)); + error( + errorLocation, + Diagnostics.Parameter_0_cannot_reference_itself, + declarationNameToString( + associatedDeclarationForContainingInitializerOrBindingName.name, + ), + ); } // And it cannot refer to any declarations which come after it - else if (candidate.valueDeclaration && candidate.valueDeclaration.pos > associatedDeclarationForContainingInitializerOrBindingName.pos && root.parent.locals && lookup(root.parent.locals, candidate.escapedName, meaning) === candidate) { - error(errorLocation, Diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name), declarationNameToString(errorLocation as Identifier)); + else if ( + candidate.valueDeclaration + && candidate.valueDeclaration.pos + > associatedDeclarationForContainingInitializerOrBindingName.pos + && root.parent.locals + && lookup(root.parent.locals, candidate.escapedName, meaning) === candidate + ) { + error( + errorLocation, + Diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, + declarationNameToString( + associatedDeclarationForContainingInitializerOrBindingName.name, + ), + declarationNameToString(errorLocation as Identifier), + ); } } - if (result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation)) { + if ( + result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias + && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation) + ) { const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(result, SymbolFlags.Value); if (typeOnlyDeclaration) { const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier @@ -2370,13 +2862,18 @@ namespace ts { return result; } - function addTypeOnlyDeclarationRelatedInfo(diagnostic: Diagnostic, typeOnlyDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, unescapedName: string) { + function addTypeOnlyDeclarationRelatedInfo( + diagnostic: Diagnostic, + typeOnlyDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, + unescapedName: string, + ) { if (!typeOnlyDeclaration) return diagnostic; return addRelatedInfo( diagnostic, createDiagnosticForNode( typeOnlyDeclaration, - typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier ? Diagnostics._0_was_exported_here : Diagnostics._0_was_imported_here, + typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier ? Diagnostics._0_was_exported_here + : Diagnostics._0_was_imported_here, unescapedName, ), ); @@ -2386,15 +2883,18 @@ namespace ts { if (location.kind !== SyntaxKind.ArrowFunction && location.kind !== SyntaxKind.FunctionExpression) { // initializers in instance property declaration of class like entities are executed in constructor and thus deferred return isTypeQueryNode(location) || (( - isFunctionLikeDeclaration(location) || - (location.kind === SyntaxKind.PropertyDeclaration && !isStatic(location)) + isFunctionLikeDeclaration(location) + || (location.kind === SyntaxKind.PropertyDeclaration && !isStatic(location)) ) && (!lastLocation || lastLocation !== (location as SignatureDeclaration | PropertyDeclaration).name)); // A name is evaluated within the enclosing scope - so it shouldn't count as deferred } if (lastLocation && lastLocation === (location as FunctionExpression | ArrowFunction).name) { return false; } // generator functions and async functions are not inlined in control flow when immediately invoked - if ((location as FunctionExpression | ArrowFunction).asteriskToken || hasSyntacticModifier(location, ModifierFlags.Async)) { + if ( + (location as FunctionExpression | ArrowFunction).asteriskToken + || hasSyntacticModifier(location, ModifierFlags.Async) + ) { return true; } return !getImmediatelyInvokedFunctionExpression(location); @@ -2415,7 +2915,8 @@ namespace ts { } function diagnosticName(nameArg: __String | Identifier | PrivateIdentifier) { - return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier); + return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) + : declarationNameToString(nameArg as Identifier); } function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) { @@ -2424,7 +2925,8 @@ namespace ts { if (decl.kind === SyntaxKind.TypeParameter) { const parent = isJSDocTemplateTag(decl.parent) ? getJSDocHost(decl.parent) : decl.parent; if (parent === container) { - return !(isJSDocTemplateTag(decl.parent) && find((decl.parent.parent as JSDoc).tags, isJSDocTypeAlias)); + return !(isJSDocTemplateTag(decl.parent) + && find((decl.parent.parent as JSDoc).tags, isJSDocTypeAlias)); } } } @@ -2433,8 +2935,15 @@ namespace ts { return false; } - function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: __String, nameArg: __String | Identifier): boolean { - if (!isIdentifier(errorLocation) || errorLocation.escapedText !== name || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation)) { + function checkAndReportErrorForMissingPrefix( + errorLocation: Node, + name: __String, + nameArg: __String | Identifier, + ): boolean { + if ( + !isIdentifier(errorLocation) || errorLocation.escapedText !== name + || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation) + ) { return false; } @@ -2450,7 +2959,12 @@ namespace ts { // Check to see if a static member exists. const constructorType = getTypeOfSymbol(classSymbol); if (getPropertyOfType(constructorType, name)) { - error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, diagnosticName(nameArg), symbolToString(classSymbol)); + error( + errorLocation, + Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, + diagnosticName(nameArg), + symbolToString(classSymbol), + ); return true; } @@ -2459,7 +2973,11 @@ namespace ts { if (location === container && !isStatic(location)) { const instanceType = (getDeclaredTypeOfSymbol(classSymbol) as InterfaceType).thisType!; // TODO: GH#18217 if (getPropertyOfType(instanceType, name)) { - error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, diagnosticName(nameArg)); + error( + errorLocation, + Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, + diagnosticName(nameArg), + ); return true; } } @@ -2473,7 +2991,11 @@ namespace ts { function checkAndReportErrorForExtendingInterface(errorLocation: Node): boolean { const expression = getEntityNameForExtendingInterface(errorLocation); if (expression && resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)) { - error(errorLocation, Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, getTextOfNode(expression)); + error( + errorLocation, + Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, + getTextOfNode(expression), + ); return true; } return false; @@ -2497,27 +3019,48 @@ namespace ts { } } - function checkAndReportErrorForUsingTypeAsNamespace(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingTypeAsNamespace( + errorLocation: Node, + name: __String, + meaning: SymbolFlags, + ): boolean { const namespaceMeaning = SymbolFlags.Namespace | (isInJSFile(errorLocation) ? SymbolFlags.Value : 0); if (meaning === namespaceMeaning) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~namespaceMeaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.Type & ~namespaceMeaning, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); const parent = errorLocation.parent; if (symbol) { if (isQualifiedName(parent)) { - Debug.assert(parent.left === errorLocation, "Should only be resolving left side of qualified name as a namespace"); + Debug.assert( + parent.left === errorLocation, + "Should only be resolving left side of qualified name as a namespace", + ); const propName = parent.right.escapedText; const propType = getPropertyOfType(getDeclaredTypeOfSymbol(symbol), propName); if (propType) { error( parent, - Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, + Diagnostics + .Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, unescapeLeadingUnderscores(name), unescapeLeadingUnderscores(propName), ); return true; } } - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_namespace_here, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_namespace_here, + unescapeLeadingUnderscores(name), + ); return true; } } @@ -2525,11 +3068,28 @@ namespace ts { return false; } - function checkAndReportErrorForUsingValueAsType(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingValueAsType( + errorLocation: Node, + name: __String, + meaning: SymbolFlags, + ): boolean { if (meaning & (SymbolFlags.Type & ~SymbolFlags.Namespace)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, ~SymbolFlags.Type & SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + ~SymbolFlags.Type & SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); if (symbol && !(symbol.flags & SymbolFlags.Namespace)) { - error(errorLocation, Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, + unescapeLeadingUnderscores(name), + ); return true; } } @@ -2537,40 +3097,82 @@ namespace ts { } function isPrimitiveTypeName(name: __String) { - return name === "any" || name === "string" || name === "number" || name === "boolean" || name === "never" || name === "unknown"; + return name === "any" || name === "string" || name === "number" || name === "boolean" || name === "never" + || name === "unknown"; } function checkAndReportErrorForExportingPrimitiveType(errorLocation: Node, name: __String): boolean { if (isPrimitiveTypeName(name) && errorLocation.parent.kind === SyntaxKind.ExportSpecifier) { - error(errorLocation, Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, name as string); + error( + errorLocation, + Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, + name as string, + ); return true; } return false; } - function checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingTypeAsValue( + errorLocation: Node, + name: __String, + meaning: SymbolFlags, + ): boolean { if (meaning & SymbolFlags.Value) { if (isPrimitiveTypeName(name)) { if (isExtendedByInterface(errorLocation)) { - error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_an_interface_can_only_extend_named_types_and_classes, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics + .An_interface_cannot_extend_a_primitive_type_like_0_an_interface_can_only_extend_named_types_and_classes, + unescapeLeadingUnderscores(name), + ); } else { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, + unescapeLeadingUnderscores(name), + ); } return true; } - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.Type & ~SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); const allFlags = symbol && getAllSymbolFlags(symbol); if (symbol && allFlags !== undefined && !(allFlags & SymbolFlags.Value)) { const rawName = unescapeLeadingUnderscores(name); if (isES2015OrLaterConstructorName(name)) { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_es2015_or_later, rawName); + error( + errorLocation, + Diagnostics + ._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_es2015_or_later, + rawName, + ); } else if (maybeMappedType(errorLocation, symbol)) { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0, rawName, rawName === "K" ? "P" : "K"); + error( + errorLocation, + Diagnostics + ._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0, + rawName, + rawName === "K" ? "P" : "K", + ); } else { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, rawName); + error( + errorLocation, + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, + rawName, + ); } return true; } @@ -2590,10 +3192,14 @@ namespace ts { } function maybeMappedType(node: Node, symbol: Symbol) { - const container = findAncestor(node.parent, n => isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit") as TypeLiteralNode | undefined; + const container = findAncestor( + node.parent, + n => isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit", + ) as TypeLiteralNode | undefined; if (container && container.members.length === 1) { const type = getDeclaredTypeOfSymbol(symbol); - return !!(type.flags & TypeFlags.Union) && allTypesAssignableToKind(type, TypeFlags.StringOrNumberLiteral, /*strict*/ true); + return !!(type.flags & TypeFlags.Union) + && allTypesAssignableToKind(type, TypeFlags.StringOrNumberLiteral, /*strict*/ true); } return false; } @@ -2611,9 +3217,22 @@ namespace ts { return false; } - function checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingNamespaceAsTypeOrValue( + errorLocation: Node, + name: __String, + meaning: SymbolFlags, + ): boolean { if (meaning & (SymbolFlags.Value & ~SymbolFlags.Type)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.NamespaceModule, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.NamespaceModule, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); if (symbol) { error( errorLocation, @@ -2624,9 +3243,22 @@ namespace ts { } } else if (meaning & (SymbolFlags.Type & ~SymbolFlags.Value)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Module, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.Module, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); if (symbol) { - error(errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_type, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics.Cannot_use_namespace_0_as_a_type, + unescapeLeadingUnderscores(name), + ); return true; } } @@ -2634,8 +3266,14 @@ namespace ts { } function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void { - Debug.assert(!!(result.flags & SymbolFlags.BlockScopedVariable || result.flags & SymbolFlags.Class || result.flags & SymbolFlags.Enum)); - if (result.flags & (SymbolFlags.Function | SymbolFlags.FunctionScopedVariable | SymbolFlags.Assignment) && result.flags & SymbolFlags.Class) { + Debug.assert( + !!(result.flags & SymbolFlags.BlockScopedVariable || result.flags & SymbolFlags.Class + || result.flags & SymbolFlags.Enum), + ); + if ( + result.flags & (SymbolFlags.Function | SymbolFlags.FunctionScopedVariable | SymbolFlags.Assignment) + && result.flags & SymbolFlags.Class + ) { // constructor functions aren't block scoped return; } @@ -2644,29 +3282,53 @@ namespace ts { d => isBlockOrCatchScoped(d) || isClassLike(d) || (d.kind === SyntaxKind.EnumDeclaration), ); - if (declaration === undefined) return Debug.fail("checkResolvedBlockScopedVariable could not find block-scoped declaration"); + if (declaration === undefined) { + return Debug.fail("checkResolvedBlockScopedVariable could not find block-scoped declaration"); + } - if (!(declaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) { + if ( + !(declaration.flags & NodeFlags.Ambient) + && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation) + ) { let diagnosticMessage; const declarationName = declarationNameToString(getNameOfDeclaration(declaration)); if (result.flags & SymbolFlags.BlockScopedVariable) { - diagnosticMessage = error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationName); + diagnosticMessage = error( + errorLocation, + Diagnostics.Block_scoped_variable_0_used_before_its_declaration, + declarationName, + ); } else if (result.flags & SymbolFlags.Class) { - diagnosticMessage = error(errorLocation, Diagnostics.Class_0_used_before_its_declaration, declarationName); + diagnosticMessage = error( + errorLocation, + Diagnostics.Class_0_used_before_its_declaration, + declarationName, + ); } else if (result.flags & SymbolFlags.RegularEnum) { - diagnosticMessage = error(errorLocation, Diagnostics.Enum_0_used_before_its_declaration, declarationName); + diagnosticMessage = error( + errorLocation, + Diagnostics.Enum_0_used_before_its_declaration, + declarationName, + ); } else { Debug.assert(!!(result.flags & SymbolFlags.ConstEnum)); if (shouldPreserveConstEnums(compilerOptions)) { - diagnosticMessage = error(errorLocation, Diagnostics.Enum_0_used_before_its_declaration, declarationName); + diagnosticMessage = error( + errorLocation, + Diagnostics.Enum_0_used_before_its_declaration, + declarationName, + ); } } if (diagnosticMessage) { - addRelatedInfo(diagnosticMessage, createDiagnosticForNode(declaration, Diagnostics._0_is_declared_here, declarationName)); + addRelatedInfo( + diagnosticMessage, + createDiagnosticForNode(declaration, Diagnostics._0_is_declared_here, declarationName), + ); } } } @@ -2725,28 +3387,42 @@ namespace ts { || node.kind === SyntaxKind.ImportSpecifier || node.kind === SyntaxKind.ExportSpecifier || node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node as ExportAssignment) - || isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) + || isBinaryExpression(node) + && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports + && exportAssignmentIsAlias(node) || isAccessExpression(node) && isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAliasableOrJsExpression(node.parent.right) || node.kind === SyntaxKind.ShorthandPropertyAssignment - || node.kind === SyntaxKind.PropertyAssignment && isAliasableOrJsExpression((node as PropertyAssignment).initializer) - || node.kind === SyntaxKind.VariableDeclaration && isVariableDeclarationInitializedToBareOrAccessedRequire(node) - || node.kind === SyntaxKind.BindingElement && isVariableDeclarationInitializedToBareOrAccessedRequire(node.parent.parent); + || node.kind === SyntaxKind.PropertyAssignment + && isAliasableOrJsExpression((node as PropertyAssignment).initializer) + || node.kind === SyntaxKind.VariableDeclaration + && isVariableDeclarationInitializedToBareOrAccessedRequire(node) + || node.kind === SyntaxKind.BindingElement + && isVariableDeclarationInitializedToBareOrAccessedRequire(node.parent.parent); } function isAliasableOrJsExpression(e: Expression) { return isAliasableExpression(e) || isFunctionExpression(e) && isJSConstructor(e); } - function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration | VariableDeclaration, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfImportEqualsDeclaration( + node: ImportEqualsDeclaration | VariableDeclaration, + dontResolveAlias: boolean, + ): Symbol | undefined { const commonJSPropertyAccess = getCommonJSPropertyAccess(node); if (commonJSPropertyAccess) { - const name = (getLeftmostAccessExpression(commonJSPropertyAccess.expression) as CallExpression).arguments[0] as StringLiteral; + const name = (getLeftmostAccessExpression(commonJSPropertyAccess.expression) as CallExpression) + .arguments[0] as StringLiteral; return isIdentifier(commonJSPropertyAccess.name) - ? resolveSymbol(getPropertyOfType(resolveExternalModuleTypeByLiteral(name), commonJSPropertyAccess.name.escapedText)) + ? resolveSymbol( + getPropertyOfType( + resolveExternalModuleTypeByLiteral(name), + commonJSPropertyAccess.name.escapedText, + ), + ) : undefined; } if (isVariableDeclaration(node) || node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { @@ -2763,8 +3439,18 @@ namespace ts { return resolved; } - function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node: ImportEqualsDeclaration, resolved: Symbol | undefined) { - if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false) && !node.isTypeOnly) { + function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol( + node: ImportEqualsDeclaration, + resolved: Symbol | undefined, + ) { + if ( + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false, + ) && !node.isTypeOnly + ) { const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(getSymbolOfNode(node))!; const isExport = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier; const message = isExport @@ -2775,27 +3461,40 @@ namespace ts { : Diagnostics._0_was_imported_here; const name = unescapeLeadingUnderscores(typeOnlyDeclaration.name.escapedText); - addRelatedInfo(error(node.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name)); + addRelatedInfo( + error(node.moduleReference, message), + createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name), + ); } } - function resolveExportByName(moduleSymbol: Symbol, name: __String, sourceNode: TypeOnlyCompatibleAliasDeclaration | undefined, dontResolveAlias: boolean) { + function resolveExportByName( + moduleSymbol: Symbol, + name: __String, + sourceNode: TypeOnlyCompatibleAliasDeclaration | undefined, + dontResolveAlias: boolean, + ) { const exportValue = moduleSymbol.exports!.get(InternalSymbolName.ExportEquals); - const exportSymbol = exportValue ? getPropertyOfType(getTypeOfSymbol(exportValue), name) : moduleSymbol.exports!.get(name); + const exportSymbol = exportValue ? getPropertyOfType(getTypeOfSymbol(exportValue), name) + : moduleSymbol.exports!.get(name); const resolved = resolveSymbol(exportSymbol, dontResolveAlias); markSymbolOfAliasDeclarationIfTypeOnly(sourceNode, exportSymbol, resolved, /*overwriteEmpty*/ false); return resolved; } function isSyntacticDefault(node: Node) { - return ((isExportAssignment(node) && !node.isExportEquals) || hasSyntacticModifier(node, ModifierFlags.Default) || isExportSpecifier(node)); + return ((isExportAssignment(node) && !node.isExportEquals) + || hasSyntacticModifier(node, ModifierFlags.Default) || isExportSpecifier(node)); } function getUsageModeForExpression(usage: Expression) { return isStringLiteralLike(usage) ? getModeForUsageLocation(getSourceFileOfNode(usage), usage) : undefined; } - function isESMFormatImportImportingCommonjsFormatFile(usageMode: SourceFile["impliedNodeFormat"], targetMode: SourceFile["impliedNodeFormat"]) { + function isESMFormatImportImportingCommonjsFormatFile( + usageMode: SourceFile["impliedNodeFormat"], + targetMode: SourceFile["impliedNodeFormat"], + ) { return usageMode === ModuleKind.ESNext && targetMode === ModuleKind.CommonJS; } @@ -2804,7 +3503,12 @@ namespace ts { return usageMode === ModuleKind.ESNext && endsWith((usage as StringLiteralLike).text, Extension.Json); } - function canHaveSyntheticDefault(file: SourceFile | undefined, moduleSymbol: Symbol, dontResolveAlias: boolean, usage: Expression) { + function canHaveSyntheticDefault( + file: SourceFile | undefined, + moduleSymbol: Symbol, + dontResolveAlias: boolean, + usage: Expression, + ) { const usageMode = file && getUsageModeForExpression(usage); if (file && usageMode !== undefined) { const result = isESMFormatImportImportingCommonjsFormatFile(usageMode, file.impliedNodeFormat); @@ -2819,13 +3523,25 @@ namespace ts { // Declaration files (and ambient modules) if (!file || file.isDeclarationFile) { // Definitely cannot have a synthetic default if they have a syntactic default member specified - const defaultExportSymbol = resolveExportByName(moduleSymbol, InternalSymbolName.Default, /*sourceNode*/ undefined, /*dontResolveAlias*/ true); // Dont resolve alias because we want the immediately exported symbol's declaration + const defaultExportSymbol = resolveExportByName( + moduleSymbol, + InternalSymbolName.Default, + /*sourceNode*/ undefined, + /*dontResolveAlias*/ true, + ); // Dont resolve alias because we want the immediately exported symbol's declaration if (defaultExportSymbol && some(defaultExportSymbol.declarations, isSyntacticDefault)) { return false; } // It _might_ still be incorrect to assume there is no __esModule marker on the import at runtime, even if there is no `default` member // So we check a bit more, - if (resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias)) { + if ( + resolveExportByName( + moduleSymbol, + escapeLeadingUnderscores("__esModule"), + /*sourceNode*/ undefined, + dontResolveAlias, + ) + ) { // If there is an `__esModule` specified in the declaration (meaning someone explicitly added it or wrote it in their code), // it definitely is a module and does not have a synthetic default return false; @@ -2840,7 +3556,13 @@ namespace ts { return hasExportAssignmentSymbol(moduleSymbol); } // JS files have a synthetic default if they do not contain ES2015+ module syntax (export = is not valid in js) _and_ do not have an __esModule marker - return typeof file.externalModuleIndicator !== "object" && !resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias); + return typeof file.externalModuleIndicator !== "object" + && !resolveExportByName( + moduleSymbol, + escapeLeadingUnderscores("__esModule"), + /*sourceNode*/ undefined, + dontResolveAlias, + ); } function getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol | undefined { @@ -2850,13 +3572,22 @@ namespace ts { } } - function getTargetofModuleDefault(moduleSymbol: Symbol, node: ImportClause | ImportOrExportSpecifier, dontResolveAlias: boolean) { + function getTargetofModuleDefault( + moduleSymbol: Symbol, + node: ImportClause | ImportOrExportSpecifier, + dontResolveAlias: boolean, + ) { let exportDefaultSymbol: Symbol | undefined; if (isShorthandAmbientModuleSymbol(moduleSymbol)) { exportDefaultSymbol = moduleSymbol; } else { - exportDefaultSymbol = resolveExportByName(moduleSymbol, InternalSymbolName.Default, node, dontResolveAlias); + exportDefaultSymbol = resolveExportByName( + moduleSymbol, + InternalSymbolName.Default, + node, + dontResolveAlias, + ); } const file = moduleSymbol.declarations?.find(isSourceFile); @@ -2868,17 +3599,24 @@ namespace ts { const hasSyntheticDefault = canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, specifier); if (!exportDefaultSymbol && !hasSyntheticDefault && !hasDefaultOnly) { if (hasExportAssignmentSymbol(moduleSymbol)) { - const compilerOptionName = moduleKind >= ModuleKind.ES2015 ? "allowSyntheticDefaultImports" : "esModuleInterop"; + const compilerOptionName = moduleKind >= ModuleKind.ES2015 ? "allowSyntheticDefaultImports" + : "esModuleInterop"; const exportEqualsSymbol = moduleSymbol.exports!.get(InternalSymbolName.ExportEquals); const exportAssignment = exportEqualsSymbol!.valueDeclaration; - const err = error(node.name, Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, symbolToString(moduleSymbol), compilerOptionName); + const err = error( + node.name, + Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, + symbolToString(moduleSymbol), + compilerOptionName, + ); if (exportAssignment) { addRelatedInfo( err, createDiagnosticForNode( exportAssignment, - Diagnostics.This_module_is_declared_with_export_and_can_only_be_used_with_a_default_import_when_using_the_0_flag, + Diagnostics + .This_module_is_declared_with_export_and_can_only_be_used_with_a_default_import_when_using_the_0_flag, compilerOptionName, ), ); @@ -2888,25 +3626,39 @@ namespace ts { reportNonDefaultExport(moduleSymbol, node); } else { - errorNoModuleMemberSymbol(moduleSymbol, moduleSymbol, node, isImportOrExportSpecifier(node) && node.propertyName || node.name); + errorNoModuleMemberSymbol( + moduleSymbol, + moduleSymbol, + node, + isImportOrExportSpecifier(node) && node.propertyName || node.name, + ); } } else if (hasSyntheticDefault || hasDefaultOnly) { // per emit behavior, a synthetic default overrides a "real" .default member if `__esModule` is not present - const resolved = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); + const resolved = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) + || resolveSymbol(moduleSymbol, dontResolveAlias); markSymbolOfAliasDeclarationIfTypeOnly(node, moduleSymbol, resolved, /*overwriteTypeOnly*/ false); return resolved; } - markSymbolOfAliasDeclarationIfTypeOnly(node, exportDefaultSymbol, /*finalTarget*/ undefined, /*overwriteTypeOnly*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + exportDefaultSymbol, + /*finalTarget*/ undefined, + /*overwriteTypeOnly*/ false, + ); return exportDefaultSymbol; } - function getModuleSpecifierForImportOrExport(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportOrExportSpecifier): Expression | undefined { + function getModuleSpecifierForImportOrExport( + node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportOrExportSpecifier, + ): Expression | undefined { switch (node.kind) { case SyntaxKind.ImportClause: return node.parent.moduleSpecifier; case SyntaxKind.ImportEqualsDeclaration: - return isExternalModuleReference(node.moduleReference) ? node.moduleReference.expression : undefined; + return isExternalModuleReference(node.moduleReference) ? node.moduleReference.expression + : undefined; case SyntaxKind.NamespaceImport: return node.parent.parent.moduleSpecifier; case SyntaxKind.ImportSpecifier: @@ -2928,17 +3680,29 @@ namespace ts { ); } else { - const diagnostic = error(node.name, Diagnostics.Module_0_has_no_default_export, symbolToString(moduleSymbol)); + const diagnostic = error( + node.name, + Diagnostics.Module_0_has_no_default_export, + symbolToString(moduleSymbol), + ); const exportStar = moduleSymbol.exports?.get(InternalSymbolName.ExportStar); if (exportStar) { const defaultExport = exportStar.declarations?.find(decl => !!( - isExportDeclaration(decl) && decl.moduleSpecifier && - resolveExternalModuleName(decl, decl.moduleSpecifier)?.exports?.has(InternalSymbolName.Default) + isExportDeclaration(decl) && decl.moduleSpecifier + && resolveExternalModuleName(decl, decl.moduleSpecifier)?.exports?.has( + InternalSymbolName.Default, + ) ) ); if (defaultExport) { - addRelatedInfo(diagnostic, createDiagnosticForNode(defaultExport, Diagnostics.export_Asterisk_does_not_re_export_a_default)); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + defaultExport, + Diagnostics.export_Asterisk_does_not_re_export_a_default, + ), + ); } } } @@ -2947,7 +3711,12 @@ namespace ts { function getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol | undefined { const moduleSpecifier = node.parent.parent.moduleSpecifier; const immediate = resolveExternalModuleName(node, moduleSpecifier); - const resolved = resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false); + const resolved = resolveESModuleSymbol( + immediate, + moduleSpecifier, + dontResolveAlias, + /*suppressUsageError*/ false, + ); markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); return resolved; } @@ -2955,7 +3724,8 @@ namespace ts { function getTargetOfNamespaceExport(node: NamespaceExport, dontResolveAlias: boolean): Symbol | undefined { const moduleSpecifier = node.parent.moduleSpecifier; const immediate = moduleSpecifier && resolveExternalModuleName(node, moduleSpecifier); - const resolved = moduleSpecifier && resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false); + const resolved = moduleSpecifier + && resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false); markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); return resolved; } @@ -2986,7 +3756,10 @@ namespace ts { return valueSymbol; } const result = createSymbol(valueSymbol.flags | typeSymbol.flags, valueSymbol.escapedName); - result.declarations = deduplicate(concatenate(valueSymbol.declarations, typeSymbol.declarations), equateValues); + result.declarations = deduplicate( + concatenate(valueSymbol.declarations, typeSymbol.declarations), + equateValues, + ); result.parent = valueSymbol.parent || typeSymbol.parent; if (valueSymbol.valueDeclaration) result.valueDeclaration = valueSymbol.valueDeclaration; if (typeSymbol.members) result.members = new Map(typeSymbol.members); @@ -2994,7 +3767,12 @@ namespace ts { return result; } - function getExportOfModule(symbol: Symbol, name: Identifier, specifier: Declaration, dontResolveAlias: boolean): Symbol | undefined { + function getExportOfModule( + symbol: Symbol, + name: Identifier, + specifier: Declaration, + dontResolveAlias: boolean, + ): Symbol | undefined { if (symbol.flags & SymbolFlags.Module) { const exportSymbol = getExportsOfSymbol(symbol).get(name.escapedText); const resolved = resolveSymbol(exportSymbol, dontResolveAlias); @@ -3012,15 +3790,26 @@ namespace ts { } } - function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration | VariableDeclaration, specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, dontResolveAlias = false): Symbol | undefined { - const moduleSpecifier = getExternalModuleRequireArgument(node) || (node as ImportDeclaration | ExportDeclaration).moduleSpecifier!; + function getExternalModuleMember( + node: ImportDeclaration | ExportDeclaration | VariableDeclaration, + specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, + dontResolveAlias = false, + ): Symbol | undefined { + const moduleSpecifier = getExternalModuleRequireArgument(node) + || (node as ImportDeclaration | ExportDeclaration).moduleSpecifier!; const moduleSymbol = resolveExternalModuleName(node, moduleSpecifier)!; // TODO: GH#18217 const name = !isPropertyAccessExpression(specifier) && specifier.propertyName || specifier.name; if (!isIdentifier(name)) { return undefined; } - const suppressInteropError = name.escapedText === InternalSymbolName.Default && !!(compilerOptions.allowSyntheticDefaultImports || getESModuleInterop(compilerOptions)); - const targetSymbol = resolveESModuleSymbol(moduleSymbol, moduleSpecifier, /*dontResolveAlias*/ false, suppressInteropError); + const suppressInteropError = name.escapedText === InternalSymbolName.Default + && !!(compilerOptions.allowSyntheticDefaultImports || getESModuleInterop(compilerOptions)); + const targetSymbol = resolveESModuleSymbol( + moduleSymbol, + moduleSpecifier, + /*dontResolveAlias*/ false, + suppressInteropError, + ); if (targetSymbol) { if (name.escapedText) { if (isShorthandAmbientModuleSymbol(moduleSymbol)) { @@ -3029,8 +3818,15 @@ namespace ts { let symbolFromVariable: Symbol | undefined; // First check if module was specified with "export=". If so, get the member from the resolved type - if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports.get(InternalSymbolName.ExportEquals)) { - symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.escapedText, /*skipObjectFunctionPropertyAugment*/ true); + if ( + moduleSymbol && moduleSymbol.exports + && moduleSymbol.exports.get(InternalSymbolName.ExportEquals) + ) { + symbolFromVariable = getPropertyOfType( + getTypeOfSymbol(targetSymbol), + name.escapedText, + /*skipObjectFunctionPropertyAugment*/ true, + ); } else { symbolFromVariable = getPropertyOfVariable(targetSymbol, name.escapedText); @@ -3041,14 +3837,18 @@ namespace ts { let symbolFromModule = getExportOfModule(targetSymbol, name, specifier, dontResolveAlias); if (symbolFromModule === undefined && name.escapedText === InternalSymbolName.Default) { const file = moduleSymbol.declarations?.find(isSourceFile); - if (isOnlyImportedAsDefault(moduleSpecifier) || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier)) { - symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); + if ( + isOnlyImportedAsDefault(moduleSpecifier) + || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier) + ) { + symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) + || resolveSymbol(moduleSymbol, dontResolveAlias); } } - const symbol = symbolFromModule && symbolFromVariable && symbolFromModule !== symbolFromVariable ? - combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) : - symbolFromModule || symbolFromVariable; + const symbol = symbolFromModule && symbolFromVariable && symbolFromModule !== symbolFromVariable + ? combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) + : symbolFromModule || symbolFromVariable; if (!symbol) { errorNoModuleMemberSymbol(moduleSymbol, targetSymbol, node, name); } @@ -3063,9 +3863,22 @@ namespace ts { const suggestion = getSuggestedSymbolForNonexistentModule(name, targetSymbol); if (suggestion !== undefined) { const suggestionName = symbolToString(suggestion); - const diagnostic = error(name, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, moduleName, declarationName, suggestionName); + const diagnostic = error( + name, + Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, + moduleName, + declarationName, + suggestionName, + ); if (suggestion.valueDeclaration) { - addRelatedInfo(diagnostic, createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName)); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + suggestion.valueDeclaration, + Diagnostics._0_is_declared_here, + suggestionName, + ), + ); } } else { @@ -3083,21 +3896,49 @@ namespace ts { } } - function reportNonExportedMember(node: Node, name: Identifier, declarationName: string, moduleSymbol: Symbol, moduleName: string): void { + function reportNonExportedMember( + node: Node, + name: Identifier, + declarationName: string, + moduleSymbol: Symbol, + moduleName: string, + ): void { const localSymbol = moduleSymbol.valueDeclaration?.locals?.get(name.escapedText); const exports = moduleSymbol.exports; if (localSymbol) { const exportedEqualsSymbol = exports?.get(InternalSymbolName.ExportEquals); if (exportedEqualsSymbol) { - getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) ? reportInvalidImportEqualsExportMember(node, name, declarationName, moduleName) : - error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); + getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) + ? reportInvalidImportEqualsExportMember(node, name, declarationName, moduleName) + : error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); } else { - const exportedSymbol = exports ? find(symbolsToArray(exports), symbol => !!getSymbolIfSameReference(symbol, localSymbol)) : undefined; - const diagnostic = exportedSymbol ? error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, symbolToString(exportedSymbol)) : - error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, moduleName, declarationName); + const exportedSymbol = exports ? find(symbolsToArray(exports), symbol => + !!getSymbolIfSameReference(symbol, localSymbol)) : undefined; + const diagnostic = exportedSymbol + ? error( + name, + Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, + moduleName, + declarationName, + symbolToString(exportedSymbol), + ) + : error( + name, + Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, + moduleName, + declarationName, + ); if (localSymbol.declarations) { - addRelatedInfo(diagnostic, ...map(localSymbol.declarations, (decl, index) => createDiagnosticForNode(decl, index === 0 ? Diagnostics._0_is_declared_here : Diagnostics.and_here, declarationName))); + addRelatedInfo( + diagnostic, + ...map(localSymbol.declarations, (decl, index) => + createDiagnosticForNode( + decl, + index === 0 ? Diagnostics._0_is_declared_here : Diagnostics.and_here, + declarationName, + )), + ); } } } @@ -3106,27 +3947,41 @@ namespace ts { } } - function reportInvalidImportEqualsExportMember(node: Node, name: Identifier, declarationName: string, moduleName: string) { + function reportInvalidImportEqualsExportMember( + node: Node, + name: Identifier, + declarationName: string, + moduleName: string, + ) { if (moduleKind >= ModuleKind.ES2015) { - const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_a_default_import : - Diagnostics._0_can_only_be_imported_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; + const message = getESModuleInterop(compilerOptions) + ? Diagnostics._0_can_only_be_imported_by_using_a_default_import + : Diagnostics + ._0_can_only_be_imported_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; error(name, message, declarationName); } else { if (isInJSFile(node)) { - const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_using_a_default_import : - Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; + const message = getESModuleInterop(compilerOptions) + ? Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_using_a_default_import + : Diagnostics + ._0_can_only_be_imported_by_using_a_require_call_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; error(name, message, declarationName); } else { - const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_a_default_import : - Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; + const message = getESModuleInterop(compilerOptions) + ? Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_a_default_import + : Diagnostics + ._0_can_only_be_imported_by_using_import_1_require_2_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; error(name, message, declarationName, declarationName, moduleName); } } } - function getTargetOfImportSpecifier(node: ImportSpecifier | BindingElement, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfImportSpecifier( + node: ImportSpecifier | BindingElement, + dontResolveAlias: boolean, + ): Symbol | undefined { if (isImportSpecifier(node) && idText(node.propertyName || node.name) === InternalSymbolName.Default) { const specifier = getModuleSpecifierForImportOrExport(node); const moduleSymbol = specifier && resolveExternalModuleName(node, specifier); @@ -3134,14 +3989,20 @@ namespace ts { return getTargetofModuleDefault(moduleSymbol, node, dontResolveAlias); } } - const root = isBindingElement(node) ? getRootDeclaration(node) as VariableDeclaration : node.parent.parent.parent; + const root = isBindingElement(node) ? getRootDeclaration(node) as VariableDeclaration + : node.parent.parent.parent; const commonJSPropertyAccess = getCommonJSPropertyAccess(root); const resolved = getExternalModuleMember(root, commonJSPropertyAccess || node, dontResolveAlias); const name = node.propertyName || node.name; if (commonJSPropertyAccess && resolved && isIdentifier(name)) { return resolveSymbol(getPropertyOfType(getTypeOfSymbol(resolved), name.escapedText), dontResolveAlias); } - markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false, + ); return resolved; } @@ -3151,9 +4012,17 @@ namespace ts { } } - function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol { + function getTargetOfNamespaceExportDeclaration( + node: NamespaceExportDeclaration, + dontResolveAlias: boolean, + ): Symbol { const resolved = resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false, + ); return resolved; } @@ -3165,17 +4034,30 @@ namespace ts { return getTargetofModuleDefault(moduleSymbol, node, !!dontResolveAlias); } } - const resolved = node.parent.parent.moduleSpecifier ? - getExternalModuleMember(node.parent.parent, node, dontResolveAlias) : - resolveEntityName(node.propertyName || node.name, meaning, /*ignoreErrors*/ false, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + const resolved = node.parent.parent.moduleSpecifier + ? getExternalModuleMember(node.parent.parent, node, dontResolveAlias) + : resolveEntityName(node.propertyName || node.name, meaning, /*ignoreErrors*/ false, dontResolveAlias); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false, + ); return resolved; } - function getTargetOfExportAssignment(node: ExportAssignment | BinaryExpression, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfExportAssignment( + node: ExportAssignment | BinaryExpression, + dontResolveAlias: boolean, + ): Symbol | undefined { const expression = isExportAssignment(node) ? node.expression : node.right; const resolved = getTargetOfAliasLikeExpression(expression, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false, + ); return resolved; } @@ -3186,7 +4068,12 @@ namespace ts { if (!isEntityName(expression) && !isEntityNameExpression(expression)) { return undefined; } - const aliasLike = resolveEntityName(expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ true, dontResolveAlias); + const aliasLike = resolveEntityName( + expression, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + /*ignoreErrors*/ true, + dontResolveAlias, + ); if (aliasLike) { return aliasLike; } @@ -3194,8 +4081,14 @@ namespace ts { return getNodeLinks(expression).resolvedSymbol; } - function getTargetOfAccessExpression(node: AccessExpression, dontRecursivelyResolve: boolean): Symbol | undefined { - if (!(isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken)) { + function getTargetOfAccessExpression( + node: AccessExpression, + dontRecursivelyResolve: boolean, + ): Symbol | undefined { + if ( + !(isBinaryExpression(node.parent) && node.parent.left === node + && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) + ) { return undefined; } @@ -3206,7 +4099,10 @@ namespace ts { switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.VariableDeclaration: - return getTargetOfImportEqualsDeclaration(node as ImportEqualsDeclaration | VariableDeclaration, dontRecursivelyResolve); + return getTargetOfImportEqualsDeclaration( + node as ImportEqualsDeclaration | VariableDeclaration, + dontRecursivelyResolve, + ); case SyntaxKind.ImportClause: return getTargetOfImportClause(node as ImportClause, dontRecursivelyResolve); case SyntaxKind.NamespaceImport: @@ -3217,16 +4113,34 @@ namespace ts { case SyntaxKind.BindingElement: return getTargetOfImportSpecifier(node as ImportSpecifier | BindingElement, dontRecursivelyResolve); case SyntaxKind.ExportSpecifier: - return getTargetOfExportSpecifier(node as ExportSpecifier, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, dontRecursivelyResolve); + return getTargetOfExportSpecifier( + node as ExportSpecifier, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + dontRecursivelyResolve, + ); case SyntaxKind.ExportAssignment: case SyntaxKind.BinaryExpression: - return getTargetOfExportAssignment(node as ExportAssignment | BinaryExpression, dontRecursivelyResolve); + return getTargetOfExportAssignment( + node as ExportAssignment | BinaryExpression, + dontRecursivelyResolve, + ); case SyntaxKind.NamespaceExportDeclaration: - return getTargetOfNamespaceExportDeclaration(node as NamespaceExportDeclaration, dontRecursivelyResolve); + return getTargetOfNamespaceExportDeclaration( + node as NamespaceExportDeclaration, + dontRecursivelyResolve, + ); case SyntaxKind.ShorthandPropertyAssignment: - return resolveEntityName((node as ShorthandPropertyAssignment).name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ true, dontRecursivelyResolve); + return resolveEntityName( + (node as ShorthandPropertyAssignment).name, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + /*ignoreErrors*/ true, + dontRecursivelyResolve, + ); case SyntaxKind.PropertyAssignment: - return getTargetOfAliasLikeExpression((node as PropertyAssignment).initializer, dontRecursivelyResolve); + return getTargetOfAliasLikeExpression( + (node as PropertyAssignment).initializer, + dontRecursivelyResolve, + ); case SyntaxKind.ElementAccessExpression: case SyntaxKind.PropertyAccessExpression: return getTargetOfAccessExpression(node as AccessExpression, dontRecursivelyResolve); @@ -3239,9 +4153,13 @@ namespace ts { * Indicates that a symbol is an alias that does not merge with a local declaration. * OR Is a JSContainer which may merge an alias with a local declaration */ - function isNonLocalAlias(symbol: Symbol | undefined, excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace): symbol is Symbol { + function isNonLocalAlias( + symbol: Symbol | undefined, + excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + ): symbol is Symbol { if (!symbol) return false; - return (symbol.flags & (SymbolFlags.Alias | excludes)) === SymbolFlags.Alias || !!(symbol.flags & SymbolFlags.Alias && symbol.flags & SymbolFlags.Assignment); + return (symbol.flags & (SymbolFlags.Alias | excludes)) === SymbolFlags.Alias + || !!(symbol.flags & SymbolFlags.Alias && symbol.flags & SymbolFlags.Assignment); } function resolveSymbol(symbol: Symbol, dontResolveAlias?: boolean): Symbol; @@ -3370,17 +4288,30 @@ namespace ts { || markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, finalTarget, overwriteEmpty); } - function markSymbolOfAliasDeclarationIfTypeOnlyWorker(aliasDeclarationLinks: SymbolLinks, target: Symbol | undefined, overwriteEmpty: boolean): boolean { - if (target && (aliasDeclarationLinks.typeOnlyDeclaration === undefined || overwriteEmpty && aliasDeclarationLinks.typeOnlyDeclaration === false)) { + function markSymbolOfAliasDeclarationIfTypeOnlyWorker( + aliasDeclarationLinks: SymbolLinks, + target: Symbol | undefined, + overwriteEmpty: boolean, + ): boolean { + if ( + target + && (aliasDeclarationLinks.typeOnlyDeclaration === undefined + || overwriteEmpty && aliasDeclarationLinks.typeOnlyDeclaration === false) + ) { const exportSymbol = target.exports?.get(InternalSymbolName.ExportEquals) ?? target; - const typeOnly = exportSymbol.declarations && find(exportSymbol.declarations, isTypeOnlyImportOrExportDeclaration); - aliasDeclarationLinks.typeOnlyDeclaration = typeOnly ?? getSymbolLinks(exportSymbol).typeOnlyDeclaration ?? false; + const typeOnly = exportSymbol.declarations + && find(exportSymbol.declarations, isTypeOnlyImportOrExportDeclaration); + aliasDeclarationLinks.typeOnlyDeclaration = typeOnly ?? getSymbolLinks(exportSymbol).typeOnlyDeclaration + ?? false; } return !!aliasDeclarationLinks.typeOnlyDeclaration; } /** Indicates that a symbol directly or indirectly resolves to a type-only import or export. */ - function getTypeOnlyAliasDeclaration(symbol: Symbol, include?: SymbolFlags): TypeOnlyAliasDeclaration | undefined { + function getTypeOnlyAliasDeclaration( + symbol: Symbol, + include?: SymbolFlags, + ): TypeOnlyAliasDeclaration | undefined { if (!(symbol.flags & SymbolFlags.Alias)) { return undefined; } @@ -3389,7 +4320,8 @@ namespace ts { return links.typeOnlyDeclaration || undefined; } if (links.typeOnlyDeclaration) { - return getAllSymbolFlags(resolveAlias(links.typeOnlyDeclaration.symbol)) & include ? links.typeOnlyDeclaration : undefined; + return getAllSymbolFlags(resolveAlias(links.typeOnlyDeclaration.symbol)) & include + ? links.typeOnlyDeclaration : undefined; } return undefined; } @@ -3398,8 +4330,9 @@ namespace ts { const symbol = getSymbolOfNode(node); const target = resolveAlias(symbol); if (target) { - const markAlias = target === unknownSymbol || - ((getAllSymbolFlags(target) & SymbolFlags.Value) && !isConstEnumOrConstEnumOnlyModule(target) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)); + const markAlias = target === unknownSymbol + || ((getAllSymbolFlags(target) & SymbolFlags.Value) && !isConstEnumOrConstEnumOnlyModule(target) + && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)); if (markAlias) { markAliasSymbolAsReferenced(symbol); @@ -3438,7 +4371,10 @@ namespace ts { } // This function is only for imports with entity names - function getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, dontResolveAlias?: boolean): Symbol | undefined { + function getSymbolOfPartOfRightHandSideOfImportEquals( + entityName: EntityName, + dontResolveAlias?: boolean, + ): Symbol | undefined { // There are three things we might try to look for. In the following examples, // the search term is enclosed in |...|: // @@ -3456,12 +4392,24 @@ namespace ts { // Case 2 in above example // entityName.kind could be a QualifiedName or a Missing identifier Debug.assert(entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration); - return resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias); + return resolveEntityName( + entityName, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + /*ignoreErrors*/ false, + dontResolveAlias, + ); } } function getFullyQualifiedName(symbol: Symbol, containingLocation?: Node): string { - return symbol.parent ? getFullyQualifiedName(symbol.parent, containingLocation) + "." + symbolToString(symbol) : symbolToString(symbol, containingLocation, /*meaning*/ undefined, SymbolFormatFlags.DoNotIncludeSymbolChain | SymbolFormatFlags.AllowAnyNodeKind); + return symbol.parent + ? getFullyQualifiedName(symbol.parent, containingLocation) + "." + symbolToString(symbol) + : symbolToString( + symbol, + containingLocation, + /*meaning*/ undefined, + SymbolFormatFlags.DoNotIncludeSymbolChain | SymbolFormatFlags.AllowAnyNodeKind, + ); } function getContainingQualifiedNameNode(node: QualifiedName) { @@ -3491,7 +4439,13 @@ namespace ts { /** * Resolves a qualified name and any involved aliases. */ - function resolveEntityName(name: EntityNameOrEntityNameExpression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean, location?: Node): Symbol | undefined { + function resolveEntityName( + name: EntityNameOrEntityNameExpression, + meaning: SymbolFlags, + ignoreErrors?: boolean, + dontResolveAlias?: boolean, + location?: Node, + ): Symbol | undefined { if (nodeIsMissing(name)) { return undefined; } @@ -3499,9 +4453,22 @@ namespace ts { const namespaceMeaning = SymbolFlags.Namespace | (isInJSFile(name) ? meaning & SymbolFlags.Value : 0); let symbol: Symbol | undefined; if (name.kind === SyntaxKind.Identifier) { - const message = meaning === namespaceMeaning || nodeIsSynthesized(name) ? Diagnostics.Cannot_find_namespace_0 : getCannotFindNameDiagnosticForName(getFirstIdentifier(name)); - const symbolFromJSPrototype = isInJSFile(name) && !nodeIsSynthesized(name) ? resolveEntityNameFromAssignmentDeclaration(name, meaning) : undefined; - symbol = getMergedSymbol(resolveName(location || name, name.escapedText, meaning, ignoreErrors || symbolFromJSPrototype ? undefined : message, name, /*isUse*/ true, false)); + const message = meaning === namespaceMeaning || nodeIsSynthesized(name) + ? Diagnostics.Cannot_find_namespace_0 + : getCannotFindNameDiagnosticForName(getFirstIdentifier(name)); + const symbolFromJSPrototype = isInJSFile(name) && !nodeIsSynthesized(name) + ? resolveEntityNameFromAssignmentDeclaration(name, meaning) : undefined; + symbol = getMergedSymbol( + resolveName( + location || name, + name.escapedText, + meaning, + ignoreErrors || symbolFromJSPrototype ? undefined : message, + name, + /*isUse*/ true, + false, + ), + ); if (!symbol) { return getMergedSymbol(symbolFromJSPrototype); } @@ -3509,7 +4476,13 @@ namespace ts { else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) { const left = name.kind === SyntaxKind.QualifiedName ? name.left : name.expression; const right = name.kind === SyntaxKind.QualifiedName ? name.right : name.name; - let namespace = resolveEntityName(left, namespaceMeaning, ignoreErrors, /*dontResolveAlias*/ false, location); + let namespace = resolveEntityName( + left, + namespaceMeaning, + ignoreErrors, + /*dontResolveAlias*/ false, + location, + ); if (!namespace || nodeIsMissing(right)) { return undefined; } @@ -3517,13 +4490,14 @@ namespace ts { return namespace; } if ( - namespace.valueDeclaration && - isInJSFile(namespace.valueDeclaration) && - isVariableDeclaration(namespace.valueDeclaration) && - namespace.valueDeclaration.initializer && - isCommonJsRequire(namespace.valueDeclaration.initializer) + namespace.valueDeclaration + && isInJSFile(namespace.valueDeclaration) + && isVariableDeclaration(namespace.valueDeclaration) + && namespace.valueDeclaration.initializer + && isCommonJsRequire(namespace.valueDeclaration.initializer) ) { - const moduleName = (namespace.valueDeclaration.initializer as CallExpression).arguments[0] as StringLiteral; + const moduleName = (namespace.valueDeclaration.initializer as CallExpression) + .arguments[0] as StringLiteral; const moduleSym = resolveExternalModuleName(moduleName, moduleName); if (moduleSym) { const resolvedModuleSymbol = resolveExternalModuleSymbol(moduleSym); @@ -3539,7 +4513,13 @@ namespace ts { const declarationName = declarationNameToString(right); const suggestionForNonexistentModule = getSuggestedSymbolForNonexistentModule(right, namespace); if (suggestionForNonexistentModule) { - error(right, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestionForNonexistentModule)); + error( + right, + Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, + namespaceName, + declarationName, + symbolToString(suggestionForNonexistentModule), + ); return undefined; } @@ -3559,11 +4539,14 @@ namespace ts { } if (meaning & SymbolFlags.Namespace && isQualifiedName(name.parent)) { - const exportedTypeSymbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type)); + const exportedTypeSymbol = getMergedSymbol( + getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type), + ); if (exportedTypeSymbol) { error( name.parent.right, - Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, + Diagnostics + .Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, symbolToString(exportedTypeSymbol), unescapeLeadingUnderscores(name.parent.right.escapedText), ); @@ -3579,9 +4562,20 @@ namespace ts { else { throw Debug.assertNever(name, "Unknown entity name kind."); } - Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); - if (!nodeIsSynthesized(name) && isEntityName(name) && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment)) { - markSymbolOfAliasDeclarationIfTypeOnly(getAliasDeclarationFromName(name), symbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ true); + Debug.assert( + (getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, + "Should never get an instantiated symbol here.", + ); + if ( + !nodeIsSynthesized(name) && isEntityName(name) + && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment) + ) { + markSymbolOfAliasDeclarationIfTypeOnly( + getAliasDeclarationFromName(name), + symbol, + /*finalTarget*/ undefined, + /*overwriteEmpty*/ true, + ); } return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol); } @@ -3596,13 +4590,23 @@ namespace ts { if (isJSDocTypeReference(name.parent)) { const secondaryLocation = getAssignmentDeclarationLocation(name.parent); if (secondaryLocation) { - return resolveName(secondaryLocation, name.escapedText, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ true); + return resolveName( + secondaryLocation, + name.escapedText, + meaning, + /*nameNotFoundMessage*/ undefined, + name, + /*isUse*/ true, + ); } } } function getAssignmentDeclarationLocation(node: TypeReferenceNode): Node | undefined { - const typeAlias = findAncestor(node, node => !(isJSDocNode(node) || node.flags & NodeFlags.JSDoc) ? "quit" : isJSDocTypeAlias(node)); + const typeAlias = findAncestor( + node, + node => !(isJSDocNode(node) || node.flags & NodeFlags.JSDoc) ? "quit" : isJSDocTypeAlias(node), + ); if (typeAlias) { return; } @@ -3614,7 +4618,10 @@ namespace ts { return getDeclarationOfJSPrototypeContainer(symbol); } } - if (host && isFunctionExpression(host) && isPrototypePropertyAssignment(host.parent) && isExpressionStatement(host.parent.parent)) { + if ( + host && isFunctionExpression(host) && isPrototypePropertyAssignment(host.parent) + && isExpressionStatement(host.parent.parent) + ) { // X.prototype.m = /** @param {K} p */ function () { } <-- look for K on X's declaration const symbol = getSymbolOfNode(host.parent.left); if (symbol) { @@ -3622,9 +4629,9 @@ namespace ts { } } if ( - host && (isObjectLiteralMethod(host) || isPropertyAssignment(host)) && - isBinaryExpression(host.parent.parent) && - getAssignmentDeclarationKind(host.parent.parent) === AssignmentDeclarationKind.Prototype + host && (isObjectLiteralMethod(host) || isPropertyAssignment(host)) + && isBinaryExpression(host.parent.parent) + && getAssignmentDeclarationKind(host.parent.parent) === AssignmentDeclarationKind.Prototype ) { // X.prototype = { /** @param {K} p */m() { } } <-- look for K on X's declaration const symbol = getSymbolOfNode(host.parent.parent.left); @@ -3644,9 +4651,9 @@ namespace ts { if (!decl) { return undefined; } - const initializer = isAssignmentDeclaration(decl) ? getAssignedExpandoInitializer(decl) : - hasOnlyExpressionInitializer(decl) ? getDeclaredExpandoInitializer(decl) : - undefined; + const initializer = isAssignmentDeclaration(decl) ? getAssignedExpandoInitializer(decl) + : hasOnlyExpressionInitializer(decl) ? getDeclaredExpandoInitializer(decl) + : undefined; return initializer || decl; } @@ -3658,10 +4665,14 @@ namespace ts { */ function getExpandoSymbol(symbol: Symbol): Symbol | undefined { const decl = symbol.valueDeclaration; - if (!decl || !isInJSFile(decl) || symbol.flags & SymbolFlags.TypeAlias || getExpandoInitializer(decl, /*isPrototypeAssignment*/ false)) { + if ( + !decl || !isInJSFile(decl) || symbol.flags & SymbolFlags.TypeAlias + || getExpandoInitializer(decl, /*isPrototypeAssignment*/ false) + ) { return undefined; } - const init = isVariableDeclaration(decl) ? getDeclaredExpandoInitializer(decl) : getAssignedExpandoInitializer(decl); + const init = isVariableDeclaration(decl) ? getDeclaredExpandoInitializer(decl) + : getAssignedExpandoInitializer(decl); if (init) { const initSymbol = getSymbolOfNode(init); if (initSymbol) { @@ -3670,21 +4681,47 @@ namespace ts { } } - function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression, ignoreErrors?: boolean): Symbol | undefined { + function resolveExternalModuleName( + location: Node, + moduleReferenceExpression: Expression, + ignoreErrors?: boolean, + ): Symbol | undefined { const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic; - const errorMessage = isClassic ? - Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option + const errorMessage = isClassic + ? Diagnostics + .Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option : Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations; - return resolveExternalModuleNameWorker(location, moduleReferenceExpression, ignoreErrors ? undefined : errorMessage); + return resolveExternalModuleNameWorker( + location, + moduleReferenceExpression, + ignoreErrors ? undefined : errorMessage, + ); } - function resolveExternalModuleNameWorker(location: Node, moduleReferenceExpression: Expression, moduleNotFoundError: DiagnosticMessage | undefined, isForAugmentation = false): Symbol | undefined { + function resolveExternalModuleNameWorker( + location: Node, + moduleReferenceExpression: Expression, + moduleNotFoundError: DiagnosticMessage | undefined, + isForAugmentation = false, + ): Symbol | undefined { return isStringLiteralLike(moduleReferenceExpression) - ? resolveExternalModule(location, moduleReferenceExpression.text, moduleNotFoundError, moduleReferenceExpression, isForAugmentation) + ? resolveExternalModule( + location, + moduleReferenceExpression.text, + moduleNotFoundError, + moduleReferenceExpression, + isForAugmentation, + ) : undefined; } - function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage | undefined, errorNode: Node, isForAugmentation = false): Symbol | undefined { + function resolveExternalModule( + location: Node, + moduleReference: string, + moduleNotFoundError: DiagnosticMessage | undefined, + errorNode: Node, + isForAugmentation = false, + ): Symbol | undefined { if (startsWith(moduleReference, "@types/")) { const diag = Diagnostics.Cannot_import_type_declaration_files_Consider_importing_0_instead_of_1; const withoutAtTypePrefix = removePrefix(moduleReference, "@types/"); @@ -3698,17 +4735,21 @@ namespace ts { const currentSourceFile = getSourceFileOfNode(location); const contextSpecifier = isStringLiteralLike(location) ? location - : findAncestor(location, isImportCall)?.arguments[0] || - findAncestor(location, isImportDeclaration)?.moduleSpecifier || - findAncestor(location, isExternalModuleImportEqualsDeclaration)?.moduleReference.expression || - findAncestor(location, isExportDeclaration)?.moduleSpecifier || - (isModuleDeclaration(location) ? location : location.parent && isModuleDeclaration(location.parent) && location.parent.name === location ? location.parent : undefined)?.name || - (isLiteralImportTypeNode(location) ? location : undefined)?.argument.literal; - const mode = contextSpecifier && isStringLiteralLike(contextSpecifier) ? getModeForUsageLocation(currentSourceFile, contextSpecifier) : currentSourceFile.impliedNodeFormat; + : findAncestor(location, isImportCall)?.arguments[0] + || findAncestor(location, isImportDeclaration)?.moduleSpecifier + || findAncestor(location, isExternalModuleImportEqualsDeclaration)?.moduleReference.expression + || findAncestor(location, isExportDeclaration)?.moduleSpecifier + || (isModuleDeclaration(location) ? location + : location.parent && isModuleDeclaration(location.parent) && location.parent.name === location + ? location.parent : undefined)?.name + || (isLiteralImportTypeNode(location) ? location : undefined)?.argument.literal; + const mode = contextSpecifier && isStringLiteralLike(contextSpecifier) + ? getModeForUsageLocation(currentSourceFile, contextSpecifier) : currentSourceFile.impliedNodeFormat; const resolvedModule = getResolvedModule(currentSourceFile, moduleReference, mode); const resolutionDiagnostic = resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule); const sourceFile = resolvedModule - && (!resolutionDiagnostic || resolutionDiagnostic === Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set) + && (!resolutionDiagnostic + || resolutionDiagnostic === Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set) && host.getSourceFile(resolvedModule.resolvedFileName); if (sourceFile) { // If there's a resolutionDiagnostic we need to report it even if a sourceFile is found. @@ -3716,32 +4757,57 @@ namespace ts { error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); } if (sourceFile.symbol) { - if (resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) { + if ( + resolvedModule.isExternalLibraryImport + && !resolutionExtensionIsTSOrJson(resolvedModule.extension) + ) { errorOnImplicitAnyModule(/*isError*/ false, errorNode, resolvedModule, moduleReference); } - if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { - const isSyncImport = (currentSourceFile.impliedNodeFormat === ModuleKind.CommonJS && !findAncestor(location, isImportCall)) || !!findAncestor(location, isImportEqualsDeclaration); - const overrideClauseHost = findAncestor(location, l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l)) as ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined; - const overrideClause = overrideClauseHost && isImportTypeNode(overrideClauseHost) ? overrideClauseHost.assertions?.assertClause : overrideClauseHost?.assertClause; + if ( + getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext + ) { + const isSyncImport = (currentSourceFile.impliedNodeFormat === ModuleKind.CommonJS + && !findAncestor(location, isImportCall)) + || !!findAncestor(location, isImportEqualsDeclaration); + const overrideClauseHost = findAncestor( + location, + l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l), + ) as ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined; + const overrideClause = overrideClauseHost && isImportTypeNode(overrideClauseHost) + ? overrideClauseHost.assertions?.assertClause : overrideClauseHost?.assertClause; // An override clause will take effect for type-only imports and import types, and allows importing the types across formats, regardless of // normal mode restrictions - if (isSyncImport && sourceFile.impliedNodeFormat === ModuleKind.ESNext && !getResolutionModeOverrideForClause(overrideClause)) { + if ( + isSyncImport && sourceFile.impliedNodeFormat === ModuleKind.ESNext + && !getResolutionModeOverrideForClause(overrideClause) + ) { if (findAncestor(location, isImportEqualsDeclaration)) { // ImportEquals in a ESM file resolving to another ESM file - error(errorNode, Diagnostics.Module_0_cannot_be_imported_using_this_construct_The_specifier_only_resolves_to_an_ES_module_which_cannot_be_imported_with_require_Use_an_ECMAScript_import_instead, moduleReference); + error( + errorNode, + Diagnostics + .Module_0_cannot_be_imported_using_this_construct_The_specifier_only_resolves_to_an_ES_module_which_cannot_be_imported_with_require_Use_an_ECMAScript_import_instead, + moduleReference, + ); } else { // CJS file resolving to an ESM file let diagnosticDetails; const ext = tryGetExtensionFromPath(currentSourceFile.fileName); - if (ext === Extension.Ts || ext === Extension.Js || ext === Extension.Tsx || ext === Extension.Jsx) { + if ( + ext === Extension.Ts || ext === Extension.Js || ext === Extension.Tsx + || ext === Extension.Jsx + ) { const scope = currentSourceFile.packageJsonScope; - const targetExt = ext === Extension.Ts ? Extension.Mts : ext === Extension.Js ? Extension.Mjs : undefined; + const targetExt = ext === Extension.Ts ? Extension.Mts + : ext === Extension.Js ? Extension.Mjs : undefined; if (scope && !scope.contents.packageJsonContent.type) { if (targetExt) { diagnosticDetails = chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_add_the_field_type_Colon_module_to_1, + Diagnostics + .To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_add_the_field_type_Colon_module_to_1, targetExt, combinePaths(scope.packageDirectory, "package.json"), ); @@ -3749,7 +4815,8 @@ namespace ts { else { diagnosticDetails = chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.To_convert_this_file_to_an_ECMAScript_module_add_the_field_type_Colon_module_to_0, + Diagnostics + .To_convert_this_file_to_an_ECMAScript_module_add_the_field_type_Colon_module_to_0, combinePaths(scope.packageDirectory, "package.json"), ); } @@ -3758,14 +4825,16 @@ namespace ts { if (targetExt) { diagnosticDetails = chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_create_a_local_package_json_file_with_type_Colon_module, + Diagnostics + .To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_create_a_local_package_json_file_with_type_Colon_module, targetExt, ); } else { diagnosticDetails = chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.To_convert_this_file_to_an_ECMAScript_module_create_a_local_package_json_file_with_type_Colon_module, + Diagnostics + .To_convert_this_file_to_an_ECMAScript_module_create_a_local_package_json_file_with_type_Colon_module, ); } } @@ -3774,7 +4843,8 @@ namespace ts { errorNode, chainDiagnosticMessages( diagnosticDetails, - Diagnostics.The_current_file_is_a_CommonJS_module_whose_imports_will_produce_require_calls_however_the_referenced_file_is_an_ECMAScript_module_and_cannot_be_imported_with_require_Consider_writing_a_dynamic_import_0_call_instead, + Diagnostics + .The_current_file_is_a_CommonJS_module_whose_imports_will_produce_require_calls_however_the_referenced_file_is_an_ECMAScript_module_and_cannot_be_imported_with_require_Consider_writing_a_dynamic_import_0_call_instead, moduleReference, ), )); @@ -3798,7 +4868,8 @@ namespace ts { // module augmentation by the specific name requested ('a.foo'), we store the merged symbol // by the augmentation name ('a.foo'), because asking for *.foo should not give you exports // from a.foo. - const augmentation = patternAmbientModuleAugmentations && patternAmbientModuleAugmentations.get(moduleReference); + const augmentation = patternAmbientModuleAugmentations + && patternAmbientModuleAugmentations.get(moduleReference); if (augmentation) { return getMergedSymbol(augmentation); } @@ -3807,13 +4878,24 @@ namespace ts { } // May be an untyped module. If so, ignore resolutionDiagnostic. - if (resolvedModule && !resolutionExtensionIsTSOrJson(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) { + if ( + resolvedModule && !resolutionExtensionIsTSOrJson(resolvedModule.extension) + && resolutionDiagnostic === undefined + || resolutionDiagnostic + === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type + ) { if (isForAugmentation) { - const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented; + const diag = Diagnostics + .Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented; error(errorNode, diag, moduleReference, resolvedModule!.resolvedFileName); } else { - errorOnImplicitAnyModule(/*isError*/ noImplicitAny && !!moduleNotFoundError, errorNode, resolvedModule!, moduleReference); + errorOnImplicitAnyModule( + /*isError*/ noImplicitAny && !!moduleNotFoundError, + errorNode, + resolvedModule!, + moduleReference, + ); } // Failed imports and untyped modules are both treated in an untyped manner; only difference is whether we give a diagnostic first. return undefined; @@ -3824,7 +4906,12 @@ namespace ts { if (resolvedModule) { const redirect = host.getProjectReferenceRedirect(resolvedModule.resolvedFileName); if (redirect) { - error(errorNode, Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, redirect, resolvedModule.resolvedFileName); + error( + errorNode, + Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, + redirect, + resolvedModule.resolvedFileName, + ); return undefined; } } @@ -3834,12 +4921,14 @@ namespace ts { } else { const tsExtension = tryExtractTSExtension(moduleReference); - const isExtensionlessRelativePathImport = pathIsRelative(moduleReference) && !hasExtension(moduleReference); + const isExtensionlessRelativePathImport = pathIsRelative(moduleReference) + && !hasExtension(moduleReference); const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions); - const resolutionIsNode16OrNext = moduleResolutionKind === ModuleResolutionKind.Node16 || - moduleResolutionKind === ModuleResolutionKind.NodeNext; + const resolutionIsNode16OrNext = moduleResolutionKind === ModuleResolutionKind.Node16 + || moduleResolutionKind === ModuleResolutionKind.NodeNext; if (tsExtension) { - const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; + const diag = + Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; const importSourceWithoutExtension = removeExtension(moduleReference, tsExtension); let replacedImportSource = importSourceWithoutExtension; /** @@ -3847,26 +4936,48 @@ namespace ts { * @see https://github.com/microsoft/TypeScript/issues/42151 */ if (moduleKind >= ModuleKind.ES2015) { - replacedImportSource += tsExtension === Extension.Mts ? ".mjs" : tsExtension === Extension.Cts ? ".cjs" : ".js"; + replacedImportSource += tsExtension === Extension.Mts ? ".mjs" + : tsExtension === Extension.Cts ? ".cjs" : ".js"; } error(errorNode, diag, tsExtension, replacedImportSource); } else if ( - !compilerOptions.resolveJsonModule && - fileExtensionIs(moduleReference, Extension.Json) && - getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic && - hasJsonModuleEmitEnabled(compilerOptions) + !compilerOptions.resolveJsonModule + && fileExtensionIs(moduleReference, Extension.Json) + && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic + && hasJsonModuleEmitEnabled(compilerOptions) ) { - error(errorNode, Diagnostics.Cannot_find_module_0_Consider_using_resolveJsonModule_to_import_module_with_json_extension, moduleReference); + error( + errorNode, + Diagnostics + .Cannot_find_module_0_Consider_using_resolveJsonModule_to_import_module_with_json_extension, + moduleReference, + ); } - else if (mode === ModuleKind.ESNext && resolutionIsNode16OrNext && isExtensionlessRelativePathImport) { - const absoluteRef = getNormalizedAbsolutePath(moduleReference, getDirectoryPath(currentSourceFile.path)); - const suggestedExt = suggestedExtensions.find(([actualExt, _importExt]) => host.fileExists(absoluteRef + actualExt))?.[1]; + else if ( + mode === ModuleKind.ESNext && resolutionIsNode16OrNext && isExtensionlessRelativePathImport + ) { + const absoluteRef = getNormalizedAbsolutePath( + moduleReference, + getDirectoryPath(currentSourceFile.path), + ); + const suggestedExt = suggestedExtensions.find(([actualExt, _importExt]) => + host.fileExists(absoluteRef + actualExt) + )?.[1]; if (suggestedExt) { - error(errorNode, Diagnostics.Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Did_you_mean_0, moduleReference + suggestedExt); + error( + errorNode, + Diagnostics + .Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Did_you_mean_0, + moduleReference + suggestedExt, + ); } else { - error(errorNode, Diagnostics.Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Consider_adding_an_extension_to_the_import_path); + error( + errorNode, + Diagnostics + .Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Consider_adding_an_extension_to_the_import_path, + ); } } else { @@ -3877,25 +4988,33 @@ namespace ts { return undefined; } - function errorOnImplicitAnyModule(isError: boolean, errorNode: Node, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): void { + function errorOnImplicitAnyModule( + isError: boolean, + errorNode: Node, + { packageId, resolvedFileName }: ResolvedModuleFull, + moduleReference: string, + ): void { const errorInfo = !isExternalModuleNameRelative(moduleReference) && packageId ? typesPackageExists(packageId.name) ? chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_1, + Diagnostics + .If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_1, packageId.name, mangleScopedPackageName(packageId.name), ) : packageBundlesTypes(packageId.name) ? chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.If_the_0_package_actually_exposes_this_module_try_adding_a_new_declaration_d_ts_file_containing_declare_module_1, + Diagnostics + .If_the_0_package_actually_exposes_this_module_try_adding_a_new_declaration_d_ts_file_containing_declare_module_1, packageId.name, moduleReference, ) : chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.Try_npm_i_save_dev_types_Slash_1_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, + Diagnostics + .Try_npm_i_save_dev_types_Slash_1_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, moduleReference, mangleScopedPackageName(packageId.name), ) @@ -3919,10 +5038,16 @@ namespace ts { } function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol; - function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined; + function resolveExternalModuleSymbol( + moduleSymbol: Symbol | undefined, + dontResolveAlias?: boolean, + ): Symbol | undefined; function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol | undefined { if (moduleSymbol?.exports) { - const exportEquals = resolveSymbol(moduleSymbol.exports.get(InternalSymbolName.ExportEquals), dontResolveAlias); + const exportEquals = resolveSymbol( + moduleSymbol.exports.get(InternalSymbolName.ExportEquals), + dontResolveAlias, + ); const exported = getCommonJsExportEquals(getMergedSymbol(exportEquals), getMergedSymbol(moduleSymbol)); return getMergedSymbol(exported) || moduleSymbol; } @@ -3930,7 +5055,10 @@ namespace ts { } function getCommonJsExportEquals(exported: Symbol | undefined, moduleSymbol: Symbol): Symbol | undefined { - if (!exported || exported === unknownSymbol || exported === moduleSymbol || moduleSymbol.exports!.size === 1 || exported.flags & SymbolFlags.Alias) { + if ( + !exported || exported === unknownSymbol || exported === moduleSymbol || moduleSymbol.exports!.size === 1 + || exported.flags & SymbolFlags.Alias + ) { return exported; } const links = getSymbolLinks(exported); @@ -3953,26 +5081,40 @@ namespace ts { // An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export =' // references a symbol that is at least declared as a module or a variable. The target of the 'export =' may // combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable). - function resolveESModuleSymbol(moduleSymbol: Symbol | undefined, referencingLocation: Node, dontResolveAlias: boolean, suppressInteropError: boolean): Symbol | undefined { + function resolveESModuleSymbol( + moduleSymbol: Symbol | undefined, + referencingLocation: Node, + dontResolveAlias: boolean, + suppressInteropError: boolean, + ): Symbol | undefined { const symbol = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias); if (!dontResolveAlias && symbol) { - if (!suppressInteropError && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable)) && !getDeclarationOfKind(symbol, SyntaxKind.SourceFile)) { + if ( + !suppressInteropError && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable)) + && !getDeclarationOfKind(symbol, SyntaxKind.SourceFile) + ) { const compilerOptionName = moduleKind >= ModuleKind.ES2015 ? "allowSyntheticDefaultImports" : "esModuleInterop"; - error(referencingLocation, Diagnostics.This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, compilerOptionName); + error( + referencingLocation, + Diagnostics + .This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, + compilerOptionName, + ); return symbol; } const referenceParent = referencingLocation.parent; if ( - (isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent)) || - isImportCall(referenceParent) + (isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent)) + || isImportCall(referenceParent) ) { - const reference = isImportCall(referenceParent) ? referenceParent.arguments[0] : referenceParent.moduleSpecifier; + const reference = isImportCall(referenceParent) ? referenceParent.arguments[0] + : referenceParent.moduleSpecifier; const type = getTypeOfSymbol(symbol); const defaultOnlyType = getTypeWithSyntheticDefaultOnly(type, symbol, moduleSymbol!, reference); if (defaultOnlyType) { @@ -3980,18 +5122,31 @@ namespace ts { } const targetFile = moduleSymbol?.declarations?.find(isSourceFile); - const isEsmCjsRef = targetFile && isESMFormatImportImportingCommonjsFormatFile(getUsageModeForExpression(reference), targetFile.impliedNodeFormat); + const isEsmCjsRef = targetFile + && isESMFormatImportImportingCommonjsFormatFile( + getUsageModeForExpression(reference), + targetFile.impliedNodeFormat, + ); if (getESModuleInterop(compilerOptions) || isEsmCjsRef) { let sigs = getSignaturesOfStructuredType(type, SignatureKind.Call); if (!sigs || !sigs.length) { sigs = getSignaturesOfStructuredType(type, SignatureKind.Construct); } if ( - (sigs && sigs.length) || - getPropertyOfType(type, InternalSymbolName.Default, /*skipObjectFunctionPropertyAugment*/ true) || - isEsmCjsRef + (sigs && sigs.length) + || getPropertyOfType( + type, + InternalSymbolName.Default, + /*skipObjectFunctionPropertyAugment*/ true, + ) + || isEsmCjsRef ) { - const moduleType = getTypeWithSyntheticDefaultImportType(type, symbol, moduleSymbol!, reference); + const moduleType = getTypeWithSyntheticDefaultImportType( + type, + symbol, + moduleSymbol!, + reference, + ); return cloneTypeAsModuleType(symbol, moduleType, referenceParent); } } @@ -4003,7 +5158,11 @@ namespace ts { /** * Create a new symbol which has the module's type less the call and construct signatures */ - function cloneTypeAsModuleType(symbol: Symbol, moduleType: Type, referenceParent: ImportDeclaration | ImportCall) { + function cloneTypeAsModuleType( + symbol: Symbol, + moduleType: Type, + referenceParent: ImportDeclaration | ImportCall, + ) { const result = createSymbol(symbol.flags, symbol.escapedName); result.declarations = symbol.declarations ? symbol.declarations.slice() : []; result.parent = symbol.parent; @@ -4014,7 +5173,13 @@ namespace ts { if (symbol.members) result.members = new Map(symbol.members); if (symbol.exports) result.exports = new Map(symbol.exports); const resolvedModuleType = resolveStructuredTypeMembers(moduleType as StructuredType); // Should already be resolved from the signature checks above - result.type = createAnonymousType(result, resolvedModuleType.members, emptyArray, emptyArray, resolvedModuleType.indexInfos); + result.type = createAnonymousType( + result, + resolvedModuleType.members, + emptyArray, + emptyArray, + resolvedModuleType.indexInfos, + ); return result; } @@ -4038,7 +5203,10 @@ namespace ts { return exports; } - function forEachExportAndPropertyOfModule(moduleSymbol: Symbol, cb: (symbol: Symbol, key: __String) => void): void { + function forEachExportAndPropertyOfModule( + moduleSymbol: Symbol, + cb: (symbol: Symbol, key: __String) => void, + ): void { const exports = getExportsOfModule(moduleSymbol); exports.forEach((symbol, key) => { if (!isReservedMemberName(key)) { @@ -4063,7 +5231,10 @@ namespace ts { } } - function tryGetMemberInModuleExportsAndProperties(memberName: __String, moduleSymbol: Symbol): Symbol | undefined { + function tryGetMemberInModuleExportsAndProperties( + memberName: __String, + moduleSymbol: Symbol, + ): Symbol | undefined { const symbol = tryGetMemberInModuleExports(memberName, moduleSymbol); if (symbol) { return symbol; @@ -4075,21 +5246,23 @@ namespace ts { } const type = getTypeOfSymbol(exportEquals); - return shouldTreatPropertiesOfExternalModuleAsExports(type) ? getPropertyOfType(type, memberName) : undefined; + return shouldTreatPropertiesOfExternalModuleAsExports(type) ? getPropertyOfType(type, memberName) + : undefined; } function shouldTreatPropertiesOfExternalModuleAsExports(resolvedExternalModuleType: Type) { - return !(resolvedExternalModuleType.flags & TypeFlags.Primitive || - getObjectFlags(resolvedExternalModuleType) & ObjectFlags.Class || + return !(resolvedExternalModuleType.flags & TypeFlags.Primitive + || getObjectFlags(resolvedExternalModuleType) & ObjectFlags.Class // `isArrayOrTupleLikeType` is too expensive to use in this auto-imports hot path - isArrayType(resolvedExternalModuleType) || - isTupleType(resolvedExternalModuleType)); + || isArrayType(resolvedExternalModuleType) + || isTupleType(resolvedExternalModuleType)); } function getExportsOfSymbol(symbol: Symbol): SymbolTable { - return symbol.flags & SymbolFlags.LateBindingContainer ? getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKind.resolvedExports) : - symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) : - symbol.exports || emptySymbols; + return symbol.flags & SymbolFlags.LateBindingContainer + ? getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKind.resolvedExports) + : symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) + : symbol.exports || emptySymbols; } function getExportsOfModule(moduleSymbol: Symbol): SymbolTable { @@ -4108,7 +5281,12 @@ namespace ts { * Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables */ - function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) { + function extendExportSymbols( + target: SymbolTable, + source: SymbolTable | undefined, + lookupTable?: ExportCollisionTrackerTable, + exportNode?: ExportDeclaration, + ) { if (!source) return; source.forEach((sourceSymbol, id) => { if (id === InternalSymbolName.Default) return; @@ -4122,7 +5300,10 @@ namespace ts { } as ExportCollisionTracker); } } - else if (lookupTable && exportNode && targetSymbol && resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol)) { + else if ( + lookupTable && exportNode && targetSymbol + && resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol) + ) { const collisionTracker = lookupTable.get(id)!; if (!collisionTracker.exportsWithDuplicate) { collisionTracker.exportsWithDuplicate = [exportNode]; @@ -4156,7 +5337,10 @@ namespace ts { const lookupTable: ExportCollisionTrackerTable = new Map(); if (exportStars.declarations) { for (const node of exportStars.declarations) { - const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); + const resolvedModule = resolveExternalModuleName( + node, + (node as ExportDeclaration).moduleSpecifier!, + ); const exportedSymbols = visit(resolvedModule); extendExportSymbols( nestedSymbols, @@ -4168,13 +5352,17 @@ namespace ts { } lookupTable.forEach(({ exportsWithDuplicate }, id) => { // It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself - if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || symbols.has(id)) { + if ( + id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) + || symbols.has(id) + ) { return; } for (const node of exportsWithDuplicate) { diagnostics.add(createDiagnosticForNode( node, - Diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, + Diagnostics + .Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, lookupTable.get(id)!.specifierText, unescapeLeadingUnderscores(id), )); @@ -4215,7 +5403,11 @@ namespace ts { // Try to make an import using an import already in the enclosing file, if possible for (const importRef of containingFile.imports) { if (nodeIsSynthesized(importRef)) continue; // Synthetic names can't be resolved by `resolveExternalModuleName` - they'll cause a debug assert if they error - const resolvedModule = resolveExternalModuleName(enclosingDeclaration, importRef, /*ignoreErrors*/ true); + const resolvedModule = resolveExternalModuleName( + enclosingDeclaration, + importRef, + /*ignoreErrors*/ true, + ); if (!resolvedModule) continue; const ref = getAliasForSymbolInContainer(resolvedModule, symbol); if (!ref) continue; @@ -4245,19 +5437,35 @@ namespace ts { * Attempts to find the symbol corresponding to the container a symbol is in - usually this * is just its' `.parent`, but for locals, this value is `undefined` */ - function getContainersOfSymbol(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): Symbol[] | undefined { + function getContainersOfSymbol( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + ): Symbol[] | undefined { const container = getParentOfSymbol(symbol); // Type parameters end up in the `members` lists but are not externally visible if (container && !(symbol.flags & SymbolFlags.TypeParameter)) { - const additionalContainers = mapDefined(container.declarations, fileSymbolIfFileSymbolExportEqualsContainer); - const reexportContainers = enclosingDeclaration && getAlternativeContainingModules(symbol, enclosingDeclaration); + const additionalContainers = mapDefined( + container.declarations, + fileSymbolIfFileSymbolExportEqualsContainer, + ); + const reexportContainers = enclosingDeclaration + && getAlternativeContainingModules(symbol, enclosingDeclaration); const objectLiteralContainer = getVariableDeclarationOfObjectLiteral(container, meaning); if ( - enclosingDeclaration && - container.flags & getQualifiedLeftMeaning(meaning) && - getAccessibleSymbolChain(container, enclosingDeclaration, SymbolFlags.Namespace, /*externalOnly*/ false) + enclosingDeclaration + && container.flags & getQualifiedLeftMeaning(meaning) + && getAccessibleSymbolChain( + container, + enclosingDeclaration, + SymbolFlags.Namespace, + /*externalOnly*/ false, + ) ) { - return append(concatenate(concatenate([container], additionalContainers), reexportContainers), objectLiteralContainer); // This order expresses a preference for the real container if it is in scope + return append( + concatenate(concatenate([container], additionalContainers), reexportContainers), + objectLiteralContainer, + ); // This order expresses a preference for the real container if it is in scope } // we potentially have a symbol which is a member of the instance side of something - look for a variable in scope with the container's type // which may be acting like a namespace (eg, `Symbol` acts like a namespace when looking up `Symbol.toStringTag`) @@ -4267,12 +5475,16 @@ namespace ts { && meaning === SymbolFlags.Value ? forEachSymbolTableInScope(enclosingDeclaration, t => { return forEachEntry(t, s => { - if (s.flags & getQualifiedLeftMeaning(meaning) && getTypeOfSymbol(s) === getDeclaredTypeOfSymbol(container)) { + if ( + s.flags & getQualifiedLeftMeaning(meaning) + && getTypeOfSymbol(s) === getDeclaredTypeOfSymbol(container) + ) { return s; } }); }) : undefined; - let res = firstVariableMatch ? [firstVariableMatch, ...additionalContainers, container] : [...additionalContainers, container]; + let res = firstVariableMatch ? [firstVariableMatch, ...additionalContainers, container] + : [...additionalContainers, container]; res = append(res, objectLiteralContainer); res = addRange(res, reexportContainers); return res; @@ -4284,12 +5496,21 @@ namespace ts { return getSymbolOfNode(d.parent); } // export ='d member of an ambient module - if (isModuleBlock(d.parent) && d.parent.parent && resolveExternalModuleSymbol(getSymbolOfNode(d.parent.parent)) === symbol) { + if ( + isModuleBlock(d.parent) && d.parent.parent + && resolveExternalModuleSymbol(getSymbolOfNode(d.parent.parent)) === symbol + ) { return getSymbolOfNode(d.parent.parent); } } - if (isClassExpression(d) && isBinaryExpression(d.parent) && d.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAccessExpression(d.parent.left) && isEntityNameExpression(d.parent.left.expression)) { - if (isModuleExportsAccessExpression(d.parent.left) || isExportsIdentifier(d.parent.left.expression)) { + if ( + isClassExpression(d) && isBinaryExpression(d.parent) + && d.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAccessExpression(d.parent.left) + && isEntityNameExpression(d.parent.left.expression) + ) { + if ( + isModuleExportsAccessExpression(d.parent.left) || isExportsIdentifier(d.parent.left.expression) + ) { return getSymbolOfNode(getSourceFileOfNode(d)); } checkExpressionCached(d.parent.left.expression); @@ -4299,7 +5520,10 @@ namespace ts { if (!length(candidates)) { return undefined; } - return mapDefined(candidates, candidate => getAliasForSymbolInContainer(candidate, symbol) ? candidate : undefined); + return mapDefined( + candidates, + candidate => getAliasForSymbolInContainer(candidate, symbol) ? candidate : undefined, + ); function fileSymbolIfFileSymbolExportEqualsContainer(d: Declaration) { return container && getFileSymbolIfFileSymbolExportEqualsContainer(d, container); @@ -4311,8 +5535,13 @@ namespace ts { // from the symbol of the declaration it is being assigned to. Since we can use the declaration to refer to the literal, however, // we'd like to make that connection here - potentially causing us to paint the declaration's visibility, and therefore the literal. const firstDecl: Node | false = !!length(symbol.declarations) && first(symbol.declarations!); - if (meaning & SymbolFlags.Value && firstDecl && firstDecl.parent && isVariableDeclaration(firstDecl.parent)) { - if (isObjectLiteralExpression(firstDecl) && firstDecl === firstDecl.parent.initializer || isTypeLiteralNode(firstDecl) && firstDecl === firstDecl.parent.type) { + if ( + meaning & SymbolFlags.Value && firstDecl && firstDecl.parent && isVariableDeclaration(firstDecl.parent) + ) { + if ( + isObjectLiteralExpression(firstDecl) && firstDecl === firstDecl.parent.initializer + || isTypeLiteralNode(firstDecl) && firstDecl === firstDecl.parent.type + ) { return getSymbolOfNode(firstDecl.parent); } } @@ -4320,7 +5549,8 @@ namespace ts { function getFileSymbolIfFileSymbolExportEqualsContainer(d: Declaration, container: Symbol) { const fileSymbol = getExternalModuleContainer(d); - const exported = fileSymbol && fileSymbol.exports && fileSymbol.exports.get(InternalSymbolName.ExportEquals); + const exported = fileSymbol && fileSymbol.exports + && fileSymbol.exports.get(InternalSymbolName.ExportEquals); return exported && getSymbolIfSameReference(exported, container) ? fileSymbol : undefined; } @@ -4351,7 +5581,10 @@ namespace ts { * Checks if two symbols, through aliasing and/or merging, refer to the same thing */ function getSymbolIfSameReference(s1: Symbol, s2: Symbol) { - if (getMergedSymbol(resolveSymbol(getMergedSymbol(s1))) === getMergedSymbol(resolveSymbol(getMergedSymbol(s2)))) { + if ( + getMergedSymbol(resolveSymbol(getMergedSymbol(s1))) + === getMergedSymbol(resolveSymbol(getMergedSymbol(s2))) + ) { return s1; } } @@ -4359,13 +5592,16 @@ namespace ts { function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol; function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined; function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined { - return getMergedSymbol(symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0 && symbol.exportSymbol || symbol); + return getMergedSymbol( + symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0 && symbol.exportSymbol || symbol, + ); } function symbolIsValue(symbol: Symbol, includeTypeOnlyMembers?: boolean): boolean { return !!( - symbol.flags & SymbolFlags.Value || - symbol.flags & SymbolFlags.Alias && getAllSymbolFlags(symbol) & SymbolFlags.Value && (includeTypeOnlyMembers || !getTypeOnlyAliasDeclaration(symbol)) + symbol.flags & SymbolFlags.Value + || symbol.flags & SymbolFlags.Alias && getAllSymbolFlags(symbol) & SymbolFlags.Value + && (includeTypeOnlyMembers || !getTypeOnlyAliasDeclaration(symbol)) ); } @@ -4390,7 +5626,11 @@ namespace ts { return new Type(checker, flags); } - function createIntrinsicType(kind: TypeFlags, intrinsicName: string, objectFlags: ObjectFlags = 0): IntrinsicType { + function createIntrinsicType( + kind: TypeFlags, + intrinsicName: string, + objectFlags: ObjectFlags = 0, + ): IntrinsicType { const type = createType(kind) as IntrinsicType; type.intrinsicName = intrinsicName; type.objectFlags = objectFlags; @@ -4424,11 +5664,11 @@ namespace ts { // with at least two underscores. The @ character indicates that the name is denoted by a well known ES // Symbol instance and the # character indicates that the name is a PrivateIdentifier. function isReservedMemberName(name: __String) { - return (name as string).charCodeAt(0) === CharacterCodes._ && - (name as string).charCodeAt(1) === CharacterCodes._ && - (name as string).charCodeAt(2) !== CharacterCodes._ && - (name as string).charCodeAt(2) !== CharacterCodes.at && - (name as string).charCodeAt(2) !== CharacterCodes.hash; + return (name as string).charCodeAt(0) === CharacterCodes._ + && (name as string).charCodeAt(1) === CharacterCodes._ + && (name as string).charCodeAt(2) !== CharacterCodes._ + && (name as string).charCodeAt(2) !== CharacterCodes.at + && (name as string).charCodeAt(2) !== CharacterCodes.hash; } function getNamedMembers(members: SymbolTable): Symbol[] { @@ -4451,7 +5691,13 @@ namespace ts { return index ? concatenate(result, [index]) : result; } - function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], indexInfos: readonly IndexInfo[]): ResolvedType { + function setStructuredTypeMembers( + type: StructuredType, + members: SymbolTable, + callSignatures: readonly Signature[], + constructSignatures: readonly Signature[], + indexInfos: readonly IndexInfo[], + ): ResolvedType { const resolved = type as ResolvedType; resolved.members = members; resolved.properties = emptyArray; @@ -4463,14 +5709,31 @@ namespace ts { return resolved; } - function createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], indexInfos: readonly IndexInfo[]): ResolvedType { - return setStructuredTypeMembers(createObjectType(ObjectFlags.Anonymous, symbol), members, callSignatures, constructSignatures, indexInfos); + function createAnonymousType( + symbol: Symbol | undefined, + members: SymbolTable, + callSignatures: readonly Signature[], + constructSignatures: readonly Signature[], + indexInfos: readonly IndexInfo[], + ): ResolvedType { + return setStructuredTypeMembers( + createObjectType(ObjectFlags.Anonymous, symbol), + members, + callSignatures, + constructSignatures, + indexInfos, + ); } function getResolvedTypeWithoutAbstractConstructSignatures(type: ResolvedType) { if (type.constructSignatures.length === 0) return type; - if (type.objectTypeWithoutAbstractConstructSignatures) return type.objectTypeWithoutAbstractConstructSignatures; - const constructSignatures = filter(type.constructSignatures, signature => !(signature.flags & SignatureFlags.Abstract)); + if (type.objectTypeWithoutAbstractConstructSignatures) { + return type.objectTypeWithoutAbstractConstructSignatures; + } + const constructSignatures = filter( + type.constructSignatures, + signature => !(signature.flags & SignatureFlags.Abstract), + ); if (type.constructSignatures === constructSignatures) return type; const typeCopy = createAnonymousType( type.symbol, @@ -4484,12 +5747,27 @@ namespace ts { return typeCopy; } - function forEachSymbolTableInScope(enclosingDeclaration: Node | undefined, callback: (symbolTable: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean, scopeNode?: Node) => T): T { + function forEachSymbolTableInScope( + enclosingDeclaration: Node | undefined, + callback: ( + symbolTable: SymbolTable, + ignoreQualification?: boolean, + isLocalNameLookup?: boolean, + scopeNode?: Node, + ) => T, + ): T { let result: T; for (let location = enclosingDeclaration; location; location = location.parent) { // Locals of a source file are not in scope (because they get merged into the global symbol table) if (location.locals && !isGlobalSourceFile(location)) { - if (result = callback(location.locals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) { + if ( + result = callback( + location.locals, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ true, + location, + ) + ) { return result; } } @@ -4504,7 +5782,14 @@ namespace ts { // `sym` may not have exports if this module declaration is backed by the symbol for a `const` that's being rewritten // into a namespace - in such cases, it's best to just let the namespace appear empty (the const members couldn't have referred // to one another anyway) - if (result = callback(sym?.exports || emptySymbols, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) { + if ( + result = callback( + sym?.exports || emptySymbols, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ true, + location, + ) + ) { return result; } break; @@ -4520,12 +5805,21 @@ namespace ts { // trigger resolving late-bound names, which we may already be in the process of doing while we're here! let table: UnderscoreEscapedMap | undefined; // TODO: Should this filtered table be cached in some way? - (getSymbolOfNode(location as ClassLikeDeclaration | InterfaceDeclaration).members || emptySymbols).forEach((memberSymbol, key) => { - if (memberSymbol.flags & (SymbolFlags.Type & ~SymbolFlags.Assignment)) { - (table || (table = createSymbolTable())).set(key, memberSymbol); - } - }); - if (table && (result = callback(table, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ false, location))) { + (getSymbolOfNode(location as ClassLikeDeclaration | InterfaceDeclaration).members + || emptySymbols).forEach((memberSymbol, key) => { + if (memberSymbol.flags & (SymbolFlags.Type & ~SymbolFlags.Assignment)) { + (table || (table = createSymbolTable())).set(key, memberSymbol); + } + }); + if ( + table + && (result = callback( + table, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ false, + location, + )) + ) { return result; } break; @@ -4540,7 +5834,13 @@ namespace ts { return rightMeaning === SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.Namespace; } - function getAccessibleSymbolChain(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean, visitedSymbolTablesMap: ESMap = new Map()): Symbol[] | undefined { + function getAccessibleSymbolChain( + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + useOnlyExternalAliasing: boolean, + visitedSymbolTablesMap: ESMap = new Map(), + ): Symbol[] | undefined { if (!(symbol && !isPropertyOrMethodDeclarationSymbol(symbol))) { return undefined; } @@ -4548,7 +5848,9 @@ namespace ts { const cache = (links.accessibleChainCache ||= new Map()); // Go from enclosingDeclaration to the first scope we check, so the cache is keyed off the scope and thus shared more const firstRelevantLocation = forEachSymbolTableInScope(enclosingDeclaration, (_, __, ___, node) => node); - const key = `${useOnlyExternalAliasing ? 0 : 1}|${firstRelevantLocation && getNodeId(firstRelevantLocation)}|${meaning}`; + const key = `${useOnlyExternalAliasing ? 0 : 1}|${ + firstRelevantLocation && getNodeId(firstRelevantLocation) + }|${meaning}`; if (cache.has(key)) { return cache.get(key); } @@ -4565,7 +5867,11 @@ namespace ts { /** * @param {ignoreQualification} boolean Set when a symbol is being looked for through the exports of another symbol (meaning we have a route to qualify it already) */ - function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean): Symbol[] | undefined { + function getAccessibleSymbolChainFromSymbolTable( + symbols: SymbolTable, + ignoreQualification?: boolean, + isLocalNameLookup?: boolean, + ): Symbol[] | undefined { if (!pushIfUnique(visitedSymbolTables!, symbols)) { return undefined; } @@ -4577,23 +5883,44 @@ namespace ts { function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) { // If the symbol is equivalent and doesn't need further qualification, this symbol is accessible - return !needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning) || + return !needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning) // If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too - !!getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing, visitedSymbolTablesMap); + || !!getAccessibleSymbolChain( + symbolFromSymbolTable.parent, + enclosingDeclaration, + getQualifiedLeftMeaning(meaning), + useOnlyExternalAliasing, + visitedSymbolTablesMap, + ); } - function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol, ignoreQualification?: boolean) { - return (symbol === (resolvedAliasSymbol || symbolFromSymbolTable) || getMergedSymbol(symbol) === getMergedSymbol(resolvedAliasSymbol || symbolFromSymbolTable)) && + function isAccessible( + symbolFromSymbolTable: Symbol, + resolvedAliasSymbol?: Symbol, + ignoreQualification?: boolean, + ) { + return (symbol === (resolvedAliasSymbol || symbolFromSymbolTable) + || getMergedSymbol(symbol) === getMergedSymbol(resolvedAliasSymbol || symbolFromSymbolTable)) // if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table) // and if symbolFromSymbolTable or alias resolution matches the symbol, // check the symbol can be qualified, it is only then this symbol is accessible - !some(symbolFromSymbolTable.declarations, hasNonGlobalAugmentationExternalModuleSymbol) && - (ignoreQualification || canQualifySymbol(getMergedSymbol(symbolFromSymbolTable), meaning)); + && !some(symbolFromSymbolTable.declarations, hasNonGlobalAugmentationExternalModuleSymbol) + && (ignoreQualification || canQualifySymbol(getMergedSymbol(symbolFromSymbolTable), meaning)); } - function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined, isLocalNameLookup: boolean | undefined): Symbol[] | undefined { + function trySymbolTable( + symbols: SymbolTable, + ignoreQualification: boolean | undefined, + isLocalNameLookup: boolean | undefined, + ): Symbol[] | undefined { // If symbol is directly available by its name in the symbol table - if (isAccessible(symbols.get(symbol!.escapedName)!, /*resolvedAliasSymbol*/ undefined, ignoreQualification)) { + if ( + isAccessible( + symbols.get(symbol!.escapedName)!, + /*resolvedAliasSymbol*/ undefined, + ignoreQualification, + ) + ) { return [symbol!]; } @@ -4603,33 +5930,56 @@ namespace ts { symbolFromSymbolTable.flags & SymbolFlags.Alias && symbolFromSymbolTable.escapedName !== InternalSymbolName.ExportEquals && symbolFromSymbolTable.escapedName !== InternalSymbolName.Default - && !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration && isExternalModule(getSourceFileOfNode(enclosingDeclaration))) + && !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration + && isExternalModule(getSourceFileOfNode(enclosingDeclaration))) // If `!useOnlyExternalAliasing`, we can use any type of alias to get the name - && (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) + && (!useOnlyExternalAliasing + || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) // If we're looking up a local name to reference directly, omit namespace reexports, otherwise when we're trawling through an export list to make a dotted name, we can keep it - && (isLocalNameLookup ? !some(symbolFromSymbolTable.declarations, isNamespaceReexportDeclaration) : true) + && (isLocalNameLookup + ? !some(symbolFromSymbolTable.declarations, isNamespaceReexportDeclaration) : true) // While exports are generally considered to be in scope, export-specifier declared symbols are _not_ // See similar comment in `resolveName` for details - && (ignoreQualification || !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) + && (ignoreQualification + || !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) ) { const resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable); - const candidate = getCandidateListForSymbol(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification); + const candidate = getCandidateListForSymbol( + symbolFromSymbolTable, + resolvedImportedSymbol, + ignoreQualification, + ); if (candidate) { return candidate; } } - if (symbolFromSymbolTable.escapedName === symbol!.escapedName && symbolFromSymbolTable.exportSymbol) { - if (isAccessible(getMergedSymbol(symbolFromSymbolTable.exportSymbol), /*aliasSymbol*/ undefined, ignoreQualification)) { + if ( + symbolFromSymbolTable.escapedName === symbol!.escapedName && symbolFromSymbolTable.exportSymbol + ) { + if ( + isAccessible( + getMergedSymbol(symbolFromSymbolTable.exportSymbol), + /*aliasSymbol*/ undefined, + ignoreQualification, + ) + ) { return [symbol!]; } } }); // If there's no result and we're looking at the global symbol table, treat `globalThis` like an alias and try to lookup thru that - return result || (symbols === globals ? getCandidateListForSymbol(globalThisSymbol, globalThisSymbol, ignoreQualification) : undefined); + return result + || (symbols === globals + ? getCandidateListForSymbol(globalThisSymbol, globalThisSymbol, ignoreQualification) + : undefined); } - function getCandidateListForSymbol(symbolFromSymbolTable: Symbol, resolvedImportedSymbol: Symbol, ignoreQualification: boolean | undefined) { + function getCandidateListForSymbol( + symbolFromSymbolTable: Symbol, + resolvedImportedSymbol: Symbol, + ignoreQualification: boolean | undefined, + ) { if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification)) { return [symbolFromSymbolTable]; } @@ -4637,8 +5987,12 @@ namespace ts { // Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain // but only if the symbolFromSymbolTable can be qualified const candidateTable = getExportsOfSymbol(resolvedImportedSymbol); - const accessibleSymbolsFromExports = candidateTable && getAccessibleSymbolChainFromSymbolTable(candidateTable, /*ignoreQualification*/ true); - if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) { + const accessibleSymbolsFromExports = candidateTable + && getAccessibleSymbolChainFromSymbolTable(candidateTable, /*ignoreQualification*/ true); + if ( + accessibleSymbolsFromExports + && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning)) + ) { return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports); } } @@ -4660,9 +6014,12 @@ namespace ts { } // Qualify if the symbol from symbol table has same meaning as expected - const shouldResolveAlias = (symbolFromSymbolTable.flags & SymbolFlags.Alias && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)); - symbolFromSymbolTable = shouldResolveAlias ? resolveAlias(symbolFromSymbolTable) : symbolFromSymbolTable; - const flags = shouldResolveAlias ? getAllSymbolFlags(symbolFromSymbolTable) : symbolFromSymbolTable.flags; + const shouldResolveAlias = (symbolFromSymbolTable.flags & SymbolFlags.Alias + && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)); + symbolFromSymbolTable = shouldResolveAlias ? resolveAlias(symbolFromSymbolTable) + : symbolFromSymbolTable; + const flags = shouldResolveAlias ? getAllSymbolFlags(symbolFromSymbolTable) + : symbolFromSymbolTable.flags; if (flags & meaning) { qualify = true; return true; @@ -4694,31 +6051,68 @@ namespace ts { } function isTypeSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node | undefined): boolean { - const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ true); + const access = isSymbolAccessibleWorker( + typeSymbol, + enclosingDeclaration, + SymbolFlags.Type, + /*shouldComputeAliasesToMakeVisible*/ false, + /*allowModules*/ true, + ); return access.accessibility === SymbolAccessibility.Accessible; } function isValueSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node | undefined): boolean { - const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, SymbolFlags.Value, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ true); + const access = isSymbolAccessibleWorker( + typeSymbol, + enclosingDeclaration, + SymbolFlags.Value, + /*shouldComputeAliasesToMakeVisible*/ false, + /*allowModules*/ true, + ); return access.accessibility === SymbolAccessibility.Accessible; } - function isSymbolAccessibleByFlags(typeSymbol: Symbol, enclosingDeclaration: Node | undefined, flags: SymbolFlags): boolean { - const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, flags, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ false); + function isSymbolAccessibleByFlags( + typeSymbol: Symbol, + enclosingDeclaration: Node | undefined, + flags: SymbolFlags, + ): boolean { + const access = isSymbolAccessibleWorker( + typeSymbol, + enclosingDeclaration, + flags, + /*shouldComputeAliasesToMakeVisible*/ false, + /*allowModules*/ false, + ); return access.accessibility === SymbolAccessibility.Accessible; } - function isAnySymbolAccessible(symbols: Symbol[] | undefined, enclosingDeclaration: Node | undefined, initialSymbol: Symbol, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, allowModules: boolean): SymbolAccessibilityResult | undefined { + function isAnySymbolAccessible( + symbols: Symbol[] | undefined, + enclosingDeclaration: Node | undefined, + initialSymbol: Symbol, + meaning: SymbolFlags, + shouldComputeAliasesToMakeVisible: boolean, + allowModules: boolean, + ): SymbolAccessibilityResult | undefined { if (!length(symbols)) return; let hadAccessibleChain: Symbol | undefined; let earlyModuleBail = false; for (const symbol of symbols!) { // Symbol is accessible if it by itself is accessible - const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/ false); + const accessibleSymbolChain = getAccessibleSymbolChain( + symbol, + enclosingDeclaration, + meaning, + /*useOnlyExternalAliasing*/ false, + ); if (accessibleSymbolChain) { hadAccessibleChain = symbol; - const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible); + const hasAccessibleDeclarations = hasVisibleDeclarations( + accessibleSymbolChain[0], + shouldComputeAliasesToMakeVisible, + ); if (hasAccessibleDeclarations) { return hasAccessibleDeclarations; } @@ -4754,7 +6148,14 @@ namespace ts { // It is accessible if the parent m is accessible because then m.c can be accessed through qualification const containers = getContainersOfSymbol(symbol, enclosingDeclaration, meaning); - const parentResult = isAnySymbolAccessible(containers, enclosingDeclaration, initialSymbol, initialSymbol === symbol ? getQualifiedLeftMeaning(meaning) : meaning, shouldComputeAliasesToMakeVisible, allowModules); + const parentResult = isAnySymbolAccessible( + containers, + enclosingDeclaration, + initialSymbol, + initialSymbol === symbol ? getQualifiedLeftMeaning(meaning) : meaning, + shouldComputeAliasesToMakeVisible, + allowModules, + ); if (parentResult) { return parentResult; } @@ -4770,7 +6171,8 @@ namespace ts { return { accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), - errorModuleName: hadAccessibleChain !== initialSymbol ? symbolToString(hadAccessibleChain, enclosingDeclaration, SymbolFlags.Namespace) : undefined, + errorModuleName: hadAccessibleChain !== initialSymbol + ? symbolToString(hadAccessibleChain, enclosingDeclaration, SymbolFlags.Namespace) : undefined, }; } } @@ -4783,13 +6185,37 @@ namespace ts { * @param meaning a SymbolFlags to check if such meaning of the symbol is accessible * @param shouldComputeAliasToMakeVisible a boolean value to indicate whether to return aliases to be mark visible in case the symbol is accessible */ - function isSymbolAccessible(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult { - return isSymbolAccessibleWorker(symbol, enclosingDeclaration, meaning, shouldComputeAliasesToMakeVisible, /*allowModules*/ true); + function isSymbolAccessible( + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + shouldComputeAliasesToMakeVisible: boolean, + ): SymbolAccessibilityResult { + return isSymbolAccessibleWorker( + symbol, + enclosingDeclaration, + meaning, + shouldComputeAliasesToMakeVisible, + /*allowModules*/ true, + ); } - function isSymbolAccessibleWorker(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, allowModules: boolean): SymbolAccessibilityResult { + function isSymbolAccessibleWorker( + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + shouldComputeAliasesToMakeVisible: boolean, + allowModules: boolean, + ): SymbolAccessibilityResult { if (symbol && enclosingDeclaration) { - const result = isAnySymbolAccessible([symbol], enclosingDeclaration, symbol, meaning, shouldComputeAliasesToMakeVisible, allowModules); + const result = isAnySymbolAccessible( + [symbol], + enclosingDeclaration, + symbol, + meaning, + shouldComputeAliasesToMakeVisible, + allowModules, + ); if (result) { return result; } @@ -4826,14 +6252,21 @@ namespace ts { } function hasExternalModuleSymbol(declaration: Node) { - return isAmbientModule(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); + return isAmbientModule(declaration) + || (declaration.kind === SyntaxKind.SourceFile + && isExternalOrCommonJsModule(declaration as SourceFile)); } function hasNonGlobalAugmentationExternalModuleSymbol(declaration: Node) { - return isModuleWithStringLiteralName(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); + return isModuleWithStringLiteralName(declaration) + || (declaration.kind === SyntaxKind.SourceFile + && isExternalOrCommonJsModule(declaration as SourceFile)); } - function hasVisibleDeclarations(symbol: Symbol, shouldComputeAliasToMakeVisible: boolean): SymbolVisibilityResult | undefined { + function hasVisibleDeclarations( + symbol: Symbol, + shouldComputeAliasToMakeVisible: boolean, + ): SymbolVisibilityResult | undefined { let aliasesToMakeVisible: LateVisibilityPaintedStatement[] | undefined; if (!every(filter(symbol.declarations, d => d.kind !== SyntaxKind.Identifier), getIsDeclarationVisible)) { return undefined; @@ -4847,16 +6280,16 @@ namespace ts { const anyImportSyntax = getAnyImportSyntax(declaration); if ( - anyImportSyntax && - !hasSyntacticModifier(anyImportSyntax, ModifierFlags.Export) && // import clause without export - isDeclarationVisible(anyImportSyntax.parent) + anyImportSyntax + && !hasSyntacticModifier(anyImportSyntax, ModifierFlags.Export) // import clause without export + && isDeclarationVisible(anyImportSyntax.parent) ) { return addVisibleAlias(declaration, anyImportSyntax); } else if ( - isVariableDeclaration(declaration) && isVariableStatement(declaration.parent.parent) && - !hasSyntacticModifier(declaration.parent.parent, ModifierFlags.Export) && // unexported variable statement - isDeclarationVisible(declaration.parent.parent.parent) + isVariableDeclaration(declaration) && isVariableStatement(declaration.parent.parent) + && !hasSyntacticModifier(declaration.parent.parent, ModifierFlags.Export) // unexported variable statement + && isDeclarationVisible(declaration.parent.parent.parent) ) { return addVisibleAlias(declaration, declaration.parent.parent); } @@ -4871,7 +6304,8 @@ namespace ts { if ( symbol.flags & SymbolFlags.Alias && isInJSFile(declaration) && declaration.parent?.parent // exported import-like top-level JS require statement && isVariableDeclaration(declaration.parent.parent) - && declaration.parent.parent.parent?.parent && isVariableStatement(declaration.parent.parent.parent.parent) + && declaration.parent.parent.parent?.parent + && isVariableStatement(declaration.parent.parent.parent.parent) && !hasSyntacticModifier(declaration.parent.parent.parent.parent, ModifierFlags.Export) && declaration.parent.parent.parent.parent.parent // check if the thing containing the variable statement is visible (ie, the file) && isDeclarationVisible(declaration.parent.parent.parent.parent.parent) @@ -4909,20 +6343,24 @@ namespace ts { } } - function isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult { + function isEntityNameVisible( + entityName: EntityNameOrEntityNameExpression, + enclosingDeclaration: Node, + ): SymbolVisibilityResult { // get symbol of the first identifier of the entityName let meaning: SymbolFlags; if ( - entityName.parent.kind === SyntaxKind.TypeQuery || - entityName.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isPartOfTypeNode(entityName.parent) || - entityName.parent.kind === SyntaxKind.ComputedPropertyName + entityName.parent.kind === SyntaxKind.TypeQuery + || entityName.parent.kind === SyntaxKind.ExpressionWithTypeArguments + && !isPartOfTypeNode(entityName.parent) + || entityName.parent.kind === SyntaxKind.ComputedPropertyName ) { // Typeof value meaning = SymbolFlags.Value | SymbolFlags.ExportValue; } else if ( - entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression || - entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration + entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression + || entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration ) { // Left identifier from type reference or TypeAlias // Entity name of the import declaration @@ -4934,11 +6372,26 @@ namespace ts { } const firstIdentifier = getFirstIdentifier(entityName); - const symbol = resolveName(enclosingDeclaration, firstIdentifier.escapedText, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); + const symbol = resolveName( + enclosingDeclaration, + firstIdentifier.escapedText, + meaning, + /*nodeNotFoundErrorMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ); if (symbol && symbol.flags & SymbolFlags.TypeParameter && meaning & SymbolFlags.Type) { return { accessibility: SymbolAccessibility.Accessible }; } - if (!symbol && isThisIdentifier(firstIdentifier) && isSymbolAccessible(getSymbolOfNode(getThisContainer(firstIdentifier, /*includeArrowFunctions*/ false)), firstIdentifier, meaning, /*computeAliases*/ false).accessibility === SymbolAccessibility.Accessible) { + if ( + !symbol && isThisIdentifier(firstIdentifier) + && isSymbolAccessible( + getSymbolOfNode(getThisContainer(firstIdentifier, /*includeArrowFunctions*/ false)), + firstIdentifier, + meaning, + /*computeAliases*/ false, + ).accessibility === SymbolAccessibility.Accessible + ) { return { accessibility: SymbolAccessibility.Accessible }; } @@ -4950,7 +6403,13 @@ namespace ts { }; } - function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, writer?: EmitTextWriter): string { + function symbolToString( + symbol: Symbol, + enclosingDeclaration?: Node, + meaning?: SymbolFlags, + flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, + writer?: EmitTextWriter, + ): string { let nodeFlags = NodeBuilderFlags.IgnoreErrors; if (flags & SymbolFormatFlags.UseOnlyExternalAliasing) { nodeFlags |= NodeBuilderFlags.UseOnlyExternalAliasing; @@ -4967,21 +6426,31 @@ namespace ts { if (flags & SymbolFormatFlags.WriteComputedProps) { nodeFlags |= NodeBuilderFlags.WriteComputedProps; } - const builder = flags & SymbolFormatFlags.AllowAnyNodeKind ? nodeBuilder.symbolToNode : nodeBuilder.symbolToEntityName; + const builder = flags & SymbolFormatFlags.AllowAnyNodeKind ? nodeBuilder.symbolToNode + : nodeBuilder.symbolToEntityName; return writer ? symbolToStringWorker(writer).getText() : usingSingleLineStringWriter(symbolToStringWorker); function symbolToStringWorker(writer: EmitTextWriter) { const entity = builder(symbol, meaning!, enclosingDeclaration, nodeFlags)!; // TODO: GH#18217 // add neverAsciiEscape for GH#39027 - const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile ? createPrinter({ removeComments: true, neverAsciiEscape: true }) : createPrinter({ removeComments: true }); + const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile + ? createPrinter({ removeComments: true, neverAsciiEscape: true }) + : createPrinter({ removeComments: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); return writer; } } - function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags = TypeFormatFlags.None, kind?: SignatureKind, writer?: EmitTextWriter): string { - return writer ? signatureToStringWorker(writer).getText() : usingSingleLineStringWriter(signatureToStringWorker); + function signatureToString( + signature: Signature, + enclosingDeclaration?: Node, + flags = TypeFormatFlags.None, + kind?: SignatureKind, + writer?: EmitTextWriter, + ): string { + return writer ? signatureToStringWorker(writer).getText() + : usingSingleLineStringWriter(signatureToStringWorker); function signatureToStringWorker(writer: EmitTextWriter) { let sigOutput: SyntaxKind; @@ -4989,19 +6458,43 @@ namespace ts { sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructorType : SyntaxKind.FunctionType; } else { - sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructSignature : SyntaxKind.CallSignature; + sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructSignature + : SyntaxKind.CallSignature; } - const sig = nodeBuilder.signatureToSignatureDeclaration(signature, sigOutput, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); + const sig = nodeBuilder.signatureToSignatureDeclaration( + signature, + sigOutput, + enclosingDeclaration, + toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors + | NodeBuilderFlags.WriteTypeParametersInQualifiedName, + ); const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); - printer.writeNode(EmitHint.Unspecified, sig!, /*sourceFile*/ sourceFile, getTrailingSemicolonDeferringWriter(writer)); // TODO: GH#18217 + printer.writeNode( + EmitHint.Unspecified, + sig!, + /*sourceFile*/ sourceFile, + getTrailingSemicolonDeferringWriter(writer), + ); // TODO: GH#18217 return writer; } } - function typeToString(type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer: EmitTextWriter = createTextWriter("")): string { + function typeToString( + type: Type, + enclosingDeclaration?: Node, + flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType + | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, + writer: EmitTextWriter = createTextWriter(""), + ): string { const noTruncation = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation; - const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | (noTruncation ? NodeBuilderFlags.NoTruncation : 0), writer); + const typeNode = nodeBuilder.typeToTypeNode( + type, + enclosingDeclaration, + toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors + | (noTruncation ? NodeBuilderFlags.NoTruncation : 0), + writer, + ); if (typeNode === undefined) return Debug.fail("should always get typenode"); // The unresolved type gets a synthesized comment on `any` to hint to users that it's not a plain `any`. // Otherwise, we always strip comments out. @@ -5011,7 +6504,8 @@ namespace ts { printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer); const result = writer.getText(); - const maxLength = noTruncation ? noTruncationMaximumTruncationLength * 2 : defaultMaximumTruncationLength * 2; + const maxLength = noTruncation ? noTruncationMaximumTruncationLength * 2 + : defaultMaximumTruncationLength * 2; if (maxLength && result && result.length >= maxLength) { return result.substr(0, maxLength - "...".length) + "..."; } @@ -5019,8 +6513,10 @@ namespace ts { } function getTypeNamesForErrorDisplay(left: Type, right: Type): [string, string] { - let leftStr = symbolValueDeclarationIsContextSensitive(left.symbol) ? typeToString(left, left.symbol.valueDeclaration) : typeToString(left); - let rightStr = symbolValueDeclarationIsContextSensitive(right.symbol) ? typeToString(right, right.symbol.valueDeclaration) : typeToString(right); + let leftStr = symbolValueDeclarationIsContextSensitive(left.symbol) + ? typeToString(left, left.symbol.valueDeclaration) : typeToString(left); + let rightStr = symbolValueDeclarationIsContextSensitive(right.symbol) + ? typeToString(right, right.symbol.valueDeclaration) : typeToString(right); if (leftStr === rightStr) { leftStr = getTypeNameForErrorDisplay(left); rightStr = getTypeNameForErrorDisplay(right); @@ -5033,7 +6529,8 @@ namespace ts { } function symbolValueDeclarationIsContextSensitive(symbol: Symbol): boolean { - return symbol && !!symbol.valueDeclaration && isExpression(symbol.valueDeclaration) && !isContextSensitive(symbol.valueDeclaration); + return symbol && !!symbol.valueDeclaration && isExpression(symbol.valueDeclaration) + && !isContextSensitive(symbol.valueDeclaration); } function toNodeBuilderFlags(flags = TypeFormatFlags.None): NodeBuilderFlags { @@ -5041,21 +6538,124 @@ namespace ts { } function isClassInstanceSide(type: Type) { - return !!type.symbol && !!(type.symbol.flags & SymbolFlags.Class) && (type === getDeclaredTypeOfClassOrInterface(type.symbol) || (!!(type.flags & TypeFlags.Object) && !!(getObjectFlags(type) & ObjectFlags.IsClassInstanceClone))); + return !!type.symbol && !!(type.symbol.flags & SymbolFlags.Class) + && (type === getDeclaredTypeOfClassOrInterface(type.symbol) + || (!!(type.flags & TypeFlags.Object) + && !!(getObjectFlags(type) & ObjectFlags.IsClassInstanceClone))); } function createNodeBuilder() { return { - typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)), - indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => indexInfoToIndexSignatureDeclarationHelper(indexInfo, context, /*typeNode*/ undefined)), - signatureToSignatureDeclaration: (signature: Signature, kind: SignatureDeclaration["kind"], enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => signatureToSignatureDeclarationHelper(signature, kind, context)), - symbolToEntityName: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => symbolToName(symbol, context, meaning, /*expectsIdentifier*/ false)), - symbolToExpression: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => symbolToExpression(symbol, context, meaning)), - symbolToTypeParameterDeclarations: (symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => typeParametersToTypeParameterDeclarations(symbol, context)), - symbolToParameterDeclaration: (symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => symbolToParameterDeclaration(symbol, context)), - typeParameterToDeclaration: (parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => typeParameterToDeclaration(parameter, context)), - symbolTableToDeclarationStatements: (symbolTable: SymbolTable, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker, bundled?: boolean) => withContext(enclosingDeclaration, flags, tracker, context => symbolTableToDeclarationStatements(symbolTable, context, bundled)), - symbolToNode: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => withContext(enclosingDeclaration, flags, tracker, context => symbolToNode(symbol, context, meaning)), + typeToTypeNode: ( + type: Type, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)), + indexInfoToIndexSignatureDeclaration: ( + indexInfo: IndexInfo, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => indexInfoToIndexSignatureDeclarationHelper(indexInfo, context, /*typeNode*/ undefined), + ), + signatureToSignatureDeclaration: ( + signature: Signature, + kind: SignatureDeclaration["kind"], + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => signatureToSignatureDeclarationHelper(signature, kind, context), + ), + symbolToEntityName: ( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => symbolToName(symbol, context, meaning, /*expectsIdentifier*/ false), + ), + symbolToExpression: ( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => symbolToExpression(symbol, context, meaning), + ), + symbolToTypeParameterDeclarations: ( + symbol: Symbol, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => typeParametersToTypeParameterDeclarations(symbol, context), + ), + symbolToParameterDeclaration: ( + symbol: Symbol, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => symbolToParameterDeclaration(symbol, context), + ), + typeParameterToDeclaration: ( + parameter: TypeParameter, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => typeParameterToDeclaration(parameter, context), + ), + symbolTableToDeclarationStatements: ( + symbolTable: SymbolTable, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + bundled?: boolean, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => symbolTableToDeclarationStatements(symbolTable, context, bundled), + ), + symbolToNode: ( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => symbolToNode(symbol, context, meaning), + ), }; function symbolToNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags) { @@ -5067,14 +6667,23 @@ namespace ts { const nameType = getSymbolLinks(symbol).nameType; if (nameType && nameType.flags & (TypeFlags.EnumLiteral | TypeFlags.UniqueESSymbol)) { context.enclosingDeclaration = nameType.symbol.valueDeclaration; - return factory.createComputedPropertyName(symbolToExpression(nameType.symbol, context, meaning)); + return factory.createComputedPropertyName( + symbolToExpression(nameType.symbol, context, meaning), + ); } } return symbolToExpression(symbol, context, meaning); } - function withContext(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker: SymbolTracker | undefined, cb: (context: NodeBuilderContext) => T): T | undefined { - Debug.assert(enclosingDeclaration === undefined || (enclosingDeclaration.flags & NodeFlags.Synthesized) === 0); + function withContext( + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + tracker: SymbolTracker | undefined, + cb: (context: NodeBuilderContext) => T, + ): T | undefined { + Debug.assert( + enclosingDeclaration === undefined || (enclosingDeclaration.flags & NodeFlags.Synthesized) === 0, + ); const context: NodeBuilderContext = { enclosingDeclaration, flags: flags || NodeBuilderFlags.None, @@ -5082,14 +6691,16 @@ namespace ts { tracker: tracker && tracker.trackSymbol ? tracker : { trackSymbol: () => false, moduleResolverHost: flags! & NodeBuilderFlags.DoNotIncludeSymbolChain ? { - getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory ? () => (host as Program).getCommonSourceDirectory() : () => "", + getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory + ? () => (host as Program).getCommonSourceDirectory() : () => "", getCurrentDirectory: () => host.getCurrentDirectory(), getSymlinkCache: maybeBind(host, host.getSymlinkCache), getPackageJsonInfoCache: () => host.getPackageJsonInfoCache?.(), useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames), redirectTargetsMap: host.redirectTargetsMap, getProjectReferenceRedirect: fileName => host.getProjectReferenceRedirect(fileName), - isSourceOfProjectReferenceRedirect: fileName => host.isSourceOfProjectReferenceRedirect(fileName), + isSourceOfProjectReferenceRedirect: fileName => + host.isSourceOfProjectReferenceRedirect(fileName), fileExists: fileName => host.fileExists(fileName), getFileIncludeReasons: () => host.getFileIncludeReasons(), readFile: host.readFile ? (fileName => host.readFile!(fileName)) : undefined, @@ -5110,16 +6721,25 @@ namespace ts { return context.encounteredError ? undefined : resultingNode; } - function wrapSymbolTrackerToReportForContext(context: NodeBuilderContext, tracker: SymbolTracker): SymbolTracker { + function wrapSymbolTrackerToReportForContext( + context: NodeBuilderContext, + tracker: SymbolTracker, + ): SymbolTracker { const oldTrackSymbol = tracker.trackSymbol; return { ...tracker, reportCyclicStructureError: wrapReportedDiagnostic(tracker.reportCyclicStructureError), reportInaccessibleThisError: wrapReportedDiagnostic(tracker.reportInaccessibleThisError), - reportInaccessibleUniqueSymbolError: wrapReportedDiagnostic(tracker.reportInaccessibleUniqueSymbolError), - reportLikelyUnsafeImportRequiredError: wrapReportedDiagnostic(tracker.reportLikelyUnsafeImportRequiredError), + reportInaccessibleUniqueSymbolError: wrapReportedDiagnostic( + tracker.reportInaccessibleUniqueSymbolError, + ), + reportLikelyUnsafeImportRequiredError: wrapReportedDiagnostic( + tracker.reportLikelyUnsafeImportRequiredError, + ), reportNonlocalAugmentation: wrapReportedDiagnostic(tracker.reportNonlocalAugmentation), - reportPrivateInBaseOfClassExpression: wrapReportedDiagnostic(tracker.reportPrivateInBaseOfClassExpression), + reportPrivateInBaseOfClassExpression: wrapReportedDiagnostic( + tracker.reportPrivateInBaseOfClassExpression, + ), reportNonSerializableProperty: wrapReportedDiagnostic(tracker.reportNonSerializableProperty), trackSymbol: oldTrackSymbol && ((...args) => { const result = oldTrackSymbol(...args); @@ -5130,7 +6750,9 @@ namespace ts { }), }; - function wrapReportedDiagnostic any>(method: T | undefined): T | undefined { + function wrapReportedDiagnostic any>( + method: T | undefined, + ): T | undefined { if (!method) { return method; } @@ -5143,7 +6765,9 @@ namespace ts { function checkTruncationLength(context: NodeBuilderContext): boolean { if (context.truncating) return context.truncating; - return context.truncating = context.approximateLength > ((context.flags & NodeBuilderFlags.NoTruncation) ? noTruncationMaximumTruncationLength : defaultMaximumTruncationLength); + return context.truncating = context.approximateLength + > ((context.flags & NodeBuilderFlags.NoTruncation) ? noTruncationMaximumTruncationLength + : defaultMaximumTruncationLength); } function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { @@ -5175,13 +6799,22 @@ namespace ts { if (type.flags & TypeFlags.Any) { if (type.aliasSymbol) { - return factory.createTypeReferenceNode(symbolToEntityNameNode(type.aliasSymbol), mapToTypeNodes(type.aliasTypeArguments, context)); + return factory.createTypeReferenceNode( + symbolToEntityNameNode(type.aliasSymbol), + mapToTypeNodes(type.aliasTypeArguments, context), + ); } if (type === unresolvedType) { - return addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, "unresolved"); + return addSyntheticLeadingComment( + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + SyntaxKind.MultiLineCommentTrivia, + "unresolved", + ); } context.approximateLength += 3; - return factory.createKeywordTypeNode(type === intrinsicMarkerType ? SyntaxKind.IntrinsicKeyword : SyntaxKind.AnyKeyword); + return factory.createKeywordTypeNode( + type === intrinsicMarkerType ? SyntaxKind.IntrinsicKeyword : SyntaxKind.AnyKeyword, + ); } if (type.flags & TypeFlags.Unknown) { return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword); @@ -5217,10 +6850,16 @@ namespace ts { } if (isImportTypeNode(parentName)) { (parentName as any).isTypeOf = true; // mutably update, node is freshly manufactured anyhow - return factory.createIndexedAccessTypeNode(parentName, factory.createLiteralTypeNode(factory.createStringLiteral(memberName))); + return factory.createIndexedAccessTypeNode( + parentName, + factory.createLiteralTypeNode(factory.createStringLiteral(memberName)), + ); } else if (isTypeReferenceNode(parentName)) { - return factory.createIndexedAccessTypeNode(factory.createTypeQueryNode(parentName.typeName), factory.createLiteralTypeNode(factory.createStringLiteral(memberName))); + return factory.createIndexedAccessTypeNode( + factory.createTypeQueryNode(parentName.typeName), + factory.createLiteralTypeNode(factory.createStringLiteral(memberName)), + ); } else { return Debug.fail("Unhandled type node kind returned from `symbolToTypeNode`."); @@ -5231,20 +6870,38 @@ namespace ts { } if (type.flags & TypeFlags.StringLiteral) { context.approximateLength += (type as StringLiteralType).value.length + 2; - return factory.createLiteralTypeNode(setEmitFlags(factory.createStringLiteral((type as StringLiteralType).value, !!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType)), EmitFlags.NoAsciiEscaping)); + return factory.createLiteralTypeNode( + setEmitFlags( + factory.createStringLiteral( + (type as StringLiteralType).value, + !!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType), + ), + EmitFlags.NoAsciiEscaping, + ), + ); } if (type.flags & TypeFlags.NumberLiteral) { const value = (type as NumberLiteralType).value; context.approximateLength += ("" + value).length; - return factory.createLiteralTypeNode(value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(-value)) : factory.createNumericLiteral(value)); + return factory.createLiteralTypeNode( + value < 0 + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(-value), + ) : factory.createNumericLiteral(value), + ); } if (type.flags & TypeFlags.BigIntLiteral) { context.approximateLength += (pseudoBigIntToString((type as BigIntLiteralType).value).length) + 1; - return factory.createLiteralTypeNode(factory.createBigIntLiteral((type as BigIntLiteralType).value)); + return factory.createLiteralTypeNode( + factory.createBigIntLiteral((type as BigIntLiteralType).value), + ); } if (type.flags & TypeFlags.BooleanLiteral) { context.approximateLength += (type as IntrinsicType).intrinsicName.length; - return factory.createLiteralTypeNode((type as IntrinsicType).intrinsicName === "true" ? factory.createTrue() : factory.createFalse()); + return factory.createLiteralTypeNode( + (type as IntrinsicType).intrinsicName === "true" ? factory.createTrue() : factory.createFalse(), + ); } if (type.flags & TypeFlags.UniqueESSymbol) { if (!(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType)) { @@ -5257,7 +6914,10 @@ namespace ts { } } context.approximateLength += 13; - return factory.createTypeOperatorNode(SyntaxKind.UniqueKeyword, factory.createKeywordTypeNode(SyntaxKind.SymbolKeyword)); + return factory.createTypeOperatorNode( + SyntaxKind.UniqueKeyword, + factory.createKeywordTypeNode(SyntaxKind.SymbolKeyword), + ); } if (type.flags & TypeFlags.Void) { context.approximateLength += 4; @@ -5296,9 +6956,16 @@ namespace ts { return factory.createThisTypeNode(); } - if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) { + if ( + !inTypeAlias && type.aliasSymbol + && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope + || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration)) + ) { const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context); - if (isReservedMemberName(type.aliasSymbol.escapedName) && !(type.aliasSymbol.flags & SymbolFlags.Class)) return factory.createTypeReferenceNode(factory.createIdentifier(""), typeArgumentNodes); + if ( + isReservedMemberName(type.aliasSymbol.escapedName) + && !(type.aliasSymbol.flags & SymbolFlags.Class) + ) return factory.createTypeReferenceNode(factory.createIdentifier(""), typeArgumentNodes); if (length(typeArgumentNodes) === 1 && type.aliasSymbol === globalArrayType.symbol) { return factory.createArrayTypeNode(typeArgumentNodes![0]); } @@ -5309,7 +6976,8 @@ namespace ts { if (objectFlags & ObjectFlags.Reference) { Debug.assert(!!(type.flags & TypeFlags.Object)); - return (type as TypeReference).node ? visitAndTransformType(type, typeReferenceToTypeNode) : typeReferenceToTypeNode(type as TypeReference); + return (type as TypeReference).node ? visitAndTransformType(type, typeReferenceToTypeNode) + : typeReferenceToTypeNode(type as TypeReference); } if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) { @@ -5321,45 +6989,61 @@ namespace ts { // we would have normally inferred based on context, we emit the constraint // using `infer T extends ?`. We omit inferred constraints from type references // as they may be elided. - const inferredConstraint = getInferredTypeParameterConstraint(type as TypeParameter, /*omitTypeReferences*/ true); + const inferredConstraint = getInferredTypeParameterConstraint( + type as TypeParameter, + /*omitTypeReferences*/ true, + ); if (!(inferredConstraint && isTypeIdenticalTo(constraint, inferredConstraint))) { context.approximateLength += 9; constraintNode = constraint && typeToTypeNodeHelper(constraint, context); } } - return factory.createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, constraintNode)); + return factory.createInferTypeNode( + typeParameterToDeclarationWithConstraint(type as TypeParameter, context, constraintNode), + ); } if ( - context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && - type.flags & TypeFlags.TypeParameter && - !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) + context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams + && type.flags & TypeFlags.TypeParameter + && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) ) { const name = typeParameterToName(type, context); context.approximateLength += idText(name).length; - return factory.createTypeReferenceNode(factory.createIdentifier(idText(name)), /*typeArguments*/ undefined); + return factory.createTypeReferenceNode( + factory.createIdentifier(idText(name)), + /*typeArguments*/ undefined, + ); } // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. if (type.symbol) { return symbolToTypeNode(type.symbol, context, SymbolFlags.Type); } - const name = (type === markerSuperTypeForCheck || type === markerSubTypeForCheck) && varianceTypeParameter && varianceTypeParameter.symbol ? - (type === markerSubTypeForCheck ? "sub-" : "super-") + symbolName(varianceTypeParameter.symbol) : "?"; + const name = + (type === markerSuperTypeForCheck || type === markerSubTypeForCheck) && varianceTypeParameter + && varianceTypeParameter.symbol + ? (type === markerSubTypeForCheck ? "sub-" : "super-") + + symbolName(varianceTypeParameter.symbol) : "?"; return factory.createTypeReferenceNode(factory.createIdentifier(name), /*typeArguments*/ undefined); } if (type.flags & TypeFlags.Union && (type as UnionType).origin) { type = (type as UnionType).origin!; } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { - const types = type.flags & TypeFlags.Union ? formatUnionTypes((type as UnionType).types) : (type as IntersectionType).types; + const types = type.flags & TypeFlags.Union ? formatUnionTypes((type as UnionType).types) + : (type as IntersectionType).types; if (length(types) === 1) { return typeToTypeNodeHelper(types[0], context); } const typeNodes = mapToTypeNodes(types, context, /*isBareList*/ true); if (typeNodes && typeNodes.length > 0) { - return type.flags & TypeFlags.Union ? factory.createUnionTypeNode(typeNodes) : factory.createIntersectionTypeNode(typeNodes); + return type.flags & TypeFlags.Union ? factory.createUnionTypeNode(typeNodes) + : factory.createIntersectionTypeNode(typeNodes); } else { - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { + if ( + !context.encounteredError + && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection) + ) { context.encounteredError = true; } return undefined!; // TODO: GH#18217 @@ -5384,7 +7068,9 @@ namespace ts { map(types, (t, i) => factory.createTemplateLiteralTypeSpan( typeToTypeNodeHelper(t, context), - (i < types.length - 1 ? factory.createTemplateMiddle : factory.createTemplateTail)(texts[i + 1]), + (i < types.length - 1 ? factory.createTemplateMiddle : factory.createTemplateTail)( + texts[i + 1], + ), )), ); context.approximateLength += 2; @@ -5412,7 +7098,10 @@ namespace ts { function conditionalTypeToTypeNode(type: ConditionalType) { const checkTypeNode = typeToTypeNodeHelper(type.checkType, context); context.approximateLength += 15; - if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && type.root.isDistributive && !(type.checkType.flags & TypeFlags.TypeParameter)) { + if ( + context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && type.root.isDistributive + && !(type.checkType.flags & TypeFlags.TypeParameter) + ) { const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); const name = typeParameterToName(newParam, context); const newTypeVariable = factory.createTypeReferenceNode(name); @@ -5420,10 +7109,17 @@ namespace ts { const newMapper = prependTypeMapping(type.root.checkType, newParam, type.mapper); const saveInferTypeParameters = context.inferTypeParameters; context.inferTypeParameters = type.root.inferTypeParameters; - const extendsTypeNode = typeToTypeNodeHelper(instantiateType(type.root.extendsType, newMapper), context); + const extendsTypeNode = typeToTypeNodeHelper( + instantiateType(type.root.extendsType, newMapper), + context, + ); context.inferTypeParameters = saveInferTypeParameters; - const trueTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(type.root.node.trueType), newMapper)); - const falseTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(type.root.node.falseType), newMapper)); + const trueTypeNode = typeToTypeNodeOrCircularityElision( + instantiateType(getTypeFromTypeNode(type.root.node.trueType), newMapper), + ); + const falseTypeNode = typeToTypeNodeOrCircularityElision( + instantiateType(getTypeFromTypeNode(type.root.node.falseType), newMapper), + ); // outermost conditional makes `T` a type parameter, allowing the inner conditionals to be distributive // second conditional makes `T` have `T & checkType` substitution, so it is correctly usable as the checkType @@ -5437,11 +7133,21 @@ namespace ts { // may also work with `infer ... extends ...` in, but would produce declarations only compatible with the latest TS. return factory.createConditionalTypeNode( checkTypeNode, - factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable.typeName) as Identifier)), + factory.createInferTypeNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + factory.cloneNode(newTypeVariable.typeName) as Identifier, + ), + ), factory.createConditionalTypeNode( factory.createTypeReferenceNode(factory.cloneNode(name)), typeToTypeNodeHelper(type.checkType, context), - factory.createConditionalTypeNode(newTypeVariable, extendsTypeNode, trueTypeNode, falseTypeNode), + factory.createConditionalTypeNode( + newTypeVariable, + extendsTypeNode, + trueTypeNode, + falseTypeNode, + ), factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), ), factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), @@ -5453,7 +7159,12 @@ namespace ts { context.inferTypeParameters = saveInferTypeParameters; const trueTypeNode = typeToTypeNodeOrCircularityElision(getTrueTypeFromConditionalType(type)); const falseTypeNode = typeToTypeNodeOrCircularityElision(getFalseTypeFromConditionalType(type)); - return factory.createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode); + return factory.createConditionalTypeNode( + checkTypeNode, + extendsTypeNode, + trueTypeNode, + falseTypeNode, + ); } function typeToTypeNodeOrCircularityElision(type: Type) { @@ -5477,37 +7188,91 @@ namespace ts { function createMappedTypeNodeFromType(type: MappedType) { Debug.assert(!!(type.flags & TypeFlags.Object)); - const readonlyToken = type.declaration.readonlyToken ? factory.createToken(type.declaration.readonlyToken.kind) as ReadonlyKeyword | PlusToken | MinusToken : undefined; - const questionToken = type.declaration.questionToken ? factory.createToken(type.declaration.questionToken.kind) as QuestionToken | PlusToken | MinusToken : undefined; + const readonlyToken = type.declaration.readonlyToken + ? factory.createToken(type.declaration.readonlyToken.kind) as + | ReadonlyKeyword + | PlusToken + | MinusToken : undefined; + const questionToken = type.declaration.questionToken + ? factory.createToken(type.declaration.questionToken.kind) as + | QuestionToken + | PlusToken + | MinusToken : undefined; let appropriateConstraintTypeNode: TypeNode; let newTypeVariable: TypeReferenceNode | undefined; if (isMappedTypeWithKeyofConstraintDeclaration(type)) { // We have a { [P in keyof T]: X } // We do this to ensure we retain the toplevel keyof-ness of the type which may be lost due to keyof distribution during `getConstraintTypeFromMappedType` - if (isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { - const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); + if ( + isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) + && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams + ) { + const newParam = createTypeParameter( + createSymbol(SymbolFlags.TypeParameter, "T" as __String), + ); const name = typeParameterToName(newParam, context); newTypeVariable = factory.createTypeReferenceNode(name); } - appropriateConstraintTypeNode = factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, newTypeVariable || typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context)); + appropriateConstraintTypeNode = factory.createTypeOperatorNode( + SyntaxKind.KeyOfKeyword, + newTypeVariable || typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context), + ); } else { - appropriateConstraintTypeNode = typeToTypeNodeHelper(getConstraintTypeFromMappedType(type), context); + appropriateConstraintTypeNode = typeToTypeNodeHelper( + getConstraintTypeFromMappedType(type), + context, + ); } - const typeParameterNode = typeParameterToDeclarationWithConstraint(getTypeParameterFromMappedType(type), context, appropriateConstraintTypeNode); - const nameTypeNode = type.declaration.nameType ? typeToTypeNodeHelper(getNameTypeFromMappedType(type)!, context) : undefined; - const templateTypeNode = typeToTypeNodeHelper(removeMissingType(getTemplateTypeFromMappedType(type), !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), context); - const mappedTypeNode = factory.createMappedTypeNode(readonlyToken, typeParameterNode, nameTypeNode, questionToken, templateTypeNode, /*members*/ undefined); + const typeParameterNode = typeParameterToDeclarationWithConstraint( + getTypeParameterFromMappedType(type), + context, + appropriateConstraintTypeNode, + ); + const nameTypeNode = type.declaration.nameType + ? typeToTypeNodeHelper(getNameTypeFromMappedType(type)!, context) : undefined; + const templateTypeNode = typeToTypeNodeHelper( + removeMissingType( + getTemplateTypeFromMappedType(type), + !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional), + ), + context, + ); + const mappedTypeNode = factory.createMappedTypeNode( + readonlyToken, + typeParameterNode, + nameTypeNode, + questionToken, + templateTypeNode, + /*members*/ undefined, + ); context.approximateLength += 10; const result = setEmitFlags(mappedTypeNode, EmitFlags.SingleLine); - if (isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { + if ( + isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) + && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams + ) { // homomorphic mapped type with a non-homomorphic naive inlining // wrap it with a conditional like `SomeModifiersType extends infer U ? {..the mapped type...} : never` to ensure the resulting // type stays homomorphic - const originalConstraint = instantiateType(getConstraintOfTypeParameter(getTypeFromTypeNode((type.declaration.typeParameter.constraint! as TypeOperatorNode).type) as TypeParameter) || unknownType, type.mapper); + const originalConstraint = instantiateType( + getConstraintOfTypeParameter( + getTypeFromTypeNode( + (type.declaration.typeParameter.constraint! as TypeOperatorNode).type, + ) as TypeParameter, + ) || unknownType, + type.mapper, + ); return factory.createConditionalTypeNode( typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context), - factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable!.typeName) as Identifier, originalConstraint.flags & TypeFlags.Unknown ? undefined : typeToTypeNodeHelper(originalConstraint, context))), + factory.createInferTypeNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + factory.cloneNode(newTypeVariable!.typeName) as Identifier, + originalConstraint.flags & TypeFlags.Unknown ? undefined + : typeToTypeNodeHelper(originalConstraint, context), + ), + ), result, factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), ); @@ -5528,9 +7293,17 @@ namespace ts { else if ( symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) - && !(symbol.valueDeclaration && isClassLike(symbol.valueDeclaration) && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral && (!isClassDeclaration(symbol.valueDeclaration) || isSymbolAccessible(symbol, context.enclosingDeclaration, isInstanceType, /*computeAliases*/ false).accessibility !== SymbolAccessibility.Accessible)) || - symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) || - shouldWriteTypeOfFunctionSymbol() + && !(symbol.valueDeclaration && isClassLike(symbol.valueDeclaration) + && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + && (!isClassDeclaration(symbol.valueDeclaration) + || isSymbolAccessible( + symbol, + context.enclosingDeclaration, + isInstanceType, + /*computeAliases*/ false, + ).accessibility !== SymbolAccessibility.Accessible)) + || symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) + || shouldWriteTypeOfFunctionSymbol() ) { return symbolToTypeNode(symbol, context, isInstanceType); } @@ -5554,26 +7327,35 @@ namespace ts { return createTypeNodeFromObjectType(type); } function shouldWriteTypeOfFunctionSymbol() { - const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) && // typeof static method - some(symbol.declarations, declaration => isStatic(declaration)); - const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) && - (symbol.parent || // is exported function symbol - forEach(symbol.declarations, declaration => declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); + const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) // typeof static method + && some(symbol.declarations, declaration => isStatic(declaration)); + const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) + && (symbol.parent // is exported function symbol + || forEach( + symbol.declarations, + declaration => + declaration.parent.kind === SyntaxKind.SourceFile + || declaration.parent.kind === SyntaxKind.ModuleBlock, + )); if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { // typeof is allowed only for static/non local functions - return (!!(context.flags & NodeBuilderFlags.UseTypeOfFunction) || (context.visitedTypes?.has(typeId))) && // it is type of the symbol uses itself recursively - (!(context.flags & NodeBuilderFlags.UseStructuralFallback) || isValueSymbolAccessible(symbol, context.enclosingDeclaration)); // And the build is going to succeed without visibility error or there is no structural fallback allowed + return (!!(context.flags & NodeBuilderFlags.UseTypeOfFunction) + || (context.visitedTypes?.has(typeId))) // it is type of the symbol uses itself recursively + && (!(context.flags & NodeBuilderFlags.UseStructuralFallback) + || isValueSymbolAccessible(symbol, context.enclosingDeclaration)); // And the build is going to succeed without visibility error or there is no structural fallback allowed } } } function visitAndTransformType(type: Type, transform: (type: Type) => T) { const typeId = type.id; - const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class; - const id = getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).node ? "N" + getNodeId((type as TypeReference).node!) : - type.flags & TypeFlags.Conditional ? "N" + getNodeId((type as ConditionalType).root.node) : - type.symbol ? (isConstructorObject ? "+" : "") + getSymbolId(type.symbol) : - undefined; + const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol + && type.symbol.flags & SymbolFlags.Class; + const id = getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).node + ? "N" + getNodeId((type as TypeReference).node!) + : type.flags & TypeFlags.Conditional ? "N" + getNodeId((type as ConditionalType).root.node) + : type.symbol ? (isConstructorObject ? "+" : "") + getSymbolId(type.symbol) + : undefined; // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead // of types allows us to catch circular references to instantiations of the same anonymous type if (!context.visitedTypes) { @@ -5614,7 +7396,10 @@ namespace ts { (result as any).truncating = true; } (result as any).addedLength = addedLength; - links?.serializedTypes?.set(key, result as TypeNode as TypeNode & { truncating?: boolean; addedLength: number; }); + links?.serializedTypes?.set( + key, + result as TypeNode as TypeNode & { truncating?: boolean; addedLength: number; }, + ); } context.visitedTypes.delete(typeId); if (id) { @@ -5626,16 +7411,47 @@ namespace ts { if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) { return node; } - return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext, deepCloneOrReuseNodes)), node); + return setTextRange( + factory.cloneNode( + visitEachChild( + node, + deepCloneOrReuseNode, + nullTransformationContext, + deepCloneOrReuseNodes, + ), + ), + node, + ); } - function deepCloneOrReuseNodes(nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; - function deepCloneOrReuseNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; - function deepCloneOrReuseNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined { + function deepCloneOrReuseNodes( + nodes: NodeArray, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray; + function deepCloneOrReuseNodes( + nodes: NodeArray | undefined, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray | undefined; + function deepCloneOrReuseNodes( + nodes: NodeArray | undefined, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray | undefined { if (nodes && nodes.length === 0) { // Ensure we explicitly make a copy of an empty array; visitNodes will not do this unless the array has elements, // which can lead to us reusing the same empty NodeArray more than once within the same AST during type noding. - return setTextRange(factory.createNodeArray(/*nodes*/ undefined, nodes.hasTrailingComma), nodes); + return setTextRange( + factory.createNodeArray(/*nodes*/ undefined, nodes.hasTrailingComma), + nodes, + ); } return visitNodes(nodes, visitor, test, start, count); } @@ -5650,34 +7466,48 @@ namespace ts { if (!resolved.properties.length && !resolved.indexInfos.length) { if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { context.approximateLength += 2; - return setEmitFlags(factory.createTypeLiteralNode(/*members*/ undefined), EmitFlags.SingleLine); + return setEmitFlags( + factory.createTypeLiteralNode(/*members*/ undefined), + EmitFlags.SingleLine, + ); } if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const signature = resolved.callSignatures[0]; - const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context) as FunctionTypeNode; + const signatureNode = signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.FunctionType, + context, + ) as FunctionTypeNode; return signatureNode; } if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { const signature = resolved.constructSignatures[0]; - const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context) as ConstructorTypeNode; + const signatureNode = signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.ConstructorType, + context, + ) as ConstructorTypeNode; return signatureNode; } } - const abstractSignatures = filter(resolved.constructSignatures, signature => !!(signature.flags & SignatureFlags.Abstract)); + const abstractSignatures = filter( + resolved.constructSignatures, + signature => !!(signature.flags & SignatureFlags.Abstract), + ); if (some(abstractSignatures)) { const types = map(abstractSignatures, getOrCreateTypeFromSignature); // count the number of type elements excluding abstract constructors - const typeElementCount = resolved.callSignatures.length + - (resolved.constructSignatures.length - abstractSignatures.length) + - resolved.indexInfos.length + + const typeElementCount = resolved.callSignatures.length + + (resolved.constructSignatures.length - abstractSignatures.length) + + resolved.indexInfos.length // exclude `prototype` when writing a class expression as a type literal, as per // the logic in `createTypeNodesFromResolvedType`. - (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral ? - countWhere(resolved.properties, p => !(p.flags & SymbolFlags.Prototype)) : - length(resolved.properties)); + + (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + ? countWhere(resolved.properties, p => !(p.flags & SymbolFlags.Prototype)) + : length(resolved.properties)); // don't include an empty object literal if there were no other static-side // properties to write, i.e. `abstract class C { }` becomes `abstract new () => {}` // and not `(abstract new () => {}) & {}` @@ -5694,7 +7524,10 @@ namespace ts { context.flags = savedFlags; const typeLiteralNode = factory.createTypeLiteralNode(members); context.approximateLength += 2; - setEmitFlags(typeLiteralNode, (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine); + setEmitFlags( + typeLiteralNode, + (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine, + ); return typeLiteralNode; } @@ -5703,14 +7536,25 @@ namespace ts { if (type.target === globalArrayType || type.target === globalReadonlyArrayType) { if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); - return factory.createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]); + return factory.createTypeReferenceNode( + type.target === globalArrayType ? "Array" : "ReadonlyArray", + [typeArgumentNode], + ); } const elementType = typeToTypeNodeHelper(typeArguments[0], context); const arrayType = factory.createArrayTypeNode(elementType); - return type.target === globalArrayType ? arrayType : factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); + return type.target === globalArrayType ? arrayType + : factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); } else if (type.target.objectFlags & ObjectFlags.Tuple) { - typeArguments = sameMap(typeArguments, (t, i) => removeMissingType(t, !!((type.target as TupleType).elementFlags[i] & ElementFlags.Optional))); + typeArguments = sameMap( + typeArguments, + (t, i) => + removeMissingType( + t, + !!((type.target as TupleType).elementFlags[i] & ElementFlags.Optional), + ), + ); if (typeArguments.length > 0) { const arity = getTypeReferenceArity(type); const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, arity), context); @@ -5719,38 +7563,60 @@ namespace ts { for (let i = 0; i < tupleConstituentNodes.length; i++) { const flags = (type.target as TupleType).elementFlags[i]; tupleConstituentNodes[i] = factory.createNamedTupleMember( - flags & ElementFlags.Variable ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined, - factory.createIdentifier(unescapeLeadingUnderscores(getTupleElementLabel((type.target as TupleType).labeledElementDeclarations![i]))), - flags & ElementFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : - tupleConstituentNodes[i], + flags & ElementFlags.Variable + ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined, + factory.createIdentifier( + unescapeLeadingUnderscores( + getTupleElementLabel( + (type.target as TupleType).labeledElementDeclarations![i], + ), + ), + ), + flags & ElementFlags.Optional + ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + flags & ElementFlags.Rest + ? factory.createArrayTypeNode(tupleConstituentNodes[i]) + : tupleConstituentNodes[i], ); } } else { for (let i = 0; i < Math.min(arity, tupleConstituentNodes.length); i++) { const flags = (type.target as TupleType).elementFlags[i]; - tupleConstituentNodes[i] = flags & ElementFlags.Variable ? factory.createRestTypeNode(flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : tupleConstituentNodes[i]) : - flags & ElementFlags.Optional ? factory.createOptionalTypeNode(tupleConstituentNodes[i]) : - tupleConstituentNodes[i]; + tupleConstituentNodes[i] = flags & ElementFlags.Variable + ? factory.createRestTypeNode( + flags & ElementFlags.Rest + ? factory.createArrayTypeNode(tupleConstituentNodes[i]) + : tupleConstituentNodes[i], + ) + : flags & ElementFlags.Optional + ? factory.createOptionalTypeNode(tupleConstituentNodes[i]) + : tupleConstituentNodes[i]; } } - const tupleTypeNode = setEmitFlags(factory.createTupleTypeNode(tupleConstituentNodes), EmitFlags.SingleLine); - return (type.target as TupleType).readonly ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode; + const tupleTypeNode = setEmitFlags( + factory.createTupleTypeNode(tupleConstituentNodes), + EmitFlags.SingleLine, + ); + return (type.target as TupleType).readonly + ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) + : tupleTypeNode; } } if (context.encounteredError || (context.flags & NodeBuilderFlags.AllowEmptyTuple)) { const tupleTypeNode = setEmitFlags(factory.createTupleTypeNode([]), EmitFlags.SingleLine); - return (type.target as TupleType).readonly ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode; + return (type.target as TupleType).readonly + ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) + : tupleTypeNode; } context.encounteredError = true; return undefined!; // TODO: GH#18217 } else if ( - context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral && - type.symbol.valueDeclaration && - isClassLike(type.symbol.valueDeclaration) && - !isValueSymbolAccessible(type.symbol, context.enclosingDeclaration) + context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + && type.symbol.valueDeclaration + && isClassLike(type.symbol.valueDeclaration) + && !isValueSymbolAccessible(type.symbol, context.enclosingDeclaration) ) { return createAnonymousTypeNode(type); } @@ -5774,9 +7640,15 @@ namespace ts { const typeArgumentSlice = mapToTypeNodes(typeArguments.slice(start, i), context); const flags = context.flags; context.flags |= NodeBuilderFlags.ForbidIndexedAccessSymbolReferences; - const ref = symbolToTypeNode(parent, context, SymbolFlags.Type, typeArgumentSlice) as TypeReferenceNode | ImportTypeNode; + const ref = symbolToTypeNode( + parent, + context, + SymbolFlags.Type, + typeArgumentSlice, + ) as TypeReferenceNode | ImportTypeNode; context.flags = flags; - resultType = !resultType ? ref : appendReferenceToType(resultType, ref as TypeReferenceNode); + resultType = !resultType ? ref + : appendReferenceToType(resultType, ref as TypeReferenceNode); } } } @@ -5789,11 +7661,15 @@ namespace ts { context.flags |= NodeBuilderFlags.ForbidIndexedAccessSymbolReferences; const finalRef = symbolToTypeNode(type.symbol, context, SymbolFlags.Type, typeArgumentNodes); context.flags = flags; - return !resultType ? finalRef : appendReferenceToType(resultType, finalRef as TypeReferenceNode); + return !resultType ? finalRef + : appendReferenceToType(resultType, finalRef as TypeReferenceNode); } } - function appendReferenceToType(root: TypeReferenceNode | ImportTypeNode, ref: TypeReferenceNode): TypeReferenceNode | ImportTypeNode { + function appendReferenceToType( + root: TypeReferenceNode | ImportTypeNode, + ref: TypeReferenceNode, + ): TypeReferenceNode | ImportTypeNode { if (isImportTypeNode(root)) { // first shift type arguments let typeArguments = root.typeArguments; @@ -5803,7 +7679,11 @@ namespace ts { qualifier = factory.updateIdentifier(qualifier, typeArguments); } else { - qualifier = factory.updateQualifiedName(qualifier, qualifier.left, factory.updateIdentifier(qualifier.right, typeArguments)); + qualifier = factory.updateQualifiedName( + qualifier, + qualifier.left, + factory.updateIdentifier(qualifier.right, typeArguments), + ); } } typeArguments = ref.typeArguments; @@ -5829,7 +7709,11 @@ namespace ts { typeName = factory.updateIdentifier(typeName, typeArguments); } else { - typeName = factory.updateQualifiedName(typeName, typeName.left, factory.updateIdentifier(typeName.right, typeArguments)); + typeName = factory.updateQualifiedName( + typeName, + typeName.left, + factory.updateIdentifier(typeName.right, typeArguments), + ); } typeArguments = ref.typeArguments; // then move qualifiers @@ -5858,18 +7742,44 @@ namespace ts { function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] | undefined { if (checkTruncationLength(context)) { - return [factory.createPropertySignature(/*modifiers*/ undefined, "...", /*questionToken*/ undefined, /*type*/ undefined)]; + return [ + factory.createPropertySignature( + /*modifiers*/ undefined, + "...", + /*questionToken*/ undefined, + /*type*/ undefined, + ), + ]; } const typeElements: TypeElement[] = []; for (const signature of resolvedType.callSignatures) { - typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, context) as CallSignatureDeclaration); + typeElements.push( + signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.CallSignature, + context, + ) as CallSignatureDeclaration, + ); } for (const signature of resolvedType.constructSignatures) { if (signature.flags & SignatureFlags.Abstract) continue; - typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, context) as ConstructSignatureDeclaration); + typeElements.push( + signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.ConstructSignature, + context, + ) as ConstructSignatureDeclaration, + ); } for (const info of resolvedType.indexInfos) { - typeElements.push(indexInfoToIndexSignatureDeclarationHelper(info, context, resolvedType.objectFlags & ObjectFlags.ReverseMapped ? createElidedInformationPlaceholder(context) : undefined)); + typeElements.push( + indexInfoToIndexSignatureDeclarationHelper( + info, + context, + resolvedType.objectFlags & ObjectFlags.ReverseMapped + ? createElidedInformationPlaceholder(context) : undefined, + ), + ); } const properties = resolvedType.properties; @@ -5884,12 +7794,25 @@ namespace ts { if (propertySymbol.flags & SymbolFlags.Prototype) { continue; } - if (getDeclarationModifierFlagsFromSymbol(propertySymbol) & (ModifierFlags.Private | ModifierFlags.Protected) && context.tracker.reportPrivateInBaseOfClassExpression) { - context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName)); + if ( + getDeclarationModifierFlagsFromSymbol(propertySymbol) + & (ModifierFlags.Private | ModifierFlags.Protected) + && context.tracker.reportPrivateInBaseOfClassExpression + ) { + context.tracker.reportPrivateInBaseOfClassExpression( + unescapeLeadingUnderscores(propertySymbol.escapedName), + ); } } if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) { - typeElements.push(factory.createPropertySignature(/*modifiers*/ undefined, `... ${properties.length - i} more ...`, /*questionToken*/ undefined, /*type*/ undefined)); + typeElements.push( + factory.createPropertySignature( + /*modifiers*/ undefined, + `... ${properties.length - i} more ...`, + /*questionToken*/ undefined, + /*type*/ undefined, + ), + ); addPropertyToElementList(properties[properties.length - 1], context, typeElements); break; } @@ -5902,7 +7825,10 @@ namespace ts { function createElidedInformationPlaceholder(context: NodeBuilderContext) { context.approximateLength += 3; if (!(context.flags & NodeBuilderFlags.NoTruncation)) { - return factory.createTypeReferenceNode(factory.createIdentifier("..."), /*typeArguments*/ undefined); + return factory.createTypeReferenceNode( + factory.createIdentifier("..."), + /*typeArguments*/ undefined, + ); } return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); } @@ -5924,10 +7850,14 @@ namespace ts { ); } - function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) { + function addPropertyToElementList( + propertySymbol: Symbol, + context: NodeBuilderContext, + typeElements: TypeElement[], + ) { const propertyIsReverseMapped = !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped); - const propertyType = shouldUsePlaceholderForProperty(propertySymbol, context) ? - anyType : getNonMissingTypeOfSymbol(propertySymbol); + const propertyType = shouldUsePlaceholderForProperty(propertySymbol, context) + ? anyType : getNonMissingTypeOfSymbol(propertySymbol); const saveEnclosingDeclaration = context.enclosingDeclaration; context.enclosingDeclaration = undefined; if (context.tracker.trackSymbol && isLateBoundName(propertySymbol.escapedName)) { @@ -5936,7 +7866,10 @@ namespace ts { if (hasLateBindableName(decl)) { if (isBinaryExpression(decl)) { const name = getNameOfDeclaration(decl); - if (name && isElementAccessExpression(name) && isPropertyAccessEntityNameExpression(name.argumentExpression)) { + if ( + name && isElementAccessExpression(name) + && isPropertyAccessEntityNameExpression(name.argumentExpression) + ) { trackComputedName(name.argumentExpression, saveEnclosingDeclaration, context); } } @@ -5949,15 +7882,28 @@ namespace ts { context.tracker.reportNonSerializableProperty(symbolToString(propertySymbol)); } } - context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] || saveEnclosingDeclaration; + context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] + || saveEnclosingDeclaration; const propertyName = getPropertyNameNodeForSymbol(propertySymbol, context); context.enclosingDeclaration = saveEnclosingDeclaration; context.approximateLength += symbolName(propertySymbol).length + 1; - const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; - if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol)) { - const signatures = getSignaturesOfType(filterType(propertyType, t => !(t.flags & TypeFlags.Undefined)), SignatureKind.Call); + const optionalToken = propertySymbol.flags & SymbolFlags.Optional + ? factory.createToken(SyntaxKind.QuestionToken) : undefined; + if ( + propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) + && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol) + ) { + const signatures = getSignaturesOfType( + filterType(propertyType, t => !(t.flags & TypeFlags.Undefined)), + SignatureKind.Call, + ); for (const signature of signatures) { - const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context, { name: propertyName, questionToken: optionalToken }) as MethodSignature; + const methodDeclaration = signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.MethodSignature, + context, + { name: propertyName, questionToken: optionalToken }, + ) as MethodSignature; typeElements.push(preserveCommentsOn(methodDeclaration)); } } @@ -5971,13 +7917,20 @@ namespace ts { context.reverseMappedStack ||= []; context.reverseMappedStack.push(propertySymbol as ReverseMappedSymbol); } - propertyTypeNode = propertyType ? serializeTypeForDeclaration(context, propertyType, propertySymbol, saveEnclosingDeclaration) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + propertyTypeNode = propertyType + ? serializeTypeForDeclaration( + context, + propertyType, + propertySymbol, + saveEnclosingDeclaration, + ) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); if (propertyIsReverseMapped) { context.reverseMappedStack!.pop(); } } - const modifiers = isReadonlySymbol(propertySymbol) ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] : undefined; + const modifiers = isReadonlySymbol(propertySymbol) + ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] : undefined; if (modifiers) { context.approximateLength += 9; } @@ -5993,10 +7946,18 @@ namespace ts { function preserveCommentsOn(node: T) { if (some(propertySymbol.declarations, d => d.kind === SyntaxKind.JSDocPropertyTag)) { - const d = propertySymbol.declarations?.find(d => d.kind === SyntaxKind.JSDocPropertyTag)! as JSDocPropertyTag; + const d = propertySymbol.declarations?.find(d => + d.kind === SyntaxKind.JSDocPropertyTag + )! as JSDocPropertyTag; const commentText = getTextOfJSDocComment(d.comment); if (commentText) { - setSyntheticLeadingComments(node, [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }]); + setSyntheticLeadingComments(node, [{ + kind: SyntaxKind.MultiLineCommentTrivia, + text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }]); } } else if (propertySymbol.valueDeclaration) { @@ -6007,7 +7968,11 @@ namespace ts { } } - function mapToTypeNodes(types: readonly Type[] | undefined, context: NodeBuilderContext, isBareList?: boolean): TypeNode[] | undefined { + function mapToTypeNodes( + types: readonly Type[] | undefined, + context: NodeBuilderContext, + isBareList?: boolean, + ): TypeNode[] | undefined { if (some(types)) { if (checkTruncationLength(context)) { if (!isBareList) { @@ -6016,20 +7981,29 @@ namespace ts { else if (types.length > 2) { return [ typeToTypeNodeHelper(types[0], context), - factory.createTypeReferenceNode(`... ${types.length - 2} more ...`, /*typeArguments*/ undefined), + factory.createTypeReferenceNode( + `... ${types.length - 2} more ...`, + /*typeArguments*/ undefined, + ), typeToTypeNodeHelper(types[types.length - 1], context), ]; } } const mayHaveNameCollisions = !(context.flags & NodeBuilderFlags.UseFullyQualifiedType); /** Map from type reference identifier text to [type, index in `result` where the type node is] */ - const seenNames = mayHaveNameCollisions ? createUnderscoreEscapedMultiMap<[Type, number]>() : undefined; + const seenNames = mayHaveNameCollisions ? createUnderscoreEscapedMultiMap<[Type, number]>() + : undefined; const result: TypeNode[] = []; let i = 0; for (const type of types) { i++; if (checkTruncationLength(context) && (i + 2 < types.length - 1)) { - result.push(factory.createTypeReferenceNode(`... ${types.length - i} more ...`, /*typeArguments*/ undefined)); + result.push( + factory.createTypeReferenceNode( + `... ${types.length - i} more ...`, + /*typeArguments*/ undefined, + ), + ); const typeNode = typeToTypeNodeHelper(types[types.length - 1], context); if (typeNode) { result.push(typeNode); @@ -6076,7 +8050,11 @@ namespace ts { || !!a.aliasSymbol && a.aliasSymbol === b.aliasSymbol; } - function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, context: NodeBuilderContext, typeNode: TypeNode | undefined): IndexSignatureDeclaration { + function indexInfoToIndexSignatureDeclarationHelper( + indexInfo: IndexInfo, + context: NodeBuilderContext, + typeNode: TypeNode | undefined, + ): IndexSignatureDeclaration { const name = getNameFromIndexInfo(indexInfo) || "x"; const indexerTypeNode = typeToTypeNodeHelper(indexInfo.keyType, context); @@ -6110,23 +8088,47 @@ namespace ts { bundledImports?: boolean; } - function signatureToSignatureDeclarationHelper(signature: Signature, kind: SignatureDeclaration["kind"], context: NodeBuilderContext, options?: SignatureToSignatureDeclarationOptions): SignatureDeclaration { + function signatureToSignatureDeclarationHelper( + signature: Signature, + kind: SignatureDeclaration["kind"], + context: NodeBuilderContext, + options?: SignatureToSignatureDeclarationOptions, + ): SignatureDeclaration { const suppressAny = context.flags & NodeBuilderFlags.SuppressAnyReturnType; if (suppressAny) context.flags &= ~NodeBuilderFlags.SuppressAnyReturnType; // suppress only toplevel `any`s context.approximateLength += 3; // Usually a signature contributes a few more characters than this, but 3 is the minimum let typeParameters: TypeParameterDeclaration[] | undefined; let typeArguments: TypeNode[] | undefined; - if (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature && signature.target && signature.mapper && signature.target.typeParameters) { - typeArguments = signature.target.typeParameters.map(parameter => typeToTypeNodeHelper(instantiateType(parameter, signature.mapper), context)); + if ( + context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature && signature.target + && signature.mapper && signature.target.typeParameters + ) { + typeArguments = signature.target.typeParameters.map(parameter => + typeToTypeNodeHelper(instantiateType(parameter, signature.mapper), context) + ); } else { - typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context)); + typeParameters = signature.typeParameters + && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context)); } const expandedParams = getExpandedParameters(signature, /*skipUnionExpanding*/ true)[0]; // If the expanded parameter list had a variadic in a non-trailing position, don't expand it - const parameters = (some(expandedParams, p => p !== expandedParams[expandedParams.length - 1] && !!(getCheckFlags(p) & CheckFlags.RestParameter)) ? signature.parameters : expandedParams).map(parameter => symbolToParameterDeclaration(parameter, context, kind === SyntaxKind.Constructor, options?.privateSymbolVisitor, options?.bundledImports)); - const thisParameter = context.flags & NodeBuilderFlags.OmitThisParameter ? undefined : tryGetThisParameterDeclaration(signature, context); + const parameters = (some( + expandedParams, + p => p !== expandedParams[expandedParams.length - 1] + && !!(getCheckFlags(p) & CheckFlags.RestParameter), + ) ? signature.parameters : expandedParams).map(parameter => + symbolToParameterDeclaration( + parameter, + context, + kind === SyntaxKind.Constructor, + options?.privateSymbolVisitor, + options?.bundledImports, + ) + ); + const thisParameter = context.flags & NodeBuilderFlags.OmitThisParameter ? undefined + : tryGetThisParameterDeclaration(signature, context); if (thisParameter) { parameters.unshift(thisParameter); } @@ -6134,19 +8136,30 @@ namespace ts { let returnTypeNode: TypeNode | undefined; const typePredicate = getTypePredicateOfSignature(signature); if (typePredicate) { - const assertsModifier = typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? - factory.createToken(SyntaxKind.AssertsKeyword) : - undefined; - const parameterName = typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? - setEmitFlags(factory.createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) : - factory.createThisTypeNode(); + const assertsModifier = typePredicate.kind === TypePredicateKind.AssertsThis + || typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? factory.createToken(SyntaxKind.AssertsKeyword) + : undefined; + const parameterName = typePredicate.kind === TypePredicateKind.Identifier + || typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? setEmitFlags( + factory.createIdentifier(typePredicate.parameterName), + EmitFlags.NoAsciiEscaping, + ) + : factory.createThisTypeNode(); const typeNode = typePredicate.type && typeToTypeNodeHelper(typePredicate.type, context); returnTypeNode = factory.createTypePredicateNode(assertsModifier, parameterName, typeNode); } else { const returnType = getReturnTypeOfSignature(signature); if (returnType && !(suppressAny && isTypeAny(returnType))) { - returnTypeNode = serializeReturnTypeForSignature(context, returnType, signature, options?.privateSymbolVisitor, options?.bundledImports); + returnTypeNode = serializeReturnTypeForSignature( + context, + returnType, + signature, + options?.privateSymbolVisitor, + options?.bundledImports, + ); } else if (!suppressAny) { returnTypeNode = factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); @@ -6158,21 +8171,94 @@ namespace ts { modifiers = factory.createModifiersFromModifierFlags(flags | ModifierFlags.Abstract); } - const node = kind === SyntaxKind.CallSignature ? factory.createCallSignature(typeParameters, parameters, returnTypeNode) : - kind === SyntaxKind.ConstructSignature ? factory.createConstructSignature(typeParameters, parameters, returnTypeNode) : - kind === SyntaxKind.MethodSignature ? factory.createMethodSignature(modifiers, options?.name ?? factory.createIdentifier(""), options?.questionToken, typeParameters, parameters, returnTypeNode) : - kind === SyntaxKind.MethodDeclaration ? factory.createMethodDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ?? factory.createIdentifier(""), /*questionToken*/ undefined, typeParameters, parameters, returnTypeNode, /*body*/ undefined) : - kind === SyntaxKind.Constructor ? factory.createConstructorDeclaration(modifiers, parameters, /*body*/ undefined) : - kind === SyntaxKind.GetAccessor ? factory.createGetAccessorDeclaration(modifiers, options?.name ?? factory.createIdentifier(""), parameters, returnTypeNode, /*body*/ undefined) : - kind === SyntaxKind.SetAccessor ? factory.createSetAccessorDeclaration(modifiers, options?.name ?? factory.createIdentifier(""), parameters, /*body*/ undefined) : - kind === SyntaxKind.IndexSignature ? factory.createIndexSignature(modifiers, parameters, returnTypeNode) : - kind === SyntaxKind.JSDocFunctionType ? factory.createJSDocFunctionType(parameters, returnTypeNode) : - kind === SyntaxKind.FunctionType ? factory.createFunctionTypeNode(typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : - kind === SyntaxKind.ConstructorType ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : - kind === SyntaxKind.FunctionDeclaration ? factory.createFunctionDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, /*body*/ undefined) : - kind === SyntaxKind.FunctionExpression ? factory.createFunctionExpression(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, factory.createBlock([])) : - kind === SyntaxKind.ArrowFunction ? factory.createArrowFunction(modifiers, typeParameters, parameters, returnTypeNode, /*equalsGreaterThanToken*/ undefined, factory.createBlock([])) : - Debug.assertNever(kind); + const node = kind === SyntaxKind.CallSignature + ? factory.createCallSignature(typeParameters, parameters, returnTypeNode) + : kind === SyntaxKind.ConstructSignature + ? factory.createConstructSignature(typeParameters, parameters, returnTypeNode) + : kind === SyntaxKind.MethodSignature + ? factory.createMethodSignature( + modifiers, + options?.name ?? factory.createIdentifier(""), + options?.questionToken, + typeParameters, + parameters, + returnTypeNode, + ) + : kind === SyntaxKind.MethodDeclaration + ? factory.createMethodDeclaration( + modifiers, + /*asteriskToken*/ undefined, + options?.name ?? factory.createIdentifier(""), + /*questionToken*/ undefined, + typeParameters, + parameters, + returnTypeNode, + /*body*/ undefined, + ) + : kind === SyntaxKind.Constructor + ? factory.createConstructorDeclaration(modifiers, parameters, /*body*/ undefined) + : kind === SyntaxKind.GetAccessor + ? factory.createGetAccessorDeclaration( + modifiers, + options?.name ?? factory.createIdentifier(""), + parameters, + returnTypeNode, + /*body*/ undefined, + ) + : kind === SyntaxKind.SetAccessor + ? factory.createSetAccessorDeclaration( + modifiers, + options?.name ?? factory.createIdentifier(""), + parameters, + /*body*/ undefined, + ) + : kind === SyntaxKind.IndexSignature + ? factory.createIndexSignature(modifiers, parameters, returnTypeNode) + : kind === SyntaxKind.JSDocFunctionType + ? factory.createJSDocFunctionType(parameters, returnTypeNode) + : kind === SyntaxKind.FunctionType + ? factory.createFunctionTypeNode( + typeParameters, + parameters, + returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier("")), + ) + : kind === SyntaxKind.ConstructorType + ? factory.createConstructorTypeNode( + modifiers, + typeParameters, + parameters, + returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier("")), + ) + : kind === SyntaxKind.FunctionDeclaration + ? factory.createFunctionDeclaration( + modifiers, + /*asteriskToken*/ undefined, + options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), + typeParameters, + parameters, + returnTypeNode, + /*body*/ undefined, + ) + : kind === SyntaxKind.FunctionExpression + ? factory.createFunctionExpression( + modifiers, + /*asteriskToken*/ undefined, + options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), + typeParameters, + parameters, + returnTypeNode, + factory.createBlock([]), + ) + : kind === SyntaxKind.ArrowFunction + ? factory.createArrowFunction( + modifiers, + typeParameters, + parameters, + returnTypeNode, + /*equalsGreaterThanToken*/ undefined, + factory.createBlock([]), + ) + : Debug.assertNever(kind); if (typeArguments) { node.typeArguments = factory.createNodeArray(typeArguments); @@ -6199,7 +8285,11 @@ namespace ts { } } - function typeParameterToDeclarationWithConstraint(type: TypeParameter, context: NodeBuilderContext, constraintNode: TypeNode | undefined): TypeParameterDeclaration { + function typeParameterToDeclarationWithConstraint( + type: TypeParameter, + context: NodeBuilderContext, + constraintNode: TypeNode | undefined, + ): TypeParameterDeclaration { const savedContextFlags = context.flags; context.flags &= ~NodeBuilderFlags.WriteTypeParametersInQualifiedName; // Avoids potential infinite loop when building for a claimspace with a generic const modifiers = factory.createModifiersFromModifierFlags(getVarianceModifiers(type)); @@ -6210,33 +8300,61 @@ namespace ts { return factory.createTypeParameterDeclaration(modifiers, name, constraintNode, defaultParameterNode); } - function typeParameterToDeclaration(type: TypeParameter, context: NodeBuilderContext, constraint = getConstraintOfTypeParameter(type)): TypeParameterDeclaration { + function typeParameterToDeclaration( + type: TypeParameter, + context: NodeBuilderContext, + constraint = getConstraintOfTypeParameter(type), + ): TypeParameterDeclaration { const constraintNode = constraint && typeToTypeNodeHelper(constraint, context); return typeParameterToDeclarationWithConstraint(type, context, constraintNode); } - function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext, preserveModifierFlags?: boolean, privateSymbolVisitor?: (s: Symbol) => void, bundledImports?: boolean): ParameterDeclaration { - let parameterDeclaration: ParameterDeclaration | JSDocParameterTag | undefined = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); + function symbolToParameterDeclaration( + parameterSymbol: Symbol, + context: NodeBuilderContext, + preserveModifierFlags?: boolean, + privateSymbolVisitor?: (s: Symbol) => void, + bundledImports?: boolean, + ): ParameterDeclaration { + let parameterDeclaration: ParameterDeclaration | JSDocParameterTag | undefined = getDeclarationOfKind< + ParameterDeclaration + >(parameterSymbol, SyntaxKind.Parameter); if (!parameterDeclaration && !isTransientSymbol(parameterSymbol)) { - parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.JSDocParameterTag); + parameterDeclaration = getDeclarationOfKind( + parameterSymbol, + SyntaxKind.JSDocParameterTag, + ); } let parameterType = getTypeOfSymbol(parameterSymbol); if (parameterDeclaration && isRequiredInitializedParameter(parameterDeclaration)) { parameterType = getOptionalType(parameterType); } - const parameterTypeNode = serializeTypeForDeclaration(context, parameterType, parameterSymbol, context.enclosingDeclaration, privateSymbolVisitor, bundledImports); + const parameterTypeNode = serializeTypeForDeclaration( + context, + parameterType, + parameterSymbol, + context.enclosingDeclaration, + privateSymbolVisitor, + bundledImports, + ); - const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags && parameterDeclaration && canHaveModifiers(parameterDeclaration) ? map(getModifiers(parameterDeclaration), factory.cloneNode) : undefined; - const isRest = parameterDeclaration && isRestParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; + const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags + && parameterDeclaration && canHaveModifiers(parameterDeclaration) + ? map(getModifiers(parameterDeclaration), factory.cloneNode) : undefined; + const isRest = parameterDeclaration && isRestParameter(parameterDeclaration) + || getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; const dotDotDotToken = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined; - const name = parameterDeclaration ? parameterDeclaration.name ? - parameterDeclaration.name.kind === SyntaxKind.Identifier ? setEmitFlags(factory.cloneNode(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) : - parameterDeclaration.name.kind === SyntaxKind.QualifiedName ? setEmitFlags(factory.cloneNode(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) : - cloneBindingName(parameterDeclaration.name) : - symbolName(parameterSymbol) : - symbolName(parameterSymbol); - const isOptional = parameterDeclaration && isOptionalParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.OptionalParameter; + const name = parameterDeclaration ? parameterDeclaration.name + ? parameterDeclaration.name.kind === SyntaxKind.Identifier + ? setEmitFlags(factory.cloneNode(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) + : parameterDeclaration.name.kind === SyntaxKind.QualifiedName + ? setEmitFlags(factory.cloneNode(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) + : cloneBindingName(parameterDeclaration.name) + : symbolName(parameterSymbol) + : symbolName(parameterSymbol); + const isOptional = parameterDeclaration && isOptionalParameter(parameterDeclaration) + || getCheckFlags(parameterSymbol) & CheckFlags.OptionalParameter; const questionToken = isOptional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; const parameterNode = factory.createParameterDeclaration( modifiers, @@ -6255,7 +8373,13 @@ namespace ts { if (context.tracker.trackSymbol && isComputedPropertyName(node) && isLateBindableName(node)) { trackComputedName(node.expression, context.enclosingDeclaration, context); } - let visited = visitEachChild(node, elideInitializerAndSetEmitFlags, nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags)!; + let visited = visitEachChild( + node, + elideInitializerAndSetEmitFlags, + nullTransformationContext, + /*nodesVisitor*/ undefined, + elideInitializerAndSetEmitFlags, + )!; if (isBindingElement(visited)) { visited = factory.updateBindingElement( visited, @@ -6273,26 +8397,51 @@ namespace ts { } } - function trackComputedName(accessExpression: EntityNameOrEntityNameExpression, enclosingDeclaration: Node | undefined, context: NodeBuilderContext) { + function trackComputedName( + accessExpression: EntityNameOrEntityNameExpression, + enclosingDeclaration: Node | undefined, + context: NodeBuilderContext, + ) { if (!context.tracker.trackSymbol) return; // get symbol of the first identifier of the entityName const firstIdentifier = getFirstIdentifier(accessExpression); - const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); + const name = resolveName( + firstIdentifier, + firstIdentifier.escapedText, + SymbolFlags.Value | SymbolFlags.ExportValue, + /*nodeNotFoundErrorMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + ); if (name) { context.tracker.trackSymbol(name, enclosingDeclaration, SymbolFlags.Value); } } - function lookupSymbolChain(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) { + function lookupSymbolChain( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + yieldModuleSymbol?: boolean, + ) { context.tracker.trackSymbol!(symbol, context.enclosingDeclaration, meaning); // TODO: GH#18217 return lookupSymbolChainWorker(symbol, context, meaning, yieldModuleSymbol); } - function lookupSymbolChainWorker(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) { + function lookupSymbolChainWorker( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + yieldModuleSymbol?: boolean, + ) { // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration. let chain: Symbol[]; const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; - if (!isTypeParameter && (context.enclosingDeclaration || context.flags & NodeBuilderFlags.UseFullyQualifiedType) && !(context.flags & NodeBuilderFlags.DoNotIncludeSymbolChain)) { + if ( + !isTypeParameter + && (context.enclosingDeclaration || context.flags & NodeBuilderFlags.UseFullyQualifiedType) + && !(context.flags & NodeBuilderFlags.DoNotIncludeSymbolChain) + ) { chain = Debug.checkDefined(getSymbolChain(symbol, meaning, /*endOfChain*/ true)); Debug.assert(chain && chain.length > 0); } @@ -6302,15 +8451,32 @@ namespace ts { return chain; /** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */ - function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined { - let accessibleSymbolChain = getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, !!(context.flags & NodeBuilderFlags.UseOnlyExternalAliasing)); + function getSymbolChain( + symbol: Symbol, + meaning: SymbolFlags, + endOfChain: boolean, + ): Symbol[] | undefined { + let accessibleSymbolChain = getAccessibleSymbolChain( + symbol, + context.enclosingDeclaration, + meaning, + !!(context.flags & NodeBuilderFlags.UseOnlyExternalAliasing), + ); let parentSpecifiers: (string | undefined)[]; if ( - !accessibleSymbolChain || - needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning)) + !accessibleSymbolChain + || needsQualification( + accessibleSymbolChain[0], + context.enclosingDeclaration, + accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning), + ) ) { // Go up and add our parent. - const parents = getContainersOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol, context.enclosingDeclaration, meaning); + const parents = getContainersOfSymbol( + accessibleSymbolChain ? accessibleSymbolChain[0] : symbol, + context.enclosingDeclaration, + meaning, + ); if (length(parents)) { parentSpecifiers = parents!.map(symbol => some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol) @@ -6321,18 +8487,28 @@ namespace ts { indices.sort(sortByBestName); const sortedParents = indices.map(i => parents![i]); for (const parent of sortedParents) { - const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false); + const parentChain = getSymbolChain( + parent, + getQualifiedLeftMeaning(meaning), + /*endOfChain*/ false, + ); if (parentChain) { if ( - parent.exports && parent.exports.get(InternalSymbolName.ExportEquals) && - getSymbolIfSameReference(parent.exports.get(InternalSymbolName.ExportEquals)!, symbol) + parent.exports && parent.exports.get(InternalSymbolName.ExportEquals) + && getSymbolIfSameReference( + parent.exports.get(InternalSymbolName.ExportEquals)!, + symbol, + ) ) { // parentChain root _is_ symbol - symbol is a module export=, so it kinda looks like it's own parent // No need to lookup an alias for the symbol in itself accessibleSymbolChain = parentChain; break; } - accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]); + accessibleSymbolChain = parentChain.concat( + accessibleSymbolChain + || [getAliasForSymbolInContainer(parent, symbol) || symbol], + ); break; } } @@ -6344,12 +8520,15 @@ namespace ts { } if ( // If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols. - endOfChain || + endOfChain // If a parent symbol is an anonymous type, don't write it. - !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral)) + || !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral)) ) { // If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.) - if (!endOfChain && !yieldModuleSymbol && !!forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { + if ( + !endOfChain && !yieldModuleSymbol + && !!forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol) + ) { return; } return [symbol]; @@ -6362,7 +8541,8 @@ namespace ts { const isBRelative = pathIsRelative(specifierB); if (pathIsRelative(specifierA) === isBRelative) { // Both relative or both non-relative, sort by number of parts - return moduleSpecifiers.countPathComponents(specifierA) - moduleSpecifiers.countPathComponents(specifierB); + return moduleSpecifiers.countPathComponents(specifierA) + - moduleSpecifiers.countPathComponents(specifierB); } if (isBRelative) { // A is non-relative, B is relative: prefer A @@ -6380,7 +8560,12 @@ namespace ts { let typeParameterNodes: NodeArray | undefined; const targetSymbol = getTargetSymbol(symbol); if (targetSymbol.flags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeAlias)) { - typeParameterNodes = factory.createNodeArray(map(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), tp => typeParameterToDeclaration(tp, context))); + typeParameterNodes = factory.createNodeArray( + map( + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), + tp => typeParameterToDeclaration(tp, context), + ), + ); } return typeParameterNodes; } @@ -6401,7 +8586,10 @@ namespace ts { const params = getTypeParametersOfClassOrInterface( parentSymbol.flags & SymbolFlags.Alias ? resolveAlias(parentSymbol) : parentSymbol, ); - typeParameterNodes = mapToTypeNodes(map(params, t => getMappedType(t, (nextSymbol as TransientSymbol).mapper!)), context); + typeParameterNodes = mapToTypeNodes( + map(params, t => getMappedType(t, (nextSymbol as TransientSymbol).mapper!)), + context, + ); } else { typeParameterNodes = typeParametersToTypeParameterDeclarations(symbol, context); @@ -6420,10 +8608,17 @@ namespace ts { return top; } - function getSpecifierForModuleSymbol(symbol: Symbol, context: NodeBuilderContext, overrideImportMode?: SourceFile["impliedNodeFormat"]) { + function getSpecifierForModuleSymbol( + symbol: Symbol, + context: NodeBuilderContext, + overrideImportMode?: SourceFile["impliedNodeFormat"], + ) { let file = getDeclarationOfKind(symbol, SyntaxKind.SourceFile); if (!file) { - const equivalentFileSymbol = firstDefined(symbol.declarations, d => getFileSymbolIfFileSymbolExportEqualsContainer(d, symbol)); + const equivalentFileSymbol = firstDefined( + symbol.declarations, + d => getFileSymbolIfFileSymbolExportEqualsContainer(d, symbol), + ); if (equivalentFileSymbol) { file = getDeclarationOfKind(equivalentFileSymbol, SyntaxKind.SourceFile); } @@ -6464,7 +8659,9 @@ namespace ts { // using the `baseUrl` compiler option (which we would otherwise never use in declaration emit) and a non-relative // specifier preference const { moduleResolverHost } = context.tracker; - const specifierCompilerOptions = isBundle ? { ...compilerOptions, baseUrl: moduleResolverHost.getCommonSourceDirectory() } : compilerOptions; + const specifierCompilerOptions = isBundle + ? { ...compilerOptions, baseUrl: moduleResolverHost.getCommonSourceDirectory() } + : compilerOptions; specifier = first(moduleSpecifiers.getModuleSpecifiers( symbol, checker, @@ -6491,42 +8688,70 @@ namespace ts { function symbolToEntityNameNode(symbol: Symbol): EntityName { const identifier = factory.createIdentifier(unescapeLeadingUnderscores(symbol.escapedName)); - return symbol.parent ? factory.createQualifiedName(symbolToEntityNameNode(symbol.parent), identifier) : identifier; - } - - function symbolToTypeNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, overrideTypeArguments?: readonly TypeNode[]): TypeNode { - const chain = lookupSymbolChain(symbol, context, meaning, !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope)); // If we're using aliases outside the current scope, dont bother with the module + return symbol.parent ? factory.createQualifiedName(symbolToEntityNameNode(symbol.parent), identifier) + : identifier; + } + + function symbolToTypeNode( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + overrideTypeArguments?: readonly TypeNode[], + ): TypeNode { + const chain = lookupSymbolChain( + symbol, + context, + meaning, + !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope), + ); // If we're using aliases outside the current scope, dont bother with the module const isTypeOf = meaning === SymbolFlags.Value; if (some(chain[0].declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { // module is root, must use `ImportTypeNode` - const nonRootParts = chain.length > 1 ? createAccessFromSymbolChain(chain, chain.length - 1, 1) : undefined; + const nonRootParts = chain.length > 1 ? createAccessFromSymbolChain(chain, chain.length - 1, 1) + : undefined; const typeParameterNodes = overrideTypeArguments || lookupTypeParameterNodes(chain, 0, context); const contextFile = getSourceFileOfNode(getOriginalNode(context.enclosingDeclaration)); const targetFile = getSourceFileOfModule(chain[0]); let specifier: string | undefined; let assertion: ImportTypeAssertionContainer | undefined; - if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { + if ( + getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext + ) { // An `import` type directed at an esm format file is only going to resolve in esm mode - set the esm mode assertion - if (targetFile?.impliedNodeFormat === ModuleKind.ESNext && targetFile.impliedNodeFormat !== contextFile?.impliedNodeFormat) { + if ( + targetFile?.impliedNodeFormat === ModuleKind.ESNext + && targetFile.impliedNodeFormat !== contextFile?.impliedNodeFormat + ) { specifier = getSpecifierForModuleSymbol(chain[0], context, ModuleKind.ESNext); - assertion = factory.createImportTypeAssertionContainer(factory.createAssertClause(factory.createNodeArray([ - factory.createAssertEntry( - factory.createStringLiteral("resolution-mode"), - factory.createStringLiteral("import"), - ), - ]))); + assertion = factory.createImportTypeAssertionContainer( + factory.createAssertClause(factory.createNodeArray([ + factory.createAssertEntry( + factory.createStringLiteral("resolution-mode"), + factory.createStringLiteral("import"), + ), + ])), + ); context.tracker.reportImportTypeNodeResolutionModeOverride?.(); } } if (!specifier) { specifier = getSpecifierForModuleSymbol(chain[0], context); } - if (!(context.flags & NodeBuilderFlags.AllowNodeModulesRelativePaths) && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic && specifier.indexOf("/node_modules/") >= 0) { + if ( + !(context.flags & NodeBuilderFlags.AllowNodeModulesRelativePaths) + && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic + && specifier.indexOf("/node_modules/") >= 0 + ) { const oldSpecifier = specifier; - if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { + if ( + getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext + ) { // We might be able to write a portable import type using a mode override; try specifier generation again, but with a different mode set - const swappedMode = contextFile?.impliedNodeFormat === ModuleKind.ESNext ? ModuleKind.CommonJS : ModuleKind.ESNext; + const swappedMode = contextFile?.impliedNodeFormat === ModuleKind.ESNext + ? ModuleKind.CommonJS : ModuleKind.ESNext; specifier = getSpecifierForModuleSymbol(chain[0], context, swappedMode); if (specifier.indexOf("/node_modules/") >= 0) { @@ -6534,12 +8759,16 @@ namespace ts { specifier = oldSpecifier; } else { - assertion = factory.createImportTypeAssertionContainer(factory.createAssertClause(factory.createNodeArray([ - factory.createAssertEntry( - factory.createStringLiteral("resolution-mode"), - factory.createStringLiteral(swappedMode === ModuleKind.ESNext ? "import" : "require"), - ), - ]))); + assertion = factory.createImportTypeAssertionContainer( + factory.createAssertClause(factory.createNodeArray([ + factory.createAssertEntry( + factory.createStringLiteral("resolution-mode"), + factory.createStringLiteral( + swappedMode === ModuleKind.ESNext ? "import" : "require", + ), + ), + ])), + ); context.tracker.reportImportTypeNodeResolutionModeOverride?.(); } } @@ -6554,19 +8783,36 @@ namespace ts { } } const lit = factory.createLiteralTypeNode(factory.createStringLiteral(specifier)); - if (context.tracker.trackExternalModuleSymbolOfImportTypeNode) context.tracker.trackExternalModuleSymbolOfImportTypeNode(chain[0]); + if (context.tracker.trackExternalModuleSymbolOfImportTypeNode) { + context.tracker.trackExternalModuleSymbolOfImportTypeNode(chain[0]); + } context.approximateLength += specifier.length + 10; // specifier + import("") if (!nonRootParts || isEntityName(nonRootParts)) { if (nonRootParts) { const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right; lastId.typeArguments = undefined; } - return factory.createImportTypeNode(lit, assertion, nonRootParts as EntityName, typeParameterNodes as readonly TypeNode[], isTypeOf); + return factory.createImportTypeNode( + lit, + assertion, + nonRootParts as EntityName, + typeParameterNodes as readonly TypeNode[], + isTypeOf, + ); } else { const splitNode = getTopmostIndexedAccessType(nonRootParts); const qualifier = (splitNode.objectType as TypeReferenceNode).typeName; - return factory.createIndexedAccessTypeNode(factory.createImportTypeNode(lit, assertion, qualifier, typeParameterNodes as readonly TypeNode[], isTypeOf), splitNode.indexType); + return factory.createIndexedAccessTypeNode( + factory.createImportTypeNode( + lit, + assertion, + qualifier, + typeParameterNodes as readonly TypeNode[], + isTypeOf, + ), + splitNode.indexType, + ); } } @@ -6584,8 +8830,13 @@ namespace ts { return factory.createTypeReferenceNode(entityName, lastTypeArgs as NodeArray); } - function createAccessFromSymbolChain(chain: Symbol[], index: number, stopper: number): EntityName | IndexedAccessTypeNode { - const typeParameterNodes = index === (chain.length - 1) ? overrideTypeArguments : lookupTypeParameterNodes(chain, index, context); + function createAccessFromSymbolChain( + chain: Symbol[], + index: number, + stopper: number, + ): EntityName | IndexedAccessTypeNode { + const typeParameterNodes = index === (chain.length - 1) ? overrideTypeArguments + : lookupTypeParameterNodes(chain, index, context); const symbol = chain[index]; const parent = chain[index - 1]; @@ -6600,7 +8851,10 @@ namespace ts { if (parent && getExportsOfSymbol(parent)) { const exports = getExportsOfSymbol(parent); forEachEntry(exports, (ex, name) => { - if (getSymbolIfSameReference(ex, symbol) && !isLateBoundName(name) && name !== InternalSymbolName.ExportEquals) { + if ( + getSymbolIfSameReference(ex, symbol) && !isLateBoundName(name) + && name !== InternalSymbolName.ExportEquals + ) { symbolName = unescapeLeadingUnderscores(name); return true; } @@ -6613,7 +8867,10 @@ namespace ts { if (name && isComputedPropertyName(name) && isEntityName(name.expression)) { const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); if (isEntityName(LHS)) { - return factory.createIndexedAccessTypeNode(factory.createParenthesizedType(factory.createTypeQueryNode(LHS)), factory.createTypeQueryNode(name.expression)); + return factory.createIndexedAccessTypeNode( + factory.createParenthesizedType(factory.createTypeQueryNode(LHS)), + factory.createTypeQueryNode(name.expression), + ); } return LHS; } @@ -6622,27 +8879,38 @@ namespace ts { context.approximateLength += symbolName.length + 1; if ( - !(context.flags & NodeBuilderFlags.ForbidIndexedAccessSymbolReferences) && parent && - getMembersOfSymbol(parent) && getMembersOfSymbol(parent).get(symbol.escapedName) && - getSymbolIfSameReference(getMembersOfSymbol(parent).get(symbol.escapedName)!, symbol) + !(context.flags & NodeBuilderFlags.ForbidIndexedAccessSymbolReferences) && parent + && getMembersOfSymbol(parent) && getMembersOfSymbol(parent).get(symbol.escapedName) + && getSymbolIfSameReference(getMembersOfSymbol(parent).get(symbol.escapedName)!, symbol) ) { // Should use an indexed access const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); if (isIndexedAccessTypeNode(LHS)) { - return factory.createIndexedAccessTypeNode(LHS, factory.createLiteralTypeNode(factory.createStringLiteral(symbolName))); + return factory.createIndexedAccessTypeNode( + LHS, + factory.createLiteralTypeNode(factory.createStringLiteral(symbolName)), + ); } else { - return factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(LHS, typeParameterNodes as readonly TypeNode[]), factory.createLiteralTypeNode(factory.createStringLiteral(symbolName))); + return factory.createIndexedAccessTypeNode( + factory.createTypeReferenceNode(LHS, typeParameterNodes as readonly TypeNode[]), + factory.createLiteralTypeNode(factory.createStringLiteral(symbolName)), + ); } } - const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); + const identifier = setEmitFlags( + factory.createIdentifier(symbolName, typeParameterNodes), + EmitFlags.NoAsciiEscaping, + ); identifier.symbol = symbol; if (index > stopper) { const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); if (!isEntityName(LHS)) { - return Debug.fail("Impossible construct - an export of an indexed access cannot be reachable"); + return Debug.fail( + "Impossible construct - an export of an indexed access cannot be reachable", + ); } return factory.createQualifiedName(LHS, identifier); } @@ -6650,8 +8918,19 @@ namespace ts { } } - function typeParameterShadowsNameInScope(escapedName: __String, context: NodeBuilderContext, type: TypeParameter) { - const result = resolveName(context.enclosingDeclaration, escapedName, SymbolFlags.Type, /*nameNotFoundArg*/ undefined, escapedName, /*isUse*/ false); + function typeParameterShadowsNameInScope( + escapedName: __String, + context: NodeBuilderContext, + type: TypeParameter, + ) { + const result = resolveName( + context.enclosingDeclaration, + escapedName, + SymbolFlags.Type, + /*nameNotFoundArg*/ undefined, + escapedName, + /*isUse*/ false, + ); if (result) { if (result.flags & SymbolFlags.TypeParameter && result === type.symbol) { return false; @@ -6676,7 +8955,10 @@ namespace ts { const rawtext = result.escapedText as string; let i = context.typeParameterNamesByTextNextNameCount?.get(rawtext) || 0; let text = rawtext; - while (context.typeParameterNamesByText?.has(text) || typeParameterShadowsNameInScope(text as __String, context, type)) { + while ( + context.typeParameterNamesByText?.has(text) + || typeParameterShadowsNameInScope(text as __String, context, type) + ) { i++; text = `${rawtext}_${i}`; } @@ -6692,9 +8974,24 @@ namespace ts { return result; } - function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: true): Identifier; - function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: false): EntityName; - function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: boolean): EntityName { + function symbolToName( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + expectsIdentifier: true, + ): Identifier; + function symbolToName( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + expectsIdentifier: false, + ): EntityName; + function symbolToName( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + expectsIdentifier: boolean, + ): EntityName { const chain = lookupSymbolChain(symbol, context, meaning); if ( @@ -6718,10 +9015,15 @@ namespace ts { context.flags ^= NodeBuilderFlags.InInitialEntityName; } - const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); + const identifier = setEmitFlags( + factory.createIdentifier(symbolName, typeParameterNodes), + EmitFlags.NoAsciiEscaping, + ); identifier.symbol = symbol; - return index > 0 ? factory.createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier; + return index > 0 + ? factory.createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) + : identifier; } } @@ -6743,17 +9045,27 @@ namespace ts { } let firstChar = symbolName.charCodeAt(0); - if (isSingleOrDoubleQuote(firstChar) && some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { + if ( + isSingleOrDoubleQuote(firstChar) + && some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol) + ) { return factory.createStringLiteral(getSpecifierForModuleSymbol(symbol, context)); } - const canUsePropertyAccess = firstChar === CharacterCodes.hash ? - symbolName.length > 1 && isIdentifierStart(symbolName.charCodeAt(1), languageVersion) : - isIdentifierStart(firstChar, languageVersion); + const canUsePropertyAccess = firstChar === CharacterCodes.hash + ? symbolName.length > 1 && isIdentifierStart(symbolName.charCodeAt(1), languageVersion) + : isIdentifierStart(firstChar, languageVersion); if (index === 0 || canUsePropertyAccess) { - const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); + const identifier = setEmitFlags( + factory.createIdentifier(symbolName, typeParameterNodes), + EmitFlags.NoAsciiEscaping, + ); identifier.symbol = symbol; - return index > 0 ? factory.createPropertyAccessExpression(createExpressionFromSymbolChain(chain, index - 1), identifier) : identifier; + return index > 0 + ? factory.createPropertyAccessExpression( + createExpressionFromSymbolChain(chain, index - 1), + identifier, + ) : identifier; } else { if (firstChar === CharacterCodes.openBracket) { @@ -6762,16 +9074,25 @@ namespace ts { } let expression: Expression | undefined; if (isSingleOrDoubleQuote(firstChar) && !(symbol.flags & SymbolFlags.EnumMember)) { - expression = factory.createStringLiteral(stripQuotes(symbolName).replace(/\\./g, s => s.substring(1)), firstChar === CharacterCodes.singleQuote); + expression = factory.createStringLiteral( + stripQuotes(symbolName).replace(/\\./g, s => s.substring(1)), + firstChar === CharacterCodes.singleQuote, + ); } else if (("" + +symbolName) === symbolName) { expression = factory.createNumericLiteral(+symbolName); } if (!expression) { - expression = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); + expression = setEmitFlags( + factory.createIdentifier(symbolName, typeParameterNodes), + EmitFlags.NoAsciiEscaping, + ); expression.symbol = symbol; } - return factory.createElementAccessExpression(createExpressionFromSymbolChain(chain, index - 1), expression); + return factory.createElementAccessExpression( + createExpressionFromSymbolChain(chain, index - 1), + expression, + ); } } } @@ -6783,27 +9104,41 @@ namespace ts { function isSingleQuotedStringNamed(d: Declaration) { const name = getNameOfDeclaration(d); - return !!(name && isStringLiteral(name) && (name.singleQuote || !nodeIsSynthesized(name) && startsWith(getTextOfNode(name, /*includeTrivia*/ false), "'"))); + return !!(name && isStringLiteral(name) + && (name.singleQuote + || !nodeIsSynthesized(name) && startsWith(getTextOfNode(name, /*includeTrivia*/ false), "'"))); } function getPropertyNameNodeForSymbol(symbol: Symbol, context: NodeBuilderContext) { - const singleQuote = !!length(symbol.declarations) && every(symbol.declarations, isSingleQuotedStringNamed); + const singleQuote = !!length(symbol.declarations) + && every(symbol.declarations, isSingleQuotedStringNamed); const fromNameType = getPropertyNameNodeForSymbolFromNameType(symbol, context, singleQuote); if (fromNameType) { return fromNameType; } const rawName = unescapeLeadingUnderscores(symbol.escapedName); const stringNamed = !!length(symbol.declarations) && every(symbol.declarations, isStringNamed); - return createPropertyNameNodeForIdentifierOrLiteral(rawName, getEmitScriptTarget(compilerOptions), singleQuote, stringNamed); + return createPropertyNameNodeForIdentifierOrLiteral( + rawName, + getEmitScriptTarget(compilerOptions), + singleQuote, + stringNamed, + ); } // See getNameForSymbolFromNameType for a stringy equivalent - function getPropertyNameNodeForSymbolFromNameType(symbol: Symbol, context: NodeBuilderContext, singleQuote?: boolean) { + function getPropertyNameNodeForSymbolFromNameType( + symbol: Symbol, + context: NodeBuilderContext, + singleQuote?: boolean, + ) { const nameType = getSymbolLinks(symbol).nameType; if (nameType) { if (nameType.flags & TypeFlags.StringOrNumberLiteral) { const name = "" + (nameType as StringLiteralType | NumberLiteralType).value; - if (!isIdentifierText(name, getEmitScriptTarget(compilerOptions)) && !isNumericLiteralName(name)) { + if ( + !isIdentifierText(name, getEmitScriptTarget(compilerOptions)) && !isNumericLiteralName(name) + ) { return factory.createStringLiteral(name, !!singleQuote); } if (isNumericLiteralName(name) && startsWith(name, "-")) { @@ -6812,7 +9147,9 @@ namespace ts { return createPropertyNameNodeForIdentifierOrLiteral(name, getEmitScriptTarget(compilerOptions)); } if (nameType.flags & TypeFlags.UniqueESSymbol) { - return factory.createComputedPropertyName(symbolToExpression((nameType as UniqueESSymbolType).symbol, context, SymbolFlags.Value)); + return factory.createComputedPropertyName( + symbolToExpression((nameType as UniqueESSymbolType).symbol, context, SymbolFlags.Value), + ); } } } @@ -6845,24 +9182,50 @@ namespace ts { } function getDeclarationWithTypeAnnotation(symbol: Symbol, enclosingDeclaration: Node | undefined) { - return symbol.declarations && find(symbol.declarations, s => !!getEffectiveTypeAnnotationNode(s) && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration))); + return symbol.declarations + && find( + symbol.declarations, + s => !!getEffectiveTypeAnnotationNode(s) + && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration)), + ); } - function existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing: TypeNode, type: Type) { - return !(getObjectFlags(type) & ObjectFlags.Reference) || !isTypeReferenceNode(existing) || length(existing.typeArguments) >= getMinTypeArgumentCount((type as TypeReference).target.typeParameters); + function existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount( + existing: TypeNode, + type: Type, + ) { + return !(getObjectFlags(type) & ObjectFlags.Reference) || !isTypeReferenceNode(existing) + || length(existing.typeArguments) + >= getMinTypeArgumentCount((type as TypeReference).target.typeParameters); } /** * Unlike `typeToTypeNodeHelper`, this handles setting up the `AllowUniqueESSymbolType` flag * so a `unique symbol` is returned when appropriate for the input symbol, rather than `typeof sym` */ - function serializeTypeForDeclaration(context: NodeBuilderContext, type: Type, symbol: Symbol, enclosingDeclaration: Node | undefined, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { + function serializeTypeForDeclaration( + context: NodeBuilderContext, + type: Type, + symbol: Symbol, + enclosingDeclaration: Node | undefined, + includePrivateSymbol?: (s: Symbol) => void, + bundled?: boolean, + ) { if (!isErrorType(type) && enclosingDeclaration) { const declWithExistingAnnotation = getDeclarationWithTypeAnnotation(symbol, enclosingDeclaration); - if (declWithExistingAnnotation && !isFunctionLikeDeclaration(declWithExistingAnnotation) && !isGetAccessorDeclaration(declWithExistingAnnotation)) { + if ( + declWithExistingAnnotation && !isFunctionLikeDeclaration(declWithExistingAnnotation) + && !isGetAccessorDeclaration(declWithExistingAnnotation) + ) { // try to reuse the existing annotation const existing = getEffectiveTypeAnnotationNode(declWithExistingAnnotation)!; - if (typeNodeIsEquivalentToType(existing, declWithExistingAnnotation, type) && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing, type)) { + if ( + typeNodeIsEquivalentToType(existing, declWithExistingAnnotation, type) + && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount( + existing, + type, + ) + ) { const result = serializeExistingTypeNode(context, existing, includePrivateSymbol, bundled); if (result) { return result; @@ -6872,8 +9235,13 @@ namespace ts { } const oldFlags = context.flags; if ( - type.flags & TypeFlags.UniqueESSymbol && - type.symbol === symbol && (!context.enclosingDeclaration || some(symbol.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!))) + type.flags & TypeFlags.UniqueESSymbol + && type.symbol === symbol + && (!context.enclosingDeclaration + || some( + symbol.declarations, + d => getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!), + )) ) { context.flags |= NodeBuilderFlags.AllowUniqueESSymbolType; } @@ -6893,14 +9261,33 @@ namespace ts { return false; } - function serializeReturnTypeForSignature(context: NodeBuilderContext, type: Type, signature: Signature, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { + function serializeReturnTypeForSignature( + context: NodeBuilderContext, + type: Type, + signature: Signature, + includePrivateSymbol?: (s: Symbol) => void, + bundled?: boolean, + ) { if (!isErrorType(type) && context.enclosingDeclaration) { const annotation = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation) { const annotated = getTypeFromTypeNode(annotation); - const thisInstantiated = annotated.flags & TypeFlags.TypeParameter && (annotated as TypeParameter).isThisType ? instantiateType(annotated, signature.mapper) : annotated; - if (thisInstantiated === type && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(annotation, type)) { - const result = serializeExistingTypeNode(context, annotation, includePrivateSymbol, bundled); + const thisInstantiated = + annotated.flags & TypeFlags.TypeParameter && (annotated as TypeParameter).isThisType + ? instantiateType(annotated, signature.mapper) : annotated; + if ( + thisInstantiated === type + && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount( + annotation, + type, + ) + ) { + const result = serializeExistingTypeNode( + context, + annotation, + includePrivateSymbol, + bundled, + ); if (result) { return result; } @@ -6910,16 +9297,37 @@ namespace ts { return typeToTypeNodeHelper(type, context); } - function trackExistingEntityName(node: T, context: NodeBuilderContext, includePrivateSymbol?: (s: Symbol) => void) { + function trackExistingEntityName( + node: T, + context: NodeBuilderContext, + includePrivateSymbol?: (s: Symbol) => void, + ) { let introducesError = false; const leftmost = getFirstIdentifier(node); - if (isInJSFile(node) && (isExportsIdentifier(leftmost) || isModuleExportsAccessExpression(leftmost.parent) || (isQualifiedName(leftmost.parent) && isModuleIdentifier(leftmost.parent.left) && isExportsIdentifier(leftmost.parent.right)))) { + if ( + isInJSFile(node) + && (isExportsIdentifier(leftmost) || isModuleExportsAccessExpression(leftmost.parent) + || (isQualifiedName(leftmost.parent) && isModuleIdentifier(leftmost.parent.left) + && isExportsIdentifier(leftmost.parent.right))) + ) { introducesError = true; return { introducesError, node }; } - const sym = resolveEntityName(leftmost, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveALias*/ true); + const sym = resolveEntityName( + leftmost, + SymbolFlags.All, + /*ignoreErrors*/ true, + /*dontResolveALias*/ true, + ); if (sym) { - if (isSymbolAccessible(sym, context.enclosingDeclaration, SymbolFlags.All, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible) { + if ( + isSymbolAccessible( + sym, + context.enclosingDeclaration, + SymbolFlags.All, + /*shouldComputeAliasesToMakeVisible*/ false, + ).accessibility !== SymbolAccessibility.Accessible + ) { introducesError = true; } else { @@ -6928,16 +9336,26 @@ namespace ts { } if (isIdentifier(node)) { const type = getDeclaredTypeOfSymbol(sym); - const name = sym.flags & SymbolFlags.TypeParameter && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) ? typeParameterToName(type, context) : factory.cloneNode(node); + const name = sym.flags & SymbolFlags.TypeParameter + && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) + ? typeParameterToName(type, context) : factory.cloneNode(node); name.symbol = sym; // for quickinfo, which uses identifier symbol information - return { introducesError, node: setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping) }; + return { + introducesError, + node: setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping), + }; } } return { introducesError, node }; } - function serializeExistingTypeNode(context: NodeBuilderContext, existing: TypeNode, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { + function serializeExistingTypeNode( + context: NodeBuilderContext, + existing: TypeNode, + includePrivateSymbol?: (s: Symbol) => void, + bundled?: boolean, + ) { if (cancellationToken && cancellationToken.throwIfCancellationRequested) { cancellationToken.throwIfCancellationRequested(); } @@ -6958,35 +9376,52 @@ namespace ts { return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword); } if (isJSDocNullableType(node)) { - return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols), factory.createLiteralTypeNode(factory.createNull())]); + return factory.createUnionTypeNode([ + visitNode(node.type, visitExistingNodeTreeSymbols), + factory.createLiteralTypeNode(factory.createNull()), + ]); } if (isJSDocOptionalType(node)) { - return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols), factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]); + return factory.createUnionTypeNode([ + visitNode(node.type, visitExistingNodeTreeSymbols), + factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword), + ]); } if (isJSDocNonNullableType(node)) { return visitNode(node.type, visitExistingNodeTreeSymbols); } if (isJSDocVariadicType(node)) { - return factory.createArrayTypeNode(visitNode((node as JSDocVariadicType).type, visitExistingNodeTreeSymbols)); + return factory.createArrayTypeNode( + visitNode((node as JSDocVariadicType).type, visitExistingNodeTreeSymbols), + ); } if (isJSDocTypeLiteral(node)) { return factory.createTypeLiteralNode(map(node.jsDocPropertyTags, t => { const name = isIdentifier(t.name) ? t.name : t.name.right; const typeViaParent = getTypeOfPropertyOfType(getTypeFromTypeNode(node), name.escapedText); - const overrideTypeNode = typeViaParent && t.typeExpression && getTypeFromTypeNode(t.typeExpression.type) !== typeViaParent ? typeToTypeNodeHelper(typeViaParent, context) : undefined; + const overrideTypeNode = typeViaParent && t.typeExpression + && getTypeFromTypeNode(t.typeExpression.type) !== typeViaParent + ? typeToTypeNodeHelper(typeViaParent, context) : undefined; return factory.createPropertySignature( /*modifiers*/ undefined, name, - t.isBracketed || t.typeExpression && isJSDocOptionalType(t.typeExpression.type) ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - overrideTypeNode || (t.typeExpression && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols)) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + t.isBracketed || t.typeExpression && isJSDocOptionalType(t.typeExpression.type) + ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + overrideTypeNode + || (t.typeExpression + && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols)) + || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), ); })); } if (isTypeReferenceNode(node) && isIdentifier(node.typeName) && node.typeName.escapedText === "") { return setOriginalNode(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), node); } - if ((isExpressionWithTypeArguments(node) || isTypeReferenceNode(node)) && isJSDocIndexSignature(node)) { + if ( + (isExpressionWithTypeArguments(node) || isTypeReferenceNode(node)) + && isJSDocIndexSignature(node) + ) { return factory.createTypeLiteralNode([factory.createIndexSignature( /*modifiers*/ undefined, [factory.createParameterDeclaration( @@ -7005,16 +9440,21 @@ namespace ts { return factory.createConstructorTypeNode( /*modifiers*/ undefined, visitNodes(node.typeParameters, visitExistingNodeTreeSymbols), - mapDefined(node.parameters, (p, i) => - p.name && isIdentifier(p.name) && p.name.escapedText === "new" ? (newTypeNode = p.type, undefined) : factory.createParameterDeclaration( - /*modifiers*/ undefined, - getEffectiveDotDotDotForParameter(p), - getNameForJSDocFunctionParameter(p, i), - p.questionToken, - visitNode(p.type, visitExistingNodeTreeSymbols), - /*initializer*/ undefined, - )), - visitNode(newTypeNode || node.type, visitExistingNodeTreeSymbols) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + mapDefined( + node.parameters, + (p, i) => + p.name && isIdentifier(p.name) && p.name.escapedText === "new" + ? (newTypeNode = p.type, undefined) : factory.createParameterDeclaration( + /*modifiers*/ undefined, + getEffectiveDotDotDotForParameter(p), + getNameForJSDocFunctionParameter(p, i), + p.questionToken, + visitNode(p.type, visitExistingNodeTreeSymbols), + /*initializer*/ undefined, + ), + ), + visitNode(newTypeNode || node.type, visitExistingNodeTreeSymbols) + || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), ); } else { @@ -7029,30 +9469,45 @@ namespace ts { visitNode(p.type, visitExistingNodeTreeSymbols), /*initializer*/ undefined, )), - visitNode(node.type, visitExistingNodeTreeSymbols) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + visitNode(node.type, visitExistingNodeTreeSymbols) + || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), ); } } - if (isTypeReferenceNode(node) && isInJSDoc(node) && (!existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(node, getTypeFromTypeNode(node)) || getIntendedTypeFromJSDocTypeReference(node) || unknownSymbol === resolveTypeReferenceName(node, SymbolFlags.Type, /*ignoreErrors*/ true))) { + if ( + isTypeReferenceNode(node) && isInJSDoc(node) + && (!existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount( + node, + getTypeFromTypeNode(node), + ) || getIntendedTypeFromJSDocTypeReference(node) + || unknownSymbol + === resolveTypeReferenceName(node, SymbolFlags.Type, /*ignoreErrors*/ true)) + ) { return setOriginalNode(typeToTypeNodeHelper(getTypeFromTypeNode(node), context), node); } if (isLiteralImportTypeNode(node)) { const nodeSymbol = getNodeLinks(node).resolvedSymbol; if ( - isInJSDoc(node) && - nodeSymbol && - ( + isInJSDoc(node) + && nodeSymbol + && ( // The import type resolved using jsdoc fallback logic - (!node.isTypeOf && !(nodeSymbol.flags & SymbolFlags.Type)) || + (!node.isTypeOf && !(nodeSymbol.flags & SymbolFlags.Type)) // The import type had type arguments autofilled by js fallback logic - !(length(node.typeArguments) >= getMinTypeArgumentCount(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(nodeSymbol))) + || !(length(node.typeArguments) + >= getMinTypeArgumentCount( + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(nodeSymbol), + )) ) ) { return setOriginalNode(typeToTypeNodeHelper(getTypeFromTypeNode(node), context), node); } return factory.updateImportTypeNode( node, - factory.updateLiteralTypeNode(node.argument, rewriteModuleSpecifier(node, node.argument.literal)), + factory.updateLiteralTypeNode( + node.argument, + rewriteModuleSpecifier(node, node.argument.literal), + ), node.assertions, node.qualifier, visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode), @@ -7061,21 +9516,31 @@ namespace ts { } if (isEntityName(node) || isEntityNameExpression(node)) { - const { introducesError, node: result } = trackExistingEntityName(node, context, includePrivateSymbol); + const { introducesError, node: result } = trackExistingEntityName( + node, + context, + includePrivateSymbol, + ); hadError = hadError || introducesError; if (result !== node) { return result; } } - if (file && isTupleTypeNode(node) && (getLineAndCharacterOfPosition(file, node.pos).line === getLineAndCharacterOfPosition(file, node.end).line)) { + if ( + file && isTupleTypeNode(node) + && (getLineAndCharacterOfPosition(file, node.pos).line + === getLineAndCharacterOfPosition(file, node.end).line) + ) { setEmitFlags(node, EmitFlags.SingleLine); } return visitEachChild(node, visitExistingNodeTreeSymbols, nullTransformationContext); function getEffectiveDotDotDotForParameter(p: ParameterDeclaration) { - return p.dotDotDotToken || (p.type && isJSDocVariadicType(p.type) ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined); + return p.dotDotDotToken + || (p.type && isJSDocVariadicType(p.type) ? factory.createToken(SyntaxKind.DotDotDotToken) + : undefined); } /** Note that `new:T` parameters are not handled, but should be before calling this function. */ @@ -7090,11 +9555,15 @@ namespace ts { if (context.tracker && context.tracker.moduleResolverHost) { const targetFile = getExternalModuleFileFromDeclaration(parent); if (targetFile) { - const getCanonicalFileName = createGetCanonicalFileName(!!host.useCaseSensitiveFileNames); + const getCanonicalFileName = createGetCanonicalFileName( + !!host.useCaseSensitiveFileNames, + ); const resolverHost = { getCanonicalFileName, - getCurrentDirectory: () => context.tracker.moduleResolverHost!.getCurrentDirectory(), - getCommonSourceDirectory: () => context.tracker.moduleResolverHost!.getCommonSourceDirectory(), + getCurrentDirectory: () => + context.tracker.moduleResolverHost!.getCurrentDirectory(), + getCommonSourceDirectory: () => + context.tracker.moduleResolverHost!.getCommonSourceDirectory(), }; const newName = getResolvedExternalModuleName(resolverHost, targetFile); return factory.createStringLiteral(newName); @@ -7103,7 +9572,11 @@ namespace ts { } else { if (context.tracker && context.tracker.trackExternalModuleSymbolOfImportTypeNode) { - const moduleSym = resolveExternalModuleNameWorker(lit, lit, /*moduleNotFoundError*/ undefined); + const moduleSym = resolveExternalModuleNameWorker( + lit, + lit, + /*moduleNotFoundError*/ undefined, + ); if (moduleSym) { context.tracker.trackExternalModuleSymbolOfImportTypeNode(moduleSym); } @@ -7114,9 +9587,21 @@ namespace ts { } } - function symbolTableToDeclarationStatements(symbolTable: SymbolTable, context: NodeBuilderContext, bundled?: boolean): Statement[] { - const serializePropertySymbolForClass = makeSerializePropertySymbol(factory.createPropertyDeclaration, SyntaxKind.MethodDeclaration, /*useAcessors*/ true); - const serializePropertySymbolForInterfaceWorker = makeSerializePropertySymbol((mods, name, question, type) => factory.createPropertySignature(mods, name, question, type), SyntaxKind.MethodSignature, /*useAcessors*/ false); + function symbolTableToDeclarationStatements( + symbolTable: SymbolTable, + context: NodeBuilderContext, + bundled?: boolean, + ): Statement[] { + const serializePropertySymbolForClass = makeSerializePropertySymbol( + factory.createPropertyDeclaration, + SyntaxKind.MethodDeclaration, + /*useAcessors*/ true, + ); + const serializePropertySymbolForInterfaceWorker = makeSerializePropertySymbol( + (mods, name, question, type) => factory.createPropertySignature(mods, name, question, type), + SyntaxKind.MethodSignature, + /*useAcessors*/ false, + ); // TODO: Use `setOriginalNode` on original declaration names where possible so these declarations see some kind of // declaration mapping @@ -7173,9 +9658,15 @@ namespace ts { function getNamesOfDeclaration(statement: Statement): Identifier[] { if (isVariableStatement(statement)) { - return filter(map(statement.declarationList.declarations, getNameOfDeclaration), isIdentifierAndNotUndefined); + return filter( + map(statement.declarationList.declarations, getNameOfDeclaration), + isIdentifierAndNotUndefined, + ); } - return filter([getNameOfDeclaration(statement as DeclarationStatement)], isIdentifierAndNotUndefined); + return filter( + [getNameOfDeclaration(statement as DeclarationStatement)], + isIdentifierAndNotUndefined, + ); } function flattenExportAssignedNamespace(statements: Statement[]) { @@ -7183,13 +9674,17 @@ namespace ts { const nsIndex = findIndex(statements, isModuleDeclaration); let ns = nsIndex !== -1 ? statements[nsIndex] as ModuleDeclaration : undefined; if ( - ns && exportAssignment && exportAssignment.isExportEquals && - isIdentifier(exportAssignment.expression) && isIdentifier(ns.name) && idText(ns.name) === idText(exportAssignment.expression) && - ns.body && isModuleBlock(ns.body) + ns && exportAssignment && exportAssignment.isExportEquals + && isIdentifier(exportAssignment.expression) && isIdentifier(ns.name) + && idText(ns.name) === idText(exportAssignment.expression) + && ns.body && isModuleBlock(ns.body) ) { // Pass 0: Correct situations where a module has both an `export = ns` and multiple top-level exports by stripping the export modifiers from // the top-level exports and exporting them in the targeted ns, as can occur when a js file has both typedefs and `module.export` assignments - const excessExports = filter(statements, s => !!(getEffectiveModifierFlags(s) & ModifierFlags.Export)); + const excessExports = filter( + statements, + s => !!(getEffectiveModifierFlags(s) & ModifierFlags.Export), + ); const name = ns.name; let body = ns.body; if (length(excessExports)) { @@ -7204,7 +9699,17 @@ namespace ts { factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(map(flatMap(excessExports, e => getNamesOfDeclaration(e)), id => factory.createExportSpecifier(/*isTypeOnly*/ false, /*alias*/ undefined, id))), + factory.createNamedExports( + map( + flatMap(excessExports, e => getNamesOfDeclaration(e)), + id => + factory.createExportSpecifier( + /*isTypeOnly*/ false, + /*alias*/ undefined, + id, + ), + ), + ), /*moduleSpecifier*/ undefined, ), ]), @@ -7218,7 +9723,11 @@ namespace ts { results = []; // If the namespace contains no export assignments or declarations, and no declarations flagged with `export`, then _everything_ is exported - // to respect this as the top level, we need to add an `export` modifier to everything - const mixinExportFlag = !some(body.statements, s => hasSyntacticModifier(s, ModifierFlags.Export) || isExportAssignment(s) || isExportDeclaration(s)); + const mixinExportFlag = !some( + body.statements, + s => hasSyntacticModifier(s, ModifierFlags.Export) || isExportAssignment(s) + || isExportDeclaration(s), + ); forEach(body.statements, s => { addResult(s, mixinExportFlag ? ModifierFlags.Export : ModifierFlags.None); // Recalculates the ambient (and export, if applicable from above) flag }); @@ -7230,23 +9739,39 @@ namespace ts { function mergeExportDeclarations(statements: Statement[]) { // Pass 2: Combine all `export {}` declarations - const exports = filter(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !!d.exportClause && isNamedExports(d.exportClause)) as ExportDeclaration[]; + const exports = filter( + statements, + d => isExportDeclaration(d) && !d.moduleSpecifier && !!d.exportClause + && isNamedExports(d.exportClause), + ) as ExportDeclaration[]; if (length(exports) > 1) { - const nonExports = filter(statements, d => !isExportDeclaration(d) || !!d.moduleSpecifier || !d.exportClause); + const nonExports = filter( + statements, + d => !isExportDeclaration(d) || !!d.moduleSpecifier || !d.exportClause, + ); statements = [ ...nonExports, factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(flatMap(exports, e => cast(e.exportClause, isNamedExports).elements)), + factory.createNamedExports( + flatMap(exports, e => cast(e.exportClause, isNamedExports).elements), + ), /*moduleSpecifier*/ undefined, ), ]; } // Pass 2b: Also combine all `export {} from "..."` declarations as needed - const reexports = filter(statements, d => isExportDeclaration(d) && !!d.moduleSpecifier && !!d.exportClause && isNamedExports(d.exportClause)) as ExportDeclaration[]; + const reexports = filter( + statements, + d => isExportDeclaration(d) && !!d.moduleSpecifier && !!d.exportClause + && isNamedExports(d.exportClause), + ) as ExportDeclaration[]; if (length(reexports) > 1) { - const groups = group(reexports, decl => isStringLiteral(decl.moduleSpecifier!) ? ">" + decl.moduleSpecifier.text : ">"); + const groups = group( + reexports, + decl => isStringLiteral(decl.moduleSpecifier!) ? ">" + decl.moduleSpecifier.text : ">", + ); if (groups.length !== reexports.length) { for (const group of groups) { if (group.length > 1) { @@ -7256,7 +9781,9 @@ namespace ts { factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(flatMap(group, e => cast(e.exportClause, isNamedExports).elements)), + factory.createNamedExports( + flatMap(group, e => cast(e.exportClause, isNamedExports).elements), + ), group[0].moduleSpecifier, ), ]; @@ -7269,17 +9796,28 @@ namespace ts { function inlineExportModifiers(statements: Statement[]) { // Pass 3: Move all `export {}`'s to `export` modifiers where possible - const index = findIndex(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !d.assertClause && !!d.exportClause && isNamedExports(d.exportClause)); + const index = findIndex( + statements, + d => isExportDeclaration(d) && !d.moduleSpecifier && !d.assertClause && !!d.exportClause + && isNamedExports(d.exportClause), + ); if (index >= 0) { - const exportDecl = statements[index] as ExportDeclaration & { readonly exportClause: NamedExports; }; + const exportDecl = statements[index] as ExportDeclaration & { + readonly exportClause: NamedExports; + }; const replacements = mapDefined(exportDecl.exportClause.elements, e => { if (!e.propertyName) { // export {name} - look thru `statements` for `name`, and if all results can take an `export` modifier, do so and filter it const indices = indicesOf(statements); const associatedIndices = filter(indices, i => nodeHasName(statements[i], e.name)); - if (length(associatedIndices) && every(associatedIndices, i => canHaveExportModifier(statements[i]))) { + if ( + length(associatedIndices) + && every(associatedIndices, i => canHaveExportModifier(statements[i])) + ) { for (const index of associatedIndices) { - statements[index] = addExportModifier(statements[index] as Extract); + statements[index] = addExportModifier( + statements[index] as Extract, + ); } return undefined; } @@ -7316,9 +9854,11 @@ namespace ts { // Not a cleanup, but as a final step: If there is a mix of `export` and non-`export` declarations, but no `export =` or `export {}` add a `export {};` so // declaration privacy is respected. if ( - enclosingDeclaration && - ((isSourceFile(enclosingDeclaration) && isExternalOrCommonJsModule(enclosingDeclaration)) || isModuleDeclaration(enclosingDeclaration)) && - (!some(statements, isExternalModuleIndicator) || (!hasScopeMarker(statements) && some(statements, needsScopeMarker))) + enclosingDeclaration + && ((isSourceFile(enclosingDeclaration) && isExternalOrCommonJsModule(enclosingDeclaration)) + || isModuleDeclaration(enclosingDeclaration)) + && (!some(statements, isExternalModuleIndicator) + || (!hasScopeMarker(statements) && some(statements, needsScopeMarker))) ) { statements.push(createEmptyExports(factory)); } @@ -7335,7 +9875,11 @@ namespace ts { return factory.updateModifiers(node, flags); } - function visitSymbolTable(symbolTable: SymbolTable, suppressNewPrivateContext?: boolean, propertyAsAlias?: boolean) { + function visitSymbolTable( + symbolTable: SymbolTable, + suppressNewPrivateContext?: boolean, + propertyAsAlias?: boolean, + ) { if (!suppressNewPrivateContext) { deferredPrivatesStack.push(new Map()); } @@ -7363,7 +9907,11 @@ namespace ts { visitedSymbols.add(getSymbolId(visitedSym)); // Only actually serialize symbols within the correct enclosing declaration, otherwise do nothing with the out-of-context symbol const skipMembershipCheck = !isPrivate; // We only call this on exported symbols when we know they're in the correct scope - if (skipMembershipCheck || (!!length(symbol.declarations) && some(symbol.declarations, d => !!findAncestor(d, n => n === enclosingDeclaration)))) { + if ( + skipMembershipCheck + || (!!length(symbol.declarations) + && some(symbol.declarations, d => !!findAncestor(d, n => n === enclosingDeclaration))) + ) { const oldContext = context; context = cloneNodeBuilderContext(context); serializeSymbolWorker(symbol, isPrivate, propertyAsAlias); @@ -7386,7 +9934,10 @@ namespace ts { function serializeSymbolWorker(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean): void { const symbolName = unescapeLeadingUnderscores(symbol.escapedName); const isDefault = symbol.escapedName === InternalSymbolName.Default; - if (isPrivate && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier) && isStringANonContextualKeyword(symbolName) && !isDefault) { + if ( + isPrivate && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier) + && isStringANonContextualKeyword(symbolName) && !isDefault + ) { // Oh no. We cannot use this symbol's name as it's name... It's likely some jsdoc had an invalid name like `export` or `default` :( context.encounteredError = true; // TODO: Issue error via symbol tracker? @@ -7396,18 +9947,31 @@ namespace ts { symbol.flags & SymbolFlags.ExportDoesNotSupportDefaultModifier || (symbol.flags & SymbolFlags.Function && length(getPropertiesOfType(getTypeOfSymbol(symbol)))) ) && !(symbol.flags & SymbolFlags.Alias); // An alias symbol should preclude needing to make an alias ourselves - let needsExportDeclaration = !needsPostExportDefault && !isPrivate && isStringANonContextualKeyword(symbolName) && !isDefault; + let needsExportDeclaration = !needsPostExportDefault && !isPrivate + && isStringANonContextualKeyword(symbolName) && !isDefault; // `serializeVariableOrProperty` will handle adding the export declaration if it is run (since `getInternalSymbolName` will create the name mapping), so we need to ensuer we unset `needsExportDeclaration` if it is if (needsPostExportDefault || needsExportDeclaration) { isPrivate = true; } - const modifierFlags = (!isPrivate ? ModifierFlags.Export : 0) | (isDefault && !needsPostExportDefault ? ModifierFlags.Default : 0); - const isConstMergedWithNS = symbol.flags & SymbolFlags.Module && - symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property) && - symbol.escapedName !== InternalSymbolName.ExportEquals; - const isConstMergedWithNSPrintableAsSignatureMerge = isConstMergedWithNS && isTypeRepresentableAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol); - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) || isConstMergedWithNSPrintableAsSignatureMerge) { - serializeAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); + const modifierFlags = (!isPrivate ? ModifierFlags.Export : 0) + | (isDefault && !needsPostExportDefault ? ModifierFlags.Default : 0); + const isConstMergedWithNS = symbol.flags & SymbolFlags.Module + && symbol.flags + & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable + | SymbolFlags.Property) + && symbol.escapedName !== InternalSymbolName.ExportEquals; + const isConstMergedWithNSPrintableAsSignatureMerge = isConstMergedWithNS + && isTypeRepresentableAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol); + if ( + symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) + || isConstMergedWithNSPrintableAsSignatureMerge + ) { + serializeAsFunctionNamespaceMerge( + getTypeOfSymbol(symbol), + symbol, + getInternalSymbolName(symbol, symbolName), + modifierFlags, + ); } if (symbol.flags & SymbolFlags.TypeAlias) { serializeTypeAlias(symbol, symbolName, modifierFlags); @@ -7415,7 +9979,9 @@ namespace ts { // Need to skip over export= symbols below - json source files get a single `Property` flagged // symbol of name `export=` which needs to be handled like an alias. It's not great, but it is what it is. if ( - symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property) + symbol.flags + & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable + | SymbolFlags.Property) && symbol.escapedName !== InternalSymbolName.ExportEquals && !(symbol.flags & SymbolFlags.Prototype) && !(symbol.flags & SymbolFlags.Class) @@ -7432,7 +9998,10 @@ namespace ts { else { const type = getTypeOfSymbol(symbol); const localName = getInternalSymbolName(symbol, symbolName); - if (!(symbol.flags & SymbolFlags.Function) && isTypeRepresentableAsFunctionNamespaceMerge(type, symbol)) { + if ( + !(symbol.flags & SymbolFlags.Function) + && isTypeRepresentableAsFunctionNamespaceMerge(type, symbol) + ) { // If the type looks like a function declaration + ns could represent it, and it's type is sourced locally, rewrite it into a function declaration + ns serializeAsFunctionNamespaceMerge(type, symbol, localName, modifierFlags); } @@ -7446,38 +10015,65 @@ namespace ts { : isConstVariable(symbol) ? NodeFlags.Const : NodeFlags.Let; - const name = (needsPostExportDefault || !(symbol.flags & SymbolFlags.Property)) ? localName : getUnusedName(localName, symbol); - let textRange: Node | undefined = symbol.declarations && find(symbol.declarations, d => isVariableDeclaration(d)); - if (textRange && isVariableDeclarationList(textRange.parent) && textRange.parent.declarations.length === 1) { + const name = (needsPostExportDefault || !(symbol.flags & SymbolFlags.Property)) + ? localName : getUnusedName(localName, symbol); + let textRange: Node | undefined = symbol.declarations + && find(symbol.declarations, d => isVariableDeclaration(d)); + if ( + textRange && isVariableDeclarationList(textRange.parent) + && textRange.parent.declarations.length === 1 + ) { textRange = textRange.parent.parent; } const propertyAccessRequire = symbol.declarations?.find(isPropertyAccessExpression); if ( - propertyAccessRequire && isBinaryExpression(propertyAccessRequire.parent) && isIdentifier(propertyAccessRequire.parent.right) + propertyAccessRequire && isBinaryExpression(propertyAccessRequire.parent) + && isIdentifier(propertyAccessRequire.parent.right) && type.symbol?.valueDeclaration && isSourceFile(type.symbol.valueDeclaration) ) { - const alias = localName === propertyAccessRequire.parent.right.escapedText ? undefined : propertyAccessRequire.parent.right; + const alias = localName === propertyAccessRequire.parent.right.escapedText + ? undefined : propertyAccessRequire.parent.right; addResult( factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, alias, localName)]), + factory.createNamedExports([ + factory.createExportSpecifier(/*isTypeOnly*/ false, alias, localName), + ]), ), ModifierFlags.None, ); - context.tracker.trackSymbol!(type.symbol, context.enclosingDeclaration, SymbolFlags.Value); + context.tracker.trackSymbol!( + type.symbol, + context.enclosingDeclaration, + SymbolFlags.Value, + ); } else { const statement = setTextRange( factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList([ - factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, serializeTypeForDeclaration(context, type, symbol, enclosingDeclaration, includePrivateSymbol, bundled)), + factory.createVariableDeclaration( + name, + /*exclamationToken*/ undefined, + serializeTypeForDeclaration( + context, + type, + symbol, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), + ), ], flags), ), textRange, ); - addResult(statement, name !== localName ? modifierFlags & ~ModifierFlags.Export : modifierFlags); + addResult( + statement, + name !== localName ? modifierFlags & ~ModifierFlags.Export : modifierFlags, + ); if (name !== localName && !isPrivate) { // We rename the variable declaration we generate for Property symbols since they may have a name which // conflicts with a local declaration. For example, given input: @@ -7504,7 +10100,13 @@ namespace ts { factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, name, localName)]), + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + name, + localName, + ), + ]), ), ModifierFlags.None, ); @@ -7534,7 +10136,11 @@ namespace ts { serializeAsClass(symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); } } - if ((symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && (!isConstMergedWithNS || isTypeOnlyNamespace(symbol))) || isConstMergedWithNSPrintableAsSignatureMerge) { + if ( + (symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) + && (!isConstMergedWithNS || isTypeOnlyNamespace(symbol))) + || isConstMergedWithNSPrintableAsSignatureMerge + ) { serializeModule(symbol, symbolName, modifierFlags); } // The class meaning serialization should handle serializing all interface members @@ -7552,21 +10158,47 @@ namespace ts { // Straightforward - only one thing to do - make an export declaration if (symbol.declarations) { for (const node of symbol.declarations) { - const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); + const resolvedModule = resolveExternalModuleName( + node, + (node as ExportDeclaration).moduleSpecifier!, + ); if (!resolvedModule) continue; - addResult(factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, /*exportClause*/ undefined, factory.createStringLiteral(getSpecifierForModuleSymbol(resolvedModule, context))), ModifierFlags.None); + addResult( + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + /*exportClause*/ undefined, + factory.createStringLiteral( + getSpecifierForModuleSymbol(resolvedModule, context), + ), + ), + ModifierFlags.None, + ); } } } if (needsPostExportDefault) { - addResult(factory.createExportAssignment(/*modifiers*/ undefined, /*isExportAssignment*/ false, factory.createIdentifier(getInternalSymbolName(symbol, symbolName))), ModifierFlags.None); + addResult( + factory.createExportAssignment( + /*modifiers*/ undefined, + /*isExportAssignment*/ false, + factory.createIdentifier(getInternalSymbolName(symbol, symbolName)), + ), + ModifierFlags.None, + ); } else if (needsExportDeclaration) { addResult( factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, getInternalSymbolName(symbol, symbolName), symbolName)]), + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + getInternalSymbolName(symbol, symbolName), + symbolName, + ), + ]), ), ModifierFlags.None, ); @@ -7582,41 +10214,52 @@ namespace ts { // will throw a wrench in this, since those may have been nested, but we'll need to synthesize them in the outer scope // anyway, as that's the only place the import they translate to is valid. In such a case, we might need to use a unique name // for the moved import; which hopefully the above `getUnusedName` call should produce. - const isExternalImportAlias = !!(symbol.flags & SymbolFlags.Alias) && !some(symbol.declarations, d => - !!findAncestor(d, isExportDeclaration) || - isNamespaceExport(d) || - (isImportEqualsDeclaration(d) && !isExternalModuleReference(d.moduleReference))); - deferredPrivatesStack[isExternalImportAlias ? 0 : (deferredPrivatesStack.length - 1)].set(getSymbolId(symbol), symbol); + const isExternalImportAlias = !!(symbol.flags & SymbolFlags.Alias) + && !some(symbol.declarations, d => + !!findAncestor(d, isExportDeclaration) + || isNamespaceExport(d) + || (isImportEqualsDeclaration(d) && !isExternalModuleReference(d.moduleReference))); + deferredPrivatesStack[isExternalImportAlias ? 0 : (deferredPrivatesStack.length - 1)].set( + getSymbolId(symbol), + symbol, + ); } function isExportingScope(enclosingDeclaration: Node) { - return ((isSourceFile(enclosingDeclaration) && (isExternalOrCommonJsModule(enclosingDeclaration) || isJsonSourceFile(enclosingDeclaration))) || - (isAmbientModule(enclosingDeclaration) && !isGlobalScopeAugmentation(enclosingDeclaration))); + return ((isSourceFile(enclosingDeclaration) + && (isExternalOrCommonJsModule(enclosingDeclaration) || isJsonSourceFile(enclosingDeclaration))) + || (isAmbientModule(enclosingDeclaration) && !isGlobalScopeAugmentation(enclosingDeclaration))); } // Prepends a `declare` and/or `export` modifier if the context requires it, and then adds `node` to `result` and returns `node` function addResult(node: Statement, additionalModifierFlags: ModifierFlags) { if (canHaveModifiers(node)) { let newModifierFlags: ModifierFlags = ModifierFlags.None; - const enclosingDeclaration = context.enclosingDeclaration && - (isJSDocTypeAlias(context.enclosingDeclaration) ? getSourceFileOfNode(context.enclosingDeclaration) : context.enclosingDeclaration); + const enclosingDeclaration = context.enclosingDeclaration + && (isJSDocTypeAlias(context.enclosingDeclaration) + ? getSourceFileOfNode(context.enclosingDeclaration) : context.enclosingDeclaration); if ( - additionalModifierFlags & ModifierFlags.Export && - enclosingDeclaration && (isExportingScope(enclosingDeclaration) || isModuleDeclaration(enclosingDeclaration)) && - canHaveExportModifier(node) + additionalModifierFlags & ModifierFlags.Export + && enclosingDeclaration + && (isExportingScope(enclosingDeclaration) || isModuleDeclaration(enclosingDeclaration)) + && canHaveExportModifier(node) ) { // Classes, namespaces, variables, functions, interfaces, and types should all be `export`ed in a module context if not private newModifierFlags |= ModifierFlags.Export; } if ( - addingDeclare && !(newModifierFlags & ModifierFlags.Export) && - (!enclosingDeclaration || !(enclosingDeclaration.flags & NodeFlags.Ambient)) && - (isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) || isClassDeclaration(node) || isModuleDeclaration(node)) + addingDeclare && !(newModifierFlags & ModifierFlags.Export) + && (!enclosingDeclaration || !(enclosingDeclaration.flags & NodeFlags.Ambient)) + && (isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) + || isClassDeclaration(node) || isModuleDeclaration(node)) ) { // Classes, namespaces, variables, enums, and functions all need `declare` modifiers to be valid in a declaration file top-level scope newModifierFlags |= ModifierFlags.Ambient; } - if ((additionalModifierFlags & ModifierFlags.Default) && (isClassDeclaration(node) || isInterfaceDeclaration(node) || isFunctionDeclaration(node))) { + if ( + (additionalModifierFlags & ModifierFlags.Default) + && (isClassDeclaration(node) || isInterfaceDeclaration(node) || isFunctionDeclaration(node)) + ) { newModifierFlags |= ModifierFlags.Default; } if (newModifierFlags) { @@ -7631,19 +10274,38 @@ namespace ts { const typeParams = getSymbolLinks(symbol).typeParameters; const typeParamDecls = map(typeParams, p => typeParameterToDeclaration(p, context)); const jsdocAliasDecl = symbol.declarations?.find(isJSDocTypeAlias); - const commentText = getTextOfJSDocComment(jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined); + const commentText = getTextOfJSDocComment( + jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined, + ); const oldFlags = context.flags; context.flags |= NodeBuilderFlags.InTypeAlias; const oldEnclosingDecl = context.enclosingDeclaration; context.enclosingDeclaration = jsdocAliasDecl; const typeNode = jsdocAliasDecl && jsdocAliasDecl.typeExpression && isJSDocTypeExpression(jsdocAliasDecl.typeExpression) - && serializeExistingTypeNode(context, jsdocAliasDecl.typeExpression.type, includePrivateSymbol, bundled) + && serializeExistingTypeNode( + context, + jsdocAliasDecl.typeExpression.type, + includePrivateSymbol, + bundled, + ) || typeToTypeNodeHelper(aliasType, context); addResult( setSyntheticLeadingComments( - factory.createTypeAliasDeclaration(/*modifiers*/ undefined, getInternalSymbolName(symbol, symbolName), typeParamDecls, typeNode), - !commentText ? [] : [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }], + factory.createTypeAliasDeclaration( + /*modifiers*/ undefined, + getInternalSymbolName(symbol, symbolName), + typeParamDecls, + typeNode, + ), + !commentText ? [] + : [{ + kind: SyntaxKind.MultiLineCommentTrivia, + text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }], ), modifierFlags, ); @@ -7657,12 +10319,29 @@ namespace ts { const typeParamDecls = map(localParams, p => typeParameterToDeclaration(p, context)); const baseTypes = getBaseTypes(interfaceType); const baseType = length(baseTypes) ? getIntersectionType(baseTypes) : undefined; - const members = flatMap(getPropertiesOfType(interfaceType), p => serializePropertySymbolForInterface(p, baseType)); - const callSignatures = serializeSignatures(SignatureKind.Call, interfaceType, baseType, SyntaxKind.CallSignature) as CallSignatureDeclaration[]; - const constructSignatures = serializeSignatures(SignatureKind.Construct, interfaceType, baseType, SyntaxKind.ConstructSignature) as ConstructSignatureDeclaration[]; + const members = flatMap( + getPropertiesOfType(interfaceType), + p => serializePropertySymbolForInterface(p, baseType), + ); + const callSignatures = serializeSignatures( + SignatureKind.Call, + interfaceType, + baseType, + SyntaxKind.CallSignature, + ) as CallSignatureDeclaration[]; + const constructSignatures = serializeSignatures( + SignatureKind.Construct, + interfaceType, + baseType, + SyntaxKind.ConstructSignature, + ) as ConstructSignatureDeclaration[]; const indexSignatures = serializeIndexSignatures(interfaceType, baseType); - const heritageClauses = !length(baseTypes) ? undefined : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, mapDefined(baseTypes, b => trySerializeAsTypeReference(b, SymbolFlags.Value)))]; + const heritageClauses = !length(baseTypes) ? undefined + : [factory.createHeritageClause( + SyntaxKind.ExtendsKeyword, + mapDefined(baseTypes, b => trySerializeAsTypeReference(b, SymbolFlags.Value)), + )]; addResult( factory.createInterfaceDeclaration( /*modifiers*/ undefined, @@ -7680,13 +10359,19 @@ namespace ts { } function isTypeOnlyNamespace(symbol: Symbol) { - return every(getNamespaceMembersForSerialization(symbol), m => !(getAllSymbolFlags(resolveSymbol(m)) & SymbolFlags.Value)); + return every( + getNamespaceMembersForSerialization(symbol), + m => !(getAllSymbolFlags(resolveSymbol(m)) & SymbolFlags.Value), + ); } function serializeModule(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { const members = getNamespaceMembersForSerialization(symbol); // Split NS members up by declaration - members whose parent symbol is the ns symbol vs those whose is not (but were added in later via merging) - const locationMap = arrayToMultiMap(members, m => m.parent && m.parent === symbol ? "real" : "merged"); + const locationMap = arrayToMultiMap( + members, + m => m.parent && m.parent === symbol ? "real" : "merged", + ); const realMembers = locationMap.get("real") || emptyArray; const mergedMembers = locationMap.get("merged") || emptyArray; // TODO: `suppressNewPrivateContext` is questionable -we need to simply be emitting privates in whatever scope they were declared in, rather @@ -7694,7 +10379,12 @@ namespace ts { // so we don't even have placeholders to fill in. if (length(realMembers)) { const localName = getInternalSymbolName(symbol, symbolName); - serializeAsNamespaceDeclaration(realMembers, localName, modifierFlags, !!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Assignment))); + serializeAsNamespaceDeclaration( + realMembers, + localName, + modifierFlags, + !!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Assignment)), + ); } if (length(mergedMembers)) { const containingFile = getSourceFileOfNode(context.enclosingDeclaration); @@ -7702,19 +10392,37 @@ namespace ts { const nsBody = factory.createModuleBlock([factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(mapDefined(filter(mergedMembers, n => n.escapedName !== InternalSymbolName.ExportEquals), s => { - const name = unescapeLeadingUnderscores(s.escapedName); - const localName = getInternalSymbolName(s, name); - const aliasDecl = s.declarations && getDeclarationOfAliasSymbol(s); - if (containingFile && (aliasDecl ? containingFile !== getSourceFileOfNode(aliasDecl) : !some(s.declarations, d => getSourceFileOfNode(d) === containingFile))) { - context.tracker?.reportNonlocalAugmentation?.(containingFile, symbol, s); - return undefined; - } - const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); - includePrivateSymbol(target || s); - const targetName = target ? getInternalSymbolName(target, unescapeLeadingUnderscores(target.escapedName)) : localName; - return factory.createExportSpecifier(/*isTypeOnly*/ false, name === targetName ? undefined : targetName, name); - })), + factory.createNamedExports( + mapDefined( + filter(mergedMembers, n => n.escapedName !== InternalSymbolName.ExportEquals), + s => { + const name = unescapeLeadingUnderscores(s.escapedName); + const localName = getInternalSymbolName(s, name); + const aliasDecl = s.declarations && getDeclarationOfAliasSymbol(s); + if ( + containingFile + && (aliasDecl ? containingFile !== getSourceFileOfNode(aliasDecl) + : !some(s.declarations, d => getSourceFileOfNode(d) === containingFile)) + ) { + context.tracker?.reportNonlocalAugmentation?.(containingFile, symbol, s); + return undefined; + } + const target = aliasDecl + && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); + includePrivateSymbol(target || s); + const targetName = target + ? getInternalSymbolName( + target, + unescapeLeadingUnderscores(target.escapedName), + ) : localName; + return factory.createExportSpecifier( + /*isTypeOnly*/ false, + name === targetName ? undefined : targetName, + name, + ); + }, + ), + ), )]); addResult( factory.createModuleDeclaration( @@ -7731,56 +10439,109 @@ namespace ts { function serializeEnum(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { addResult( factory.createEnumDeclaration( - factory.createModifiersFromModifierFlags(isConstEnumSymbol(symbol) ? ModifierFlags.Const : 0), + factory.createModifiersFromModifierFlags( + isConstEnumSymbol(symbol) ? ModifierFlags.Const : 0, + ), getInternalSymbolName(symbol, symbolName), - map(filter(getPropertiesOfType(getTypeOfSymbol(symbol)), p => !!(p.flags & SymbolFlags.EnumMember)), p => { - // TODO: Handle computed names - // I hate that to get the initialized value we need to walk back to the declarations here; but there's no - // other way to get the possible const value of an enum member that I'm aware of, as the value is cached - // _on the declaration_, not on the declaration's symbol... - const initializedValue = p.declarations && p.declarations[0] && isEnumMember(p.declarations[0]) ? getConstantValue(p.declarations[0]) : undefined; - return factory.createEnumMember( - unescapeLeadingUnderscores(p.escapedName), - initializedValue === undefined ? undefined : - typeof initializedValue === "string" ? factory.createStringLiteral(initializedValue) : - factory.createNumericLiteral(initializedValue), - ); - }), + map( + filter( + getPropertiesOfType(getTypeOfSymbol(symbol)), + p => !!(p.flags & SymbolFlags.EnumMember), + ), + p => { + // TODO: Handle computed names + // I hate that to get the initialized value we need to walk back to the declarations here; but there's no + // other way to get the possible const value of an enum member that I'm aware of, as the value is cached + // _on the declaration_, not on the declaration's symbol... + const initializedValue = + p.declarations && p.declarations[0] && isEnumMember(p.declarations[0]) + ? getConstantValue(p.declarations[0]) : undefined; + return factory.createEnumMember( + unescapeLeadingUnderscores(p.escapedName), + initializedValue === undefined ? undefined + : typeof initializedValue === "string" + ? factory.createStringLiteral(initializedValue) + : factory.createNumericLiteral(initializedValue), + ); + }, + ), ), modifierFlags, ); } - function serializeAsFunctionNamespaceMerge(type: Type, symbol: Symbol, localName: string, modifierFlags: ModifierFlags) { + function serializeAsFunctionNamespaceMerge( + type: Type, + symbol: Symbol, + localName: string, + modifierFlags: ModifierFlags, + ) { const signatures = getSignaturesOfType(type, SignatureKind.Call); for (const sig of signatures) { // Each overload becomes a separate function declaration, in order - const decl = signatureToSignatureDeclarationHelper(sig, SyntaxKind.FunctionDeclaration, context, { name: factory.createIdentifier(localName), privateSymbolVisitor: includePrivateSymbol, bundledImports: bundled }) as FunctionDeclaration; + const decl = signatureToSignatureDeclarationHelper( + sig, + SyntaxKind.FunctionDeclaration, + context, + { + name: factory.createIdentifier(localName), + privateSymbolVisitor: includePrivateSymbol, + bundledImports: bundled, + }, + ) as FunctionDeclaration; addResult(setTextRange(decl, getSignatureTextRangeLocation(sig)), modifierFlags); } // Module symbol emit will take care of module-y members, provided it has exports - if (!(symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && !!symbol.exports && !!symbol.exports.size)) { + if ( + !(symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && !!symbol.exports + && !!symbol.exports.size) + ) { const props = filter(getPropertiesOfType(type), isNamespaceMember); - serializeAsNamespaceDeclaration(props, localName, modifierFlags, /*suppressNewPrivateContext*/ true); + serializeAsNamespaceDeclaration( + props, + localName, + modifierFlags, + /*suppressNewPrivateContext*/ true, + ); } } function getSignatureTextRangeLocation(signature: Signature) { if (signature.declaration && signature.declaration.parent) { - if (isBinaryExpression(signature.declaration.parent) && getAssignmentDeclarationKind(signature.declaration.parent) === AssignmentDeclarationKind.Property) { + if ( + isBinaryExpression(signature.declaration.parent) + && getAssignmentDeclarationKind(signature.declaration.parent) + === AssignmentDeclarationKind.Property + ) { return signature.declaration.parent; } // for expressions assigned to `var`s, use the `var` as the text range - if (isVariableDeclaration(signature.declaration.parent) && signature.declaration.parent.parent) { + if ( + isVariableDeclaration(signature.declaration.parent) && signature.declaration.parent.parent + ) { return signature.declaration.parent.parent; } } return signature.declaration; } - function serializeAsNamespaceDeclaration(props: readonly Symbol[], localName: string, modifierFlags: ModifierFlags, suppressNewPrivateContext: boolean) { + function serializeAsNamespaceDeclaration( + props: readonly Symbol[], + localName: string, + modifierFlags: ModifierFlags, + suppressNewPrivateContext: boolean, + ) { if (length(props)) { - const localVsRemoteMap = arrayToMultiMap(props, p => !length(p.declarations) || some(p.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!)) ? "local" : "remote"); + const localVsRemoteMap = arrayToMultiMap( + props, + p => !length(p.declarations) + || some( + p.declarations, + d => getSourceFileOfNode(d) + === getSourceFileOfNode(context.enclosingDeclaration!), + ) + ? "local" : "remote", + ); const localProps = localVsRemoteMap.get("local") || emptyArray; // handle remote props first - we need to make an `import` declaration that points at the module containing each remote // prop in the outermost scope (TODO: a namespace within a namespace would need to be appropriately handled by this) @@ -7799,7 +10560,12 @@ namespace ts { // Add a namespace // Create namespace as non-synthetic so it is usable as an enclosing declaration - let fakespace = parseNodeFactory.createModuleDeclaration(/*modifiers*/ undefined, factory.createIdentifier(localName), factory.createModuleBlock([]), NodeFlags.Namespace); + let fakespace = parseNodeFactory.createModuleDeclaration( + /*modifiers*/ undefined, + factory.createIdentifier(localName), + factory.createModuleBlock([]), + NodeFlags.Namespace, + ); setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration); fakespace.locals = createSymbolTable(props); fakespace.symbol = props[0].parent!; @@ -7812,19 +10578,34 @@ namespace ts { const oldContext = context; context = subcontext; // TODO: implement handling for the localVsRemoteMap.get("remote") - should be difficult to trigger (see comment above), as only interesting cross-file js merges should make this possible - visitSymbolTable(createSymbolTable(localProps), suppressNewPrivateContext, /*propertyAsAlias*/ true); + visitSymbolTable( + createSymbolTable(localProps), + suppressNewPrivateContext, + /*propertyAsAlias*/ true, + ); context = oldContext; addingDeclare = oldAddingDeclare; const declarations = results; results = oldResults; // replace namespace with synthetic version - const defaultReplaced = map(declarations, d => - isExportAssignment(d) && !d.isExportEquals && isIdentifier(d.expression) ? factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, d.expression, factory.createIdentifier(InternalSymbolName.Default))]), - ) : d); - const exportModifierStripped = every(defaultReplaced, d => hasSyntacticModifier(d, ModifierFlags.Export)) ? map(defaultReplaced, removeExportModifier) : defaultReplaced; + const defaultReplaced = map( + declarations, + d => isExportAssignment(d) && !d.isExportEquals && isIdentifier(d.expression) + ? factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + d.expression, + factory.createIdentifier(InternalSymbolName.Default), + ), + ]), + ) : d, + ); + const exportModifierStripped = every(defaultReplaced, d => + hasSyntacticModifier(d, ModifierFlags.Export)) + ? map(defaultReplaced, removeExportModifier) : defaultReplaced; fakespace = factory.updateModuleDeclaration( fakespace, fakespace.modifiers, @@ -7836,11 +10617,15 @@ namespace ts { } function isNamespaceMember(p: Symbol) { - return !!(p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias)) || - !(p.flags & SymbolFlags.Prototype || p.escapedName === "prototype" || p.valueDeclaration && isStatic(p.valueDeclaration) && isClassLike(p.valueDeclaration.parent)); + return !!(p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias)) + || !(p.flags & SymbolFlags.Prototype || p.escapedName === "prototype" + || p.valueDeclaration && isStatic(p.valueDeclaration) + && isClassLike(p.valueDeclaration.parent)); } - function sanitizeJSDocImplements(clauses: readonly ExpressionWithTypeArguments[]): ExpressionWithTypeArguments[] | undefined { + function sanitizeJSDocImplements( + clauses: readonly ExpressionWithTypeArguments[], + ): ExpressionWithTypeArguments[] | undefined { const result = mapDefined(clauses, e => { const oldEnclosing = context.enclosingDeclaration; context.enclosingDeclaration = e; @@ -7850,16 +10635,22 @@ namespace ts { return cleanup(/*result*/ undefined); // Empty heritage clause, should be an error, but prefer emitting no heritage clauses to reemitting the empty one } let introducesError: boolean; - ({ introducesError, node: expr } = trackExistingEntityName(expr, context, includePrivateSymbol)); + ({ introducesError, node: expr } = trackExistingEntityName( + expr, + context, + includePrivateSymbol, + )); if (introducesError) { return cleanup(/*result*/ undefined); } } return cleanup(factory.createExpressionWithTypeArguments( expr, - map(e.typeArguments, a => - serializeExistingTypeNode(context, a, includePrivateSymbol, bundled) - || typeToTypeNodeHelper(getTypeFromTypeNode(a), context)), + map( + e.typeArguments, + a => serializeExistingTypeNode(context, a, includePrivateSymbol, bundled) + || typeToTypeNodeHelper(getTypeFromTypeNode(a), context), + ), )); function cleanup(result: T): T { @@ -7885,13 +10676,19 @@ namespace ts { const implementsExpressions = originalImplements && sanitizeJSDocImplements(originalImplements) || mapDefined(getImplementsTypes(classType), serializeImplementedType); const staticType = getTypeOfSymbol(symbol); - const isClass = !!staticType.symbol?.valueDeclaration && isClassLike(staticType.symbol.valueDeclaration); + const isClass = !!staticType.symbol?.valueDeclaration + && isClassLike(staticType.symbol.valueDeclaration); const staticBaseType = isClass ? getBaseConstructorTypeOfClass(staticType as InterfaceType) : anyType; const heritageClauses = [ - ...!length(baseTypes) ? [] : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))], - ...!length(implementsExpressions) ? [] : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)], + ...!length(baseTypes) ? [] + : [factory.createHeritageClause( + SyntaxKind.ExtendsKeyword, + map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)), + )], + ...!length(implementsExpressions) ? [] + : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)], ]; const symbolProps = getNonInheritedProperties(classType, baseTypes, getPropertiesOfType(classType)); const publicSymbolProps = filter(symbolProps, s => { @@ -7909,31 +10706,47 @@ namespace ts { return !!valueDecl && isNamedDeclaration(valueDecl) && isPrivateIdentifier(valueDecl.name); }); // Boil down all private properties into a single one. - const privateProperties = hasPrivateIdentifier ? - [factory.createPropertyDeclaration( + const privateProperties = hasPrivateIdentifier + ? [factory.createPropertyDeclaration( /*modifiers*/ undefined, factory.createPrivateIdentifier("#private"), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined, - )] : - emptyArray; - const publicProperties = flatMap(publicSymbolProps, p => serializePropertySymbolForClass(p, /*isStatic*/ false, baseTypes[0])); + )] + : emptyArray; + const publicProperties = flatMap( + publicSymbolProps, + p => serializePropertySymbolForClass(p, /*isStatic*/ false, baseTypes[0]), + ); // Consider static members empty if symbol also has function or module meaning - function namespacey emit will handle statics const staticMembers = flatMap( - filter(getPropertiesOfType(staticType), p => !(p.flags & SymbolFlags.Prototype) && p.escapedName !== "prototype" && !isNamespaceMember(p)), + filter( + getPropertiesOfType(staticType), + p => !(p.flags & SymbolFlags.Prototype) && p.escapedName !== "prototype" + && !isNamespaceMember(p), + ), p => serializePropertySymbolForClass(p, /*isStatic*/ true, staticBaseType), ); // When we encounter an `X.prototype.y` assignment in a JS file, we bind `X` as a class regardless as to whether // the value is ever initialized with a class or function-like value. For cases where `X` could never be // created via `new`, we will inject a `private constructor()` declaration to indicate it is not createable. - const isNonConstructableClassLikeInJsFile = !isClass && - !!symbol.valueDeclaration && - isInJSFile(symbol.valueDeclaration) && - !some(getSignaturesOfType(staticType, SignatureKind.Construct)); - const constructors = isNonConstructableClassLikeInJsFile ? - [factory.createConstructorDeclaration(factory.createModifiersFromModifierFlags(ModifierFlags.Private), [], /*body*/ undefined)] : - serializeSignatures(SignatureKind.Construct, staticType, staticBaseType, SyntaxKind.Constructor) as ConstructorDeclaration[]; + const isNonConstructableClassLikeInJsFile = !isClass + && !!symbol.valueDeclaration + && isInJSFile(symbol.valueDeclaration) + && !some(getSignaturesOfType(staticType, SignatureKind.Construct)); + const constructors = isNonConstructableClassLikeInJsFile + ? [factory.createConstructorDeclaration( + factory.createModifiersFromModifierFlags(ModifierFlags.Private), + [], + /*body*/ undefined, + )] + : serializeSignatures( + SignatureKind.Construct, + staticType, + staticBaseType, + SyntaxKind.Constructor, + ) as ConstructorDeclaration[]; const indexSignatures = serializeIndexSignatures(classType, baseTypes[0]); context.enclosingDeclaration = oldEnclosing; addResult( @@ -7943,9 +10756,16 @@ namespace ts { localName, typeParamDecls, heritageClauses, - [...indexSignatures, ...staticMembers, ...constructors, ...publicProperties, ...privateProperties], + [ + ...indexSignatures, + ...staticMembers, + ...constructors, + ...publicProperties, + ...privateProperties, + ], ), - symbol.declarations && filter(symbol.declarations, d => isClassDeclaration(d) || isClassExpression(d))[0], + symbol.declarations + && filter(symbol.declarations, d => isClassDeclaration(d) || isClassExpression(d))[0], ), modifierFlags, ); @@ -7985,8 +10805,13 @@ namespace ts { } // If `target` refers to a shorthand module symbol, the name we're trying to pull out isn;t recoverable from the target symbol // In such a scenario, we must fall back to looking for an alias declaration on `symbol` and pulling the target name from that - let verbatimTargetName = isShorthandAmbientModuleSymbol(target) && getSomeTargetNameFromDeclarations(symbol.declarations) || unescapeLeadingUnderscores(target.escapedName); - if (verbatimTargetName === InternalSymbolName.ExportEquals && (getESModuleInterop(compilerOptions) || compilerOptions.allowSyntheticDefaultImports)) { + let verbatimTargetName = + isShorthandAmbientModuleSymbol(target) && getSomeTargetNameFromDeclarations(symbol.declarations) + || unescapeLeadingUnderscores(target.escapedName); + if ( + verbatimTargetName === InternalSymbolName.ExportEquals + && (getESModuleInterop(compilerOptions) || compilerOptions.allowSyntheticDefaultImports) + ) { // target refers to an `export=` symbol that was hoisted into a synthetic default - rename here to match verbatimTargetName = InternalSymbolName.Default; } @@ -8006,7 +10831,8 @@ namespace ts { /*name*/ undefined, factory.createNamedImports([factory.createImportSpecifier( /*isTypeOnly*/ false, - propertyName && isIdentifier(propertyName) ? factory.createIdentifier(idText(propertyName)) : undefined, + propertyName && isIdentifier(propertyName) + ? factory.createIdentifier(idText(propertyName)) : undefined, factory.createIdentifier(localName), )]), ), @@ -8018,7 +10844,10 @@ namespace ts { break; } // We don't know how to serialize this (nested?) binding element - Debug.failBadSyntaxKind(node.parent?.parent || node, "Unhandled binding element grandparent kind in declaration serialization"); + Debug.failBadSyntaxKind( + node.parent?.parent || node, + "Unhandled binding element grandparent kind in declaration serialization", + ); break; case SyntaxKind.ShorthandPropertyAssignment: if (node.parent?.parent?.kind === SyntaxKind.BinaryExpression) { @@ -8033,7 +10862,8 @@ namespace ts { // commonjs require: const x = require('y') if (isPropertyAccessExpression((node as VariableDeclaration).initializer!)) { // const x = require('y').z - const initializer = (node as VariableDeclaration).initializer! as PropertyAccessExpression; // require('y').z + const initializer = (node as VariableDeclaration) + .initializer! as PropertyAccessExpression; // require('y').z const uniqueName = factory.createUniqueName(localName); // _x const specifier = getSpecifierForModuleSymbol(target.parent || target, context); // 'y' // import _x = require('y'); @@ -8062,13 +10892,17 @@ namespace ts { case SyntaxKind.ImportEqualsDeclaration: // This _specifically_ only exists to handle json declarations - where we make aliases, but since // we emit no declarations for the json document, must not refer to it in the declarations - if (target.escapedName === InternalSymbolName.ExportEquals && some(target.declarations, isJsonSourceFile)) { + if ( + target.escapedName === InternalSymbolName.ExportEquals + && some(target.declarations, isJsonSourceFile) + ) { serializeMaybeAliasAssignment(symbol); break; } // Could be a local `import localName = ns.member` or // an external `import localName = require("whatever")` - const isLocalImport = !(target.flags & SymbolFlags.ValueModule) && !isVariableDeclaration(node); + const isLocalImport = !(target.flags & SymbolFlags.ValueModule) + && !isVariableDeclaration(node); addResult( factory.createImportEqualsDeclaration( /*modifiers*/ undefined, @@ -8076,7 +10910,9 @@ namespace ts { factory.createIdentifier(localName), isLocalImport ? symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false) - : factory.createExternalModuleReference(factory.createStringLiteral(getSpecifierForModuleSymbol(target, context))), + : factory.createExternalModuleReference( + factory.createStringLiteral(getSpecifierForModuleSymbol(target, context)), + ), ), isLocalImport ? modifierFlags : ModifierFlags.None, ); @@ -8085,17 +10921,28 @@ namespace ts { // export as namespace foo // TODO: Not part of a file's local or export symbol tables // Is bound into file.symbol.globalExports instead, which we don't currently traverse - addResult(factory.createNamespaceExportDeclaration(idText((node as NamespaceExportDeclaration).name)), ModifierFlags.None); + addResult( + factory.createNamespaceExportDeclaration( + idText((node as NamespaceExportDeclaration).name), + ), + ModifierFlags.None, + ); break; case SyntaxKind.ImportClause: addResult( factory.createImportDeclaration( /*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, factory.createIdentifier(localName), /*namedBindings*/ undefined), + factory.createImportClause( + /*isTypeOnly*/ false, + factory.createIdentifier(localName), + /*namedBindings*/ undefined, + ), // We use `target.parent || target` below as `target.parent` is unset when the target is a module which has been export assigned // And then made into a default by the `esModuleInterop` or `allowSyntheticDefaultImports` flag // In such cases, the `target` refers to the module itself already - factory.createStringLiteral(getSpecifierForModuleSymbol(target.parent || target, context)), + factory.createStringLiteral( + getSpecifierForModuleSymbol(target.parent || target, context), + ), /*assertClause*/ undefined, ), ModifierFlags.None, @@ -8105,7 +10952,11 @@ namespace ts { addResult( factory.createImportDeclaration( /*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, /*importClause*/ undefined, factory.createNamespaceImport(factory.createIdentifier(localName))), + factory.createImportClause( + /*isTypeOnly*/ false, + /*importClause*/ undefined, + factory.createNamespaceImport(factory.createIdentifier(localName)), + ), factory.createStringLiteral(getSpecifierForModuleSymbol(target, context)), /*assertClause*/ undefined, ), @@ -8133,12 +10984,15 @@ namespace ts { factory.createNamedImports([ factory.createImportSpecifier( /*isTypeOnly*/ false, - localName !== verbatimTargetName ? factory.createIdentifier(verbatimTargetName) : undefined, + localName !== verbatimTargetName + ? factory.createIdentifier(verbatimTargetName) : undefined, factory.createIdentifier(localName), ), ]), ), - factory.createStringLiteral(getSpecifierForModuleSymbol(target.parent || target, context)), + factory.createStringLiteral( + getSpecifierForModuleSymbol(target.parent || target, context), + ), /*assertClause*/ undefined, ), ModifierFlags.None, @@ -8153,7 +11007,8 @@ namespace ts { serializeExportSpecifier( unescapeLeadingUnderscores(symbol.escapedName), specifier ? verbatimTargetName : targetName, - specifier && isStringLiteralLike(specifier) ? factory.createStringLiteral(specifier.text) : undefined, + specifier && isStringLiteralLike(specifier) + ? factory.createStringLiteral(specifier.text) : undefined, ); break; case SyntaxKind.ExportAssignment: @@ -8165,7 +11020,10 @@ namespace ts { // Could be best encoded as though an export specifier or as though an export assignment // If name is default or export=, do an export assignment // Otherwise do an export specifier - if (symbol.escapedName === InternalSymbolName.Default || symbol.escapedName === InternalSymbolName.ExportEquals) { + if ( + symbol.escapedName === InternalSymbolName.Default + || symbol.escapedName === InternalSymbolName.ExportEquals + ) { serializeMaybeAliasAssignment(symbol); } else { @@ -8173,7 +11031,10 @@ namespace ts { } break; default: - return Debug.failBadSyntaxKind(node, "Unhandled alias declaration kind in symbol serializer!"); + return Debug.failBadSyntaxKind( + node, + "Unhandled alias declaration kind in symbol serializer!", + ); } } @@ -8182,7 +11043,13 @@ namespace ts { factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, localName !== targetName ? targetName : undefined, localName)]), + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + localName !== targetName ? targetName : undefined, + localName, + ), + ]), specifier, ), ModifierFlags.None, @@ -8207,13 +11074,35 @@ namespace ts { // serialize what the alias points to, preserve the declaration's initializer const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); // If the target resolves and resolves to a thing defined in this file, emit as an alias, otherwise emit as a const - if (target && length(target.declarations) && some(target.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(enclosingDeclaration))) { + if ( + target && length(target.declarations) + && some( + target.declarations, + d => getSourceFileOfNode(d) === getSourceFileOfNode(enclosingDeclaration), + ) + ) { // In case `target` refers to a namespace member, look at the declaration and serialize the leftmost symbol in it // eg, `namespace A { export class B {} }; exports = A.B;` // Technically, this is all that's required in the case where the assignment is an entity name expression - const expr = aliasDecl && ((isExportAssignment(aliasDecl) || isBinaryExpression(aliasDecl)) ? getExportAssignmentExpression(aliasDecl) : getPropertyAssignmentAliasLikeExpression(aliasDecl as ShorthandPropertyAssignment | PropertyAssignment | PropertyAccessExpression)); - const first = expr && isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) : undefined; - const referenced = first && resolveEntityName(first, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, enclosingDeclaration); + const expr = aliasDecl + && ((isExportAssignment(aliasDecl) || isBinaryExpression(aliasDecl)) + ? getExportAssignmentExpression(aliasDecl) + : getPropertyAssignmentAliasLikeExpression( + aliasDecl as + | ShorthandPropertyAssignment + | PropertyAssignment + | PropertyAccessExpression, + )); + const first = expr && isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) + : undefined; + const referenced = first + && resolveEntityName( + first, + SymbolFlags.All, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + enclosingDeclaration, + ); if (referenced || target) { includePrivateSymbol(referenced || target); } @@ -8266,20 +11155,37 @@ namespace ts { const typeToSerialize = getWidenedType(getTypeOfSymbol(getMergedSymbol(symbol))); if (isTypeRepresentableAsFunctionNamespaceMerge(typeToSerialize, symbol)) { // If there are no index signatures and `typeToSerialize` is an object type, emit as a namespace instead of a const - serializeAsFunctionNamespaceMerge(typeToSerialize, symbol, varName, isExportAssignmentCompatibleSymbolName ? ModifierFlags.None : ModifierFlags.Export); + serializeAsFunctionNamespaceMerge( + typeToSerialize, + symbol, + varName, + isExportAssignmentCompatibleSymbolName ? ModifierFlags.None : ModifierFlags.Export, + ); } else { const statement = factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList([ - factory.createVariableDeclaration(varName, /*exclamationToken*/ undefined, serializeTypeForDeclaration(context, typeToSerialize, symbol, enclosingDeclaration, includePrivateSymbol, bundled)), + factory.createVariableDeclaration( + varName, + /*exclamationToken*/ undefined, + serializeTypeForDeclaration( + context, + typeToSerialize, + symbol, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), + ), ], NodeFlags.Const), ); // Inlined JSON types exported with [module.]exports= will already emit an export=, so should use `declare`. // Otherwise, the type itself should be exported. addResult( statement, - target && target.flags & SymbolFlags.Property && target.escapedName === InternalSymbolName.ExportEquals ? ModifierFlags.Ambient + target && target.flags & SymbolFlags.Property + && target.escapedName === InternalSymbolName.ExportEquals ? ModifierFlags.Ambient : name === varName ? ModifierFlags.Export : ModifierFlags.None, ); @@ -8305,16 +11211,24 @@ namespace ts { // context source file, and whose property names are all valid identifiers and not late-bound, _and_ // whose input is not type annotated (if the input symbol has an annotation we can reuse, we should prefer it) const ctxSrc = getSourceFileOfNode(context.enclosingDeclaration); - return getObjectFlags(typeToSerialize) & (ObjectFlags.Anonymous | ObjectFlags.Mapped) && - !length(getIndexInfosOfType(typeToSerialize)) && - !isClassInstanceSide(typeToSerialize) && // While a class instance is potentially representable as a NS, prefer printing a reference to the instance type and serializing the class - !!(length(filter(getPropertiesOfType(typeToSerialize), isNamespaceMember)) || length(getSignaturesOfType(typeToSerialize, SignatureKind.Call))) && - !length(getSignaturesOfType(typeToSerialize, SignatureKind.Construct)) && // TODO: could probably serialize as function + ns + class, now that that's OK - !getDeclarationWithTypeAnnotation(hostSymbol, enclosingDeclaration) && - !(typeToSerialize.symbol && some(typeToSerialize.symbol.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) && - !some(getPropertiesOfType(typeToSerialize), p => isLateBoundName(p.escapedName)) && - !some(getPropertiesOfType(typeToSerialize), p => some(p.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) && - every(getPropertiesOfType(typeToSerialize), p => isIdentifierText(symbolName(p), languageVersion)); + return getObjectFlags(typeToSerialize) & (ObjectFlags.Anonymous | ObjectFlags.Mapped) + && !length(getIndexInfosOfType(typeToSerialize)) + && !isClassInstanceSide(typeToSerialize) // While a class instance is potentially representable as a NS, prefer printing a reference to the instance type and serializing the class + && !!(length(filter(getPropertiesOfType(typeToSerialize), isNamespaceMember)) + || length(getSignaturesOfType(typeToSerialize, SignatureKind.Call))) + && !length(getSignaturesOfType(typeToSerialize, SignatureKind.Construct)) // TODO: could probably serialize as function + ns + class, now that that's OK + && !getDeclarationWithTypeAnnotation(hostSymbol, enclosingDeclaration) + && !(typeToSerialize.symbol + && some(typeToSerialize.symbol.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) + && !some(getPropertiesOfType(typeToSerialize), p => isLateBoundName(p.escapedName)) + && !some( + getPropertiesOfType(typeToSerialize), + p => some(p.declarations, d => getSourceFileOfNode(d) !== ctxSrc), + ) + && every( + getPropertiesOfType(typeToSerialize), + p => isIdentifierText(symbolName(p), languageVersion), + ); } function makeSerializePropertySymbol( @@ -8327,7 +11241,11 @@ namespace ts { ) => T, methodKind: SignatureDeclaration["kind"], useAccessors: true, - ): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => T | AccessorDeclaration | (T | AccessorDeclaration)[]; + ): ( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined, + ) => T | AccessorDeclaration | (T | AccessorDeclaration)[]; function makeSerializePropertySymbol( createProperty: ( modifiers: readonly Modifier[] | undefined, @@ -8349,8 +11267,16 @@ namespace ts { ) => T, methodKind: SignatureDeclaration["kind"], useAccessors: boolean, - ): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => T | AccessorDeclaration | (T | AccessorDeclaration)[] { - return function serializePropertySymbol(p: Symbol, isStatic: boolean, baseType: Type | undefined): T | AccessorDeclaration | (T | AccessorDeclaration)[] { + ): ( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined, + ) => T | AccessorDeclaration | (T | AccessorDeclaration)[] { + return function serializePropertySymbol( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined, + ): T | AccessorDeclaration | (T | AccessorDeclaration)[] { const modifierFlags = getDeclarationModifierFlagsFromSymbol(p); const isPrivate = !!(modifierFlags & ModifierFlags.Private); if (isStatic && (p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias))) { @@ -8359,17 +11285,30 @@ namespace ts { return []; } if ( - p.flags & SymbolFlags.Prototype || - (baseType && getPropertyOfType(baseType, p.escapedName) + p.flags & SymbolFlags.Prototype + || (baseType && getPropertyOfType(baseType, p.escapedName) && isReadonlySymbol(getPropertyOfType(baseType, p.escapedName)!) === isReadonlySymbol(p) - && (p.flags & SymbolFlags.Optional) === (getPropertyOfType(baseType, p.escapedName)!.flags & SymbolFlags.Optional) - && isTypeIdenticalTo(getTypeOfSymbol(p), getTypeOfPropertyOfType(baseType, p.escapedName)!)) + && (p.flags & SymbolFlags.Optional) + === (getPropertyOfType(baseType, p.escapedName)!.flags & SymbolFlags.Optional) + && isTypeIdenticalTo( + getTypeOfSymbol(p), + getTypeOfPropertyOfType(baseType, p.escapedName)!, + )) ) { return []; } const flag = (modifierFlags & ~ModifierFlags.Async) | (isStatic ? ModifierFlags.Static : 0); const name = getPropertyNameNodeForSymbol(p, context); - const firstPropertyLikeDecl = p.declarations?.find(or(isPropertyDeclaration, isAccessor, isVariableDeclaration, isPropertySignature, isBinaryExpression, isPropertyAccessExpression)); + const firstPropertyLikeDecl = p.declarations?.find( + or( + isPropertyDeclaration, + isAccessor, + isVariableDeclaration, + isPropertySignature, + isBinaryExpression, + isPropertyAccessExpression, + ), + ); if (p.flags & SymbolFlags.Accessor && useAccessors) { const result: AccessorDeclaration[] = []; if (p.flags & SymbolFlags.SetAccessor) { @@ -8382,7 +11321,15 @@ namespace ts { /*dotDotDotToken*/ undefined, "arg", /*questionToken*/ undefined, - isPrivate ? undefined : serializeTypeForDeclaration(context, getTypeOfSymbol(p), p, enclosingDeclaration, includePrivateSymbol, bundled), + isPrivate ? undefined + : serializeTypeForDeclaration( + context, + getTypeOfSymbol(p), + p, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), )], /*body*/ undefined, ), @@ -8396,7 +11343,15 @@ namespace ts { factory.createModifiersFromModifierFlags(flag), name, [], - isPrivate ? undefined : serializeTypeForDeclaration(context, getTypeOfSymbol(p), p, enclosingDeclaration, includePrivateSymbol, bundled), + isPrivate ? undefined + : serializeTypeForDeclaration( + context, + getTypeOfSymbol(p), + p, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), /*body*/ undefined, ), p.declarations?.find(isGetAccessor) || firstPropertyLikeDecl, @@ -8409,15 +11364,27 @@ namespace ts { else if (p.flags & (SymbolFlags.Property | SymbolFlags.Variable | SymbolFlags.Accessor)) { return setTextRange( createProperty( - factory.createModifiersFromModifierFlags((isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag), + factory.createModifiersFromModifierFlags( + (isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag, + ), name, - p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - isPrivate ? undefined : serializeTypeForDeclaration(context, getWriteTypeOfSymbol(p), p, enclosingDeclaration, includePrivateSymbol, bundled), + p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) + : undefined, + isPrivate ? undefined + : serializeTypeForDeclaration( + context, + getWriteTypeOfSymbol(p), + p, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), // TODO: https://github.com/microsoft/TypeScript/pull/32372#discussion_r328386357 // interface members can't have initializers, however class members _can_ /*initializer*/ undefined, ), - p.declarations?.find(or(isPropertyDeclaration, isVariableDeclaration)) || firstPropertyLikeDecl, + p.declarations?.find(or(isPropertyDeclaration, isVariableDeclaration)) + || firstPropertyLikeDecl, ); } if (p.flags & (SymbolFlags.Method | SymbolFlags.Function)) { @@ -8426,13 +11393,18 @@ namespace ts { if (flag & ModifierFlags.Private) { return setTextRange( createProperty( - factory.createModifiersFromModifierFlags((isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag), + factory.createModifiersFromModifierFlags( + (isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag, + ), name, - p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) + : undefined, /*type*/ undefined, /*initializer*/ undefined, ), - p.declarations?.find(isFunctionLikeDeclaration) || signatures[0] && signatures[0].declaration || p.declarations && p.declarations[0], + p.declarations?.find(isFunctionLikeDeclaration) + || signatures[0] && signatures[0].declaration + || p.declarations && p.declarations[0], ); } @@ -8445,11 +11417,14 @@ namespace ts { context, { name, - questionToken: p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + questionToken: p.flags & SymbolFlags.Optional + ? factory.createToken(SyntaxKind.QuestionToken) : undefined, modifiers: flag ? factory.createModifiersFromModifierFlags(flag) : undefined, }, ); - const location = sig.declaration && isPrototypePropertyAssignment(sig.declaration.parent) ? sig.declaration.parent : sig.declaration; + const location = + sig.declaration && isPrototypePropertyAssignment(sig.declaration.parent) + ? sig.declaration.parent : sig.declaration; results.push(setTextRange(decl, location)); } return results as unknown as T[]; @@ -8463,7 +11438,12 @@ namespace ts { return serializePropertySymbolForInterfaceWorker(p, /*isStatic*/ false, baseType); } - function serializeSignatures(kind: SignatureKind, input: Type, baseType: Type | undefined, outputKind: SignatureDeclaration["kind"]) { + function serializeSignatures( + kind: SignatureKind, + input: Type, + baseType: Type | undefined, + outputKind: SignatureDeclaration["kind"], + ) { const signatures = getSignaturesOfType(input, kind); if (kind === SignatureKind.Construct) { if (!baseType && every(signatures, s => length(s.parameters) === 0)) { @@ -8478,7 +11458,16 @@ namespace ts { if (baseSigs.length === signatures.length) { let failed = false; for (let i = 0; i < baseSigs.length; i++) { - if (!compareSignaturesIdentical(signatures[i], baseSigs[i], /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical)) { + if ( + !compareSignaturesIdentical( + signatures[i], + baseSigs[i], + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true, + compareTypesIdentical, + ) + ) { failed = true; break; } @@ -8491,7 +11480,10 @@ namespace ts { let privateProtected: ModifierFlags = 0; for (const s of signatures) { if (s.declaration) { - privateProtected |= getSelectedEffectiveModifierFlags(s.declaration, ModifierFlags.Private | ModifierFlags.Protected); + privateProtected |= getSelectedEffectiveModifierFlags( + s.declaration, + ModifierFlags.Private | ModifierFlags.Protected, + ); } } if (privateProtected) { @@ -8540,11 +11532,18 @@ namespace ts { const statement = factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList([ - factory.createVariableDeclaration(tempName, /*exclamationToken*/ undefined, typeToTypeNodeHelper(staticType, context)), + factory.createVariableDeclaration( + tempName, + /*exclamationToken*/ undefined, + typeToTypeNodeHelper(staticType, context), + ), ], NodeFlags.Const), ); addResult(statement, ModifierFlags.None); - return factory.createExpressionWithTypeArguments(factory.createIdentifier(tempName), /*typeArgs*/ undefined); + return factory.createExpressionWithTypeArguments( + factory.createIdentifier(tempName), + /*typeArgs*/ undefined, + ); } function trySerializeAsTypeReference(t: Type, flags: SymbolFlags) { @@ -8553,7 +11552,10 @@ namespace ts { // We don't use `isValueSymbolAccessible` below. since that considers alternative containers (like modules) // which we can't write out in a syntactically valid way as an expression - if ((t as TypeReference).target && isSymbolAccessibleByFlags((t as TypeReference).target.symbol, enclosingDeclaration, flags)) { + if ( + (t as TypeReference).target + && isSymbolAccessibleByFlags((t as TypeReference).target.symbol, enclosingDeclaration, flags) + ) { typeArgs = map(getTypeArguments(t as TypeReference), t => typeToTypeNodeHelper(t, context)); reference = symbolToExpression((t as TypeReference).target.symbol, context, SymbolFlags.Type); } @@ -8571,7 +11573,10 @@ namespace ts { return ref; } if (t.symbol) { - return factory.createExpressionWithTypeArguments(symbolToExpression(t.symbol, context, SymbolFlags.Type), /*typeArgs*/ undefined); + return factory.createExpressionWithTypeArguments( + symbolToExpression(t.symbol, context, SymbolFlags.Type), + /*typeArgs*/ undefined, + ); } } @@ -8599,12 +11604,16 @@ namespace ts { } function getNameCandidateWorker(symbol: Symbol, localName: string) { - if (localName === InternalSymbolName.Default || localName === InternalSymbolName.Class || localName === InternalSymbolName.Function) { + if ( + localName === InternalSymbolName.Default || localName === InternalSymbolName.Class + || localName === InternalSymbolName.Function + ) { const flags = context.flags; context.flags |= NodeBuilderFlags.InInitialEntityName; const nameCandidate = getNameOfSymbolAsWritten(symbol, context); context.flags = flags; - localName = nameCandidate.length > 0 && isSingleOrDoubleQuote(nameCandidate.charCodeAt(0)) ? stripQuotes(nameCandidate) : nameCandidate; + localName = nameCandidate.length > 0 && isSingleOrDoubleQuote(nameCandidate.charCodeAt(0)) + ? stripQuotes(nameCandidate) : nameCandidate; } if (localName === InternalSymbolName.Default) { localName = "_default"; @@ -8612,7 +11621,9 @@ namespace ts { else if (localName === InternalSymbolName.ExportEquals) { localName = "_exports"; } - localName = isIdentifierText(localName, languageVersion) && !isStringANonContextualKeyword(localName) ? localName : "_" + localName.replace(/[^a-zA-Z0-9]/g, "_"); + localName = + isIdentifierText(localName, languageVersion) && !isStringANonContextualKeyword(localName) + ? localName : "_" + localName.replace(/[^a-zA-Z0-9]/g, "_"); return localName; } @@ -8629,14 +11640,30 @@ namespace ts { } } - function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer?: EmitTextWriter): string { - return writer ? typePredicateToStringWorker(writer).getText() : usingSingleLineStringWriter(typePredicateToStringWorker); + function typePredicateToString( + typePredicate: TypePredicate, + enclosingDeclaration?: Node, + flags: TypeFormatFlags = TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, + writer?: EmitTextWriter, + ): string { + return writer ? typePredicateToStringWorker(writer).getText() + : usingSingleLineStringWriter(typePredicateToStringWorker); function typePredicateToStringWorker(writer: EmitTextWriter) { const predicate = factory.createTypePredicateNode( - typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createToken(SyntaxKind.AssertsKeyword) : undefined, - typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createIdentifier(typePredicate.parameterName) : factory.createThisTypeNode(), - typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)!, // TODO: GH#18217 + typePredicate.kind === TypePredicateKind.AssertsThis + || typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? factory.createToken(SyntaxKind.AssertsKeyword) : undefined, + typePredicate.kind === TypePredicateKind.Identifier + || typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? factory.createIdentifier(typePredicate.parameterName) : factory.createThisTypeNode(), + typePredicate.type + && nodeBuilder.typeToTypeNode( + typePredicate.type, + enclosingDeclaration, + toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors + | NodeBuilderFlags.WriteTypeParametersInQualifiedName, + )!, // TODO: GH#18217 ); const printer = createPrinter({ removeComments: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); @@ -8653,10 +11680,15 @@ namespace ts { flags |= t.flags; if (!(t.flags & TypeFlags.Nullable)) { if (t.flags & (TypeFlags.BooleanLiteral | TypeFlags.EnumLiteral)) { - const baseType = t.flags & TypeFlags.BooleanLiteral ? booleanType : getBaseTypeOfEnumLiteralType(t as LiteralType); + const baseType = t.flags & TypeFlags.BooleanLiteral ? booleanType + : getBaseTypeOfEnumLiteralType(t as LiteralType); if (baseType.flags & TypeFlags.Union) { const count = (baseType as UnionType).types.length; - if (i + count <= types.length && getRegularTypeOfLiteralType(types[i + count - 1]) === getRegularTypeOfLiteralType((baseType as UnionType).types[count - 1])) { + if ( + i + count <= types.length + && getRegularTypeOfLiteralType(types[i + count - 1]) + === getRegularTypeOfLiteralType((baseType as UnionType).types[count - 1]) + ) { result.push(baseType); i += count - 1; continue; @@ -8692,9 +11724,9 @@ namespace ts { } function isTopLevelInExternalModuleAugmentation(node: Node): boolean { - return node && node.parent && - node.parent.kind === SyntaxKind.ModuleBlock && - isExternalModuleAugmentation(node.parent.parent); + return node && node.parent + && node.parent.kind === SyntaxKind.ModuleBlock + && isExternalModuleAugmentation(node.parent.parent); } interface NodeBuilderContext { @@ -8751,13 +11783,16 @@ namespace ts { */ function getNameOfSymbolAsWritten(symbol: Symbol, context?: NodeBuilderContext): string { if ( - context && symbol.escapedName === InternalSymbolName.Default && !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) && + context && symbol.escapedName === InternalSymbolName.Default + && !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) // If it's not the first part of an entity name, it must print as `default` - (!(context.flags & NodeBuilderFlags.InInitialEntityName) || + && (!(context.flags & NodeBuilderFlags.InInitialEntityName) // if the symbol is synthesized, it will only be referenced externally it must print as `default` - !symbol.declarations || + || !symbol.declarations // if not in the same binding context (source file, module declaration), it must print as `default` - (context.enclosingDeclaration && findAncestor(symbol.declarations[0], isDefaultBindingContext) !== findAncestor(context.enclosingDeclaration, isDefaultBindingContext))) + || (context.enclosingDeclaration + && findAncestor(symbol.declarations[0], isDefaultBindingContext) + !== findAncestor(context.enclosingDeclaration, isDefaultBindingContext))) ) { return "default"; } @@ -8790,10 +11825,14 @@ namespace ts { case SyntaxKind.ClassExpression: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - if (context && !context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) { + if ( + context && !context.encounteredError + && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier) + ) { context.encounteredError = true; } - return declaration.kind === SyntaxKind.ClassExpression ? "(Anonymous class)" : "(Anonymous function)"; + return declaration.kind === SyntaxKind.ClassExpression ? "(Anonymous class)" + : "(Anonymous function)"; } } const name = getNameOfSymbolFromNameType(symbol, context); @@ -8818,13 +11857,14 @@ namespace ts { case SyntaxKind.JSDocEnumTag: // Top-level jsdoc type aliases are considered exported // First parent is comment node, second is hosting declaration or token; we only care about those tokens or declarations whose parent is a source file - return !!(node.parent && node.parent.parent && node.parent.parent.parent && isSourceFile(node.parent.parent.parent)); + return !!(node.parent && node.parent.parent && node.parent.parent.parent + && isSourceFile(node.parent.parent.parent)); case SyntaxKind.BindingElement: return isDeclarationVisible(node.parent.parent); case SyntaxKind.VariableDeclaration: if ( - isBindingPattern((node as VariableDeclaration).name) && - !((node as VariableDeclaration).name as BindingPattern).elements.length + isBindingPattern((node as VariableDeclaration).name) + && !((node as VariableDeclaration).name as BindingPattern).elements.length ) { // If the binding pattern is empty, this variable declaration is not visible return false; @@ -8844,8 +11884,9 @@ namespace ts { const parent = getDeclarationContainer(node); // If the node is not exported or it is not ambient module element (except import declaration) if ( - !(getCombinedModifierFlags(node as Declaration) & ModifierFlags.Export) && - !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && parent.flags & NodeFlags.Ambient) + !(getCombinedModifierFlags(node as Declaration) & ModifierFlags.Export) + && !(node.kind !== SyntaxKind.ImportEqualsDeclaration + && parent.kind !== SyntaxKind.SourceFile && parent.flags & NodeFlags.Ambient) ) { return isGlobalSourceFile(parent); } @@ -8912,10 +11953,20 @@ namespace ts { function collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined { let exportSymbol: Symbol | undefined; if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) { - exportSymbol = resolveName(node, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, node, /*isUse*/ false); + exportSymbol = resolveName( + node, + node.escapedText, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + /*nameNotFoundMessage*/ undefined, + node, + /*isUse*/ false, + ); } else if (node.parent.kind === SyntaxKind.ExportSpecifier) { - exportSymbol = getTargetOfExportSpecifier(node.parent as ExportSpecifier, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); + exportSymbol = getTargetOfExportSpecifier( + node.parent as ExportSpecifier, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + ); } let result: Node[] | undefined; let visited: Set | undefined; @@ -8941,7 +11992,14 @@ namespace ts { // Add the referenced top container visible const internalModuleReference = declaration.moduleReference as Identifier | QualifiedName; const firstIdentifier = getFirstIdentifier(internalModuleReference); - const importSymbol = resolveName(declaration, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, undefined, undefined, /*isUse*/ false); + const importSymbol = resolveName( + declaration, + firstIdentifier.escapedText, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + undefined, + undefined, + /*isUse*/ false, + ); if (importSymbol && visited) { if (tryAddToSet(visited, getSymbolId(importSymbol))) { buildVisibleNodeList(importSymbol.declarations); @@ -9047,7 +12105,9 @@ namespace ts { // the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter. // It is an error to explicitly declare a static property member with the name 'prototype'. const classType = getDeclaredTypeOfSymbol(getParentOfSymbol(prototype)!) as InterfaceType; - return classType.typeParameters ? createTypeReference(classType as GenericType, map(classType.typeParameters, _ => anyType)) : classType; + return classType.typeParameters + ? createTypeReference(classType as GenericType, map(classType.typeParameters, _ => anyType)) + : classType; } // Return the type of the given property in the given type, or undefined if no such property exists @@ -9057,7 +12117,8 @@ namespace ts { } function getTypeOfPropertyOrIndexSignature(type: Type, name: __String): Type { - return getTypeOfPropertyOfType(type, name) || getApplicableIndexInfoForName(type, name)?.type || unknownType; + return getTypeOfPropertyOfType(type, name) || getApplicableIndexInfoForName(type, name)?.type + || unknownType; } function isTypeAny(type: Type | undefined) { @@ -9077,7 +12138,8 @@ namespace ts { return getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); } const symbol = getSymbolOfNode(node); - return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); + return symbol && getSymbolLinks(symbol).type + || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); } function getRestType(source: Type, properties: PropertyName[], symbol: Symbol | undefined): Type { @@ -9095,10 +12157,14 @@ namespace ts { const unspreadableToRestKeys: Type[] = []; for (const prop of getPropertiesOfType(source)) { - const literalTypeFromProperty = getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique); + const literalTypeFromProperty = getLiteralTypeFromProperty( + prop, + TypeFlags.StringOrNumberLiteralOrUnique, + ); if ( !isTypeAssignableTo(literalTypeFromProperty, omitKeyType) - && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) + && !(getDeclarationModifierFlagsFromSymbol(prop) + & (ModifierFlags.Private | ModifierFlags.Protected)) && isSpreadableProperty(prop) ) { spreadableProperties.push(prop); @@ -9136,11 +12202,13 @@ namespace ts { } function isGenericTypeWithUndefinedConstraint(type: Type) { - return !!(type.flags & TypeFlags.Instantiable) && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.Undefined); + return !!(type.flags & TypeFlags.Instantiable) + && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.Undefined); } function getNonUndefinedType(type: Type) { - const typeOrConstraint = someType(type, isGenericTypeWithUndefinedConstraint) ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type; + const typeOrConstraint = someType(type, isGenericTypeWithUndefinedConstraint) + ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type; return getTypeWithFacts(typeOrConstraint, TypeFacts.NEUndefined); } @@ -9153,18 +12221,24 @@ namespace ts { // [ x ] = obj; // Expression // We construct a synthetic element access expression corresponding to 'obj.x' such that the control // flow analyzer doesn't have to handle all the different syntactic forms. - function getFlowTypeOfDestructuring(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, declaredType: Type) { + function getFlowTypeOfDestructuring( + node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, + declaredType: Type, + ) { const reference = getSyntheticElementAccess(node); return reference ? getFlowTypeOfReference(reference, declaredType) : declaredType; } - function getSyntheticElementAccess(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression): ElementAccessExpression | undefined { + function getSyntheticElementAccess( + node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, + ): ElementAccessExpression | undefined { const parentAccess = getParentElementAccess(node); if (parentAccess && parentAccess.flowNode) { const propName = getDestructuringPropertyName(node); if (propName) { const literal = setTextRange(parseNodeFactory.createStringLiteral(propName), node); - const lhsExpr = isLeftHandSideExpression(parentAccess) ? parentAccess : parseNodeFactory.createParenthesizedExpression(parentAccess); + const lhsExpr = isLeftHandSideExpression(parentAccess) ? parentAccess + : parseNodeFactory.createParenthesizedExpression(parentAccess); const result = setTextRange(parseNodeFactory.createElementAccessExpression(lhsExpr, literal), node); setParent(literal, result); setParent(result, node); @@ -9177,7 +12251,9 @@ namespace ts { } } - function getParentElementAccess(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression) { + function getParentElementAccess( + node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, + ) { const ancestor = node.parent.parent; switch (ancestor.kind) { case SyntaxKind.BindingElement: @@ -9192,10 +12268,14 @@ namespace ts { } } - function getDestructuringPropertyName(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression) { + function getDestructuringPropertyName( + node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, + ) { const parent = node.parent; if (node.kind === SyntaxKind.BindingElement && parent.kind === SyntaxKind.ObjectBindingPattern) { - return getLiteralPropertyNameText((node as BindingElement).propertyName || (node as BindingElement).name as Identifier); + return getLiteralPropertyNameText( + (node as BindingElement).propertyName || (node as BindingElement).name as Identifier, + ); } if (node.kind === SyntaxKind.PropertyAssignment || node.kind === SyntaxKind.ShorthandPropertyAssignment) { return getLiteralPropertyNameText((node as PropertyAssignment | ShorthandPropertyAssignment).name); @@ -9205,7 +12285,8 @@ namespace ts { function getLiteralPropertyNameText(name: PropertyName) { const type = getLiteralTypeFromPropertyName(name); - return type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral) ? "" + (type as StringLiteralType | NumberLiteralType).value : undefined; + return type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral) + ? "" + (type as StringLiteralType | NumberLiteralType).value : undefined; } /** Return the inferred type for a binding element */ @@ -9226,7 +12307,10 @@ namespace ts { parentType = getNonNullableType(parentType); } // Filter `undefined` from the type we check against if the parent has an initializer and that initializer is not possibly `undefined` - else if (strictNullChecks && pattern.parent.initializer && !(getTypeFacts(getTypeOfInitializer(pattern.parent.initializer)) & TypeFacts.EQUndefined)) { + else if ( + strictNullChecks && pattern.parent.initializer + && !(getTypeFacts(getTypeOfInitializer(pattern.parent.initializer)) & TypeFacts.EQUndefined) + ) { parentType = getTypeWithFacts(parentType, TypeFacts.NEUndefined); } @@ -9250,7 +12334,12 @@ namespace ts { // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) const name = declaration.propertyName || declaration.name as Identifier; const indexType = getLiteralTypeFromPropertyName(name); - const declaredType = getIndexedAccessType(parentType, indexType, AccessFlags.ExpressionPosition, name); + const declaredType = getIndexedAccessType( + parentType, + indexType, + AccessFlags.ExpressionPosition, + name, + ); type = getFlowTypeOfDestructuring(declaration, declaredType); } } @@ -9258,20 +12347,28 @@ namespace ts { // This elementType will be used if the specific property corresponding to this index is not // present (aka the tuple element property). This call also checks that the parentType is in // fact an iterable or array (depending on target language). - const elementType = checkIteratedTypeOrElementType(IterationUse.Destructuring | (declaration.dotDotDotToken ? 0 : IterationUse.PossiblyOutOfBounds), parentType, undefinedType, pattern); + const elementType = checkIteratedTypeOrElementType( + IterationUse.Destructuring | (declaration.dotDotDotToken ? 0 : IterationUse.PossiblyOutOfBounds), + parentType, + undefinedType, + pattern, + ); const index = pattern.elements.indexOf(declaration); if (declaration.dotDotDotToken) { // If the parent is a tuple type, the rest element has a tuple type of the // remaining tuple element types. Otherwise, the rest element has an array type with same // element type as the parent type. - type = everyType(parentType, isTupleType) ? - mapType(parentType, t => sliceTupleType(t as TupleTypeReference, index)) : - createArrayType(elementType); + type = everyType(parentType, isTupleType) + ? mapType(parentType, t => sliceTupleType(t as TupleTypeReference, index)) + : createArrayType(elementType); } else if (isArrayLikeType(parentType)) { const indexType = getNumberLiteralType(index); - const accessFlags = AccessFlags.ExpressionPosition | (hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0); - const declaredType = getIndexedAccessTypeOrUndefined(parentType, indexType, accessFlags, declaration.name) || errorType; + const accessFlags = AccessFlags.ExpressionPosition + | (hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0); + const declaredType = + getIndexedAccessTypeOrUndefined(parentType, indexType, accessFlags, declaration.name) + || errorType; type = getFlowTypeOfDestructuring(declaration, declaredType); } else { @@ -9284,9 +12381,17 @@ namespace ts { if (getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration))) { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. - return strictNullChecks && !(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined) ? getNonUndefinedType(type) : type; + return strictNullChecks + && !(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) + & TypeFacts.IsUndefined) ? getNonUndefinedType(type) : type; } - return widenTypeInferredFromInitializer(declaration, getUnionType([getNonUndefinedType(type), checkDeclarationInitializer(declaration, CheckMode.Normal)], UnionReduction.Subtype)); + return widenTypeInferredFromInitializer( + declaration, + getUnionType( + [getNonUndefinedType(type), checkDeclarationInitializer(declaration, CheckMode.Normal)], + UnionReduction.Subtype, + ), + ); } function getTypeForDeclarationFromJSDocComment(declaration: Node) { @@ -9299,12 +12404,14 @@ namespace ts { function isNullOrUndefined(node: Expression) { const expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); - return expr.kind === SyntaxKind.NullKeyword || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(expr as Identifier) === undefinedSymbol; + return expr.kind === SyntaxKind.NullKeyword + || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(expr as Identifier) === undefinedSymbol; } function isEmptyArrayLiteral(node: Expression) { const expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); - return expr.kind === SyntaxKind.ArrayLiteralExpression && (expr as ArrayLiteralExpression).elements.length === 0; + return expr.kind === SyntaxKind.ArrayLiteralExpression + && (expr as ArrayLiteralExpression).elements.length === 0; } function addOptionality(type: Type, isProperty = false, isOptional = true): Type { @@ -9313,15 +12420,26 @@ namespace ts { // Return the inferred type for a variable, parameter, or property declaration function getTypeForVariableLikeDeclaration( - declaration: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement | JSDocPropertyLikeTag, + declaration: + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature + | VariableDeclaration + | BindingElement + | JSDocPropertyLikeTag, includeOptionality: boolean, checkMode: CheckMode, ): Type | undefined { // A variable declared in a for..in statement is of type string, or of type keyof T when the // right hand expression is of a type parameter type. if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForInStatement) { - const indexType = getIndexType(getNonNullableTypeIfNeeded(checkExpression(declaration.parent.parent.expression, /*checkMode*/ checkMode))); - return indexType.flags & (TypeFlags.TypeParameter | TypeFlags.Index) ? getExtractStringType(indexType) : stringType; + const indexType = getIndexType( + getNonNullableTypeIfNeeded( + checkExpression(declaration.parent.parent.expression, /*checkMode*/ checkMode), + ), + ); + return indexType.flags & (TypeFlags.TypeParameter | TypeFlags.Index) ? getExtractStringType(indexType) + : stringType; } if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { @@ -9337,11 +12455,12 @@ namespace ts { return getTypeForBindingElement(declaration as BindingElement); } - const isProperty = isPropertyDeclaration(declaration) && !hasAccessorModifier(declaration) || isPropertySignature(declaration); + const isProperty = isPropertyDeclaration(declaration) && !hasAccessorModifier(declaration) + || isPropertySignature(declaration); const isOptional = includeOptionality && ( - isProperty && !!declaration.questionToken || - isParameter(declaration) && (!!declaration.questionToken || isJSDocOptionalParameter(declaration)) || - isOptionalJSDocPropertyLikeTag(declaration) + isProperty && !!declaration.questionToken + || isParameter(declaration) && (!!declaration.questionToken || isJSDocOptionalParameter(declaration)) + || isOptionalJSDocPropertyLikeTag(declaration) ); // Use type from type annotation if one is present @@ -9351,14 +12470,18 @@ namespace ts { } if ( - (noImplicitAny || isInJSFile(declaration)) && - isVariableDeclaration(declaration) && !isBindingPattern(declaration.name) && - !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !(declaration.flags & NodeFlags.Ambient) + (noImplicitAny || isInJSFile(declaration)) + && isVariableDeclaration(declaration) && !isBindingPattern(declaration.name) + && !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) + && !(declaration.flags & NodeFlags.Ambient) ) { // If --noImplicitAny is on or the declaration is in a Javascript file, // use control flow tracked 'any' type for non-ambient, non-exported var or let variables with no // initializer or a 'null' or 'undefined' initializer. - if (!(getCombinedNodeFlags(declaration) & NodeFlags.Const) && (!declaration.initializer || isNullOrUndefined(declaration.initializer))) { + if ( + !(getCombinedNodeFlags(declaration) & NodeFlags.Const) + && (!declaration.initializer || isNullOrUndefined(declaration.initializer)) + ) { return autoType; } // Use control flow tracked 'any[]' type for non-ambient, non-exported variables with an empty array @@ -9372,7 +12495,10 @@ namespace ts { const func = declaration.parent as FunctionLikeDeclaration; // For a parameter of a set accessor, use the type of the get accessor if one is present if (func.kind === SyntaxKind.SetAccessor && hasBindableName(func)) { - const getter = getDeclarationOfKind(getSymbolOfNode(declaration.parent), SyntaxKind.GetAccessor); + const getter = getDeclarationOfKind( + getSymbolOfNode(declaration.parent), + SyntaxKind.GetAccessor, + ); if (getter) { const getterSignature = getSignatureFromDeclaration(getter); const thisParameter = getAccessorThisParameter(func as AccessorDeclaration); @@ -9387,7 +12513,8 @@ namespace ts { const parameterTypeOfTypeTag = getParameterTypeOfTypeTag(func, declaration); if (parameterTypeOfTypeTag) return parameterTypeOfTypeTag; // Use contextual parameter type if one is available - const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration); + const type = declaration.symbol.escapedName === InternalSymbolName.This + ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration); if (type) { return addOptionality(type, /*isProperty*/ false, isOptional); } @@ -9397,12 +12524,19 @@ namespace ts { // not a parameter of a contextually typed function if (hasOnlyExpressionInitializer(declaration) && !!declaration.initializer) { if (isInJSFile(declaration) && !isParameter(declaration)) { - const containerObjectType = getJSContainerObjectType(declaration, getSymbolOfNode(declaration), getDeclaredExpandoInitializer(declaration)); + const containerObjectType = getJSContainerObjectType( + declaration, + getSymbolOfNode(declaration), + getDeclaredExpandoInitializer(declaration), + ); if (containerObjectType) { return containerObjectType; } } - const type = widenTypeInferredFromInitializer(declaration, checkDeclarationInitializer(declaration, checkMode)); + const type = widenTypeInferredFromInitializer( + declaration, + checkDeclarationInitializer(declaration, checkMode), + ); return addOptionality(type, isProperty, isOptional); } @@ -9411,16 +12545,18 @@ namespace ts { // Use control flow analysis of this.xxx assignments in the constructor or static block to determine the type of the property. if (!hasStaticModifier(declaration)) { const constructor = findConstructorDeclaration(declaration.parent); - const type = constructor ? getFlowTypeInConstructor(declaration.symbol, constructor) : - getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) : - undefined; + const type = constructor ? getFlowTypeInConstructor(declaration.symbol, constructor) + : getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient + ? getTypeOfPropertyInBaseClass(declaration.symbol) + : undefined; return type && addOptionality(type, /*isProperty*/ true, isOptional); } else { const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration); - const type = staticBlocks.length ? getFlowTypeInStaticBlocks(declaration.symbol, staticBlocks) : - getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) : - undefined; + const type = staticBlocks.length ? getFlowTypeInStaticBlocks(declaration.symbol, staticBlocks) + : getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient + ? getTypeOfPropertyInBaseClass(declaration.symbol) + : undefined; return type && addOptionality(type, /*isProperty*/ true, isOptional); } } @@ -9434,7 +12570,11 @@ namespace ts { // If the declaration specifies a binding pattern and is not a parameter of a contextually // typed function, use the type implied by the binding pattern if (isBindingPattern(declaration.name)) { - return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ false, /*reportErrors*/ true); + return getTypeFromBindingPattern( + declaration.name, + /*includePatternInType*/ false, + /*reportErrors*/ true, + ); } // No type specified and nothing can be inferred @@ -9449,11 +12589,20 @@ namespace ts { const links = getSymbolLinks(symbol); if (links.isConstructorDeclaredProperty === undefined) { links.isConstructorDeclaredProperty = false; - links.isConstructorDeclaredProperty = !!getDeclaringConstructor(symbol) && every(symbol.declarations, declaration => - isBinaryExpression(declaration) && - isPossiblyAliasedThisProperty(declaration) && - (declaration.left.kind !== SyntaxKind.ElementAccessExpression || isStringOrNumericLiteralLike((declaration.left as ElementAccessExpression).argumentExpression)) && - !getAnnotatedTypeForAssignmentDeclaration(/*declaredType*/ undefined, declaration, symbol, declaration)); + links.isConstructorDeclaredProperty = !!getDeclaringConstructor(symbol) + && every(symbol.declarations, declaration => + isBinaryExpression(declaration) + && isPossiblyAliasedThisProperty(declaration) + && (declaration.left.kind !== SyntaxKind.ElementAccessExpression + || isStringOrNumericLiteralLike( + (declaration.left as ElementAccessExpression).argumentExpression, + )) + && !getAnnotatedTypeForAssignmentDeclaration( + /*declaredType*/ undefined, + declaration, + symbol, + declaration, + )); } return links.isConstructorDeclaredProperty; } @@ -9464,8 +12613,8 @@ namespace ts { // A property is auto-typed when its declaration has no type annotation or initializer and we're in // noImplicitAny mode or a .js file. const declaration = symbol.valueDeclaration; - return declaration && isPropertyDeclaration(declaration) && !getEffectiveTypeAnnotationNode(declaration) && - !declaration.initializer && (noImplicitAny || isInJSFile(declaration)); + return declaration && isPropertyDeclaration(declaration) && !getEffectiveTypeAnnotationNode(declaration) + && !declaration.initializer && (noImplicitAny || isInJSFile(declaration)); } function getDeclaringConstructor(symbol: Symbol) { @@ -9484,9 +12633,17 @@ namespace ts { function getFlowTypeFromCommonJSExport(symbol: Symbol) { const file = getSourceFileOfNode(symbol.declarations![0]); const accessName = unescapeLeadingUnderscores(symbol.escapedName); - const areAllModuleExports = symbol.declarations!.every(d => isInJSFile(d) && isAccessExpression(d) && isModuleExportsAccessExpression(d.expression)); + const areAllModuleExports = symbol.declarations!.every(d => + isInJSFile(d) && isAccessExpression(d) && isModuleExportsAccessExpression(d.expression) + ); const reference = areAllModuleExports - ? factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createIdentifier("module"), factory.createIdentifier("exports")), accessName) + ? factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("module"), + factory.createIdentifier("exports"), + ), + accessName, + ) : factory.createPropertyAccessExpression(factory.createIdentifier("exports"), accessName); if (areAllModuleExports) { setParent((reference.expression as PropertyAccessExpression).expression, reference.expression); @@ -9508,7 +12665,12 @@ namespace ts { reference.flowNode = staticBlock.returnFlowNode; const flowType = getFlowTypeOfProperty(reference, symbol); if (noImplicitAny && (flowType === autoType || flowType === autoArrayType)) { - error(symbol.valueDeclaration, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); + error( + symbol.valueDeclaration, + Diagnostics.Member_0_implicitly_has_an_1_type, + symbolToString(symbol), + typeToString(flowType), + ); } // We don't infer a type if assignments are only null or undefined. if (everyType(flowType, isNullableType)) { @@ -9528,7 +12690,12 @@ namespace ts { reference.flowNode = constructor.returnFlowNode; const flowType = getFlowTypeOfProperty(reference, symbol); if (noImplicitAny && (flowType === autoType || flowType === autoArrayType)) { - error(symbol.valueDeclaration, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); + error( + symbol.valueDeclaration, + Diagnostics.Member_0_implicitly_has_an_1_type, + symbolToString(symbol), + typeToString(flowType), + ); } // We don't infer a type if assignments are only null or undefined. return everyType(flowType, isNullableType) ? undefined : convertAutoToAny(flowType); @@ -9536,7 +12703,8 @@ namespace ts { function getFlowTypeOfProperty(reference: Node, prop: Symbol | undefined) { const initialType = prop?.valueDeclaration - && (!isAutoTypedProperty(prop) || getEffectiveModifierFlags(prop.valueDeclaration) & ModifierFlags.Ambient) + && (!isAutoTypedProperty(prop) + || getEffectiveModifierFlags(prop.valueDeclaration) & ModifierFlags.Ambient) && getTypeOfPropertyInBaseClass(prop) || undefinedType; return getFlowTypeOfReference(reference, autoType, initialType); @@ -9550,7 +12718,8 @@ namespace ts { if (tag && tag.typeExpression) { return getTypeFromTypeNode(tag.typeExpression); } - const containerObjectType = symbol.valueDeclaration && getJSContainerObjectType(symbol.valueDeclaration, symbol, container); + const containerObjectType = symbol.valueDeclaration + && getJSContainerObjectType(symbol.valueDeclaration, symbol, container); return containerObjectType || getWidenedLiteralType(checkExpressionCached(container)); } let type; @@ -9566,9 +12735,11 @@ namespace ts { if (symbol.declarations) { let jsdocType: Type | undefined; for (const declaration of symbol.declarations) { - const expression = (isBinaryExpression(declaration) || isCallExpression(declaration)) ? declaration : - isAccessExpression(declaration) ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration : - undefined; + const expression = (isBinaryExpression(declaration) || isCallExpression(declaration)) + ? declaration + : isAccessExpression(declaration) + ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration + : undefined; if (!expression) { continue; // Non-assignment declaration merged in (eg, an Identifier to mark the thing as a namespace) - skip over it and pull type info from elsewhere } @@ -9576,7 +12747,10 @@ namespace ts { const kind = isAccessExpression(expression) ? getAssignmentDeclarationPropertyAccessKind(expression) : getAssignmentDeclarationKind(expression); - if (kind === AssignmentDeclarationKind.ThisProperty || isBinaryExpression(expression) && isPossiblyAliasedThisProperty(expression, kind)) { + if ( + kind === AssignmentDeclarationKind.ThisProperty + || isBinaryExpression(expression) && isPossiblyAliasedThisProperty(expression, kind) + ) { if (isDeclarationInConstructor(expression)) { definedInConstructor = true; } @@ -9585,10 +12759,23 @@ namespace ts { } } if (!isCallExpression(expression)) { - jsdocType = getAnnotatedTypeForAssignmentDeclaration(jsdocType, expression, symbol, declaration); + jsdocType = getAnnotatedTypeForAssignmentDeclaration( + jsdocType, + expression, + symbol, + declaration, + ); } if (!jsdocType) { - (types || (types = [])).push((isBinaryExpression(expression) || isCallExpression(expression)) ? getInitializerTypeFromAssignmentDeclaration(symbol, resolvedSymbol, expression, kind) : neverType); + (types || (types = [])).push( + (isBinaryExpression(expression) || isCallExpression(expression)) + ? getInitializerTypeFromAssignmentDeclaration( + symbol, + resolvedSymbol, + expression, + kind, + ) : neverType, + ); } } type = jsdocType; @@ -9597,7 +12784,8 @@ namespace ts { if (!length(types)) { return errorType; // No types from any declarations :( } - let constructorTypes = definedInConstructor && symbol.declarations ? getConstructorDefinedThisAssignmentTypes(types!, symbol.declarations) : undefined; + let constructorTypes = definedInConstructor && symbol.declarations + ? getConstructorDefinedThisAssignmentTypes(types!, symbol.declarations) : undefined; // use only the constructor types unless they were only assigned null | undefined (including widening variants) if (definedInMethod) { const propType = getTypeOfPropertyInBaseClass(symbol); @@ -9606,11 +12794,14 @@ namespace ts { definedInConstructor = true; } } - const sourceTypes = some(constructorTypes, t => !!(t.flags & ~TypeFlags.Nullable)) ? constructorTypes : types; // TODO: GH#18217 + const sourceTypes = some(constructorTypes, t => !!(t.flags & ~TypeFlags.Nullable)) + ? constructorTypes : types; // TODO: GH#18217 type = getUnionType(sourceTypes!); } } - const widened = getWidenedType(addOptionality(type, /*isProperty*/ false, definedInMethod && !definedInConstructor)); + const widened = getWidenedType( + addOptionality(type, /*isProperty*/ false, definedInMethod && !definedInConstructor), + ); if (symbol.valueDeclaration && filterType(widened, t => !!(t.flags & ~TypeFlags.Nullable)) === neverType) { reportImplicitAny(symbol.valueDeclaration, anyType); return anyType; @@ -9639,7 +12830,12 @@ namespace ts { return type; } - function getAnnotatedTypeForAssignmentDeclaration(declaredType: Type | undefined, expression: Expression, symbol: Symbol, declaration: Declaration) { + function getAnnotatedTypeForAssignmentDeclaration( + declaredType: Type | undefined, + expression: Expression, + symbol: Symbol, + declaration: Declaration, + ) { const typeNode = getEffectiveTypeAnnotationNode(expression.parent); if (typeNode) { const type = getWidenedType(getTypeFromTypeNode(typeNode)); @@ -9647,7 +12843,12 @@ namespace ts { return type; } else if (!isErrorType(declaredType) && !isErrorType(type) && !isTypeIdenticalTo(declaredType, type)) { - errorNextVariableOrPropertyDeclarationMustHaveSameType(/*firstDeclaration*/ undefined, declaredType, declaration, type); + errorNextVariableOrPropertyDeclarationMustHaveSameType( + /*firstDeclaration*/ undefined, + declaredType, + declaration, + type, + ); } } if (symbol.parent?.valueDeclaration) { @@ -9664,12 +12865,19 @@ namespace ts { } /** If we don't have an explicit JSDoc type, get the type from the initializer. */ - function getInitializerTypeFromAssignmentDeclaration(symbol: Symbol, resolvedSymbol: Symbol | undefined, expression: BinaryExpression | CallExpression, kind: AssignmentDeclarationKind) { + function getInitializerTypeFromAssignmentDeclaration( + symbol: Symbol, + resolvedSymbol: Symbol | undefined, + expression: BinaryExpression | CallExpression, + kind: AssignmentDeclarationKind, + ) { if (isCallExpression(expression)) { if (resolvedSymbol) { return getTypeOfSymbol(resolvedSymbol); // This shouldn't happen except under some hopefully forbidden merges of export assignments and object define assignments } - const objectLitType = checkExpressionCached((expression as BindableObjectDefinePropertyCall).arguments[2]); + const objectLitType = checkExpressionCached( + (expression as BindableObjectDefinePropertyCall).arguments[2], + ); const valueType = getTypeOfPropertyOfType(objectLitType, "value" as __String); if (valueType) { return valueType; @@ -9693,14 +12901,17 @@ namespace ts { if (containsSameNamedThisProperty(expression.left, expression.right)) { return anyType; } - const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) && (isModuleExportsAccessExpression(expression.left.expression) || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression))); + const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty + && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) + && (isModuleExportsAccessExpression(expression.left.expression) + || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression))); const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) : isDirectExport ? getRegularTypeOfLiteralType(checkExpressionCached(expression.right)) : getWidenedLiteralType(checkExpressionCached(expression.right)); if ( - type.flags & TypeFlags.Object && - kind === AssignmentDeclarationKind.ModuleExports && - symbol.escapedName === InternalSymbolName.ExportEquals + type.flags & TypeFlags.Object + && kind === AssignmentDeclarationKind.ModuleExports + && symbol.escapedName === InternalSymbolName.ExportEquals ) { const exportedType = resolveStructuredTypeMembers(type as ObjectType); const members = createSymbolTable(); @@ -9723,16 +12934,30 @@ namespace ts { // but we may have a JS file with `module.exports = { a: true }` along with a TypeScript module augmentation // declaring an `export const a: number`. In that case, we issue a duplicate identifier error, because // it's unclear what that's supposed to mean, so it's probably a mistake. - if (s.valueDeclaration && exportedMember.valueDeclaration && getSourceFileOfNode(s.valueDeclaration) !== getSourceFileOfNode(exportedMember.valueDeclaration)) { + if ( + s.valueDeclaration && exportedMember.valueDeclaration + && getSourceFileOfNode(s.valueDeclaration) + !== getSourceFileOfNode(exportedMember.valueDeclaration) + ) { const unescapedName = unescapeLeadingUnderscores(s.escapedName); - const exportedMemberName = tryCast(exportedMember.valueDeclaration, isNamedDeclaration)?.name || exportedMember.valueDeclaration; + const exportedMemberName = + tryCast(exportedMember.valueDeclaration, isNamedDeclaration)?.name + || exportedMember.valueDeclaration; addRelatedInfo( error(s.valueDeclaration, Diagnostics.Duplicate_identifier_0, unescapedName), - createDiagnosticForNode(exportedMemberName, Diagnostics._0_was_also_declared_here, unescapedName), + createDiagnosticForNode( + exportedMemberName, + Diagnostics._0_was_also_declared_here, + unescapedName, + ), ); addRelatedInfo( error(exportedMemberName, Diagnostics.Duplicate_identifier_0, unescapedName), - createDiagnosticForNode(s.valueDeclaration, Diagnostics._0_was_also_declared_here, unescapedName), + createDiagnosticForNode( + s.valueDeclaration, + Diagnostics._0_was_also_declared_here, + unescapedName, + ), ); } const union = createSymbol(s.flags | exportedMember.flags, name); @@ -9768,7 +12993,10 @@ namespace ts { } } result.objectFlags |= getObjectFlags(type) & ObjectFlags.JSLiteral; // Propagate JSLiteral flag - if (result.symbol && result.symbol.flags & SymbolFlags.Class && type === getDeclaredTypeOfClassOrInterface(result.symbol)) { + if ( + result.symbol && result.symbol.flags & SymbolFlags.Class + && type === getDeclaredTypeOfClassOrInterface(result.symbol) + ) { result.objectFlags |= ObjectFlags.IsClassInstanceClone; // Propagate the knowledge that this type is equivalent to the symbol's class instance type } return result; @@ -9790,17 +13018,21 @@ namespace ts { const thisContainer = getThisContainer(expression, /*includeArrowFunctions*/ false); // Properties defined in a constructor (or base constructor, or javascript constructor function) don't get undefined added. // Function expressions that are assigned to the prototype count as methods. - return thisContainer.kind === SyntaxKind.Constructor || - thisContainer.kind === SyntaxKind.FunctionDeclaration || - (thisContainer.kind === SyntaxKind.FunctionExpression && !isPrototypePropertyAssignment(thisContainer.parent)); + return thisContainer.kind === SyntaxKind.Constructor + || thisContainer.kind === SyntaxKind.FunctionDeclaration + || (thisContainer.kind === SyntaxKind.FunctionExpression + && !isPrototypePropertyAssignment(thisContainer.parent)); } - function getConstructorDefinedThisAssignmentTypes(types: Type[], declarations: Declaration[]): Type[] | undefined { + function getConstructorDefinedThisAssignmentTypes( + types: Type[], + declarations: Declaration[], + ): Type[] | undefined { Debug.assert(types.length === declarations.length); return types.filter((_, i) => { const declaration = declarations[i]; - const expression = isBinaryExpression(declaration) ? declaration : - isBinaryExpression(declaration.parent) ? declaration.parent : undefined; + const expression = isBinaryExpression(declaration) ? declaration + : isBinaryExpression(declaration.parent) ? declaration.parent : undefined; return expression && isDeclarationInConstructor(expression); }); } @@ -9808,13 +13040,24 @@ namespace ts { // Return the type implied by a binding pattern element. This is the type of the initializer of the element if // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding // pattern. Otherwise, it is the type any. - function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type { + function getTypeFromBindingElement( + element: BindingElement, + includePatternInType?: boolean, + reportErrors?: boolean, + ): Type { if (element.initializer) { // The type implied by a binding pattern is independent of context, so we check the initializer with no // contextual type or, if the element itself is a binding pattern, with the type implied by that binding // pattern. - const contextualType = isBindingPattern(element.name) ? getTypeFromBindingPattern(element.name, /*includePatternInType*/ true, /*reportErrors*/ false) : unknownType; - return addOptionality(widenTypeInferredFromInitializer(element, checkDeclarationInitializer(element, CheckMode.Normal, contextualType))); + const contextualType = isBindingPattern(element.name) + ? getTypeFromBindingPattern(element.name, /*includePatternInType*/ true, /*reportErrors*/ false) + : unknownType; + return addOptionality( + widenTypeInferredFromInitializer( + element, + checkDeclarationInitializer(element, CheckMode.Normal, contextualType), + ), + ); } if (isBindingPattern(element.name)) { return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors); @@ -9830,7 +13073,11 @@ namespace ts { } // Return the type implied by an object binding pattern - function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { + function getTypeFromObjectBindingPattern( + pattern: ObjectBindingPattern, + includePatternInType: boolean, + reportErrors: boolean, + ): Type { const members = createSymbolTable(); let stringIndexInfo: IndexInfo | undefined; let objectFlags = ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; @@ -9854,7 +13101,13 @@ namespace ts { symbol.bindingElement = e; members.set(symbol.escapedName, symbol); }); - const result = createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo ? [stringIndexInfo] : emptyArray); + const result = createAnonymousType( + undefined, + members, + emptyArray, + emptyArray, + stringIndexInfo ? [stringIndexInfo] : emptyArray, + ); result.objectFlags |= objectFlags; if (includePatternInType) { result.pattern = pattern; @@ -9864,16 +13117,35 @@ namespace ts { } // Return the type implied by an array binding pattern - function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { + function getTypeFromArrayBindingPattern( + pattern: BindingPattern, + includePatternInType: boolean, + reportErrors: boolean, + ): Type { const elements = pattern.elements; const lastElement = lastOrUndefined(elements); - const restElement = lastElement && lastElement.kind === SyntaxKind.BindingElement && lastElement.dotDotDotToken ? lastElement : undefined; + const restElement = + lastElement && lastElement.kind === SyntaxKind.BindingElement && lastElement.dotDotDotToken + ? lastElement : undefined; if (elements.length === 0 || elements.length === 1 && restElement) { return languageVersion >= ScriptTarget.ES2015 ? createIterableType(anyType) : anyArrayType; } - const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors)); - const minLength = findLastIndex(elements, e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), elements.length - 1) + 1; - const elementFlags = map(elements, (e, i) => e === restElement ? ElementFlags.Rest : i >= minLength ? ElementFlags.Optional : ElementFlags.Required); + const elementTypes = map( + elements, + e => isOmittedExpression(e) ? anyType + : getTypeFromBindingElement(e, includePatternInType, reportErrors), + ); + const minLength = findLastIndex( + elements, + e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), + elements.length - 1, + ) + 1; + const elementFlags = map( + elements, + (e, i) => + e === restElement ? ElementFlags.Rest + : i >= minLength ? ElementFlags.Optional : ElementFlags.Required, + ); let result = createTupleType(elementTypes, elementFlags) as TypeReference; if (includePatternInType) { result = cloneTypeReference(result); @@ -9890,7 +13162,11 @@ namespace ts { // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of // the parameter. - function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType = false, reportErrors = false): Type { + function getTypeFromBindingPattern( + pattern: BindingPattern, + includePatternInType = false, + reportErrors = false, + ): Type { return pattern.kind === SyntaxKind.ObjectBindingPattern ? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors) : getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors); @@ -9905,8 +13181,21 @@ namespace ts { // Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the // binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the // tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string. - function getWidenedTypeForVariableLikeDeclaration(declaration: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement | JSDocPropertyLikeTag, reportErrors?: boolean): Type { - return widenTypeForVariableLikeDeclaration(getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true, CheckMode.Normal), declaration, reportErrors); + function getWidenedTypeForVariableLikeDeclaration( + declaration: + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature + | VariableDeclaration + | BindingElement + | JSDocPropertyLikeTag, + reportErrors?: boolean, + ): Type { + return widenTypeForVariableLikeDeclaration( + getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true, CheckMode.Normal), + declaration, + reportErrors, + ); } function isGlobalSymbolConstructor(node: Node) { @@ -9926,7 +13215,10 @@ namespace ts { } // always widen a 'unique symbol' type if the type was created for a different declaration. - if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) && type.symbol !== getSymbolOfNode(declaration)) { + if ( + type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) + && type.symbol !== getSymbolOfNode(declaration) + ) { type = esSymbolType; } @@ -10029,12 +13321,19 @@ namespace ts { } let type: Type; if (declaration.kind === SyntaxKind.ExportAssignment) { - type = widenTypeForVariableLikeDeclaration(tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionCached((declaration as ExportAssignment).expression), declaration); + type = widenTypeForVariableLikeDeclaration( + tryGetTypeFromEffectiveTypeNode(declaration) + || checkExpressionCached((declaration as ExportAssignment).expression), + declaration, + ); } else if ( - isBinaryExpression(declaration) || - (isInJSFile(declaration) && - (isCallExpression(declaration) || (isPropertyAccessExpression(declaration) || isBindableStaticElementAccessExpression(declaration)) && isBinaryExpression(declaration.parent))) + isBinaryExpression(declaration) + || (isInJSFile(declaration) + && (isCallExpression(declaration) + || (isPropertyAccessExpression(declaration) + || isBindableStaticElementAccessExpression(declaration)) + && isBinaryExpression(declaration.parent))) ) { type = getWidenedTypeForAssignmentDeclaration(symbol); } @@ -10051,12 +13350,16 @@ namespace ts { || isSourceFile(declaration) ) { // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty` - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { + if ( + symbol.flags + & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum + | SymbolFlags.ValueModule) + ) { return getTypeOfFuncClassEnumModule(symbol); } - type = isBinaryExpression(declaration.parent) ? - getWidenedTypeForAssignmentDeclaration(symbol) : - tryGetTypeFromEffectiveTypeNode(declaration) || anyType; + type = isBinaryExpression(declaration.parent) + ? getWidenedTypeForAssignmentDeclaration(symbol) + : tryGetTypeFromEffectiveTypeNode(declaration) || anyType; } else if (isPropertyAssignment(declaration)) { type = tryGetTypeFromEffectiveTypeNode(declaration) || checkPropertyAssignment(declaration); @@ -10065,10 +13368,12 @@ namespace ts { type = tryGetTypeFromEffectiveTypeNode(declaration) || checkJsxAttribute(declaration); } else if (isShorthandPropertyAssignment(declaration)) { - type = tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal); + type = tryGetTypeFromEffectiveTypeNode(declaration) + || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal); } else if (isObjectLiteralMethod(declaration)) { - type = tryGetTypeFromEffectiveTypeNode(declaration) || checkObjectLiteralMethod(declaration, CheckMode.Normal); + type = tryGetTypeFromEffectiveTypeNode(declaration) + || checkObjectLiteralMethod(declaration, CheckMode.Normal); } else if ( isParameter(declaration) @@ -10089,7 +13394,10 @@ namespace ts { type = getTypeOfEnumMember(symbol); } else { - return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol)); + return Debug.fail( + "Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + + Debug.formatSymbol(symbol), + ); } if (!popTypeResolution()) { @@ -10102,7 +13410,9 @@ namespace ts { return type; } - function getAnnotatedAccessorTypeNode(accessor: AccessorDeclaration | PropertyDeclaration | undefined): TypeNode | undefined { + function getAnnotatedAccessorTypeNode( + accessor: AccessorDeclaration | PropertyDeclaration | undefined, + ): TypeNode | undefined { if (accessor) { switch (accessor.kind) { case SyntaxKind.GetAccessor: @@ -10120,7 +13430,9 @@ namespace ts { return undefined; } - function getAnnotatedAccessorType(accessor: AccessorDeclaration | PropertyDeclaration | undefined): Type | undefined { + function getAnnotatedAccessorType( + accessor: AccessorDeclaration | PropertyDeclaration | undefined, + ): Type | undefined { const node = getAnnotatedAccessorTypeNode(accessor); return node && getTypeFromTypeNode(node); } @@ -10142,40 +13454,79 @@ namespace ts { } const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor); - const accessor = tryCast(getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), isAutoAccessorPropertyDeclaration); + const accessor = tryCast( + getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), + isAutoAccessorPropertyDeclaration, + ); // We try to resolve a getter type annotation, a setter type annotation, or a getter function // body return type inference, in that order. - let type = getter && isInJSFile(getter) && getTypeForDeclarationFromJSDocComment(getter) || - getAnnotatedAccessorType(getter) || - getAnnotatedAccessorType(setter) || - getAnnotatedAccessorType(accessor) || - getter && getter.body && getReturnTypeFromBody(getter) || - accessor && accessor.initializer && getWidenedTypeForVariableLikeDeclaration(accessor, /*includeOptionality*/ true); + let type = getter && isInJSFile(getter) && getTypeForDeclarationFromJSDocComment(getter) + || getAnnotatedAccessorType(getter) + || getAnnotatedAccessorType(setter) + || getAnnotatedAccessorType(accessor) + || getter && getter.body && getReturnTypeFromBody(getter) + || accessor && accessor.initializer + && getWidenedTypeForVariableLikeDeclaration(accessor, /*includeOptionality*/ true); if (!type) { if (setter && !isPrivateWithinAmbient(setter)) { - errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol)); + errorOrSuggestion( + noImplicitAny, + setter, + Diagnostics + .Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, + symbolToString(symbol), + ); } else if (getter && !isPrivateWithinAmbient(getter)) { - errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol)); + errorOrSuggestion( + noImplicitAny, + getter, + Diagnostics + .Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, + symbolToString(symbol), + ); } else if (accessor && !isPrivateWithinAmbient(accessor)) { - errorOrSuggestion(noImplicitAny, accessor, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), "any"); + errorOrSuggestion( + noImplicitAny, + accessor, + Diagnostics.Member_0_implicitly_has_an_1_type, + symbolToString(symbol), + "any", + ); } type = anyType; } if (!popTypeResolution()) { if (getAnnotatedAccessorTypeNode(getter)) { - error(getter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + getter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); } else if (getAnnotatedAccessorTypeNode(setter)) { - error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + setter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); } else if (getAnnotatedAccessorTypeNode(accessor)) { - error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + setter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); } else if (getter && noImplicitAny) { - error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol)); + error( + getter, + Diagnostics + ._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, + symbolToString(symbol), + ); } type = anyType; } @@ -10192,11 +13543,18 @@ namespace ts { } const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor) - ?? tryCast(getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), isAutoAccessorPropertyDeclaration); + ?? tryCast( + getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), + isAutoAccessorPropertyDeclaration, + ); let writeType = getAnnotatedAccessorType(setter); if (!popTypeResolution()) { if (getAnnotatedAccessorTypeNode(setter)) { - error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + setter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); } writeType = anyType; } @@ -10208,16 +13566,18 @@ namespace ts { function getBaseTypeVariableOfClass(symbol: Symbol) { const baseConstructorType = getBaseConstructorTypeOfClass(getDeclaredTypeOfClassOrInterface(symbol)); - return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType : - baseConstructorType.flags & TypeFlags.Intersection ? find((baseConstructorType as IntersectionType).types, t => !!(t.flags & TypeFlags.TypeVariable)) : - undefined; + return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType + : baseConstructorType.flags & TypeFlags.Intersection + ? find((baseConstructorType as IntersectionType).types, t => !!(t.flags & TypeFlags.TypeVariable)) + : undefined; } function getTypeOfFuncClassEnumModule(symbol: Symbol): Type { let links = getSymbolLinks(symbol); const originalLinks = links; if (!links.type) { - const expando = symbol.valueDeclaration && getSymbolOfExpando(symbol.valueDeclaration, /*allowDeclaration*/ false); + const expando = symbol.valueDeclaration + && getSymbolOfExpando(symbol.valueDeclaration, /*allowDeclaration*/ false); if (expando) { const merged = mergeJSSymbols(symbol, expando); if (merged) { @@ -10236,20 +13596,26 @@ namespace ts { return anyType; } else if ( - declaration && (declaration.kind === SyntaxKind.BinaryExpression || - isAccessExpression(declaration) && - declaration.parent.kind === SyntaxKind.BinaryExpression) + declaration && (declaration.kind === SyntaxKind.BinaryExpression + || isAccessExpression(declaration) + && declaration.parent.kind === SyntaxKind.BinaryExpression) ) { return getWidenedTypeForAssignmentDeclaration(symbol); } - else if (symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) && declaration.commonJsModuleIndicator) { + else if ( + symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) + && declaration.commonJsModuleIndicator + ) { const resolvedModule = resolveExternalModuleSymbol(symbol); if (resolvedModule !== symbol) { if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { return errorType; } const exportEquals = getMergedSymbol(symbol.exports!.get(InternalSymbolName.ExportEquals)!); - const type = getWidenedTypeForAssignmentDeclaration(exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule); + const type = getWidenedTypeForAssignmentDeclaration( + exportEquals, + exportEquals === resolvedModule ? undefined : resolvedModule, + ); if (!popTypeResolution()) { return reportCircularityError(symbol); } @@ -10275,14 +13641,19 @@ namespace ts { const links = getSymbolLinks(symbol); if (!links.type) { const targetSymbol = resolveAlias(symbol); - const exportSymbol = symbol.declarations && getTargetOfAliasDeclaration(getDeclarationOfAliasSymbol(symbol)!, /*dontResolveAlias*/ true); - const declaredType = firstDefined(exportSymbol?.declarations, d => isExportAssignment(d) ? tryGetTypeFromEffectiveTypeNode(d) : undefined); + const exportSymbol = symbol.declarations + && getTargetOfAliasDeclaration(getDeclarationOfAliasSymbol(symbol)!, /*dontResolveAlias*/ true); + const declaredType = firstDefined( + exportSymbol?.declarations, + d => isExportAssignment(d) ? tryGetTypeFromEffectiveTypeNode(d) : undefined, + ); // It only makes sense to get the type of a value symbol. If the result of resolving // the alias is not a value, then it has no type. To get the type associated with a // type symbol, call getDeclaredTypeOfSymbol. // This check is important because without it, a call to getTypeOfSymbol could end // up recursively calling getTypeOfAlias, causing a stack overflow. - links.type = exportSymbol?.declarations && isDuplicatedCommonJSExport(exportSymbol.declarations) && symbol.declarations!.length ? getFlowTypeFromCommonJSExport(exportSymbol) + links.type = exportSymbol?.declarations && isDuplicatedCommonJSExport(exportSymbol.declarations) + && symbol.declarations!.length ? getFlowTypeFromCommonJSExport(exportSymbol) : isDuplicatedCommonJSExport(symbol.declarations) ? autoType : declaredType ? declaredType : getAllSymbolFlags(targetSymbol) & SymbolFlags.Value ? getTypeOfSymbol(targetSymbol) @@ -10298,19 +13669,32 @@ namespace ts { function getWriteTypeOfInstantiatedSymbol(symbol: Symbol): Type { const links = getSymbolLinks(symbol); - return links.writeType || (links.writeType = instantiateType(getWriteTypeOfSymbol(links.target!), links.mapper)); + return links.writeType + || (links.writeType = instantiateType(getWriteTypeOfSymbol(links.target!), links.mapper)); } function reportCircularityError(symbol: Symbol) { const declaration = symbol.valueDeclaration as VariableLikeDeclaration; // Check if variable has type annotation that circularly references the variable itself if (getEffectiveTypeAnnotationNode(declaration)) { - error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + symbol.valueDeclaration, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); return errorType; } // Check if variable has initializer that circularly references the variable itself - if (noImplicitAny && (declaration.kind !== SyntaxKind.Parameter || (declaration as HasInitializer).initializer)) { - error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer, symbolToString(symbol)); + if ( + noImplicitAny + && (declaration.kind !== SyntaxKind.Parameter || (declaration as HasInitializer).initializer) + ) { + error( + symbol.valueDeclaration, + Diagnostics + ._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer, + symbolToString(symbol), + ); } // Circularities could also result from parameters in function expressions that end up // having themselves as contextual types following type argument inference. In those cases @@ -10323,7 +13707,8 @@ namespace ts { if (!links.type) { Debug.assertIsDefined(links.deferralParent); Debug.assertIsDefined(links.deferralConstituents); - links.type = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralConstituents) : getIntersectionType(links.deferralConstituents); + links.type = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralConstituents) + : getIntersectionType(links.deferralConstituents); } return links.type; } @@ -10333,7 +13718,9 @@ namespace ts { if (!links.writeType && links.deferralWriteConstituents) { Debug.assertIsDefined(links.deferralParent); Debug.assertIsDefined(links.deferralConstituents); - links.writeType = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralWriteConstituents) : getIntersectionType(links.deferralWriteConstituents); + links.writeType = links.deferralParent.flags & TypeFlags.Union + ? getUnionType(links.deferralWriteConstituents) + : getIntersectionType(links.deferralWriteConstituents); } return links.writeType; } @@ -10346,16 +13733,16 @@ namespace ts { function getWriteTypeOfSymbol(symbol: Symbol): Type { const checkFlags = getCheckFlags(symbol); if (symbol.flags & SymbolFlags.Property) { - return checkFlags & CheckFlags.SyntheticProperty ? - checkFlags & CheckFlags.DeferredType ? - getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) : - (symbol as TransientSymbol).writeType || (symbol as TransientSymbol).type! : - getTypeOfSymbol(symbol); + return checkFlags & CheckFlags.SyntheticProperty + ? checkFlags & CheckFlags.DeferredType + ? getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) + : (symbol as TransientSymbol).writeType || (symbol as TransientSymbol).type! + : getTypeOfSymbol(symbol); } if (symbol.flags & SymbolFlags.Accessor) { - return checkFlags & CheckFlags.Instantiated ? - getWriteTypeOfInstantiatedSymbol(symbol) : - getWriteTypeOfAccessors(symbol); + return checkFlags & CheckFlags.Instantiated + ? getWriteTypeOfInstantiatedSymbol(symbol) + : getWriteTypeOfAccessors(symbol); } return getTypeOfSymbol(symbol); } @@ -10377,7 +13764,11 @@ namespace ts { if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { return getTypeOfVariableOrParameterOrProperty(symbol); } - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { + if ( + symbol.flags + & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum + | SymbolFlags.ValueModule) + ) { return getTypeOfFuncClassEnumModule(symbol); } if (symbol.flags & SymbolFlags.EnumMember) { @@ -10425,9 +13816,15 @@ namespace ts { // Appends the type parameters given by a list of declarations to a set of type parameters and returns the resulting set. // The function allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set // in-place and returns the same array. - function appendTypeParameters(typeParameters: TypeParameter[] | undefined, declarations: readonly TypeParameterDeclaration[]): TypeParameter[] | undefined { + function appendTypeParameters( + typeParameters: TypeParameter[] | undefined, + declarations: readonly TypeParameterDeclaration[], + ): TypeParameter[] | undefined { for (const declaration of declarations) { - typeParameters = appendIfUnique(typeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode(declaration))); + typeParameters = appendIfUnique( + typeParameters, + getDeclaredTypeOfTypeParameter(getSymbolOfNode(declaration)), + ); } return typeParameters; } @@ -10439,7 +13836,10 @@ namespace ts { if (node && isBinaryExpression(node)) { // prototype assignments get the outer type parameters of their constructor function const assignmentKind = getAssignmentDeclarationKind(node); - if (assignmentKind === AssignmentDeclarationKind.Prototype || assignmentKind === AssignmentDeclarationKind.PrototypeProperty) { + if ( + assignmentKind === AssignmentDeclarationKind.Prototype + || assignmentKind === AssignmentDeclarationKind.PrototypeProperty + ) { const symbol = getSymbolOfNode(node.left); if (symbol && symbol.parent && !findAncestor(symbol.parent.valueDeclaration, d => node === d)) { node = symbol.parent.valueDeclaration!; @@ -10472,15 +13872,27 @@ namespace ts { case SyntaxKind.ConditionalType: { const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); if (node.kind === SyntaxKind.MappedType) { - return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((node as MappedTypeNode).typeParameter))); + return append( + outerTypeParameters, + getDeclaredTypeOfTypeParameter(getSymbolOfNode((node as MappedTypeNode).typeParameter)), + ); } else if (node.kind === SyntaxKind.ConditionalType) { - return concatenate(outerTypeParameters, getInferTypeParameters(node as ConditionalTypeNode)); + return concatenate( + outerTypeParameters, + getInferTypeParameters(node as ConditionalTypeNode), + ); } - const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters)); - const thisType = includeThisTypes && - (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) && - getDeclaredTypeOfClassOrInterface(getSymbolOfNode(node as ClassLikeDeclaration | InterfaceDeclaration)).thisType; + const outerAndOwnTypeParameters = appendTypeParameters( + outerTypeParameters, + getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters), + ); + const thisType = includeThisTypes + && (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression + || node.kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) + && getDeclaredTypeOfClassOrInterface( + getSymbolOfNode(node as ClassLikeDeclaration | InterfaceDeclaration), + ).thisType; return thisType ? append(outerAndOwnTypeParameters, thisType) : outerAndOwnTypeParameters; } case SyntaxKind.JSDocParameterTag: @@ -10492,7 +13904,13 @@ namespace ts { case SyntaxKind.JSDoc: { const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); return (node as JSDoc).tags - ? appendTypeParameters(outerTypeParameters, flatMap((node as JSDoc).tags, t => isJSDocTemplateTag(t) ? t.typeParameters : undefined)) + ? appendTypeParameters( + outerTypeParameters, + flatMap( + (node as JSDoc).tags, + t => isJSDocTemplateTag(t) ? t.typeParameters : undefined, + ), + ) : outerTypeParameters; } } @@ -10501,8 +13919,12 @@ namespace ts { // The outer type parameters are those defined by enclosing generic classes, methods, or functions. function getOuterTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] | undefined { - const declaration = symbol.flags & SymbolFlags.Class ? symbol.valueDeclaration : getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration)!; - Debug.assert(!!declaration, "Class was missing valueDeclaration -OR- non-class had no interface declarations"); + const declaration = symbol.flags & SymbolFlags.Class ? symbol.valueDeclaration + : getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration)!; + Debug.assert( + !!declaration, + "Class was missing valueDeclaration -OR- non-class had no interface declarations", + ); return getOuterTypeParameters(declaration); } @@ -10515,13 +13937,17 @@ namespace ts { let result: TypeParameter[] | undefined; for (const node of symbol.declarations) { if ( - node.kind === SyntaxKind.InterfaceDeclaration || - node.kind === SyntaxKind.ClassDeclaration || - node.kind === SyntaxKind.ClassExpression || - isJSConstructor(node) || - isTypeAlias(node) + node.kind === SyntaxKind.InterfaceDeclaration + || node.kind === SyntaxKind.ClassDeclaration + || node.kind === SyntaxKind.ClassExpression + || isJSConstructor(node) + || isTypeAlias(node) ) { - const declaration = node as InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag; + const declaration = node as + | InterfaceDeclaration + | TypeAliasDeclaration + | JSDocTypedefTag + | JSDocCallbackTag; result = appendTypeParameters(result, getEffectiveTypeParameterDeclarations(declaration)); } } @@ -10531,7 +13957,10 @@ namespace ts { // The full set of type parameters for a generic class or interface type consists of its outer type parameters plus // its locally declared type parameters. function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] | undefined { - return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)); + return concatenate( + getOuterTypeParametersOfClassOrInterface(symbol), + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), + ); } // A type is a mixin constructor if it has a single construct signature taking no type parameters and a single @@ -10564,16 +13993,34 @@ namespace ts { return decl && getEffectiveBaseTypeNode(decl); } - function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: readonly TypeNode[] | undefined, location: Node): readonly Signature[] { + function getConstructorsForTypeArguments( + type: Type, + typeArgumentNodes: readonly TypeNode[] | undefined, + location: Node, + ): readonly Signature[] { const typeArgCount = length(typeArgumentNodes); const isJavascript = isInJSFile(location); - return filter(getSignaturesOfType(type, SignatureKind.Construct), sig => (isJavascript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters)); + return filter( + getSignaturesOfType(type, SignatureKind.Construct), + sig => + (isJavascript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) + && typeArgCount <= length(sig.typeParameters), + ); } - function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: readonly TypeNode[] | undefined, location: Node): readonly Signature[] { + function getInstantiatedConstructorsForTypeArguments( + type: Type, + typeArgumentNodes: readonly TypeNode[] | undefined, + location: Node, + ): readonly Signature[] { const signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location); const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode); - return sameMap(signatures, sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments, isInJSFile(location)) : sig); + return sameMap( + signatures, + sig => + some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments, isInJSFile(location)) + : sig, + ); } /** @@ -10606,11 +14053,22 @@ namespace ts { resolveStructuredTypeMembers(baseConstructorType as ObjectType); } if (!popTypeResolution()) { - error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol)); + error( + type.symbol.valueDeclaration, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, + symbolToString(type.symbol), + ); return type.resolvedBaseConstructorType = errorType; } - if (!(baseConstructorType.flags & TypeFlags.Any) && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) { - const err = error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType)); + if ( + !(baseConstructorType.flags & TypeFlags.Any) && baseConstructorType !== nullWideningType + && !isConstructorType(baseConstructorType) + ) { + const err = error( + baseTypeNode.expression, + Diagnostics.Type_0_is_not_a_constructor_function_type, + typeToString(baseConstructorType), + ); if (baseConstructorType.flags & TypeFlags.TypeParameter) { const constraint = getConstraintFromTypeParameter(baseConstructorType); let ctorReturn: Type = unknownType; @@ -10621,7 +14079,15 @@ namespace ts { } } if (baseConstructorType.symbol.declarations) { - addRelatedInfo(err, createDiagnosticForNode(baseConstructorType.symbol.declarations[0], Diagnostics.Did_you_mean_for_0_to_be_constrained_to_type_new_args_Colon_any_1, symbolToString(baseConstructorType.symbol), typeToString(ctorReturn))); + addRelatedInfo( + err, + createDiagnosticForNode( + baseConstructorType.symbol.declarations[0], + Diagnostics.Did_you_mean_for_0_to_be_constrained_to_type_new_args_Colon_any_1, + symbolToString(baseConstructorType.symbol), + typeToString(ctorReturn), + ), + ); } } return type.resolvedBaseConstructorType = errorType; @@ -10654,7 +14120,11 @@ namespace ts { } function reportCircularBaseType(node: Node, type: Type) { - error(node, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); + error( + node, + Diagnostics.Type_0_recursively_references_itself_as_a_base_type, + typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), + ); } function getBaseTypes(type: InterfaceType): BaseType[] { @@ -10676,7 +14146,10 @@ namespace ts { } if (!popTypeResolution() && type.symbol.declarations) { for (const declaration of type.symbol.declarations) { - if (declaration.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.InterfaceDeclaration) { + if ( + declaration.kind === SyntaxKind.ClassDeclaration + || declaration.kind === SyntaxKind.InterfaceDeclaration + ) { reportCircularBaseType(declaration, type); } } @@ -10688,7 +14161,10 @@ namespace ts { } function getTupleBaseType(type: TupleType) { - const elementTypes = sameMap(type.typeParameters, (t, i) => type.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t); + const elementTypes = sameMap( + type.typeParameters, + (t, i) => type.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t, + ); return createArrayType(getUnionType(elementTypes || emptyArray), type.readonly); } @@ -10700,10 +14176,11 @@ namespace ts { } const baseTypeNode = getBaseTypeNodeOfClass(type)!; let baseType: Type; - const originalBaseType = baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined; + const originalBaseType = baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) + : undefined; if ( - baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class && - areAllOuterTypeParametersApplied(originalBaseType!) + baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class + && areAllOuterTypeParametersApplied(originalBaseType!) ) { // When base constructor type is a class with no captured type arguments we know that the constructors all have the same type parameters as the // class and all return the instance type of the class. There is no need for further checks and we can apply the @@ -10717,9 +14194,16 @@ namespace ts { // The class derives from a "class-like" constructor function, check that we have at least one construct signature // with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere // we check that all instantiated signatures return the same type. - const constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments, baseTypeNode); + const constructors = getInstantiatedConstructorsForTypeArguments( + baseConstructorType, + baseTypeNode.typeArguments, + baseTypeNode, + ); if (!constructors.length) { - error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments); + error( + baseTypeNode.expression, + Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments, + ); return type.resolvedBaseTypes = emptyArray; } baseType = getReturnTypeOfSignature(constructors[0]); @@ -10731,12 +14215,21 @@ namespace ts { const reducedBaseType = getReducedType(baseType); if (!isValidBaseType(reducedBaseType)) { const elaboration = elaborateNeverIntersection(/*errorInfo*/ undefined, baseType); - const diagnostic = chainDiagnosticMessages(elaboration, Diagnostics.Base_constructor_return_type_0_is_not_an_object_type_or_intersection_of_object_types_with_statically_known_members, typeToString(reducedBaseType)); + const diagnostic = chainDiagnosticMessages( + elaboration, + Diagnostics + .Base_constructor_return_type_0_is_not_an_object_type_or_intersection_of_object_types_with_statically_known_members, + typeToString(reducedBaseType), + ); diagnostics.add(createDiagnosticForNodeFromMessageChain(baseTypeNode.expression, diagnostic)); return type.resolvedBaseTypes = emptyArray; } if (type === reducedBaseType || hasBaseType(reducedBaseType, type)) { - error(type.symbol.valueDeclaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); + error( + type.symbol.valueDeclaration, + Diagnostics.Type_0_recursively_references_itself_as_a_base_type, + typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), + ); return type.resolvedBaseTypes = emptyArray; } if (type.resolvedBaseTypes === resolvingEmptyArray) { @@ -10771,15 +14264,19 @@ namespace ts { } // TODO: Given that we allow type parmeters here now, is this `!isGenericMappedType(type)` check really needed? // There's no reason a `T` should be allowed while a `Readonly` should not. - return !!(type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) && !isGenericMappedType(type) || - type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isValidBaseType)); + return !!(type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) + && !isGenericMappedType(type) + || type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isValidBaseType)); } function resolveBaseTypesOfInterface(type: InterfaceType): void { type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; if (type.symbol.declarations) { for (const declaration of type.symbol.declarations) { - if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration)) { + if ( + declaration.kind === SyntaxKind.InterfaceDeclaration + && getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration) + ) { for (const node of getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration)!) { const baseType = getReducedType(getTypeFromTypeNode(node)); if (!isErrorType(baseType)) { @@ -10797,7 +14294,11 @@ namespace ts { } } else { - error(node, Diagnostics.An_interface_can_only_extend_an_object_type_or_intersection_of_object_types_with_statically_known_members); + error( + node, + Diagnostics + .An_interface_can_only_extend_an_object_type_or_intersection_of_object_types_with_statically_known_members, + ); } } } @@ -10826,8 +14327,15 @@ namespace ts { if (baseTypeNodes) { for (const node of baseTypeNodes) { if (isEntityNameExpression(node.expression)) { - const baseSymbol = resolveEntityName(node.expression, SymbolFlags.Type, /*ignoreErrors*/ true); - if (!baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType) { + const baseSymbol = resolveEntityName( + node.expression, + SymbolFlags.Type, + /*ignoreErrors*/ true, + ); + if ( + !baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) + || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType + ) { return false; } } @@ -10843,13 +14351,19 @@ namespace ts { const originalLinks = links; if (!links.declaredType) { const kind = symbol.flags & SymbolFlags.Class ? ObjectFlags.Class : ObjectFlags.Interface; - const merged = mergeJSSymbols(symbol, symbol.valueDeclaration && getAssignedClassSymbol(symbol.valueDeclaration)); + const merged = mergeJSSymbols( + symbol, + symbol.valueDeclaration && getAssignedClassSymbol(symbol.valueDeclaration), + ); if (merged) { // note:we overwrite links because we just cloned the symbol symbol = links = merged; } - const type = originalLinks.declaredType = links.declaredType = createObjectType(kind, symbol) as InterfaceType; + const type = originalLinks.declaredType = links.declaredType = createObjectType( + kind, + symbol, + ) as InterfaceType; const outerTypeParameters = getOuterTypeParametersOfClassOrInterface(symbol); const localTypeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); // A class or interface is generic if it has type parameters or a "this" type. We always give classes a "this" type @@ -10857,7 +14371,10 @@ namespace ts { // property types inferred from initializers and method return types inferred from return statements are very hard // to exhaustively analyze). We give interfaces a "this" type if we can't definitely determine that they are free of // "this" references. - if (outerTypeParameters || localTypeParameters || kind === ObjectFlags.Class || !isThislessInterface(symbol)) { + if ( + outerTypeParameters || localTypeParameters || kind === ObjectFlags.Class + || !isThislessInterface(symbol) + ) { type.objectFlags |= ObjectFlags.Reference; type.typeParameters = concatenate(outerTypeParameters, localTypeParameters); type.outerTypeParameters = outerTypeParameters; @@ -10883,7 +14400,10 @@ namespace ts { return errorType; } - const declaration = Debug.checkDefined(symbol.declarations?.find(isTypeAlias), "Type alias symbol with no valid declaration found"); + const declaration = Debug.checkDefined( + symbol.declarations?.find(isTypeAlias), + "Type alias symbol with no valid declaration found", + ); const typeNode = isJSDocTypeAlias(declaration) ? declaration.typeExpression : declaration.type; // If typeNode is missing, we will error in checkJSDocTypedefTag. let type = typeNode ? getTypeFromTypeNode(typeNode) : errorType; @@ -10901,10 +14421,18 @@ namespace ts { else { type = errorType; if (declaration.kind === SyntaxKind.JSDocEnumTag) { - error(declaration.typeExpression.type, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + error( + declaration.typeExpression.type, + Diagnostics.Type_alias_0_circularly_references_itself, + symbolToString(symbol), + ); } else { - error(isNamedDeclaration(declaration) ? declaration.name || declaration : declaration, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + error( + isNamedDeclaration(declaration) ? declaration.name || declaration : declaration, + Diagnostics.Type_alias_0_circularly_references_itself, + symbolToString(symbol), + ); } } links.declaredType = type; @@ -10917,7 +14445,8 @@ namespace ts { return true; } else if (expr.kind === SyntaxKind.BinaryExpression) { - return isStringConcatExpression((expr as BinaryExpression).left) && isStringConcatExpression((expr as BinaryExpression).right); + return isStringConcatExpression((expr as BinaryExpression).left) + && isStringConcatExpression((expr as BinaryExpression).right); } return false; } @@ -10933,10 +14462,11 @@ namespace ts { case SyntaxKind.NoSubstitutionTemplateLiteral: return true; case SyntaxKind.PrefixUnaryExpression: - return (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && - (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.NumericLiteral; + return (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken + && (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.NumericLiteral; case SyntaxKind.Identifier: - return nodeIsMissing(expr) || !!getSymbolOfNode(member.parent).exports!.get((expr as Identifier).escapedText); + return nodeIsMissing(expr) + || !!getSymbolOfNode(member.parent).exports!.get((expr as Identifier).escapedText); case SyntaxKind.BinaryExpression: return isStringConcatExpression(expr); default: @@ -10968,7 +14498,8 @@ namespace ts { } function getBaseTypeOfEnumLiteralType(type: Type) { - return type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union) ? getDeclaredTypeOfSymbol(getParentOfSymbol(type.symbol)!) : type; + return type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union) + ? getDeclaredTypeOfSymbol(getParentOfSymbol(type.symbol)!) : type; } function getDeclaredTypeOfEnum(symbol: Symbol): Type { @@ -10984,7 +14515,13 @@ namespace ts { if (declaration.kind === SyntaxKind.EnumDeclaration) { for (const member of (declaration as EnumDeclaration).members) { const value = getEnumMemberValue(member); - const memberType = getFreshTypeOfLiteralType(getEnumLiteralType(value !== undefined ? value : 0, enumCount, getSymbolOfNode(member))); + const memberType = getFreshTypeOfLiteralType( + getEnumLiteralType( + value !== undefined ? value : 0, + enumCount, + getSymbolOfNode(member), + ), + ); getSymbolLinks(getSymbolOfNode(member)).declaredType = memberType; memberTypeList.push(getRegularTypeOfLiteralType(memberType)); } @@ -10992,7 +14529,12 @@ namespace ts { } } if (memberTypeList.length) { - const enumType = getUnionType(memberTypeList, UnionReduction.Literal, symbol, /*aliasTypeArguments*/ undefined); + const enumType = getUnionType( + memberTypeList, + UnionReduction.Literal, + symbol, + /*aliasTypeArguments*/ undefined, + ); if (enumType.flags & TypeFlags.Union) { enumType.flags |= TypeFlags.EnumLiteral; enumType.symbol = symbol; @@ -11075,7 +14617,8 @@ namespace ts { case SyntaxKind.ArrayType: return isThislessType((node as ArrayTypeNode).elementType); case SyntaxKind.TypeReference: - return !(node as TypeReferenceNode).typeArguments || (node as TypeReferenceNode).typeArguments!.every(isThislessType); + return !(node as TypeReferenceNode).typeArguments + || (node as TypeReferenceNode).typeArguments!.every(isThislessType); } return false; } @@ -11103,9 +14646,9 @@ namespace ts { function isThislessFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { const returnType = getEffectiveReturnTypeNode(node); const typeParameters = getEffectiveTypeParameterDeclarations(node); - return (node.kind === SyntaxKind.Constructor || (!!returnType && isThislessType(returnType))) && - node.parameters.every(isThislessVariableLikeDeclaration) && - typeParameters.every(isThislessTypeParameter); + return (node.kind === SyntaxKind.Constructor || (!!returnType && isThislessType(returnType))) + && node.parameters.every(isThislessVariableLikeDeclaration) + && typeParameters.every(isThislessTypeParameter); } /** @@ -11128,7 +14671,9 @@ namespace ts { case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return isThislessFunctionLikeDeclaration(declaration as FunctionLikeDeclaration | AccessorDeclaration); + return isThislessFunctionLikeDeclaration( + declaration as FunctionLikeDeclaration | AccessorDeclaration, + ); } } } @@ -11137,10 +14682,17 @@ namespace ts { // The mappingThisOnly flag indicates that the only type parameter being mapped is "this". When the flag is true, // we check symbols to see if we can quickly conclude they are free of "this" references, thus needing no instantiation. - function createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper, mappingThisOnly: boolean): SymbolTable { + function createInstantiatedSymbolTable( + symbols: Symbol[], + mapper: TypeMapper, + mappingThisOnly: boolean, + ): SymbolTable { const result = createSymbolTable(); for (const symbol of symbols) { - result.set(symbol.escapedName, mappingThisOnly && isThisless(symbol) ? symbol : instantiateSymbol(symbol, mapper)); + result.set( + symbol.escapedName, + mappingThisOnly && isThisless(symbol) ? symbol : instantiateSymbol(symbol, mapper), + ); } return result; } @@ -11154,7 +14706,8 @@ namespace ts { } function isStaticPrivateIdentifierProperty(s: Symbol): boolean { - return !!s.valueDeclaration && isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) && isStatic(s.valueDeclaration); + return !!s.valueDeclaration && isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) + && isStatic(s.valueDeclaration); } function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers { @@ -11167,8 +14720,12 @@ namespace ts { (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = emptyArray; (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = emptyArray; - (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.Call)); - (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.New)); + (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = getSignaturesOfSymbol( + members.get(InternalSymbolName.Call), + ); + (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = getSignaturesOfSymbol( + members.get(InternalSymbolName.New), + ); (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = getIndexInfosOfSymbol(symbol); } return type as InterfaceTypeWithDeclaredMembers; @@ -11177,7 +14734,9 @@ namespace ts { /** * Indicates whether a type can be used as a property name. */ - function isTypeUsableAsPropertyName(type: Type): type is StringLiteralType | NumberLiteralType | UniqueESSymbolType { + function isTypeUsableAsPropertyName( + type: Type, + ): type is StringLiteralType | NumberLiteralType | UniqueESSymbolType { return !!(type.flags & TypeFlags.StringOrNumberLiteralOrUnique); } @@ -11195,19 +14754,23 @@ namespace ts { } const expr = isComputedPropertyName(node) ? node.expression : node.argumentExpression; return isEntityNameExpression(expr) - && isTypeUsableAsPropertyName(isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached(expr)); + && isTypeUsableAsPropertyName( + isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached(expr), + ); } function isLateBoundName(name: __String): boolean { - return (name as string).charCodeAt(0) === CharacterCodes._ && - (name as string).charCodeAt(1) === CharacterCodes._ && - (name as string).charCodeAt(2) === CharacterCodes.at; + return (name as string).charCodeAt(0) === CharacterCodes._ + && (name as string).charCodeAt(1) === CharacterCodes._ + && (name as string).charCodeAt(2) === CharacterCodes.at; } /** * Indicates whether a declaration has a late-bindable dynamic name. */ - function hasLateBindableName(node: Declaration): node is LateBoundDeclaration | LateBoundBinaryExpressionDeclaration { + function hasLateBindableName( + node: Declaration, + ): node is LateBoundDeclaration | LateBoundBinaryExpressionDeclaration { const name = getNameOfDeclaration(node); return !!name && isLateBindableName(name); } @@ -11244,7 +14807,11 @@ namespace ts { * late-bound members that `addDeclarationToSymbol` in binder.ts performs for early-bound * members. */ - function addDeclarationToLateBoundSymbol(symbol: Symbol, member: LateBoundDeclaration | BinaryExpression, symbolFlags: SymbolFlags) { + function addDeclarationToLateBoundSymbol( + symbol: Symbol, + member: LateBoundDeclaration | BinaryExpression, + symbolFlags: SymbolFlags, + ) { Debug.assert(!!(getCheckFlags(symbol) & CheckFlags.Late), "Expected a late-bound symbol."); symbol.flags |= symbolFlags; getSymbolLinks(member.symbol).lateSymbol = symbol; @@ -11289,7 +14856,12 @@ namespace ts { * @param lateSymbols The late-bound symbols of the parent. * @param decl The member to bind. */ - function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: UnderscoreEscapedMap, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) { + function lateBindMember( + parent: Symbol, + earlySymbols: SymbolTable | undefined, + lateSymbols: UnderscoreEscapedMap, + decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration, + ) { Debug.assert(!!decl.symbol, "The member is expected to have a symbol."); const links = getNodeLinks(decl); if (!links.resolvedSymbol) { @@ -11297,14 +14869,20 @@ namespace ts { // fall back to the early-bound name of this member. links.resolvedSymbol = decl.symbol; const declName = isBinaryExpression(decl) ? decl.left : decl.name; - const type = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) : checkComputedPropertyName(declName); + const type = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) + : checkComputedPropertyName(declName); if (isTypeUsableAsPropertyName(type)) { const memberName = getPropertyNameFromType(type); const symbolFlags = decl.symbol.flags; // Get or add a late-bound symbol for the member. This allows us to merge late-bound accessor declarations. let lateSymbol = lateSymbols.get(memberName); - if (!lateSymbol) lateSymbols.set(memberName, lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late)); + if (!lateSymbol) { + lateSymbols.set( + memberName, + lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late), + ); + } // Report an error if a late-bound member has the same name as an early-bound member, // or if we have another early-bound symbol declaration with the same name and @@ -11313,9 +14891,19 @@ namespace ts { if (lateSymbol.flags & getExcludedSymbolFlags(symbolFlags) || earlySymbol) { // If we have an existing early-bound member, combine its declarations so that we can // report an error at each declaration. - const declarations = earlySymbol ? concatenate(earlySymbol.declarations, lateSymbol.declarations) : lateSymbol.declarations; - const name = !(type.flags & TypeFlags.UniqueESSymbol) && unescapeLeadingUnderscores(memberName) || declarationNameToString(declName); - forEach(declarations, declaration => error(getNameOfDeclaration(declaration) || declaration, Diagnostics.Property_0_was_also_declared_here, name)); + const declarations = earlySymbol + ? concatenate(earlySymbol.declarations, lateSymbol.declarations) : lateSymbol.declarations; + const name = !(type.flags & TypeFlags.UniqueESSymbol) && unescapeLeadingUnderscores(memberName) + || declarationNameToString(declName); + forEach( + declarations, + declaration => + error( + getNameOfDeclaration(declaration) || declaration, + Diagnostics.Property_0_was_also_declared_here, + name, + ), + ); error(declName || decl, Diagnostics.Duplicate_property_0, name); lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late); } @@ -11333,13 +14921,16 @@ namespace ts { return links.resolvedSymbol; } - function getResolvedMembersOrExportsOfSymbol(symbol: Symbol, resolutionKind: MembersOrExportsResolutionKind): UnderscoreEscapedMap { + function getResolvedMembersOrExportsOfSymbol( + symbol: Symbol, + resolutionKind: MembersOrExportsResolutionKind, + ): UnderscoreEscapedMap { const links = getSymbolLinks(symbol); if (!links[resolutionKind]) { const isStatic = resolutionKind === MembersOrExportsResolutionKind.resolvedExports; - const earlySymbols = !isStatic ? symbol.members : - symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol) : - symbol.exports; + const earlySymbols = !isStatic ? symbol.members + : symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol) + : symbol.exports; // In the event we recursively resolve the members/exports of the symbol, we // set the initial value of resolvedMembers/resolvedExports to the early-bound @@ -11364,7 +14955,9 @@ namespace ts { if (assignments) { const decls = arrayFrom(assignments.values()); for (const member of decls) { - const assignmentKind = getAssignmentDeclarationKind(member as BinaryExpression | CallExpression); + const assignmentKind = getAssignmentDeclarationKind( + member as BinaryExpression | CallExpression, + ); const isInstanceMember = assignmentKind === AssignmentDeclarationKind.PrototypeProperty || isBinaryExpression(member) && isPossiblyAliasedThisProperty(member, assignmentKind) || assignmentKind === AssignmentDeclarationKind.ObjectDefinePrototypeProperty @@ -11423,32 +15016,48 @@ namespace ts { const target = (type as TypeReference).target; const typeArguments = getTypeArguments(type as TypeReference); if (length(target.typeParameters) === length(typeArguments)) { - const ref = createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])); + const ref = createTypeReference( + target, + concatenate(typeArguments, [thisArgument || target.thisType!]), + ); return needApparentType ? getApparentType(ref) : ref; } } else if (type.flags & TypeFlags.Intersection) { - const types = sameMap((type as IntersectionType).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType)); + const types = sameMap( + (type as IntersectionType).types, + t => getTypeWithThisArgument(t, thisArgument, needApparentType), + ); return types !== (type as IntersectionType).types ? getIntersectionType(types) : type; } return needApparentType ? getApparentType(type) : type; } - function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: readonly TypeParameter[], typeArguments: readonly Type[]) { + function resolveObjectTypeMembers( + type: ObjectType, + source: InterfaceTypeWithDeclaredMembers, + typeParameters: readonly TypeParameter[], + typeArguments: readonly Type[], + ) { let mapper: TypeMapper | undefined; let members: SymbolTable; let callSignatures: readonly Signature[]; let constructSignatures: readonly Signature[]; let indexInfos: readonly IndexInfo[]; if (rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) { - members = source.symbol ? getMembersOfSymbol(source.symbol) : createSymbolTable(source.declaredProperties); + members = source.symbol ? getMembersOfSymbol(source.symbol) + : createSymbolTable(source.declaredProperties); callSignatures = source.declaredCallSignatures; constructSignatures = source.declaredConstructSignatures; indexInfos = source.declaredIndexInfos; } else { mapper = createTypeMapper(typeParameters, typeArguments); - members = createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1); + members = createInstantiatedSymbolTable( + source.declaredProperties, + mapper, + /*mappingThisOnly*/ typeParameters.length === 1, + ); callSignatures = instantiateSignatures(source.declaredCallSignatures, mapper); constructSignatures = instantiateSignatures(source.declaredConstructSignatures, mapper); indexInfos = instantiateIndexInfos(source.declaredIndexInfos, mapper); @@ -11461,12 +15070,24 @@ namespace ts { setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); const thisArgument = lastOrUndefined(typeArguments); for (const baseType of baseTypes) { - const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType; + const instantiatedBaseType = thisArgument + ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType; addInheritedMembers(members, getPropertiesOfType(instantiatedBaseType)); - callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call)); - constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct)); - const inheritedIndexInfos = instantiatedBaseType !== anyType ? getIndexInfosOfType(instantiatedBaseType) : [createIndexInfo(stringType, anyType, /*isReadonly*/ false)]; - indexInfos = concatenate(indexInfos, filter(inheritedIndexInfos, info => !findIndexInfo(indexInfos, info.keyType))); + callSignatures = concatenate( + callSignatures, + getSignaturesOfType(instantiatedBaseType, SignatureKind.Call), + ); + constructSignatures = concatenate( + constructSignatures, + getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct), + ); + const inheritedIndexInfos = instantiatedBaseType !== anyType + ? getIndexInfosOfType(instantiatedBaseType) + : [createIndexInfo(stringType, anyType, /*isReadonly*/ false)]; + indexInfos = concatenate( + indexInfos, + filter(inheritedIndexInfos, info => !findIndexInfo(indexInfos, info.keyType)), + ); } } setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); @@ -11480,7 +15101,8 @@ namespace ts { const source = resolveDeclaredMembers(type.target); const typeParameters = concatenate(source.typeParameters!, [source.thisType!]); const typeArguments = getTypeArguments(type); - const paddedTypeArguments = typeArguments.length === typeParameters.length ? typeArguments : concatenate(typeArguments, [type]); + const paddedTypeArguments = typeArguments.length === typeParameters.length ? typeArguments + : concatenate(typeArguments, [type]); resolveObjectTypeMembers(type, source, typeParameters, paddedTypeArguments); } @@ -11511,7 +15133,16 @@ namespace ts { } function cloneSignature(sig: Signature): Signature { - const result = createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags); + const result = createSignature( + sig.declaration, + sig.typeParameters, + sig.thisParameter, + sig.parameters, + /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, + sig.minArgumentCount, + sig.flags & SignatureFlags.PropagatingFlags, + ); result.target = sig.target; result.mapper = sig.mapper; result.compositeSignatures = sig.compositeSignatures; @@ -11541,7 +15172,11 @@ namespace ts { } function createOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags) { - Debug.assert(callChainFlags === SignatureFlags.IsInnerCallChain || callChainFlags === SignatureFlags.IsOuterCallChain, "An optional call signature can either be for an inner call chain or an outer call chain, but not both."); + Debug.assert( + callChainFlags === SignatureFlags.IsInnerCallChain + || callChainFlags === SignatureFlags.IsOuterCallChain, + "An optional call signature can either be for an inner call chain or an outer call chain, but not both.", + ); const result = cloneSignature(signature); result.flags |= callChainFlags; return result; @@ -11554,8 +15189,14 @@ namespace ts { if (isTupleType(restType)) { return [expandSignatureParametersWithTupleMembers(restType, restIndex)]; } - else if (!skipUnionExpanding && restType.flags & TypeFlags.Union && every((restType as UnionType).types, isTupleType)) { - return map((restType as UnionType).types, t => expandSignatureParametersWithTupleMembers(t as TupleTypeReference, restIndex)); + else if ( + !skipUnionExpanding && restType.flags & TypeFlags.Union + && every((restType as UnionType).types, isTupleType) + ) { + return map( + (restType as UnionType).types, + t => expandSignatureParametersWithTupleMembers(t as TupleTypeReference, restIndex), + ); } } return [sig.parameters]; @@ -11568,8 +15209,8 @@ namespace ts { const tupleLabelName = !!associatedNames && getTupleElementLabel(associatedNames[i]); const name = tupleLabelName || getParameterNameAtPosition(sig, restIndex + i, restType); const flags = restType.target.elementFlags[i]; - const checkFlags = flags & ElementFlags.Variable ? CheckFlags.RestParameter : - flags & ElementFlags.Optional ? CheckFlags.OptionalParameter : 0; + const checkFlags = flags & ElementFlags.Variable ? CheckFlags.RestParameter + : flags & ElementFlags.Optional ? CheckFlags.OptionalParameter : 0; const symbol = createSymbol(SymbolFlags.FunctionScopedVariable, name, checkFlags); symbol.type = flags & ElementFlags.Rest ? createArrayType(t) : t; return symbol; @@ -11584,7 +15225,18 @@ namespace ts { const declaration = getClassLikeDeclarationOfSymbol(classType.symbol); const isAbstract = !!declaration && hasSyntacticModifier(declaration, ModifierFlags.Abstract); if (baseSignatures.length === 0) { - return [createSignature(undefined, classType.localTypeParameters, undefined, emptyArray, classType, /*resolvedTypePredicate*/ undefined, 0, isAbstract ? SignatureFlags.Abstract : SignatureFlags.None)]; + return [ + createSignature( + undefined, + classType.localTypeParameters, + undefined, + emptyArray, + classType, + /*resolvedTypePredicate*/ undefined, + 0, + isAbstract ? SignatureFlags.Abstract : SignatureFlags.None, + ), + ]; } const baseTypeNode = getBaseTypeNodeOfClass(classType)!; const isJavaScript = isInJSFile(baseTypeNode); @@ -11595,7 +15247,16 @@ namespace ts { const minTypeArgumentCount = getMinTypeArgumentCount(baseSig.typeParameters); const typeParamCount = length(baseSig.typeParameters); if (isJavaScript || typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount) { - const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript)) : cloneSignature(baseSig); + const sig = typeParamCount + ? createSignatureInstantiation( + baseSig, + fillMissingTypeArguments( + typeArguments, + baseSig.typeParameters, + minTypeArgumentCount, + isJavaScript, + ), + ) : cloneSignature(baseSig); sig.typeParameters = classType.localTypeParameters; sig.resolvedReturnType = classType; sig.flags = isAbstract ? sig.flags | SignatureFlags.Abstract : sig.flags & ~SignatureFlags.Abstract; @@ -11605,15 +15266,34 @@ namespace ts { return result; } - function findMatchingSignature(signatureList: readonly Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature | undefined { + function findMatchingSignature( + signatureList: readonly Signature[], + signature: Signature, + partialMatch: boolean, + ignoreThisTypes: boolean, + ignoreReturnTypes: boolean, + ): Signature | undefined { for (const s of signatureList) { - if (compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, partialMatch ? compareTypesSubtypeOf : compareTypesIdentical)) { + if ( + compareSignaturesIdentical( + s, + signature, + partialMatch, + ignoreThisTypes, + ignoreReturnTypes, + partialMatch ? compareTypesSubtypeOf : compareTypesIdentical, + ) + ) { return s; } } } - function findMatchingSignatures(signatureLists: readonly (readonly Signature[])[], signature: Signature, listIndex: number): Signature[] | undefined { + function findMatchingSignatures( + signatureLists: readonly (readonly Signature[])[], + signature: Signature, + listIndex: number, + ): Signature[] | undefined { if (signature.typeParameters) { // We require an exact match for generic signatures, so we only return signatures from the first // signature list and only if they have exact matches in the other signature lists. @@ -11621,7 +15301,15 @@ namespace ts { return undefined; } for (let i = 1; i < signatureLists.length; i++) { - if (!findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false)) { + if ( + !findMatchingSignature( + signatureLists[i], + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ false, + ) + ) { return undefined; } } @@ -11631,7 +15319,14 @@ namespace ts { for (let i = 0; i < signatureLists.length; i++) { // Allow matching non-generic signatures to have excess parameters and different return types. // Prefer matching this types if possible. - const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true); + const match = i === listIndex ? signature + : findMatchingSignature( + signatureLists[i], + signature, + /*partialMatch*/ true, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true, + ); if (!match) { return undefined; } @@ -11654,16 +15349,33 @@ namespace ts { } for (const signature of signatureLists[i]) { // Only process signatures with parameter lists that aren't already in the result list - if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true)) { + if ( + !result + || !findMatchingSignature( + result, + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true, + ) + ) { const unionSignatures = findMatchingSignatures(signatureLists, signature, i); if (unionSignatures) { let s = signature; // Union the result types when more than one signature matches if (unionSignatures.length > 1) { let thisParameter = signature.thisParameter; - const firstThisParameterOfUnionSignatures = forEach(unionSignatures, sig => sig.thisParameter); + const firstThisParameterOfUnionSignatures = forEach( + unionSignatures, + sig => sig.thisParameter, + ); if (firstThisParameterOfUnionSignatures) { - const thisType = getIntersectionType(mapDefined(unionSignatures, sig => sig.thisParameter && getTypeOfSymbol(sig.thisParameter))); + const thisType = getIntersectionType( + mapDefined( + unionSignatures, + sig => sig.thisParameter && getTypeOfSymbol(sig.thisParameter), + ), + ); thisParameter = createSymbolWithType(firstThisParameterOfUnionSignatures, thisType); } s = createUnionSignature(signature, unionSignatures); @@ -11684,8 +15396,14 @@ namespace ts { for (const signatures of signatureLists) { if (signatures !== masterList) { const signature = signatures[0]; - Debug.assert(!!signature, "getUnionSignatures bails early on empty signature lists and should not have empty lists on second pass"); - results = !!signature.typeParameters && some(results, s => !!s.typeParameters && !compareTypeParametersIdentical(signature.typeParameters, s.typeParameters)) ? undefined : map(results, sig => combineSignaturesOfUnionMembers(sig, signature)); + Debug.assert( + !!signature, + "getUnionSignatures bails early on empty signature lists and should not have empty lists on second pass", + ); + results = !!signature.typeParameters && some(results, s => + !!s.typeParameters + && !compareTypeParametersIdentical(signature.typeParameters, s.typeParameters)) + ? undefined : map(results, sig => combineSignaturesOfUnionMembers(sig, signature)); if (!results) { break; } @@ -11696,7 +15414,10 @@ namespace ts { return result || emptyArray; } - function compareTypeParametersIdentical(sourceParams: readonly TypeParameter[] | undefined, targetParams: readonly TypeParameter[] | undefined): boolean { + function compareTypeParametersIdentical( + sourceParams: readonly TypeParameter[] | undefined, + targetParams: readonly TypeParameter[] | undefined, + ): boolean { if (length(sourceParams) !== length(targetParams)) { return false; } @@ -11710,7 +15431,12 @@ namespace ts { const target = targetParams[i]; if (source === target) continue; // We instantiate the target type parameter constraints into the source types so we can recognize `` as the same as `` - if (!isTypeIdenticalTo(getConstraintFromTypeParameter(source) || unknownType, instantiateType(getConstraintFromTypeParameter(target) || unknownType, mapper))) return false; + if ( + !isTypeIdenticalTo( + getConstraintFromTypeParameter(source) || unknownType, + instantiateType(getConstraintFromTypeParameter(target) || unknownType, mapper), + ) + ) return false; // We don't compare defaults - we just use the type parameter defaults from the first signature that seems to match. // It might make sense to combine these defaults in the future, but doing so intelligently requires knowing // if the parameter is used covariantly or contravariantly (so we intersect if it's used like a parameter or union if used like a return type) @@ -11720,14 +15446,21 @@ namespace ts { return true; } - function combineUnionThisParam(left: Symbol | undefined, right: Symbol | undefined, mapper: TypeMapper | undefined): Symbol | undefined { + function combineUnionThisParam( + left: Symbol | undefined, + right: Symbol | undefined, + mapper: TypeMapper | undefined, + ): Symbol | undefined { if (!left || !right) { return left || right; } // A signature `this` type might be a read or a write position... It's very possible that it should be invariant // and we should refuse to merge signatures if there are `this` types and they do not match. However, so as to be // permissive when calling, for now, we'll intersect the `this` types just like we do for param types in union signatures. - const thisType = getIntersectionType([getTypeOfSymbol(left), instantiateType(getTypeOfSymbol(right), mapper)]); + const thisType = getIntersectionType([ + getTypeOfSymbol(left), + instantiateType(getTypeOfSymbol(right), mapper), + ]); return createSymbolWithType(left, thisType); } @@ -11755,10 +15488,10 @@ namespace ts { const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); - const paramName = leftName === rightName ? leftName : - !leftName ? rightName : - !rightName ? leftName : - undefined; + const paramName = leftName === rightName ? leftName + : !leftName ? rightName + : !rightName ? leftName + : undefined; const paramSymbol = createSymbol( SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), paramName || `arg${i}` as __String, @@ -11799,9 +15532,13 @@ namespace ts { (left.flags | right.flags) & SignatureFlags.PropagatingFlags, ); result.compositeKind = TypeFlags.Union; - result.compositeSignatures = concatenate(left.compositeKind !== TypeFlags.Intersection && left.compositeSignatures || [left], [right]); + result.compositeSignatures = concatenate( + left.compositeKind !== TypeFlags.Intersection && left.compositeSignatures || [left], + [right], + ); if (paramMapper) { - result.mapper = left.compositeKind !== TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; + result.mapper = left.compositeKind !== TypeFlags.Intersection && left.mapper && left.compositeSignatures + ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; } return result; } @@ -11813,7 +15550,13 @@ namespace ts { for (const info of sourceInfos) { const indexType = info.keyType; if (every(types, t => !!getIndexInfoOfType(t, indexType))) { - result.push(createIndexInfo(indexType, getUnionType(map(types, t => getIndexTypeOfType(t, indexType)!)), some(types, t => getIndexInfoOfType(t, indexType)!.isReadonly))); + result.push( + createIndexInfo( + indexType, + getUnionType(map(types, t => getIndexTypeOfType(t, indexType)!)), + some(types, t => getIndexInfoOfType(t, indexType)!.isReadonly), + ), + ); } } return result; @@ -11824,8 +15567,15 @@ namespace ts { function resolveUnionTypeMembers(type: UnionType) { // The members and properties collections are empty for union types. To get all properties of a union // type use getPropertiesOfType (only the language service uses this). - const callSignatures = getUnionSignatures(map(type.types, t => t === globalFunctionType ? [unknownSignature] : getSignaturesOfType(t, SignatureKind.Call))); - const constructSignatures = getUnionSignatures(map(type.types, t => getSignaturesOfType(t, SignatureKind.Construct))); + const callSignatures = getUnionSignatures( + map( + type.types, + t => t === globalFunctionType ? [unknownSignature] : getSignaturesOfType(t, SignatureKind.Call), + ), + ); + const constructSignatures = getUnionSignatures( + map(type.types, t => getSignaturesOfType(t, SignatureKind.Construct)), + ); const indexInfos = getUnionIndexInfos(type.types); setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, indexInfos); } @@ -11837,7 +15587,10 @@ namespace ts { } function findMixins(types: readonly Type[]): readonly boolean[] { - const constructorTypeCount = countWhere(types, t => getSignaturesOfType(t, SignatureKind.Construct).length > 0); + const constructorTypeCount = countWhere( + types, + t => getSignaturesOfType(t, SignatureKind.Construct).length > 0, + ); const mixinFlags = map(types, isMixinConstructorType); if (constructorTypeCount > 0 && constructorTypeCount === countWhere(mixinFlags, b => b)) { const firstMixinIndex = mixinFlags.indexOf(/*searchElement*/ true); @@ -11846,14 +15599,21 @@ namespace ts { return mixinFlags; } - function includeMixinType(type: Type, types: readonly Type[], mixinFlags: readonly boolean[], index: number): Type { + function includeMixinType( + type: Type, + types: readonly Type[], + mixinFlags: readonly boolean[], + index: number, + ): Type { const mixedTypes: Type[] = []; for (let i = 0; i < types.length; i++) { if (i === index) { mixedTypes.push(type); } else if (mixinFlags[i]) { - mixedTypes.push(getReturnTypeOfSignature(getSignaturesOfType(types[i], SignatureKind.Construct)[0])); + mixedTypes.push( + getReturnTypeOfSignature(getSignaturesOfType(types[i], SignatureKind.Construct)[0]), + ); } } return getIntersectionType(mixedTypes); @@ -11880,21 +15640,46 @@ namespace ts { if (signatures.length && mixinCount > 0) { signatures = map(signatures, s => { const clone = cloneSignature(s); - clone.resolvedReturnType = includeMixinType(getReturnTypeOfSignature(s), types, mixinFlags, i); + clone.resolvedReturnType = includeMixinType( + getReturnTypeOfSignature(s), + types, + mixinFlags, + i, + ); return clone; }); } constructSignatures = appendSignatures(constructSignatures, signatures); } callSignatures = appendSignatures(callSignatures, getSignaturesOfType(t, SignatureKind.Call)); - indexInfos = reduceLeft(getIndexInfosOfType(t), (infos, newInfo) => appendIndexInfo(infos, newInfo, /*union*/ false), indexInfos); + indexInfos = reduceLeft( + getIndexInfosOfType(t), + (infos, newInfo) => appendIndexInfo(infos, newInfo, /*union*/ false), + indexInfos, + ); } - setStructuredTypeMembers(type, emptySymbols, callSignatures || emptyArray, constructSignatures || emptyArray, indexInfos || emptyArray); + setStructuredTypeMembers( + type, + emptySymbols, + callSignatures || emptyArray, + constructSignatures || emptyArray, + indexInfos || emptyArray, + ); } function appendSignatures(signatures: Signature[] | undefined, newSignatures: readonly Signature[]) { for (const sig of newSignatures) { - if (!signatures || every(signatures, s => !compareSignaturesIdentical(s, sig, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, compareTypesIdentical))) { + if ( + !signatures || every(signatures, s => + !compareSignaturesIdentical( + s, + sig, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ false, + compareTypesIdentical, + )) + ) { signatures = append(signatures, sig); } } @@ -11906,7 +15691,12 @@ namespace ts { for (let i = 0; i < indexInfos.length; i++) { const info = indexInfos[i]; if (info.keyType === newInfo.keyType) { - indexInfos[i] = createIndexInfo(info.keyType, union ? getUnionType([info.type, newInfo.type]) : getIntersectionType([info.type, newInfo.type]), union ? info.isReadonly || newInfo.isReadonly : info.isReadonly && newInfo.isReadonly); + indexInfos[i] = createIndexInfo( + info.keyType, + union ? getUnionType([info.type, newInfo.type]) + : getIntersectionType([info.type, newInfo.type]), + union ? info.isReadonly || newInfo.isReadonly : info.isReadonly && newInfo.isReadonly, + ); return indexInfos; } } @@ -11920,9 +15710,19 @@ namespace ts { function resolveAnonymousTypeMembers(type: AnonymousType) { if (type.target) { setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, emptyArray); - const members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper!, /*mappingThisOnly*/ false); - const callSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper!); - const constructSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper!); + const members = createInstantiatedSymbolTable( + getPropertiesOfObjectType(type.target), + type.mapper!, + /*mappingThisOnly*/ false, + ); + const callSignatures = instantiateSignatures( + getSignaturesOfType(type.target, SignatureKind.Call), + type.mapper!, + ); + const constructSignatures = instantiateSignatures( + getSignaturesOfType(type.target, SignatureKind.Construct), + type.mapper!, + ); const indexInfos = instantiateIndexInfos(getIndexInfosOfType(type.target), type.mapper!); setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); return; @@ -11945,7 +15745,11 @@ namespace ts { if (symbol === globalThisSymbol) { const varsOnly = new Map() as SymbolTable; members.forEach(p => { - if (!(p.flags & SymbolFlags.BlockScoped) && !(p.flags & SymbolFlags.ValueModule && p.declarations?.length && every(p.declarations, isAmbientModule))) { + if ( + !(p.flags & SymbolFlags.BlockScoped) + && !(p.flags & SymbolFlags.ValueModule && p.declarations?.length + && every(p.declarations, isAmbientModule)) + ) { varsOnly.set(p.escapedName, p); } }); @@ -11975,8 +15779,8 @@ namespace ts { indexInfos = append(indexInfos, baseConstructorIndexInfo); } if ( - symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum || - some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike))) + symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum + || some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike))) ) { indexInfos = append(indexInfos, enumNumberIndexInfo); } @@ -11992,16 +15796,26 @@ namespace ts { // And likewise for construct signatures for classes if (symbol.flags & SymbolFlags.Class) { const classType = getDeclaredTypeOfClassOrInterface(symbol); - let constructSignatures = symbol.members ? getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Constructor)) : emptyArray; + let constructSignatures = symbol.members + ? getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Constructor)) : emptyArray; if (symbol.flags & SymbolFlags.Function) { constructSignatures = addRange( constructSignatures.slice(), mapDefined( type.callSignatures, sig => - isJSConstructor(sig.declaration) ? - createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, classType, /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags) : - undefined, + isJSConstructor(sig.declaration) + ? createSignature( + sig.declaration, + sig.typeParameters, + sig.thisParameter, + sig.parameters, + classType, + /*resolvedTypePredicate*/ undefined, + sig.minArgumentCount, + sig.flags & SignatureFlags.PropagatingFlags, + ) + : undefined, ), ); } @@ -12012,12 +15826,21 @@ namespace ts { } } - type ReplaceableIndexedAccessType = IndexedAccessType & { objectType: TypeParameter; indexType: TypeParameter; }; + type ReplaceableIndexedAccessType = IndexedAccessType & { + objectType: TypeParameter; + indexType: TypeParameter; + }; function replaceIndexedAccess(instantiable: Type, type: ReplaceableIndexedAccessType, replacement: Type) { // map type.indexType to 0 // map type.objectType to `[TReplacement]` // thus making the indexed access `[TReplacement][0]` or `TReplacement` - return instantiateType(instantiable, createTypeMapper([type.indexType, type.objectType], [getNumberLiteralType(0), createTupleType([replacement])])); + return instantiateType( + instantiable, + createTypeMapper([type.indexType, type.objectType], [ + getNumberLiteralType(0), + createTupleType([replacement]), + ]), + ); } function resolveReverseMappedTypeMembers(type: ReverseMappedType) { @@ -12025,11 +15848,21 @@ namespace ts { const modifiers = getMappedTypeModifiers(type.mappedType); const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true; const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional; - const indexInfos = indexInfo ? [createIndexInfo(stringType, inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType), readonlyMask && indexInfo.isReadonly)] : emptyArray; + const indexInfos = indexInfo + ? [createIndexInfo( + stringType, + inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType), + readonlyMask && indexInfo.isReadonly, + )] : emptyArray; const members = createSymbolTable(); for (const prop of getPropertiesOfType(type.source)) { - const checkFlags = CheckFlags.ReverseMapped | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0); - const inferredProp = createSymbol(SymbolFlags.Property | prop.flags & optionalMask, prop.escapedName, checkFlags) as ReverseMappedSymbol; + const checkFlags = CheckFlags.ReverseMapped + | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0); + const inferredProp = createSymbol( + SymbolFlags.Property | prop.flags & optionalMask, + prop.escapedName, + checkFlags, + ) as ReverseMappedSymbol; inferredProp.declarations = prop.declarations; inferredProp.nameType = getSymbolLinks(prop).nameType; inferredProp.propertyType = getTypeOfSymbol(prop); @@ -12042,7 +15875,11 @@ namespace ts { // inferring to the "type parameter" (or indexed access) shared by the constraint and template. So, to reduce the number of // type identities produced, we simplify such indexed access occurences const newTypeParam = (type.constraintType.type as IndexedAccessType).objectType; - const newMappedType = replaceIndexedAccess(type.mappedType, type.constraintType.type as ReplaceableIndexedAccessType, newTypeParam); + const newMappedType = replaceIndexedAccess( + type.mappedType, + type.constraintType.type as ReplaceableIndexedAccessType, + newTypeParam, + ); inferredProp.mappedType = newMappedType as MappedType; inferredProp.constraintType = getIndexType(newTypeParam) as IndexType; } @@ -12068,7 +15905,14 @@ namespace ts { const checkType = (type as ConditionalType).checkType; const constraint = getLowerBoundOfKeyType(checkType); if (constraint !== checkType) { - return getConditionalTypeInstantiation(type as ConditionalType, prependTypeMapping((type as ConditionalType).root.checkType, constraint, (type as ConditionalType).mapper)); + return getConditionalTypeInstantiation( + type as ConditionalType, + prependTypeMapping( + (type as ConditionalType).root.checkType, + constraint, + (type as ConditionalType).mapper, + ), + ); } } return type; @@ -12080,7 +15924,10 @@ namespace ts { // Similarly to getTypeFromIntersectionTypeNode, we preserve the special string & {}, number & {}, // and bigint & {} intersections that are used to prevent subtype reduction in union types. const types = (type as IntersectionType).types; - if (types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) && types[1] === emptyTypeLiteralType) { + if ( + types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) + && types[1] === emptyTypeLiteralType + ) { return type; } return getIntersectionType(sameMap((type as UnionType).types, getLowerBoundOfKeyType)); @@ -12092,7 +15939,12 @@ namespace ts { return getCheckFlags(s) & CheckFlags.Late; } - function forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(type: Type, include: TypeFlags, stringsOnly: boolean, cb: (keyType: Type) => void) { + function forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( + type: Type, + include: TypeFlags, + stringsOnly: boolean, + cb: (keyType: Type) => void, + ) { for (const prop of getPropertiesOfType(type)) { cb(getLiteralTypeFromProperty(prop, include)); } @@ -12125,7 +15977,12 @@ namespace ts { const include = keyofStringsOnly ? TypeFlags.StringLiteral : TypeFlags.StringOrNumberLiteralOrUnique; if (isMappedTypeWithKeyofConstraintDeclaration(type)) { // We have a { [P in keyof T]: X } - forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(modifiersType, include, keyofStringsOnly, addMemberForKeyType); + forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( + modifiersType, + include, + keyofStringsOnly, + addMemberForKeyType, + ); } else { forEachType(getLowerBoundOfKeyType(constraintType), addMemberForKeyType); @@ -12133,7 +15990,8 @@ namespace ts { setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos || emptyArray); function addMemberForKeyType(keyType: Type) { - const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; + const propNameType = nameType + ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; forEachType(propNameType, t => addMemberForKeyTypeWorker(keyType, t)); } @@ -12151,14 +16009,23 @@ namespace ts { existingProp.keyType = getUnionType([existingProp.keyType, keyType]); } else { - const modifiersProp = isTypeUsableAsPropertyName(keyType) ? getPropertyOfType(modifiersType, getPropertyNameFromType(keyType)) : undefined; - const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional || - !(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional); - const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly || - !(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp)); - const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional; + const modifiersProp = isTypeUsableAsPropertyName(keyType) + ? getPropertyOfType(modifiersType, getPropertyNameFromType(keyType)) : undefined; + const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional + || !(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp + && modifiersProp.flags & SymbolFlags.Optional); + const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly + || !(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp + && isReadonlySymbol(modifiersProp)); + const stripOptional = strictNullChecks && !isOptional && modifiersProp + && modifiersProp.flags & SymbolFlags.Optional; const lateFlag: CheckFlags = modifiersProp ? getIsLateCheckFlag(modifiersProp) : 0; - const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, lateFlag | CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0)) as MappedSymbol; + const prop = createSymbol( + SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), + propName, + lateFlag | CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) + | (stripOptional ? CheckFlags.StripOptional : 0), + ) as MappedSymbol; prop.mappedType = type; prop.nameType = propNameType; prop.keyType = keyType; @@ -12172,11 +16039,18 @@ namespace ts { } } else if (isValidIndexKeyType(propNameType) || propNameType.flags & (TypeFlags.Any | TypeFlags.Enum)) { - const indexKeyType = propNameType.flags & (TypeFlags.Any | TypeFlags.String) ? stringType : - propNameType.flags & (TypeFlags.Number | TypeFlags.Enum) ? numberType : - propNameType; - const propType = instantiateType(templateType, appendTypeMapping(type.mapper, typeParameter, keyType)); - const indexInfo = createIndexInfo(indexKeyType, propType, !!(templateModifiers & MappedTypeModifiers.IncludeReadonly)); + const indexKeyType = propNameType.flags & (TypeFlags.Any | TypeFlags.String) ? stringType + : propNameType.flags & (TypeFlags.Number | TypeFlags.Enum) ? numberType + : propNameType; + const propType = instantiateType( + templateType, + appendTypeMapping(type.mapper, typeParameter, keyType), + ); + const indexInfo = createIndexInfo( + indexKeyType, + propType, + !!(templateModifiers & MappedTypeModifiers.IncludeReadonly), + ); indexInfos = appendIndexInfo(indexInfos, indexInfo, /*union*/ true); } } @@ -12190,16 +16064,27 @@ namespace ts { return errorType; } const templateType = getTemplateTypeFromMappedType(mappedType.target as MappedType || mappedType); - const mapper = appendTypeMapping(mappedType.mapper, getTypeParameterFromMappedType(mappedType), symbol.keyType); + const mapper = appendTypeMapping( + mappedType.mapper, + getTypeParameterFromMappedType(mappedType), + symbol.keyType, + ); const propType = instantiateType(templateType, mapper); // When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the // type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks // mode, if the underlying property is optional we remove 'undefined' from the type. - let type = strictNullChecks && symbol.flags & SymbolFlags.Optional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType, /*isProperty*/ true) : - symbol.checkFlags & CheckFlags.StripOptional ? removeMissingOrUndefinedType(propType) : - propType; + let type = strictNullChecks && symbol.flags & SymbolFlags.Optional + && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) + ? getOptionalType(propType, /*isProperty*/ true) + : symbol.checkFlags & CheckFlags.StripOptional ? removeMissingOrUndefinedType(propType) + : propType; if (!popTypeResolution()) { - error(currentNode, Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, symbolToString(symbol), typeToString(mappedType)); + error( + currentNode, + Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, + symbolToString(symbol), + typeToString(mappedType), + ); type = errorType; } symbol.type = type; @@ -12208,26 +16093,37 @@ namespace ts { } function getTypeParameterFromMappedType(type: MappedType) { - return type.typeParameter || - (type.typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(type.declaration.typeParameter))); + return type.typeParameter + || (type.typeParameter = getDeclaredTypeOfTypeParameter( + getSymbolOfNode(type.declaration.typeParameter), + )); } function getConstraintTypeFromMappedType(type: MappedType) { - return type.constraintType || - (type.constraintType = getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)) || errorType); + return type.constraintType + || (type.constraintType = getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)) + || errorType); } function getNameTypeFromMappedType(type: MappedType) { - return type.declaration.nameType ? - type.nameType || (type.nameType = instantiateType(getTypeFromTypeNode(type.declaration.nameType), type.mapper)) : - undefined; + return type.declaration.nameType + ? type.nameType + || (type.nameType = instantiateType(getTypeFromTypeNode(type.declaration.nameType), type.mapper)) + : undefined; } function getTemplateTypeFromMappedType(type: MappedType) { - return type.templateType || - (type.templateType = type.declaration.type ? - instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), /*isProperty*/ true, !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), type.mapper) : - errorType); + return type.templateType + || (type.templateType = type.declaration.type + ? instantiateType( + addOptionality( + getTypeFromTypeNode(type.declaration.type), + /*isProperty*/ true, + !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional), + ), + type.mapper, + ) + : errorType); } function getConstraintDeclarationForMappedType(type: MappedType) { @@ -12236,8 +16132,8 @@ namespace ts { function isMappedTypeWithKeyofConstraintDeclaration(type: MappedType) { const constraintDeclaration = getConstraintDeclarationForMappedType(type)!; // TODO: GH#18217 - return constraintDeclaration.kind === SyntaxKind.TypeOperator && - (constraintDeclaration as TypeOperatorNode).operator === SyntaxKind.KeyOfKeyword; + return constraintDeclaration.kind === SyntaxKind.TypeOperator + && (constraintDeclaration as TypeOperatorNode).operator === SyntaxKind.KeyOfKeyword; } function getModifiersTypeFromMappedType(type: MappedType) { @@ -12246,7 +16142,10 @@ namespace ts { // If the constraint declaration is a 'keyof T' node, the modifiers type is T. We check // AST nodes here because, when T is a non-generic type, the logic below eagerly resolves // 'keyof T' to a literal union type and we can't recover T from that type. - type.modifiersType = instantiateType(getTypeFromTypeNode((getConstraintDeclarationForMappedType(type) as TypeOperatorNode).type), type.mapper); + type.modifiersType = instantiateType( + getTypeFromTypeNode((getConstraintDeclarationForMappedType(type) as TypeOperatorNode).type), + type.mapper, + ); } else { // Otherwise, get the declared constraint type, and if the constraint type is a type parameter, @@ -12254,8 +16153,10 @@ namespace ts { // the modifiers type is T. Otherwise, the modifiers type is unknown. const declaredType = getTypeFromMappedTypeNode(type.declaration) as MappedType; const constraint = getConstraintTypeFromMappedType(declaredType); - const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint as TypeParameter) : constraint; - type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint as IndexType).type, type.mapper) : unknownType; + const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter + ? getConstraintOfTypeParameter(constraint as TypeParameter) : constraint; + type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index + ? instantiateType((extendedConstraint as IndexType).type, type.mapper) : unknownType; } } return type.modifiersType; @@ -12263,13 +16164,18 @@ namespace ts { function getMappedTypeModifiers(type: MappedType): MappedTypeModifiers { const declaration = type.declaration; - return (declaration.readonlyToken ? declaration.readonlyToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeReadonly : MappedTypeModifiers.IncludeReadonly : 0) | - (declaration.questionToken ? declaration.questionToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeOptional : MappedTypeModifiers.IncludeOptional : 0); + return (declaration.readonlyToken + ? declaration.readonlyToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeReadonly + : MappedTypeModifiers.IncludeReadonly : 0) + | (declaration.questionToken + ? declaration.questionToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeOptional + : MappedTypeModifiers.IncludeOptional : 0); } function getMappedTypeOptionality(type: MappedType): number { const modifiers = getMappedTypeModifiers(type); - return modifiers & MappedTypeModifiers.ExcludeOptional ? -1 : modifiers & MappedTypeModifiers.IncludeOptional ? 1 : 0; + return modifiers & MappedTypeModifiers.ExcludeOptional ? -1 + : modifiers & MappedTypeModifiers.IncludeOptional ? 1 : 0; } function getCombinedMappedTypeOptionality(type: MappedType): number { @@ -12279,7 +16185,8 @@ namespace ts { } function isPartialMappedType(type: Type) { - return !!(getObjectFlags(type) & ObjectFlags.Mapped && getMappedTypeModifiers(type as MappedType) & MappedTypeModifiers.IncludeOptional); + return !!(getObjectFlags(type) & ObjectFlags.Mapped + && getMappedTypeModifiers(type as MappedType) & MappedTypeModifiers.IncludeOptional); } function isGenericMappedType(type: Type): type is MappedType { @@ -12292,7 +16199,15 @@ namespace ts { // To determine this, we substitute the constraint type (that we now know isn't generic) for the iteration // type and check whether the resulting type is generic. const nameType = getNameTypeFromMappedType(type as MappedType); - if (nameType && isGenericIndexType(instantiateType(nameType, makeUnaryTypeMapper(getTypeParameterFromMappedType(type as MappedType), constraint)))) { + if ( + nameType + && isGenericIndexType( + instantiateType( + nameType, + makeUnaryTypeMapper(getTypeParameterFromMappedType(type as MappedType), constraint), + ), + ) + ) { return true; } } @@ -12380,9 +16295,9 @@ namespace ts { function getPropertiesOfType(type: Type): Symbol[] { type = getReducedApparentType(type); - return type.flags & TypeFlags.UnionOrIntersection ? - getPropertiesOfUnionOrIntersectionType(type as UnionType) : - getPropertiesOfObjectType(type); + return type.flags & TypeFlags.UnionOrIntersection + ? getPropertiesOfUnionOrIntersectionType(type as UnionType) + : getPropertiesOfObjectType(type); } function forEachPropertyOfType(type: Type, action: (symbol: Symbol, escapedName: __String) => void): void { @@ -12396,11 +16311,15 @@ namespace ts { } } - function isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression | JsxAttributes): boolean { + function isTypeInvalidDueToUnionDiscriminant( + contextualType: Type, + obj: ObjectLiteralExpression | JsxAttributes, + ): boolean { const list = obj.properties as NodeArray; return list.some(property => { const nameType = property.name && getLiteralTypeFromPropertyName(property.name); - const name = nameType && isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) : undefined; + const name = nameType && isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) + : undefined; const expected = name === undefined ? undefined : getTypeOfPropertyOfType(contextualType, name); return !!expected && isLiteralType(expected) && !isTypeAssignableTo(getTypeOfNode(property), expected); }); @@ -12426,14 +16345,15 @@ namespace ts { } function getConstraintOfType(type: InstantiableType | UnionOrIntersectionType): Type | undefined { - return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type as TypeParameter) : - type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type as IndexedAccessType) : - type.flags & TypeFlags.Conditional ? getConstraintOfConditionalType(type as ConditionalType) : - getBaseConstraintOfType(type); + return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type as TypeParameter) + : type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type as IndexedAccessType) + : type.flags & TypeFlags.Conditional ? getConstraintOfConditionalType(type as ConditionalType) + : getBaseConstraintOfType(type); } function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type | undefined { - return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined; + return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) + : undefined; } function getConstraintOfIndexedAccess(type: IndexedAccessType) { @@ -12453,7 +16373,11 @@ namespace ts { } const indexConstraint = getSimplifiedTypeOrConstraint(type.indexType); if (indexConstraint && indexConstraint !== type.indexType) { - const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint, type.accessFlags); + const indexedAccess = getIndexedAccessTypeOrUndefined( + type.objectType, + indexConstraint, + type.accessFlags, + ); if (indexedAccess) { return indexedAccess; } @@ -12473,7 +16397,8 @@ namespace ts { // in effect treating `any` like `never` rather than `unknown` in this location. const trueConstraint = getInferredTrueTypeFromConditionalType(type); const falseConstraint = getFalseTypeFromConditionalType(type); - type.resolvedDefaultConstraint = isTypeAny(trueConstraint) ? falseConstraint : isTypeAny(falseConstraint) ? trueConstraint : getUnionType([trueConstraint, falseConstraint]); + type.resolvedDefaultConstraint = isTypeAny(trueConstraint) ? falseConstraint + : isTypeAny(falseConstraint) ? trueConstraint : getUnionType([trueConstraint, falseConstraint]); } return type.resolvedDefaultConstraint; } @@ -12494,7 +16419,10 @@ namespace ts { const simplified = getSimplifiedType(type.checkType, /*writing*/ false); const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified; if (constraint && constraint !== type.checkType) { - const instantiated = getConditionalTypeInstantiation(type, prependTypeMapping(type.root.checkType, constraint, type.mapper)); + const instantiated = getConditionalTypeInstantiation( + type, + prependTypeMapping(type.root.checkType, constraint, type.mapper), + ); if (!(instantiated.flags & TypeFlags.Never)) { return instantiated; } @@ -12519,7 +16447,10 @@ namespace ts { // We keep following constraints as long as we have an instantiable type that is known // not to be circular or infinite (hence we stop on index access types). let constraint = getConstraintOfType(t); - while (constraint && constraint.flags & (TypeFlags.TypeParameter | TypeFlags.Index | TypeFlags.Conditional)) { + while ( + constraint + && constraint.flags & (TypeFlags.TypeParameter | TypeFlags.Index | TypeFlags.Conditional) + ) { constraint = getConstraintOfType(constraint); } if (constraint) { @@ -12552,9 +16483,14 @@ namespace ts { } function getBaseConstraintOfType(type: Type): Type | undefined { - if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) { + if ( + type.flags + & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral + | TypeFlags.StringMapping) + ) { const constraint = getResolvedBaseConstraint(type as InstantiableType | UnionOrIntersectionType); - return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined; + return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint + : undefined; } return type.flags & TypeFlags.Index ? keyofConstraintType : undefined; } @@ -12605,9 +16541,22 @@ namespace ts { if (t.flags & TypeFlags.TypeParameter) { const errorNode = getConstraintDeclaration(t as TypeParameter); if (errorNode) { - const diagnostic = error(errorNode, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(t)); - if (currentNode && !isNodeDescendantOf(errorNode, currentNode) && !isNodeDescendantOf(currentNode, errorNode)) { - addRelatedInfo(diagnostic, createDiagnosticForNode(currentNode, Diagnostics.Circularity_originates_in_type_at_this_location)); + const diagnostic = error( + errorNode, + Diagnostics.Type_parameter_0_has_a_circular_constraint, + typeToString(t), + ); + if ( + currentNode && !isNodeDescendantOf(errorNode, currentNode) + && !isNodeDescendantOf(currentNode, errorNode) + ) { + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + currentNode, + Diagnostics.Circularity_originates_in_type_at_this_location, + ), + ); } } } @@ -12626,9 +16575,9 @@ namespace ts { function computeBaseConstraint(t: Type): Type | undefined { if (t.flags & TypeFlags.TypeParameter) { const constraint = getConstraintFromTypeParameter(t as TypeParameter); - return (t as TypeParameter).isThisType || !constraint ? - constraint : - getBaseConstraint(constraint); + return (t as TypeParameter).isThisType || !constraint + ? constraint + : getBaseConstraint(constraint); } if (t.flags & TypeFlags.UnionOrIntersection) { const types = (t as UnionOrIntersectionType).types; @@ -12649,9 +16598,9 @@ namespace ts { if (!different) { return t; } - return t.flags & TypeFlags.Union && baseTypes.length === types.length ? getUnionType(baseTypes) : - t.flags & TypeFlags.Intersection && baseTypes.length ? getIntersectionType(baseTypes) : - undefined; + return t.flags & TypeFlags.Union && baseTypes.length === types.length ? getUnionType(baseTypes) + : t.flags & TypeFlags.Intersection && baseTypes.length ? getIntersectionType(baseTypes) + : undefined; } if (t.flags & TypeFlags.Index) { return keyofConstraintType; @@ -12659,21 +16608,33 @@ namespace ts { if (t.flags & TypeFlags.TemplateLiteral) { const types = (t as TemplateLiteralType).types; const constraints = mapDefined(types, getBaseConstraint); - return constraints.length === types.length ? getTemplateLiteralType((t as TemplateLiteralType).texts, constraints) : stringType; + return constraints.length === types.length + ? getTemplateLiteralType((t as TemplateLiteralType).texts, constraints) : stringType; } if (t.flags & TypeFlags.StringMapping) { const constraint = getBaseConstraint((t as StringMappingType).type); - return constraint && constraint !== (t as StringMappingType).type ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType; + return constraint && constraint !== (t as StringMappingType).type + ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType; } if (t.flags & TypeFlags.IndexedAccess) { if (isMappedTypeGenericIndexedAccess(t)) { // For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic, // we substitute an instantiation of E where P is replaced with X. - return getBaseConstraint(substituteIndexedMappedType((t as IndexedAccessType).objectType as MappedType, (t as IndexedAccessType).indexType)); + return getBaseConstraint( + substituteIndexedMappedType( + (t as IndexedAccessType).objectType as MappedType, + (t as IndexedAccessType).indexType, + ), + ); } const baseObjectType = getBaseConstraint((t as IndexedAccessType).objectType); const baseIndexType = getBaseConstraint((t as IndexedAccessType).indexType); - const baseIndexedAccess = baseObjectType && baseIndexType && getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, (t as IndexedAccessType).accessFlags); + const baseIndexedAccess = baseObjectType && baseIndexType + && getIndexedAccessTypeOrUndefined( + baseObjectType, + baseIndexType, + (t as IndexedAccessType).accessFlags, + ); return baseIndexedAccess && getBaseConstraint(baseIndexedAccess); } if (t.flags & TypeFlags.Conditional) { @@ -12688,19 +16649,25 @@ namespace ts { } function getApparentTypeOfIntersectionType(type: IntersectionType) { - return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type, /*apparentType*/ true)); + return type.resolvedApparentType + || (type.resolvedApparentType = getTypeWithThisArgument(type, type, /*apparentType*/ true)); } function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined { if (!typeParameter.default) { if (typeParameter.target) { const targetDefault = getResolvedTypeParameterDefault(typeParameter.target); - typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintType; + typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) + : noConstraintType; } else { // To block recursion, set the initial value to the resolvingDefaultType. typeParameter.default = resolvingDefaultType; - const defaultDeclaration = typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default); + const defaultDeclaration = typeParameter.symbol + && forEach( + typeParameter.symbol.declarations, + decl => isTypeParameterDeclaration(decl) && decl.default, + ); const defaultType = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintType; if (typeParameter.default === resolvingDefaultType) { // If we have not been called recursively, set the correct default type. @@ -12735,7 +16702,11 @@ namespace ts { * Indicates whether the declaration of a typeParameter has a default type. */ function hasTypeParameterDefault(typeParameter: TypeParameter): boolean { - return !!(typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default)); + return !!(typeParameter.symbol + && forEach( + typeParameter.symbol.declarations, + decl => isTypeParameterDeclaration(decl) && decl.default, + )); } function getApparentTypeOfMappedType(type: MappedType) { @@ -12755,9 +16726,11 @@ namespace ts { function isMappedTypeGenericIndexedAccess(type: Type) { let objectType; - return !!(type.flags & TypeFlags.IndexedAccess && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped && - !isGenericMappedType(objectType) && isGenericIndexType((type as IndexedAccessType).indexType) && - !(getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.ExcludeOptional) && !(objectType as MappedType).declaration.nameType); + return !!(type.flags & TypeFlags.IndexedAccess + && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped + && !isGenericMappedType(objectType) && isGenericIndexType((type as IndexedAccessType).indexType) + && !(getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.ExcludeOptional) + && !(objectType as MappedType).declaration.nameType); } /** @@ -12767,17 +16740,17 @@ namespace ts { */ function getApparentType(type: Type): Type { const t = !(type.flags & TypeFlags.Instantiable) ? type : getBaseConstraintOfType(type) || unknownType; - return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) : - t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType) : - t.flags & TypeFlags.StringLike ? globalStringType : - t.flags & TypeFlags.NumberLike ? globalNumberType : - t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType() : - t.flags & TypeFlags.BooleanLike ? globalBooleanType : - t.flags & TypeFlags.ESSymbolLike ? getGlobalESSymbolType() : - t.flags & TypeFlags.NonPrimitive ? emptyObjectType : - t.flags & TypeFlags.Index ? keyofConstraintType : - t.flags & TypeFlags.Unknown && !strictNullChecks ? emptyObjectType : - t; + return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) + : t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType) + : t.flags & TypeFlags.StringLike ? globalStringType + : t.flags & TypeFlags.NumberLike ? globalNumberType + : t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType() + : t.flags & TypeFlags.BooleanLike ? globalBooleanType + : t.flags & TypeFlags.ESSymbolLike ? getGlobalESSymbolType() + : t.flags & TypeFlags.NonPrimitive ? emptyObjectType + : t.flags & TypeFlags.Index ? keyofConstraintType + : t.flags & TypeFlags.Unknown && !strictNullChecks ? emptyObjectType + : t; } function getReducedApparentType(type: Type): Type { @@ -12788,7 +16761,11 @@ namespace ts { return getReducedType(getApparentType(getReducedType(type))); } - function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { + function createUnionOrIntersectionProperty( + containingType: UnionOrIntersectionType, + name: __String, + skipObjectFunctionPropertyAugment?: boolean, + ): Symbol | undefined { let singleProp: Symbol | undefined; let propSet: ESMap | undefined; let indexTypes: Type[] | undefined; @@ -12817,15 +16794,21 @@ namespace ts { singleProp = prop; } else if (prop !== singleProp) { - const isInstantiation = (getTargetSymbol(prop) || prop) === (getTargetSymbol(singleProp) || singleProp); + const isInstantiation = + (getTargetSymbol(prop) || prop) === (getTargetSymbol(singleProp) || singleProp); // If the symbols are instances of one another with identical types - consider the symbols // equivalent and just use the first one, which thus allows us to avoid eliding private // members when intersecting a (this-)instantiations of a class with its raw base or another instance - if (isInstantiation && compareProperties(singleProp, prop, (a, b) => a === b ? Ternary.True : Ternary.False) === Ternary.True) { + if ( + isInstantiation + && compareProperties(singleProp, prop, (a, b) => a === b ? Ternary.True : Ternary.False) + === Ternary.True + ) { // If we merged instantiations of a generic type, we replicate the symbol parent resetting behavior we used // to do when we recorded multiple distinct symbols so that we still get, eg, `Array.length` printed // back and not `Array.length` when we're looking at a `.length` access on a `string[] | number[]` - mergedInstantiations = !!singleProp.parent && !!length(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(singleProp.parent)); + mergedInstantiations = !!singleProp.parent + && !!length(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(singleProp.parent)); } else { if (!propSet) { @@ -12844,10 +16827,12 @@ namespace ts { else if (!isUnion && !isReadonlySymbol(prop)) { checkFlags &= ~CheckFlags.Readonly; } - checkFlags |= (!(modifiers & ModifierFlags.NonPublicAccessibilityModifier) ? CheckFlags.ContainsPublic : 0) | - (modifiers & ModifierFlags.Protected ? CheckFlags.ContainsProtected : 0) | - (modifiers & ModifierFlags.Private ? CheckFlags.ContainsPrivate : 0) | - (modifiers & ModifierFlags.Static ? CheckFlags.ContainsStatic : 0); + checkFlags |= + (!(modifiers & ModifierFlags.NonPublicAccessibilityModifier) ? CheckFlags.ContainsPublic + : 0) + | (modifiers & ModifierFlags.Protected ? CheckFlags.ContainsProtected : 0) + | (modifiers & ModifierFlags.Private ? CheckFlags.ContainsPrivate : 0) + | (modifiers & ModifierFlags.Static ? CheckFlags.ContainsStatic : 0); if (!isPrototypeProperty(prop)) { syntheticFlag = CheckFlags.SyntheticProperty; } @@ -12856,7 +16841,10 @@ namespace ts { const indexInfo = !isLateBoundName(name) && getApplicableIndexInfoForName(type, name); if (indexInfo) { checkFlags |= CheckFlags.WritePartial | (indexInfo.isReadonly ? CheckFlags.Readonly : 0); - indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type); + indexTypes = append( + indexTypes, + isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type, + ); } else if (isObjectLiteralType(type) && !(getObjectFlags(type) & ObjectFlags.ContainsSpread)) { checkFlags |= CheckFlags.WritePartial; @@ -12869,11 +16857,11 @@ namespace ts { } } if ( - !singleProp || - isUnion && - (propSet || checkFlags & CheckFlags.Partial) && - checkFlags & (CheckFlags.ContainsPrivate | CheckFlags.ContainsProtected) && - !(propSet && getCommonDeclarationsOfSymbols(arrayFrom(propSet.values()))) + !singleProp + || isUnion + && (propSet || checkFlags & CheckFlags.Partial) + && checkFlags & (CheckFlags.ContainsPrivate | CheckFlags.ContainsProtected) + && !(propSet && getCommonDeclarationsOfSymbols(arrayFrom(propSet.values()))) ) { // No property was found, or, in a union, a property has a private or protected declaration in one // constituent, but is missing or has a different declaration in another constituent. @@ -12965,15 +16953,19 @@ namespace ts { // constituents, in which case the isPartial flag is set when the containing type is union type. We need // these partial properties when identifying discriminant properties, but otherwise they are filtered out // and do not appear to be present in the union type. - function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { - let property = type.propertyCacheWithoutObjectFunctionPropertyAugment?.get(name) || - !skipObjectFunctionPropertyAugment ? type.propertyCache?.get(name) : undefined; + function getUnionOrIntersectionProperty( + type: UnionOrIntersectionType, + name: __String, + skipObjectFunctionPropertyAugment?: boolean, + ): Symbol | undefined { + let property = type.propertyCacheWithoutObjectFunctionPropertyAugment?.get(name) + || !skipObjectFunctionPropertyAugment ? type.propertyCache?.get(name) : undefined; if (!property) { property = createUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment); if (property) { - const properties = skipObjectFunctionPropertyAugment ? - type.propertyCacheWithoutObjectFunctionPropertyAugment ||= createSymbolTable() : - type.propertyCache ||= createSymbolTable(); + const properties = skipObjectFunctionPropertyAugment + ? type.propertyCacheWithoutObjectFunctionPropertyAugment ||= createSymbolTable() + : type.propertyCache ||= createSymbolTable(); properties.set(name, property); } } @@ -13002,7 +16994,11 @@ namespace ts { return commonDeclarations; } - function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { + function getPropertyOfUnionOrIntersectionType( + type: UnionOrIntersectionType, + name: __String, + skipObjectFunctionPropertyAugment?: boolean, + ): Symbol | undefined { const property = getUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment); // We need to filter out partial properties in union types return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined; @@ -13016,12 +17012,16 @@ namespace ts { */ function getReducedType(type: Type): Type { if (type.flags & TypeFlags.Union && (type as UnionType).objectFlags & ObjectFlags.ContainsIntersections) { - return (type as UnionType).resolvedReducedType || ((type as UnionType).resolvedReducedType = getReducedUnionType(type as UnionType)); + return (type as UnionType).resolvedReducedType + || ((type as UnionType).resolvedReducedType = getReducedUnionType(type as UnionType)); } else if (type.flags & TypeFlags.Intersection) { if (!((type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersectionComputed)) { - (type as IntersectionType).objectFlags |= ObjectFlags.IsNeverIntersectionComputed | - (some(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isNeverReducedProperty) ? ObjectFlags.IsNeverIntersection : 0); + (type as IntersectionType).objectFlags |= ObjectFlags.IsNeverIntersectionComputed + | (some( + getPropertiesOfUnionOrIntersectionType(type as IntersectionType), + isNeverReducedProperty, + ) ? ObjectFlags.IsNeverIntersection : 0); } return (type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type; } @@ -13047,9 +17047,10 @@ namespace ts { function isDiscriminantWithNeverType(prop: Symbol) { // Return true for a synthetic non-optional property with non-uniform types, where at least one is // a literal type and none is never, that reduces to never. - return !(prop.flags & SymbolFlags.Optional) && - (getCheckFlags(prop) & (CheckFlags.Discriminant | CheckFlags.HasNeverType)) === CheckFlags.Discriminant && - !!(getTypeOfSymbol(prop).flags & TypeFlags.Never); + return !(prop.flags & SymbolFlags.Optional) + && (getCheckFlags(prop) & (CheckFlags.Discriminant | CheckFlags.HasNeverType)) + === CheckFlags.Discriminant + && !!(getTypeOfSymbol(prop).flags & TypeFlags.Never); } function isConflictingPrivateProperty(prop: Symbol) { @@ -13059,13 +17060,31 @@ namespace ts { function elaborateNeverIntersection(errorInfo: DiagnosticMessageChain | undefined, type: Type) { if (type.flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsNeverIntersection) { - const neverProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isDiscriminantWithNeverType); + const neverProp = find( + getPropertiesOfUnionOrIntersectionType(type as IntersectionType), + isDiscriminantWithNeverType, + ); if (neverProp) { - return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_has_conflicting_types_in_some_constituents, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(neverProp)); + return chainDiagnosticMessages( + errorInfo, + Diagnostics + .The_intersection_0_was_reduced_to_never_because_property_1_has_conflicting_types_in_some_constituents, + typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), + symbolToString(neverProp), + ); } - const privateProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isConflictingPrivateProperty); + const privateProp = find( + getPropertiesOfUnionOrIntersectionType(type as IntersectionType), + isConflictingPrivateProperty, + ); if (privateProp) { - return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_exists_in_multiple_constituents_and_is_private_in_some, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(privateProp)); + return chainDiagnosticMessages( + errorInfo, + Diagnostics + .The_intersection_0_was_reduced_to_never_because_property_1_exists_in_multiple_constituents_and_is_private_in_some, + typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), + symbolToString(privateProp), + ); } } return errorInfo; @@ -13079,7 +17098,12 @@ namespace ts { * @param type a type to look up property from * @param name a name of property to look up in a given type */ - function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean, includeTypeOnlyMembers?: boolean): Symbol | undefined { + function getPropertyOfType( + type: Type, + name: __String, + skipObjectFunctionPropertyAugment?: boolean, + includeTypeOnlyMembers?: boolean, + ): Symbol | undefined { type = getReducedApparentType(type); if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); @@ -13088,10 +17112,10 @@ namespace ts { return symbol; } if (skipObjectFunctionPropertyAugment) return undefined; - const functionType = resolved === anyFunctionType ? globalFunctionType : - resolved.callSignatures.length ? globalCallableFunctionType : - resolved.constructSignatures.length ? globalNewableFunctionType : - undefined; + const functionType = resolved === anyFunctionType ? globalFunctionType + : resolved.callSignatures.length ? globalCallableFunctionType + : resolved.constructSignatures.length ? globalNewableFunctionType + : undefined; if (functionType) { const symbol = getPropertyOfObjectType(functionType, name); if (symbol) { @@ -13101,7 +17125,11 @@ namespace ts { return getPropertyOfObjectType(globalObjectType, name); } if (type.flags & TypeFlags.UnionOrIntersection) { - return getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, skipObjectFunctionPropertyAugment); + return getPropertyOfUnionOrIntersectionType( + type as UnionOrIntersectionType, + name, + skipObjectFunctionPropertyAugment, + ); } return undefined; } @@ -13147,18 +17175,26 @@ namespace ts { // When more than one index signature is applicable we create a synthetic IndexInfo. Instead of computing // the intersected key type, we just use unknownType for the key type as nothing actually depends on the // keyType property of the returned IndexInfo. - return applicableInfos ? createIndexInfo(unknownType, getIntersectionType(map(applicableInfos, info => info.type)), reduceLeft(applicableInfos, (isReadonly, info) => isReadonly && info.isReadonly, /*initial*/ true)) : - applicableInfo ? applicableInfo : - stringIndexInfo && isApplicableIndexType(keyType, stringType) ? stringIndexInfo : - undefined; + return applicableInfos + ? createIndexInfo( + unknownType, + getIntersectionType(map(applicableInfos, info => info.type)), + reduceLeft(applicableInfos, (isReadonly, info) => isReadonly && info.isReadonly, /*initial*/ true), + ) + : applicableInfo ? applicableInfo + : stringIndexInfo && isApplicableIndexType(keyType, stringType) ? stringIndexInfo + : undefined; } function isApplicableIndexType(source: Type, target: Type): boolean { // A 'string' index signature applies to types assignable to 'string' or 'number', and a 'number' index // signature applies to types assignable to 'number', `${number}` and numeric string literal types. - return isTypeAssignableTo(source, target) || - target === stringType && isTypeAssignableTo(source, numberType) || - target === numberType && (source === numericStringType || !!(source.flags & TypeFlags.StringLiteral) && isNumericLiteralName((source as StringLiteralType).value)); + return isTypeAssignableTo(source, target) + || target === stringType && isTypeAssignableTo(source, numberType) + || target === numberType + && (source === numericStringType + || !!(source.flags & TypeFlags.StringLiteral) + && isNumericLiteralName((source as StringLiteralType).value)); } function getIndexInfosOfStructuredType(type: Type): readonly IndexInfo[] { @@ -13194,12 +17230,17 @@ namespace ts { } function getApplicableIndexInfoForName(type: Type, name: __String): IndexInfo | undefined { - return getApplicableIndexInfo(type, isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name))); + return getApplicableIndexInfo( + type, + isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name)), + ); } // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual // type checking functions). - function getTypeParametersFromDeclaration(declaration: DeclarationWithTypeParameters): readonly TypeParameter[] | undefined { + function getTypeParametersFromDeclaration( + declaration: DeclarationWithTypeParameters, + ): readonly TypeParameter[] | undefined { let result: TypeParameter[] | undefined; for (const node of getEffectiveTypeParameterDeclarations(declaration)) { result = appendIfUnique(result, getDeclaredTypeOfTypeParameter(node.symbol)); @@ -13223,7 +17264,9 @@ namespace ts { return isInJSFile(node) && ( // node.type should only be a JSDocOptionalType when node is a parameter of a JSDocFunctionType node.type && node.type.kind === SyntaxKind.JSDocOptionalType - || getJSDocParameterTags(node).some(({ isBracketed, typeExpression }) => isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType) + || getJSDocParameterTags(node).some(({ isBracketed, typeExpression }) => + isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType + ) ); } @@ -13248,13 +17291,17 @@ namespace ts { // Only consider syntactic or instantiated parameters as optional, not `void` parameters as this function is used // in grammar checks and checking for `void` too early results in parameter types widening too early // and causes some noImplicitAny errors to be lost. - return parameterIndex >= getMinArgumentCount(signature, MinArgumentCountFlags.StrongArityForUntypedJS | MinArgumentCountFlags.VoidIsNonOptional); + return parameterIndex + >= getMinArgumentCount( + signature, + MinArgumentCountFlags.StrongArityForUntypedJS | MinArgumentCountFlags.VoidIsNonOptional, + ); } const iife = getImmediatelyInvokedFunctionExpression(node.parent); if (iife) { - return !node.type && - !node.dotDotDotToken && - node.parent.parameters.indexOf(node) >= iife.arguments.length; + return !node.type + && !node.dotDotDotToken + && node.parent.parameters.indexOf(node) >= iife.arguments.length; } return false; @@ -13272,7 +17319,12 @@ namespace ts { return isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType; } - function createTypePredicate(kind: TypePredicateKind, parameterName: string | undefined, parameterIndex: number | undefined, type: Type | undefined): TypePredicate { + function createTypePredicate( + kind: TypePredicateKind, + parameterName: string | undefined, + parameterIndex: number | undefined, + type: Type | undefined, + ): TypePredicate { return { kind, parameterName, parameterIndex, type } as TypePredicate; } @@ -13300,15 +17352,33 @@ namespace ts { * @param typeParameters The requested type parameters. * @param minTypeArgumentCount The minimum number of required type arguments. */ - function fillMissingTypeArguments(typeArguments: readonly Type[], typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[]; - function fillMissingTypeArguments(typeArguments: readonly Type[] | undefined, typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[] | undefined; - function fillMissingTypeArguments(typeArguments: readonly Type[] | undefined, typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean) { + function fillMissingTypeArguments( + typeArguments: readonly Type[], + typeParameters: readonly TypeParameter[] | undefined, + minTypeArgumentCount: number, + isJavaScriptImplicitAny: boolean, + ): Type[]; + function fillMissingTypeArguments( + typeArguments: readonly Type[] | undefined, + typeParameters: readonly TypeParameter[] | undefined, + minTypeArgumentCount: number, + isJavaScriptImplicitAny: boolean, + ): Type[] | undefined; + function fillMissingTypeArguments( + typeArguments: readonly Type[] | undefined, + typeParameters: readonly TypeParameter[] | undefined, + minTypeArgumentCount: number, + isJavaScriptImplicitAny: boolean, + ) { const numTypeParameters = length(typeParameters); if (!numTypeParameters) { return []; } const numTypeArguments = length(typeArguments); - if (isJavaScriptImplicitAny || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters)) { + if ( + isJavaScriptImplicitAny + || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters) + ) { const result = typeArguments ? typeArguments.slice() : []; // Map invalid forward references in default types to the error type for (let i = numTypeArguments; i < numTypeParameters; i++) { @@ -13317,10 +17387,15 @@ namespace ts { const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny); for (let i = numTypeArguments; i < numTypeParameters; i++) { let defaultType = getDefaultFromTypeParameter(typeParameters![i]); - if (isJavaScriptImplicitAny && defaultType && (isTypeIdenticalTo(defaultType, unknownType) || isTypeIdenticalTo(defaultType, emptyObjectType))) { + if ( + isJavaScriptImplicitAny && defaultType + && (isTypeIdenticalTo(defaultType, unknownType) + || isTypeIdenticalTo(defaultType, emptyObjectType)) + ) { defaultType = anyType; } - result[i] = defaultType ? instantiateType(defaultType, createTypeMapper(typeParameters!, result)) : baseDefaultType; + result[i] = defaultType ? instantiateType(defaultType, createTypeMapper(typeParameters!, result)) + : baseDefaultType; } result.length = typeParameters!.length; return result; @@ -13338,11 +17413,11 @@ namespace ts { let hasThisParameter = false; const iife = getImmediatelyInvokedFunctionExpression(declaration); const isJSConstructSignature = isJSDocConstructSignature(declaration); - const isUntypedSignatureInJSFile = !iife && - isInJSFile(declaration) && - isValueSignatureDeclaration(declaration) && - !hasJSDocParameterTags(declaration) && - !getJSDocType(declaration); + const isUntypedSignatureInJSFile = !iife + && isInJSFile(declaration) + && isValueSignatureDeclaration(declaration) + && !hasJSDocParameterTags(declaration) + && !getJSDocType(declaration); if (isUntypedSignatureInJSFile) { flags |= SignatureFlags.IsUntypedSignatureInJSFile; } @@ -13354,10 +17429,18 @@ namespace ts { const param = declaration.parameters[i]; let paramSymbol = param.symbol; - const type = isJSDocParameterTag(param) ? (param.typeExpression && param.typeExpression.type) : param.type; + const type = isJSDocParameterTag(param) ? (param.typeExpression && param.typeExpression.type) + : param.type; // Include parameter symbol instead of property symbol in the signature if (paramSymbol && !!(paramSymbol.flags & SymbolFlags.Property) && !isBindingPattern(param.name)) { - const resolvedSymbol = resolveName(param, paramSymbol.escapedName, SymbolFlags.Value, undefined, undefined, /*isUse*/ false); + const resolvedSymbol = resolveName( + param, + paramSymbol.escapedName, + SymbolFlags.Value, + undefined, + undefined, + /*isUse*/ false, + ); paramSymbol = resolvedSymbol!; } if (i === 0 && paramSymbol.escapedName === InternalSymbolName.This) { @@ -13373,10 +17456,10 @@ namespace ts { } // Record a new minimum argument count if this is not an optional parameter - const isOptionalParameter = isOptionalJSDocPropertyLikeTag(param) || - param.initializer || param.questionToken || isRestParameter(param) || - iife && parameters.length > iife.arguments.length && !type || - isJSDocOptionalParameter(param); + const isOptionalParameter = isOptionalJSDocPropertyLikeTag(param) + || param.initializer || param.questionToken || isRestParameter(param) + || iife && parameters.length > iife.arguments.length && !type + || isJSDocOptionalParameter(param); if (!isOptionalParameter) { minArgumentCount = parameters.length; } @@ -13384,31 +17467,48 @@ namespace ts { // If only one accessor includes a this-type annotation, the other behaves as if it had the same type annotation if ( - (declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) && - hasBindableName(declaration) && - (!hasThisParameter || !thisParameter) + (declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) + && hasBindableName(declaration) + && (!hasThisParameter || !thisParameter) ) { - const otherKind = declaration.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; + const otherKind = declaration.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor + : SyntaxKind.GetAccessor; const other = getDeclarationOfKind(getSymbolOfNode(declaration), otherKind); if (other) { thisParameter = getAnnotatedAccessorThisParameter(other); } } - const classType = declaration.kind === SyntaxKind.Constructor ? - getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent as ClassDeclaration).symbol)) + const classType = declaration.kind === SyntaxKind.Constructor + ? getDeclaredTypeOfClassOrInterface( + getMergedSymbol((declaration.parent as ClassDeclaration).symbol), + ) : undefined; - const typeParameters = classType ? classType.localTypeParameters : getTypeParametersFromDeclaration(declaration); - if (hasRestParameter(declaration) || isInJSFile(declaration) && maybeAddJsSyntheticRestParameter(declaration, parameters)) { + const typeParameters = classType ? classType.localTypeParameters + : getTypeParametersFromDeclaration(declaration); + if ( + hasRestParameter(declaration) + || isInJSFile(declaration) && maybeAddJsSyntheticRestParameter(declaration, parameters) + ) { flags |= SignatureFlags.HasRestParameter; } if ( - isConstructorTypeNode(declaration) && hasSyntacticModifier(declaration, ModifierFlags.Abstract) || - isConstructorDeclaration(declaration) && hasSyntacticModifier(declaration.parent, ModifierFlags.Abstract) + isConstructorTypeNode(declaration) && hasSyntacticModifier(declaration, ModifierFlags.Abstract) + || isConstructorDeclaration(declaration) + && hasSyntacticModifier(declaration.parent, ModifierFlags.Abstract) ) { flags |= SignatureFlags.Abstract; } - links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, minArgumentCount, flags); + links.resolvedSignature = createSignature( + declaration, + typeParameters, + thisParameter, + parameters, + /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, + minArgumentCount, + flags, + ); } return links.resolvedSignature; } @@ -13419,15 +17519,26 @@ namespace ts { * OR * 2. It has at least one parameter, and the last parameter has a matching `@param` with a type that starts with `...` */ - function maybeAddJsSyntheticRestParameter(declaration: SignatureDeclaration | JSDocSignature, parameters: Symbol[]): boolean { + function maybeAddJsSyntheticRestParameter( + declaration: SignatureDeclaration | JSDocSignature, + parameters: Symbol[], + ): boolean { if (isJSDocSignature(declaration) || !containsArgumentsReference(declaration)) { return false; } const lastParam = lastOrUndefined(declaration.parameters); - const lastParamTags = lastParam ? getJSDocParameterTags(lastParam) : getJSDocTags(declaration).filter(isJSDocParameterTag); - const lastParamVariadicType = firstDefined(lastParamTags, p => p.typeExpression && isJSDocVariadicType(p.typeExpression.type) ? p.typeExpression.type : undefined); + const lastParamTags = lastParam ? getJSDocParameterTags(lastParam) + : getJSDocTags(declaration).filter(isJSDocParameterTag); + const lastParamVariadicType = firstDefined( + lastParamTags, + p => p.typeExpression && isJSDocVariadicType(p.typeExpression.type) ? p.typeExpression.type : undefined, + ); - const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args" as __String, CheckFlags.RestParameter); + const syntheticArgsSymbol = createSymbol( + SymbolFlags.Variable, + "args" as __String, + CheckFlags.RestParameter, + ); if (lastParamVariadicType) { // Parameter has effective annotation, lock in type syntheticArgsSymbol.type = createArrayType(getTypeFromTypeNode(lastParamVariadicType.type)); @@ -13484,7 +17595,8 @@ namespace ts { if (!node) return false; switch (node.kind) { case SyntaxKind.Identifier: - return (node as Identifier).escapedText === argumentsSymbol.escapedName && getReferencedValueSymbol(node as Identifier) === argumentsSymbol; + return (node as Identifier).escapedText === argumentsSymbol.escapedName + && getReferencedValueSymbol(node as Identifier) === argumentsSymbol; case SyntaxKind.PropertyDeclaration: case SyntaxKind.MethodDeclaration: @@ -13501,7 +17613,8 @@ namespace ts { return traverse((node as PropertyAssignment).initializer); default: - return !nodeStartsNewLexicalEnvironment(node) && !isPartOfTypeNode(node) && !!forEachChild(node, traverse); + return !nodeStartsNewLexicalEnvironment(node) && !isPartOfTypeNode(node) + && !!forEachChild(node, traverse); } } } @@ -13524,10 +17637,10 @@ namespace ts { // If this is a function or method declaration, get the signature from the @type tag for the sake of optional parameters. // Exclude contextually-typed kinds because we already apply the @type tag to the context, plus applying it here to the initializer would supress checks that the two are compatible. result.push( - (!isFunctionExpressionOrArrowFunction(decl) && - !isObjectLiteralMethod(decl) && - getSignatureOfTypeTag(decl)) || - getSignatureFromDeclaration(decl), + (!isFunctionExpressionOrArrowFunction(decl) + && !isObjectLiteralMethod(decl) + && getSignatureOfTypeTag(decl)) + || getSignatureFromDeclaration(decl), ); } return result; @@ -13555,10 +17668,13 @@ namespace ts { if (!signature.resolvedTypePredicate) { if (signature.target) { const targetTypePredicate = getTypePredicateOfSignature(signature.target); - signature.resolvedTypePredicate = targetTypePredicate ? instantiateTypePredicate(targetTypePredicate, signature.mapper!) : noTypePredicate; + signature.resolvedTypePredicate = targetTypePredicate + ? instantiateTypePredicate(targetTypePredicate, signature.mapper!) : noTypePredicate; } else if (signature.compositeSignatures) { - signature.resolvedTypePredicate = getUnionOrIntersectionTypePredicate(signature.compositeSignatures, signature.compositeKind) || noTypePredicate; + signature.resolvedTypePredicate = + getUnionOrIntersectionTypePredicate(signature.compositeSignatures, signature.compositeKind) + || noTypePredicate; } else { const type = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); @@ -13569,24 +17685,41 @@ namespace ts { jsdocPredicate = getTypePredicateOfSignature(jsdocSignature); } } - signature.resolvedTypePredicate = type && isTypePredicateNode(type) ? - createTypePredicateFromTypePredicateNode(type, signature) : - jsdocPredicate || noTypePredicate; + signature.resolvedTypePredicate = type && isTypePredicateNode(type) + ? createTypePredicateFromTypePredicateNode(type, signature) + : jsdocPredicate || noTypePredicate; } Debug.assert(!!signature.resolvedTypePredicate); } return signature.resolvedTypePredicate === noTypePredicate ? undefined : signature.resolvedTypePredicate; } - function createTypePredicateFromTypePredicateNode(node: TypePredicateNode, signature: Signature): TypePredicate { + function createTypePredicateFromTypePredicateNode( + node: TypePredicateNode, + signature: Signature, + ): TypePredicate { const parameterName = node.parameterName; const type = node.type && getTypeFromTypeNode(node.type); - return parameterName.kind === SyntaxKind.ThisType ? - createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) : - createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsIdentifier : TypePredicateKind.Identifier, parameterName.escapedText as string, findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type); + return parameterName.kind === SyntaxKind.ThisType + ? createTypePredicate( + node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, + /*parameterName*/ undefined, + /*parameterIndex*/ undefined, + type, + ) + : createTypePredicate( + node.assertsModifier ? TypePredicateKind.AssertsIdentifier : TypePredicateKind.Identifier, + parameterName.escapedText as string, + findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), + type, + ); } - function getUnionOrIntersectionType(types: Type[], kind: TypeFlags | undefined, unionReduction?: UnionReduction) { + function getUnionOrIntersectionType( + types: Type[], + kind: TypeFlags | undefined, + unionReduction?: UnionReduction, + ) { return kind !== TypeFlags.Intersection ? getUnionType(types, unionReduction) : getIntersectionType(types); } @@ -13595,10 +17728,20 @@ namespace ts { if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) { return errorType; } - let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper) : - signature.compositeSignatures ? instantiateType(getUnionOrIntersectionType(map(signature.compositeSignatures, getReturnTypeOfSignature), signature.compositeKind, UnionReduction.Subtype), signature.mapper) : - getReturnTypeFromAnnotation(signature.declaration!) || - (nodeIsMissing((signature.declaration as FunctionLikeDeclaration).body) ? anyType : getReturnTypeFromBody(signature.declaration as FunctionLikeDeclaration)); + let type = signature.target + ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper) + : signature.compositeSignatures + ? instantiateType( + getUnionOrIntersectionType( + map(signature.compositeSignatures, getReturnTypeOfSignature), + signature.compositeKind, + UnionReduction.Subtype, + ), + signature.mapper, + ) + : getReturnTypeFromAnnotation(signature.declaration!) + || (nodeIsMissing((signature.declaration as FunctionLikeDeclaration).body) ? anyType + : getReturnTypeFromBody(signature.declaration as FunctionLikeDeclaration)); if (signature.flags & SignatureFlags.IsInnerCallChain) { type = addOptionalTypeMarker(type); } @@ -13615,10 +17758,19 @@ namespace ts { const declaration = signature.declaration as Declaration; const name = getNameOfDeclaration(declaration); if (name) { - error(name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(name)); + error( + name, + Diagnostics + ._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, + declarationNameToString(name), + ); } else { - error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions); + error( + declaration, + Diagnostics + .Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, + ); } } } @@ -13631,7 +17783,9 @@ namespace ts { function getReturnTypeFromAnnotation(declaration: SignatureDeclaration | JSDocSignature) { if (declaration.kind === SyntaxKind.Constructor) { - return getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent as ClassDeclaration).symbol)); + return getDeclaredTypeOfClassOrInterface( + getMergedSymbol((declaration.parent as ClassDeclaration).symbol), + ); } if (isJSDocConstructSignature(declaration)) { return getTypeFromTypeNode((declaration.parameters[0] as ParameterDeclaration).type!); // TODO: GH#18217 @@ -13645,7 +17799,10 @@ namespace ts { if (jsDocType) { return jsDocType; } - const setter = getDeclarationOfKind(getSymbolOfNode(declaration), SyntaxKind.SetAccessor); + const setter = getDeclarationOfKind( + getSymbolOfNode(declaration), + SyntaxKind.SetAccessor, + ); const setterType = getAnnotatedAccessorType(setter); if (setterType) { return setterType; @@ -13655,7 +17812,8 @@ namespace ts { } function isResolvingReturnTypeOfSignature(signature: Signature) { - return !signature.resolvedReturnType && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0; + return !signature.resolvedReturnType + && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0; } function getRestTypeOfSignature(signature: Signature): Type { @@ -13671,10 +17829,25 @@ namespace ts { return undefined; } - function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: readonly TypeParameter[]): Signature { - const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript)); + function getSignatureInstantiation( + signature: Signature, + typeArguments: Type[] | undefined, + isJavascript: boolean, + inferredTypeParameters?: readonly TypeParameter[], + ): Signature { + const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments( + signature, + fillMissingTypeArguments( + typeArguments, + signature.typeParameters, + getMinTypeArgumentCount(signature.typeParameters), + isJavascript, + ), + ); if (inferredTypeParameters) { - const returnSignature = getSingleCallOrConstructSignature(getReturnTypeOfSignature(instantiatedSignature)); + const returnSignature = getSingleCallOrConstructSignature( + getReturnTypeOfSignature(instantiatedSignature), + ); if (returnSignature) { const newReturnSignature = cloneSignature(returnSignature); newReturnSignature.typeParameters = inferredTypeParameters; @@ -13686,8 +17859,12 @@ namespace ts { return instantiatedSignature; } - function getSignatureInstantiationWithoutFillingInTypeArguments(signature: Signature, typeArguments: readonly Type[] | undefined): Signature { - const instantiations = signature.instantiations || (signature.instantiations = new Map()); + function getSignatureInstantiationWithoutFillingInTypeArguments( + signature: Signature, + typeArguments: readonly Type[] | undefined, + ): Signature { + const instantiations = signature.instantiations + || (signature.instantiations = new Map()); const id = getTypeListId(typeArguments); let instantiation = instantiations.get(id); if (!instantiation) { @@ -13696,29 +17873,44 @@ namespace ts { return instantiation; } - function createSignatureInstantiation(signature: Signature, typeArguments: readonly Type[] | undefined): Signature { - return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true); + function createSignatureInstantiation( + signature: Signature, + typeArguments: readonly Type[] | undefined, + ): Signature { + return instantiateSignature( + signature, + createSignatureTypeMapper(signature, typeArguments), + /*eraseTypeParameters*/ true, + ); } - function createSignatureTypeMapper(signature: Signature, typeArguments: readonly Type[] | undefined): TypeMapper { + function createSignatureTypeMapper( + signature: Signature, + typeArguments: readonly Type[] | undefined, + ): TypeMapper { return createTypeMapper(signature.typeParameters!, typeArguments); } function getErasedSignature(signature: Signature): Signature { - return signature.typeParameters ? - signature.erasedSignatureCache || (signature.erasedSignatureCache = createErasedSignature(signature)) : - signature; + return signature.typeParameters + ? signature.erasedSignatureCache || (signature.erasedSignatureCache = createErasedSignature(signature)) + : signature; } function createErasedSignature(signature: Signature) { // Create an instantiation of the signature where all type arguments are the any type. - return instantiateSignature(signature, createTypeEraser(signature.typeParameters!), /*eraseTypeParameters*/ true); + return instantiateSignature( + signature, + createTypeEraser(signature.typeParameters!), + /*eraseTypeParameters*/ true, + ); } function getCanonicalSignature(signature: Signature): Signature { - return signature.typeParameters ? - signature.canonicalSignatureCache || (signature.canonicalSignatureCache = createCanonicalSignature(signature)) : - signature; + return signature.typeParameters + ? signature.canonicalSignatureCache + || (signature.canonicalSignatureCache = createCanonicalSignature(signature)) + : signature; } function createCanonicalSignature(signature: Signature) { @@ -13730,7 +17922,10 @@ namespace ts { // that uses the original type identities for all unconstrained type parameters. return getSignatureInstantiation( signature, - map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp), + map( + signature.typeParameters, + tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp, + ), isInJSFile(signature.declaration), ); } @@ -13742,8 +17937,14 @@ namespace ts { return signature.baseSignatureCache; } const typeEraser = createTypeEraser(typeParameters); - const baseConstraintMapper = createTypeMapper(typeParameters, map(typeParameters, tp => getConstraintOfTypeParameter(tp) || unknownType)); - let baseConstraints: readonly Type[] = map(typeParameters, tp => instantiateType(tp, baseConstraintMapper) || unknownType); + const baseConstraintMapper = createTypeMapper( + typeParameters, + map(typeParameters, tp => getConstraintOfTypeParameter(tp) || unknownType), + ); + let baseConstraints: readonly Type[] = map( + typeParameters, + tp => instantiateType(tp, baseConstraintMapper) || unknownType, + ); // Run N type params thru the immediate constraint mapper up to N times // This way any noncircular interdependent type parameters are definitely resolved to their external dependencies for (let i = 0; i < typeParameters.length - 1; i++) { @@ -13751,7 +17952,11 @@ namespace ts { } // and then apply a type eraser to remove any remaining circularly dependent type parameters baseConstraints = instantiateTypes(baseConstraints, typeEraser); - return signature.baseSignatureCache = instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true); + return signature.baseSignatureCache = instantiateSignature( + signature, + createTypeMapper(typeParameters, baseConstraints), + /*eraseTypeParameters*/ true, + ); } return signature; } @@ -13765,7 +17970,8 @@ namespace ts { const kind = signature.declaration?.kind; // If declaration is undefined, it is likely to be the signature of the default constructor. - const isConstructor = kind === undefined || kind === SyntaxKind.Constructor || kind === SyntaxKind.ConstructSignature || kind === SyntaxKind.ConstructorType; + const isConstructor = kind === undefined || kind === SyntaxKind.Constructor + || kind === SyntaxKind.ConstructSignature || kind === SyntaxKind.ConstructorType; const type = createObjectType(ObjectFlags.Anonymous); type.members = emptySymbols; @@ -13787,7 +17993,12 @@ namespace ts { return symbolTable.get(InternalSymbolName.Index); } - function createIndexInfo(keyType: Type, type: Type, isReadonly: boolean, declaration?: IndexSignatureDeclaration): IndexInfo { + function createIndexInfo( + keyType: Type, + type: Type, + isReadonly: boolean, + declaration?: IndexSignatureDeclaration, + ): IndexInfo { return { keyType, type, isReadonly, declaration }; } @@ -13805,7 +18016,14 @@ namespace ts { if (parameter.type) { forEachType(getTypeFromTypeNode(parameter.type), keyType => { if (isValidIndexKeyType(keyType) && !findIndexInfo(indexInfos, keyType)) { - indexInfos.push(createIndexInfo(keyType, declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, hasEffectiveModifier(declaration, ModifierFlags.Readonly), declaration)); + indexInfos.push( + createIndexInfo( + keyType, + declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, + hasEffectiveModifier(declaration, ModifierFlags.Readonly), + declaration, + ), + ); } }); } @@ -13817,12 +18035,17 @@ namespace ts { } function isValidIndexKeyType(type: Type): boolean { - return !!(type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.ESSymbol)) || isPatternLiteralType(type) || - !!(type.flags & TypeFlags.Intersection) && !isGenericType(type) && some((type as IntersectionType).types, isValidIndexKeyType); + return !!(type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.ESSymbol)) + || isPatternLiteralType(type) + || !!(type.flags & TypeFlags.Intersection) && !isGenericType(type) + && some((type as IntersectionType).types, isValidIndexKeyType); } function getConstraintDeclaration(type: TypeParameter): TypeNode | undefined { - return mapDefined(filter(type.symbol && type.symbol.declarations, isTypeParameterDeclaration), getEffectiveConstraintOfTypeParameter)[0]; + return mapDefined( + filter(type.symbol && type.symbol.declarations, isTypeParameterDeclaration), + getEffectiveConstraintOfTypeParameter, + )[0]; } function getInferredTypeParameterConstraint(typeParameter: TypeParameter, omitTypeReferences?: boolean) { @@ -13834,7 +18057,8 @@ namespace ts { // (such as 'Foo'), T's constraint is inferred from the constraint of the // corresponding type parameter in 'Foo'. When multiple 'infer T' declarations are // present, we form an intersection of the inferred constraint types. - const [childTypeParameter = declaration.parent, grandParent] = walkUpParenthesizedTypesAndGetParentAndChild(declaration.parent.parent); + const [childTypeParameter = declaration.parent, grandParent] = + walkUpParenthesizedTypesAndGetParentAndChild(declaration.parent.parent); if (grandParent.kind === SyntaxKind.TypeReference && !omitTypeReferences) { const typeReference = grandParent as TypeReferenceNode; const typeParameters = getTypeParametersForTypeReference(typeReference); @@ -13852,7 +18076,11 @@ namespace ts { const mapper = makeDeferredTypeMapper( typeParameters, typeParameters.map((_, index) => () => { - return getEffectiveTypeArgumentAtIndex(typeReference, typeParameters, index); + return getEffectiveTypeArgumentAtIndex( + typeReference, + typeParameters, + index, + ); }), ); const constraint = instantiateType(declaredConstraint, mapper); @@ -13866,9 +18094,11 @@ namespace ts { // When an 'infer T' declaration is immediately contained in a rest parameter declaration, a rest type // or a named rest tuple element, we infer an 'unknown[]' constraint. else if ( - grandParent.kind === SyntaxKind.Parameter && (grandParent as ParameterDeclaration).dotDotDotToken || - grandParent.kind === SyntaxKind.RestType || - grandParent.kind === SyntaxKind.NamedTupleMember && (grandParent as NamedTupleMember).dotDotDotToken + grandParent.kind === SyntaxKind.Parameter + && (grandParent as ParameterDeclaration).dotDotDotToken + || grandParent.kind === SyntaxKind.RestType + || grandParent.kind === SyntaxKind.NamedTupleMember + && (grandParent as NamedTupleMember).dotDotDotToken ) { inferences = append(inferences, createArrayType(unknownType)); } @@ -13879,21 +18109,38 @@ namespace ts { } // When an 'infer T' declaration is in the constraint position of a mapped type, we infer a 'keyof any' // constraint. - else if (grandParent.kind === SyntaxKind.TypeParameter && grandParent.parent.kind === SyntaxKind.MappedType) { + else if ( + grandParent.kind === SyntaxKind.TypeParameter + && grandParent.parent.kind === SyntaxKind.MappedType + ) { inferences = append(inferences, keyofConstraintType); } // When an 'infer T' declaration is the template of a mapped type, and that mapped type is the extends // clause of a conditional whose check type is also a mapped type, give it a constraint equal to the template // of the check type's mapped type else if ( - grandParent.kind === SyntaxKind.MappedType && (grandParent as MappedTypeNode).type && - skipParentheses((grandParent as MappedTypeNode).type!) === declaration.parent && grandParent.parent.kind === SyntaxKind.ConditionalType && - (grandParent.parent as ConditionalTypeNode).extendsType === grandParent && (grandParent.parent as ConditionalTypeNode).checkType.kind === SyntaxKind.MappedType && - ((grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode).type + grandParent.kind === SyntaxKind.MappedType && (grandParent as MappedTypeNode).type + && skipParentheses((grandParent as MappedTypeNode).type!) === declaration.parent + && grandParent.parent.kind === SyntaxKind.ConditionalType + && (grandParent.parent as ConditionalTypeNode).extendsType === grandParent + && (grandParent.parent as ConditionalTypeNode).checkType.kind === SyntaxKind.MappedType + && ((grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode).type ) { - const checkMappedType = (grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode; + const checkMappedType = (grandParent.parent as ConditionalTypeNode) + .checkType as MappedTypeNode; const nodeType = getTypeFromTypeNode(checkMappedType.type!); - inferences = append(inferences, instantiateType(nodeType, makeUnaryTypeMapper(getDeclaredTypeOfTypeParameter(getSymbolOfNode(checkMappedType.typeParameter)), checkMappedType.typeParameter.constraint ? getTypeFromTypeNode(checkMappedType.typeParameter.constraint) : keyofConstraintType))); + inferences = append( + inferences, + instantiateType( + nodeType, + makeUnaryTypeMapper( + getDeclaredTypeOfTypeParameter(getSymbolOfNode(checkMappedType.typeParameter)), + checkMappedType.typeParameter.constraint + ? getTypeFromTypeNode(checkMappedType.typeParameter.constraint) + : keyofConstraintType, + ), + ), + ); } } } @@ -13906,19 +18153,22 @@ namespace ts { if (!typeParameter.constraint) { if (typeParameter.target) { const targetConstraint = getConstraintOfTypeParameter(typeParameter.target); - typeParameter.constraint = targetConstraint ? instantiateType(targetConstraint, typeParameter.mapper) : noConstraintType; + typeParameter.constraint = targetConstraint + ? instantiateType(targetConstraint, typeParameter.mapper) : noConstraintType; } else { const constraintDeclaration = getConstraintDeclaration(typeParameter); if (!constraintDeclaration) { - typeParameter.constraint = getInferredTypeParameterConstraint(typeParameter) || noConstraintType; + typeParameter.constraint = getInferredTypeParameterConstraint(typeParameter) + || noConstraintType; } else { let type = getTypeFromTypeNode(constraintDeclaration); if (type.flags & TypeFlags.Any && !isErrorType(type)) { // Allow errorType to propegate to keep downstream errors suppressed // use keyofConstraintType as the base constraint for mapped type key constraints (unknown isn;t assignable to that, but `any` was), // use unknown otherwise - type = constraintDeclaration.parent.parent.kind === SyntaxKind.MappedType ? keyofConstraintType : unknownType; + type = constraintDeclaration.parent.parent.kind === SyntaxKind.MappedType + ? keyofConstraintType : unknownType; } typeParameter.constraint = type; } @@ -13929,7 +18179,8 @@ namespace ts { function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol | undefined { const tp = getDeclarationOfKind(typeParameter.symbol, SyntaxKind.TypeParameter)!; - const host = isJSDocTemplateTag(tp.parent) ? getEffectiveContainerForJSDocTemplateTag(tp.parent) : tp.parent; + const host = isJSDocTemplateTag(tp.parent) ? getEffectiveContainerForJSDocTemplateTag(tp.parent) + : tp.parent; return host && getSymbolOfNode(host); } @@ -13958,7 +18209,9 @@ namespace ts { } function getAliasId(aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { - return aliasSymbol ? `@${getSymbolId(aliasSymbol)}` + (aliasTypeArguments ? `:${getTypeListId(aliasTypeArguments)}` : "") : ""; + return aliasSymbol + ? `@${getSymbolId(aliasSymbol)}` + (aliasTypeArguments ? `:${getTypeListId(aliasTypeArguments)}` : "") + : ""; } // This function is used to propagate certain flags when creating new object type references and union types. @@ -13997,11 +18250,18 @@ namespace ts { return type; } - function createDeferredTypeReference(target: GenericType, node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): DeferredTypeReference { + function createDeferredTypeReference( + target: GenericType, + node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, + mapper?: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): DeferredTypeReference { if (!aliasSymbol) { aliasSymbol = getAliasSymbolForTypeNode(node); const localAliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); - aliasTypeArguments = mapper ? instantiateTypes(localAliasTypeArguments, mapper) : localAliasTypeArguments; + aliasTypeArguments = mapper ? instantiateTypes(localAliasTypeArguments, mapper) + : localAliasTypeArguments; } const type = createObjectType(ObjectFlags.Reference, target.symbol) as DeferredTypeReference; type.target = target; @@ -14018,18 +18278,24 @@ namespace ts { return type.target.localTypeParameters?.map(() => errorType) || emptyArray; } const node = type.node; - const typeArguments = !node ? emptyArray : - node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) : - node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : - map(node.elements, getTypeFromTypeNode); + const typeArguments = !node ? emptyArray + : node.kind === SyntaxKind.TypeReference + ? concatenate( + type.target.outerTypeParameters, + getEffectiveTypeArguments(node, type.target.localTypeParameters!), + ) + : node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] + : map(node.elements, getTypeFromTypeNode); if (popTypeResolution()) { - type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; + type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) + : typeArguments; } else { type.resolvedTypeArguments = type.target.localTypeParameters?.map(() => errorType) || emptyArray; error( type.node || currentNode, - type.target.symbol ? Diagnostics.Type_arguments_for_0_circularly_reference_themselves : Diagnostics.Tuple_type_arguments_circularly_reference_themselves, + type.target.symbol ? Diagnostics.Type_arguments_for_0_circularly_reference_themselves + : Diagnostics.Tuple_type_arguments_circularly_reference_themselves, type.target.symbol && symbolToString(type.target.symbol), ); } @@ -14052,38 +18318,72 @@ namespace ts { const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); const isJs = isInJSFile(node); const isJsImplicitAny = !noImplicitAny && isJs; - if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { - const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) && !isJSDocAugmentsTag(node.parent); - const diag = minTypeArgumentCount === typeParameters.length ? - missingAugmentsTag ? - Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag : - Diagnostics.Generic_type_0_requires_1_type_argument_s : - missingAugmentsTag ? - Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag : - Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments; - - const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); + if ( + !isJsImplicitAny + && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) + ) { + const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) + && !isJSDocAugmentsTag(node.parent); + const diag = minTypeArgumentCount === typeParameters.length + ? missingAugmentsTag + ? Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag + : Diagnostics.Generic_type_0_requires_1_type_argument_s + : missingAugmentsTag + ? Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag + : Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments; + + const typeStr = typeToString( + type, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.WriteArrayAsGenericType, + ); error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length); if (!isJs) { // TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments) return errorType; } } - if (node.kind === SyntaxKind.TypeReference && isDeferredTypeReferenceNode(node as TypeReferenceNode, length(node.typeArguments) !== typeParameters.length)) { - return createDeferredTypeReference(type as GenericType, node as TypeReferenceNode, /*mapper*/ undefined); + if ( + node.kind === SyntaxKind.TypeReference + && isDeferredTypeReferenceNode( + node as TypeReferenceNode, + length(node.typeArguments) !== typeParameters.length, + ) + ) { + return createDeferredTypeReference( + type as GenericType, + node as TypeReferenceNode, + /*mapper*/ undefined, + ); } // In a type reference, the outer type parameters of the referenced class or interface are automatically // supplied as type arguments and the type reference only specifies arguments for the local type parameters // of the class or interface. - const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isJs)); + const typeArguments = concatenate( + type.outerTypeParameters, + fillMissingTypeArguments( + typeArgumentsFromTypeReferenceNode(node), + typeParameters, + minTypeArgumentCount, + isJs, + ), + ); return createTypeReference(type as GenericType, typeArguments); } return checkNoTypeArguments(node, symbol) ? type : errorType; } - function getTypeAliasInstantiation(symbol: Symbol, typeArguments: readonly Type[] | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getTypeAliasInstantiation( + symbol: Symbol, + typeArguments: readonly Type[] | undefined, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { const type = getDeclaredTypeOfSymbol(symbol); - if (type === intrinsicMarkerType && intrinsicTypeKinds.has(symbol.escapedName as string) && typeArguments && typeArguments.length === 1) { + if ( + type === intrinsicMarkerType && intrinsicTypeKinds.has(symbol.escapedName as string) && typeArguments + && typeArguments.length === 1 + ) { return getStringMappingType(symbol, typeArguments[0]); } const links = getSymbolLinks(symbol); @@ -14091,7 +18391,23 @@ namespace ts { const id = getTypeListId(typeArguments) + getAliasId(aliasSymbol, aliasTypeArguments); let instantiation = links.instantiations!.get(id); if (!instantiation) { - links.instantiations!.set(id, instantiation = instantiateTypeWithAlias(type, createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters), isInJSFile(symbol.valueDeclaration))), aliasSymbol, aliasTypeArguments)); + links.instantiations!.set( + id, + instantiation = instantiateTypeWithAlias( + type, + createTypeMapper( + typeParameters, + fillMissingTypeArguments( + typeArguments, + typeParameters, + getMinTypeArgumentCount(typeParameters), + isInJSFile(symbol.valueDeclaration), + ), + ), + aliasSymbol, + aliasTypeArguments, + ), + ); } return instantiation; } @@ -14122,9 +18438,9 @@ namespace ts { if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) { error( node, - minTypeArgumentCount === typeParameters.length ? - Diagnostics.Generic_type_0_requires_1_type_argument_s : - Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments, + minTypeArgumentCount === typeParameters.length + ? Diagnostics.Generic_type_0_requires_1_type_argument_s + : Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments, symbolToString(symbol), minTypeArgumentCount, typeParameters.length, @@ -14136,8 +18452,14 @@ namespace ts { // accessible--which in turn may lead to a large structural expansion of the type when generating // a .d.ts file. See #43622 for an example. const aliasSymbol = getAliasSymbolForTypeNode(node); - const newAliasSymbol = aliasSymbol && (isLocalTypeAlias(symbol) || !isLocalTypeAlias(aliasSymbol)) ? aliasSymbol : undefined; - return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node), newAliasSymbol, getTypeArgumentsForAliasSymbol(newAliasSymbol)); + const newAliasSymbol = aliasSymbol && (isLocalTypeAlias(symbol) || !isLocalTypeAlias(aliasSymbol)) + ? aliasSymbol : undefined; + return getTypeAliasInstantiation( + symbol, + typeArgumentsFromTypeReferenceNode(node), + newAliasSymbol, + getTypeArgumentsForAliasSymbol(newAliasSymbol), + ); } return checkNoTypeArguments(node, symbol) ? type : errorType; } @@ -14165,22 +18487,28 @@ namespace ts { } function getSymbolPath(symbol: Symbol): string { - return symbol.parent ? `${getSymbolPath(symbol.parent)}.${symbol.escapedName}` : symbol.escapedName as string; + return symbol.parent ? `${getSymbolPath(symbol.parent)}.${symbol.escapedName}` + : symbol.escapedName as string; } function getUnresolvedSymbolForEntityName(name: EntityNameOrEntityNameExpression) { - const identifier = name.kind === SyntaxKind.QualifiedName ? name.right : - name.kind === SyntaxKind.PropertyAccessExpression ? name.name : - name; + const identifier = name.kind === SyntaxKind.QualifiedName ? name.right + : name.kind === SyntaxKind.PropertyAccessExpression ? name.name + : name; const text = identifier.escapedText; if (text) { - const parentSymbol = name.kind === SyntaxKind.QualifiedName ? getUnresolvedSymbolForEntityName(name.left) : - name.kind === SyntaxKind.PropertyAccessExpression ? getUnresolvedSymbolForEntityName(name.expression) : - undefined; + const parentSymbol = name.kind === SyntaxKind.QualifiedName + ? getUnresolvedSymbolForEntityName(name.left) + : name.kind === SyntaxKind.PropertyAccessExpression + ? getUnresolvedSymbolForEntityName(name.expression) + : undefined; const path = parentSymbol ? `${getSymbolPath(parentSymbol)}.${text}` : text as string; let result = unresolvedSymbols.get(path); if (!result) { - unresolvedSymbols.set(path, result = createSymbol(SymbolFlags.TypeAlias, text, CheckFlags.Unresolved)); + unresolvedSymbols.set( + path, + result = createSymbol(SymbolFlags.TypeAlias, text, CheckFlags.Unresolved), + ); result.parent = parentSymbol; result.declaredType = unresolvedType; } @@ -14189,14 +18517,18 @@ namespace ts { return unknownSymbol; } - function resolveTypeReferenceName(typeReference: TypeReferenceType, meaning: SymbolFlags, ignoreErrors?: boolean) { + function resolveTypeReferenceName( + typeReference: TypeReferenceType, + meaning: SymbolFlags, + ignoreErrors?: boolean, + ) { const name = getTypeReferenceName(typeReference); if (!name) { return unknownSymbol; } const symbol = resolveEntityName(name, meaning, ignoreErrors); - return symbol && symbol !== unknownSymbol ? symbol : - ignoreErrors ? unknownSymbol : getUnresolvedSymbolForEntityName(name); + return symbol && symbol !== unknownSymbol ? symbol + : ignoreErrors ? unknownSymbol : getUnresolvedSymbolForEntityName(name); } function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { @@ -14239,7 +18571,8 @@ namespace ts { const valueType = getTypeOfSymbol(symbol); let typeType = valueType; if (symbol.valueDeclaration) { - const isImportTypeWithQualifier = node.kind === SyntaxKind.ImportType && (node as ImportTypeNode).qualifier; + const isImportTypeWithQualifier = node.kind === SyntaxKind.ImportType + && (node as ImportTypeNode).qualifier; // valueType might not have a symbol, eg, {import('./b').STRING_LITERAL} if (valueType.symbol && valueType.symbol !== symbol && isImportTypeWithQualifier) { typeType = getTypeReferenceType(node, valueType.symbol); @@ -14252,8 +18585,8 @@ namespace ts { function getSubstitutionType(baseType: Type, constraint: Type) { if ( - constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || - !isGenericType(baseType) && !isGenericType(constraint) + constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType + || !isGenericType(baseType) && !isGenericType(constraint) ) { return baseType; } @@ -14278,9 +18611,15 @@ namespace ts { } function getImpliedConstraint(type: Type, checkNode: TypeNode, extendsNode: TypeNode): Type | undefined { - return isUnaryTupleTypeNode(checkNode) && isUnaryTupleTypeNode(extendsNode) ? getImpliedConstraint(type, (checkNode as TupleTypeNode).elements[0], (extendsNode as TupleTypeNode).elements[0]) : - getActualTypeVariable(getTypeFromTypeNode(checkNode)) === getActualTypeVariable(type) ? getTypeFromTypeNode(extendsNode) : - undefined; + return isUnaryTupleTypeNode(checkNode) && isUnaryTupleTypeNode(extendsNode) + ? getImpliedConstraint( + type, + (checkNode as TupleTypeNode).elements[0], + (extendsNode as TupleTypeNode).elements[0], + ) + : getActualTypeVariable(getTypeFromTypeNode(checkNode)) === getActualTypeVariable(type) + ? getTypeFromTypeNode(extendsNode) + : undefined; } function getConditionalFlowTypeOfType(type: Type, node: Node) { @@ -14295,15 +18634,25 @@ namespace ts { } // Always substitute on type parameters, regardless of variance, since even // in contravariant positions, they may rely on substituted constraints to be valid - if ((covariant || type.flags & TypeFlags.TypeVariable) && parent.kind === SyntaxKind.ConditionalType && node === (parent as ConditionalTypeNode).trueType) { - const constraint = getImpliedConstraint(type, (parent as ConditionalTypeNode).checkType, (parent as ConditionalTypeNode).extendsType); + if ( + (covariant || type.flags & TypeFlags.TypeVariable) && parent.kind === SyntaxKind.ConditionalType + && node === (parent as ConditionalTypeNode).trueType + ) { + const constraint = getImpliedConstraint( + type, + (parent as ConditionalTypeNode).checkType, + (parent as ConditionalTypeNode).extendsType, + ); if (constraint) { constraints = append(constraints, constraint); } } // Given a homomorphic mapped type { [K in keyof T]: XXX }, where T is constrained to an array or tuple type, in the // template type XXX, K has an added constraint of number | `${number}`. - else if (type.flags & TypeFlags.TypeParameter && parent.kind === SyntaxKind.MappedType && node === (parent as MappedTypeNode).type) { + else if ( + type.flags & TypeFlags.TypeParameter && parent.kind === SyntaxKind.MappedType + && node === (parent as MappedTypeNode).type + ) { const mappedType = getTypeFromTypeNode(parent as TypeNode) as MappedType; if (getTypeParameterFromMappedType(mappedType) === getActualTypeVariable(type)) { const typeParameter = getHomomorphicTypeVariable(mappedType); @@ -14321,12 +18670,19 @@ namespace ts { } function isJSDocTypeReference(node: Node): node is TypeReferenceNode { - return !!(node.flags & NodeFlags.JSDoc) && (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ImportType); + return !!(node.flags & NodeFlags.JSDoc) + && (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ImportType); } function checkNoTypeArguments(node: NodeWithTypeArguments, symbol?: Symbol) { if (node.typeArguments) { - error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : (node as TypeReferenceNode).typeName ? declarationNameToString((node as TypeReferenceNode).typeName) : anon); + error( + node, + Diagnostics.Type_0_is_not_generic, + symbol ? symbolToString(symbol) + : (node as TypeReferenceNode).typeName + ? declarationNameToString((node as TypeReferenceNode).typeName) : anon, + ); return false; } return true; @@ -14361,13 +18717,15 @@ namespace ts { case "array": return (!typeArgs || !typeArgs.length) && !noImplicitAny ? anyArrayType : undefined; case "promise": - return (!typeArgs || !typeArgs.length) && !noImplicitAny ? createPromiseType(anyType) : undefined; + return (!typeArgs || !typeArgs.length) && !noImplicitAny ? createPromiseType(anyType) + : undefined; case "Object": if (typeArgs && typeArgs.length === 2) { if (isJSDocIndexSignature(node)) { const indexed = getTypeFromTypeNode(typeArgs[0]); const target = getTypeFromTypeNode(typeArgs[1]); - const indexInfo = indexed === stringType || indexed === numberType ? [createIndexInfo(indexed, target, /*isReadonly*/ false)] : emptyArray; + const indexInfo = indexed === stringType || indexed === numberType + ? [createIndexInfo(indexed, target, /*isReadonly*/ false)] : emptyArray; return createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, indexInfo); } return anyType; @@ -14456,26 +18814,47 @@ namespace ts { } const type = getDeclaredTypeOfSymbol(symbol); if (!(type.flags & TypeFlags.Object)) { - error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbolName(symbol)); + error( + getTypeDeclaration(symbol), + Diagnostics.Global_type_0_must_be_a_class_or_interface_type, + symbolName(symbol), + ); return arity ? emptyGenericType : emptyObjectType; } if (length((type as InterfaceType).typeParameters) !== arity) { - error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbolName(symbol), arity); + error( + getTypeDeclaration(symbol), + Diagnostics.Global_type_0_must_have_1_type_parameter_s, + symbolName(symbol), + arity, + ); return arity ? emptyGenericType : emptyObjectType; } return type as ObjectType; } function getGlobalValueSymbol(name: __String, reportErrors: boolean): Symbol | undefined { - return getGlobalSymbol(name, SymbolFlags.Value, reportErrors ? Diagnostics.Cannot_find_global_value_0 : undefined); + return getGlobalSymbol( + name, + SymbolFlags.Value, + reportErrors ? Diagnostics.Cannot_find_global_value_0 : undefined, + ); } function getGlobalTypeSymbol(name: __String, reportErrors: boolean): Symbol | undefined { - return getGlobalSymbol(name, SymbolFlags.Type, reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined); + return getGlobalSymbol( + name, + SymbolFlags.Type, + reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined, + ); } function getGlobalTypeAliasSymbol(name: __String, arity: number, reportErrors: boolean): Symbol | undefined { - const symbol = getGlobalSymbol(name, SymbolFlags.Type, reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined); + const symbol = getGlobalSymbol( + name, + SymbolFlags.Type, + reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined, + ); if (symbol) { // Resolve the declared type of the symbol. This resolves type parameters for the type // alias so that we can check arity. @@ -14489,9 +18868,22 @@ namespace ts { return symbol; } - function getGlobalSymbol(name: __String, meaning: SymbolFlags, diagnostic: DiagnosticMessage | undefined): Symbol | undefined { + function getGlobalSymbol( + name: __String, + meaning: SymbolFlags, + diagnostic: DiagnosticMessage | undefined, + ): Symbol | undefined { // Don't track references for global symbols anyway, so value if `isReference` is arbitrary - return resolveName(undefined, name, meaning, diagnostic, name, /*isUse*/ false, /*excludeGlobals*/ false, /*getSpellingSuggestions*/ false); + return resolveName( + undefined, + name, + meaning, + diagnostic, + name, + /*isUse*/ false, + /*excludeGlobals*/ false, + /*getSpellingSuggestions*/ false, + ); } function getGlobalType(name: __String, arity: 0, reportErrors: true): ObjectType; @@ -14505,17 +18897,22 @@ namespace ts { function getGlobalTypedPropertyDescriptorType() { // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times - return deferredGlobalTypedPropertyDescriptorType ||= getGlobalType("TypedPropertyDescriptor" as __String, /*arity*/ 1, /*reportErrors*/ true) || emptyGenericType; + return deferredGlobalTypedPropertyDescriptorType ||= + getGlobalType("TypedPropertyDescriptor" as __String, /*arity*/ 1, /*reportErrors*/ true) + || emptyGenericType; } function getGlobalTemplateStringsArrayType() { // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times - return deferredGlobalTemplateStringsArrayType ||= getGlobalType("TemplateStringsArray" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; + return deferredGlobalTemplateStringsArrayType ||= + getGlobalType("TemplateStringsArray" as __String, /*arity*/ 0, /*reportErrors*/ true) + || emptyObjectType; } function getGlobalImportMetaType() { // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times - return deferredGlobalImportMetaType ||= getGlobalType("ImportMeta" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; + return deferredGlobalImportMetaType ||= + getGlobalType("ImportMeta" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; } function getGlobalImportMetaExpressionType() { @@ -14531,13 +18928,23 @@ namespace ts { const members = createSymbolTable([metaPropertySymbol]); symbol.members = members; - deferredGlobalImportMetaExpressionType = createAnonymousType(symbol, members, emptyArray, emptyArray, emptyArray); + deferredGlobalImportMetaExpressionType = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + emptyArray, + ); } return deferredGlobalImportMetaExpressionType; } function getGlobalImportCallOptionsType(reportErrors: boolean) { - return (deferredGlobalImportCallOptionsType ||= getGlobalType("ImportCallOptions" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return (deferredGlobalImportCallOptionsType ||= getGlobalType( + "ImportCallOptions" as __String, + /*arity*/ 0, + reportErrors, + )) || emptyObjectType; } function getGlobalESSymbolConstructorSymbol(reportErrors: boolean): Symbol | undefined { @@ -14545,19 +18952,31 @@ namespace ts { } function getGlobalESSymbolConstructorTypeSymbol(reportErrors: boolean): Symbol | undefined { - return deferredGlobalESSymbolConstructorTypeSymbol ||= getGlobalTypeSymbol("SymbolConstructor" as __String, reportErrors); + return deferredGlobalESSymbolConstructorTypeSymbol ||= getGlobalTypeSymbol( + "SymbolConstructor" as __String, + reportErrors, + ); } function getGlobalESSymbolType() { - return (deferredGlobalESSymbolType ||= getGlobalType("Symbol" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType; + return (deferredGlobalESSymbolType ||= getGlobalType( + "Symbol" as __String, + /*arity*/ 0, + /*reportErrors*/ false, + )) || emptyObjectType; } function getGlobalPromiseType(reportErrors: boolean) { - return (deferredGlobalPromiseType ||= getGlobalType("Promise" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalPromiseType ||= getGlobalType("Promise" as __String, /*arity*/ 1, reportErrors)) + || emptyGenericType; } function getGlobalPromiseLikeType(reportErrors: boolean) { - return (deferredGlobalPromiseLikeType ||= getGlobalType("PromiseLike" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalPromiseLikeType ||= getGlobalType( + "PromiseLike" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalPromiseConstructorSymbol(reportErrors: boolean): Symbol | undefined { @@ -14565,47 +18984,82 @@ namespace ts { } function getGlobalPromiseConstructorLikeType(reportErrors: boolean) { - return (deferredGlobalPromiseConstructorLikeType ||= getGlobalType("PromiseConstructorLike" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return (deferredGlobalPromiseConstructorLikeType ||= getGlobalType( + "PromiseConstructorLike" as __String, + /*arity*/ 0, + reportErrors, + )) || emptyObjectType; } function getGlobalAsyncIterableType(reportErrors: boolean) { - return (deferredGlobalAsyncIterableType ||= getGlobalType("AsyncIterable" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalAsyncIterableType ||= getGlobalType( + "AsyncIterable" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalAsyncIteratorType(reportErrors: boolean) { - return (deferredGlobalAsyncIteratorType ||= getGlobalType("AsyncIterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return (deferredGlobalAsyncIteratorType ||= getGlobalType( + "AsyncIterator" as __String, + /*arity*/ 3, + reportErrors, + )) || emptyGenericType; } function getGlobalAsyncIterableIteratorType(reportErrors: boolean) { - return (deferredGlobalAsyncIterableIteratorType ||= getGlobalType("AsyncIterableIterator" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalAsyncIterableIteratorType ||= getGlobalType( + "AsyncIterableIterator" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalAsyncGeneratorType(reportErrors: boolean) { - return (deferredGlobalAsyncGeneratorType ||= getGlobalType("AsyncGenerator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return (deferredGlobalAsyncGeneratorType ||= getGlobalType( + "AsyncGenerator" as __String, + /*arity*/ 3, + reportErrors, + )) || emptyGenericType; } function getGlobalIterableType(reportErrors: boolean) { - return (deferredGlobalIterableType ||= getGlobalType("Iterable" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalIterableType ||= getGlobalType("Iterable" as __String, /*arity*/ 1, reportErrors)) + || emptyGenericType; } function getGlobalIteratorType(reportErrors: boolean) { - return (deferredGlobalIteratorType ||= getGlobalType("Iterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return (deferredGlobalIteratorType ||= getGlobalType("Iterator" as __String, /*arity*/ 3, reportErrors)) + || emptyGenericType; } function getGlobalIterableIteratorType(reportErrors: boolean) { - return (deferredGlobalIterableIteratorType ||= getGlobalType("IterableIterator" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalIterableIteratorType ||= getGlobalType( + "IterableIterator" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalGeneratorType(reportErrors: boolean) { - return (deferredGlobalGeneratorType ||= getGlobalType("Generator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return (deferredGlobalGeneratorType ||= getGlobalType("Generator" as __String, /*arity*/ 3, reportErrors)) + || emptyGenericType; } function getGlobalIteratorYieldResultType(reportErrors: boolean) { - return (deferredGlobalIteratorYieldResultType ||= getGlobalType("IteratorYieldResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalIteratorYieldResultType ||= getGlobalType( + "IteratorYieldResult" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalIteratorReturnResultType(reportErrors: boolean) { - return (deferredGlobalIteratorReturnResultType ||= getGlobalType("IteratorReturnResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalIteratorReturnResultType ||= getGlobalType( + "IteratorReturnResult" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalTypeOrUndefined(name: __String, arity = 0): ObjectType | undefined { @@ -14615,24 +19069,31 @@ namespace ts { function getGlobalExtractSymbol(): Symbol | undefined { // We always report an error, so cache a result in the event we could not resolve the symbol to prevent reporting it multiple times - deferredGlobalExtractSymbol ||= getGlobalTypeAliasSymbol("Extract" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; + deferredGlobalExtractSymbol ||= + getGlobalTypeAliasSymbol("Extract" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; return deferredGlobalExtractSymbol === unknownSymbol ? undefined : deferredGlobalExtractSymbol; } function getGlobalOmitSymbol(): Symbol | undefined { // We always report an error, so cache a result in the event we could not resolve the symbol to prevent reporting it multiple times - deferredGlobalOmitSymbol ||= getGlobalTypeAliasSymbol("Omit" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; + deferredGlobalOmitSymbol ||= + getGlobalTypeAliasSymbol("Omit" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; return deferredGlobalOmitSymbol === unknownSymbol ? undefined : deferredGlobalOmitSymbol; } function getGlobalAwaitedSymbol(reportErrors: boolean): Symbol | undefined { // Only cache `unknownSymbol` if we are reporting errors so that we don't report the error more than once. - deferredGlobalAwaitedSymbol ||= getGlobalTypeAliasSymbol("Awaited" as __String, /*arity*/ 1, reportErrors) || (reportErrors ? unknownSymbol : undefined); + deferredGlobalAwaitedSymbol ||= getGlobalTypeAliasSymbol("Awaited" as __String, /*arity*/ 1, reportErrors) + || (reportErrors ? unknownSymbol : undefined); return deferredGlobalAwaitedSymbol === unknownSymbol ? undefined : deferredGlobalAwaitedSymbol; } function getGlobalBigIntType() { - return (deferredGlobalBigIntType ||= getGlobalType("BigInt" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType; + return (deferredGlobalBigIntType ||= getGlobalType( + "BigInt" as __String, + /*arity*/ 0, + /*reportErrors*/ false, + )) || emptyObjectType; } function getGlobalNaNSymbol(): Symbol | undefined { @@ -14640,15 +19101,20 @@ namespace ts { } function getGlobalRecordSymbol(): Symbol | undefined { - deferredGlobalRecordSymbol ||= getGlobalTypeAliasSymbol("Record" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; + deferredGlobalRecordSymbol ||= + getGlobalTypeAliasSymbol("Record" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; return deferredGlobalRecordSymbol === unknownSymbol ? undefined : deferredGlobalRecordSymbol; } /** * Instantiates a global type that is generic with some element type, and returns that instantiation. */ - function createTypeFromGenericGlobalType(genericGlobalType: GenericType, typeArguments: readonly Type[]): ObjectType { - return genericGlobalType !== emptyGenericType ? createTypeReference(genericGlobalType, typeArguments) : emptyObjectType; + function createTypeFromGenericGlobalType( + genericGlobalType: GenericType, + typeArguments: readonly Type[], + ): ObjectType { + return genericGlobalType !== emptyGenericType ? createTypeReference(genericGlobalType, typeArguments) + : emptyObjectType; } function createTypedPropertyDescriptorType(propertyType: Type): Type { @@ -14670,9 +19136,9 @@ namespace ts { case SyntaxKind.RestType: return getRestTypeElementFlags(node as RestTypeNode); case SyntaxKind.NamedTupleMember: - return (node as NamedTupleMember).questionToken ? ElementFlags.Optional : - (node as NamedTupleMember).dotDotDotToken ? getRestTypeElementFlags(node as NamedTupleMember) : - ElementFlags.Required; + return (node as NamedTupleMember).questionToken ? ElementFlags.Optional + : (node as NamedTupleMember).dotDotDotToken ? getRestTypeElementFlags(node as NamedTupleMember) + : ElementFlags.Required; default: return ElementFlags.Required; } @@ -14690,16 +19156,24 @@ namespace ts { } const elementFlags = map((node as TupleTypeNode).elements, getTupleElementFlags); const missingName = some((node as TupleTypeNode).elements, e => e.kind !== SyntaxKind.NamedTupleMember); - return getTupleTargetType(elementFlags, readonly, /*associatedNames*/ missingName ? undefined : (node as TupleTypeNode).elements as readonly NamedTupleMember[]); + return getTupleTargetType( + elementFlags, + readonly, + /*associatedNames*/ missingName ? undefined + : (node as TupleTypeNode).elements as readonly NamedTupleMember[], + ); } // Return true if the given type reference node is directly aliased or if it needs to be deferred // because it is possibly contained in a circular chain of eagerly resolved types. - function isDeferredTypeReferenceNode(node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, hasDefaultTypeArguments?: boolean) { + function isDeferredTypeReferenceNode( + node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, + hasDefaultTypeArguments?: boolean, + ) { return !!getAliasSymbolForTypeNode(node) || isResolvedByTypeAlias(node) && ( - node.kind === SyntaxKind.ArrayType ? mayResolveTypeAlias(node.elementType) : - node.kind === SyntaxKind.TupleType ? some(node.elements, mayResolveTypeAlias) : - hasDefaultTypeArguments || some(node.typeArguments, mayResolveTypeAlias) + node.kind === SyntaxKind.ArrayType ? mayResolveTypeAlias(node.elementType) + : node.kind === SyntaxKind.TupleType ? some(node.elements, mayResolveTypeAlias) + : hasDefaultTypeArguments || some(node.typeArguments, mayResolveTypeAlias) ); } @@ -14731,11 +19205,14 @@ namespace ts { function mayResolveTypeAlias(node: Node): boolean { switch (node.kind) { case SyntaxKind.TypeReference: - return isJSDocTypeReference(node) || !!(resolveTypeReferenceName(node as TypeReferenceNode, SymbolFlags.Type).flags & SymbolFlags.TypeAlias); + return isJSDocTypeReference(node) + || !!(resolveTypeReferenceName(node as TypeReferenceNode, SymbolFlags.Type).flags + & SymbolFlags.TypeAlias); case SyntaxKind.TypeQuery: return true; case SyntaxKind.TypeOperator: - return (node as TypeOperatorNode).operator !== SyntaxKind.UniqueKeyword && mayResolveTypeAlias((node as TypeOperatorNode).type); + return (node as TypeOperatorNode).operator !== SyntaxKind.UniqueKeyword + && mayResolveTypeAlias((node as TypeOperatorNode).type); case SyntaxKind.ParenthesizedType: case SyntaxKind.OptionalType: case SyntaxKind.NamedTupleMember: @@ -14743,17 +19220,24 @@ namespace ts { case SyntaxKind.JSDocNullableType: case SyntaxKind.JSDocNonNullableType: case SyntaxKind.JSDocTypeExpression: - return mayResolveTypeAlias((node as ParenthesizedTypeNode | OptionalTypeNode | JSDocTypeReferencingNode | NamedTupleMember).type); + return mayResolveTypeAlias( + (node as ParenthesizedTypeNode | OptionalTypeNode | JSDocTypeReferencingNode | NamedTupleMember) + .type, + ); case SyntaxKind.RestType: - return (node as RestTypeNode).type.kind !== SyntaxKind.ArrayType || mayResolveTypeAlias(((node as RestTypeNode).type as ArrayTypeNode).elementType); + return (node as RestTypeNode).type.kind !== SyntaxKind.ArrayType + || mayResolveTypeAlias(((node as RestTypeNode).type as ArrayTypeNode).elementType); case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: return some((node as UnionOrIntersectionTypeNode).types, mayResolveTypeAlias); case SyntaxKind.IndexedAccessType: - return mayResolveTypeAlias((node as IndexedAccessTypeNode).objectType) || mayResolveTypeAlias((node as IndexedAccessTypeNode).indexType); + return mayResolveTypeAlias((node as IndexedAccessTypeNode).objectType) + || mayResolveTypeAlias((node as IndexedAccessTypeNode).indexType); case SyntaxKind.ConditionalType: - return mayResolveTypeAlias((node as ConditionalTypeNode).checkType) || mayResolveTypeAlias((node as ConditionalTypeNode).extendsType) || - mayResolveTypeAlias((node as ConditionalTypeNode).trueType) || mayResolveTypeAlias((node as ConditionalTypeNode).falseType); + return mayResolveTypeAlias((node as ConditionalTypeNode).checkType) + || mayResolveTypeAlias((node as ConditionalTypeNode).extendsType) + || mayResolveTypeAlias((node as ConditionalTypeNode).trueType) + || mayResolveTypeAlias((node as ConditionalTypeNode).falseType); } return false; } @@ -14765,12 +19249,17 @@ namespace ts { if (target === emptyGenericType) { links.resolvedType = emptyObjectType; } - else if (!(node.kind === SyntaxKind.TupleType && some(node.elements, e => !!(getTupleElementFlags(e) & ElementFlags.Variadic))) && isDeferredTypeReferenceNode(node)) { - links.resolvedType = node.kind === SyntaxKind.TupleType && node.elements.length === 0 ? target : - createDeferredTypeReference(target, node, /*mapper*/ undefined); + else if ( + !(node.kind === SyntaxKind.TupleType + && some(node.elements, e => !!(getTupleElementFlags(e) & ElementFlags.Variadic))) + && isDeferredTypeReferenceNode(node) + ) { + links.resolvedType = node.kind === SyntaxKind.TupleType && node.elements.length === 0 ? target + : createDeferredTypeReference(target, node, /*mapper*/ undefined); } else { - const elementTypes = node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : map(node.elements, getTypeFromTypeNode); + const elementTypes = node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] + : map(node.elements, getTypeFromTypeNode); links.resolvedType = createNormalizedTypeReference(target, elementTypes); } } @@ -14781,21 +19270,39 @@ namespace ts { return isTypeOperatorNode(node) && node.operator === SyntaxKind.ReadonlyKeyword; } - function createTupleType(elementTypes: readonly Type[], elementFlags?: readonly ElementFlags[], readonly = false, namedMemberDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[]) { - const tupleTarget = getTupleTargetType(elementFlags || map(elementTypes, _ => ElementFlags.Required), readonly, namedMemberDeclarations); - return tupleTarget === emptyGenericType ? emptyObjectType : - elementTypes.length ? createNormalizedTypeReference(tupleTarget, elementTypes) : - tupleTarget; + function createTupleType( + elementTypes: readonly Type[], + elementFlags?: readonly ElementFlags[], + readonly = false, + namedMemberDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[], + ) { + const tupleTarget = getTupleTargetType( + elementFlags || map(elementTypes, _ => ElementFlags.Required), + readonly, + namedMemberDeclarations, + ); + return tupleTarget === emptyGenericType ? emptyObjectType + : elementTypes.length ? createNormalizedTypeReference(tupleTarget, elementTypes) + : tupleTarget; } - function getTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[]): GenericType { + function getTupleTargetType( + elementFlags: readonly ElementFlags[], + readonly: boolean, + namedMemberDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[], + ): GenericType { if (elementFlags.length === 1 && elementFlags[0] & ElementFlags.Rest) { // [...X[]] is equivalent to just X[] return readonly ? globalReadonlyArrayType : globalArrayType; } - const key = map(elementFlags, f => f & ElementFlags.Required ? "#" : f & ElementFlags.Optional ? "?" : f & ElementFlags.Rest ? "." : "*").join() + - (readonly ? "R" : "") + - (namedMemberDeclarations && namedMemberDeclarations.length ? "," + map(namedMemberDeclarations, getNodeId).join(",") : ""); + const key = map( + elementFlags, + f => f & ElementFlags.Required ? "#" + : f & ElementFlags.Optional ? "?" : f & ElementFlags.Rest ? "." : "*", + ).join() + + (readonly ? "R" : "") + + (namedMemberDeclarations && namedMemberDeclarations.length + ? "," + map(namedMemberDeclarations, getNodeId).join(",") : ""); let type = tupleTypes.get(key); if (!type) { tupleTypes.set(key, type = createTupleTargetType(elementFlags, readonly, namedMemberDeclarations)); @@ -14810,7 +19317,11 @@ namespace ts { // // Note that the generic type created by this function has no symbol associated with it. The same // is true for each of the synthesized type parameters. - function createTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration)[] | undefined): TupleType { + function createTupleTargetType( + elementFlags: readonly ElementFlags[], + readonly: boolean, + namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration)[] | undefined, + ): TupleType { const arity = elementFlags.length; const minLength = countWhere(elementFlags, f => !!(f & (ElementFlags.Required | ElementFlags.Variadic))); let typeParameters: TypeParameter[] | undefined; @@ -14823,7 +19334,11 @@ namespace ts { const flags = elementFlags[i]; combinedFlags |= flags; if (!(combinedFlags & ElementFlags.Variable)) { - const property = createSymbol(SymbolFlags.Property | (flags & ElementFlags.Optional ? SymbolFlags.Optional : 0), "" + i as __String, readonly ? CheckFlags.Readonly : 0); + const property = createSymbol( + SymbolFlags.Property | (flags & ElementFlags.Optional ? SymbolFlags.Optional : 0), + "" + i as __String, + readonly ? CheckFlags.Readonly : 0, + ); property.tupleLabelDeclaration = namedMemberDeclarations?.[i]; property.type = typeParameter; properties.push(property); @@ -14831,7 +19346,11 @@ namespace ts { } } const fixedLength = properties.length; - const lengthSymbol = createSymbol(SymbolFlags.Property, "length" as __String, readonly ? CheckFlags.Readonly : 0); + const lengthSymbol = createSymbol( + SymbolFlags.Property, + "length" as __String, + readonly ? CheckFlags.Readonly : 0, + ); if (combinedFlags & ElementFlags.Variable) { lengthSymbol.type = numberType; } @@ -14841,7 +19360,9 @@ namespace ts { lengthSymbol.type = getUnionType(literalTypes); } properties.push(lengthSymbol); - const type = createObjectType(ObjectFlags.Tuple | ObjectFlags.Reference) as TupleType & InterfaceTypeWithDeclaredMembers; + const type = createObjectType(ObjectFlags.Tuple | ObjectFlags.Reference) as + & TupleType + & InterfaceTypeWithDeclaredMembers; type.typeParameters = typeParameters; type.outerTypeParameters = undefined; type.localTypeParameters = typeParameters; @@ -14867,7 +19388,9 @@ namespace ts { } function createNormalizedTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined) { - return target.objectFlags & ObjectFlags.Tuple ? createNormalizedTupleType(target as TupleType, typeArguments!) : createTypeReference(target, typeArguments); + return target.objectFlags & ObjectFlags.Tuple + ? createNormalizedTupleType(target as TupleType, typeArguments!) + : createTypeReference(target, typeArguments); } function createNormalizedTupleType(target: TupleType, elementTypes: readonly Type[]): Type { @@ -14877,11 +19400,24 @@ namespace ts { } if (target.combinedFlags & ElementFlags.Variadic) { // Transform [A, ...(X | Y | Z)] into [A, ...X] | [A, ...Y] | [A, ...Z] - const unionIndex = findIndex(elementTypes, (t, i) => !!(target.elementFlags[i] & ElementFlags.Variadic && t.flags & (TypeFlags.Never | TypeFlags.Union))); + const unionIndex = findIndex( + elementTypes, + (t, i) => + !!(target.elementFlags[i] & ElementFlags.Variadic + && t.flags & (TypeFlags.Never | TypeFlags.Union)), + ); if (unionIndex >= 0) { - return checkCrossProductUnion(map(elementTypes, (t, i) => target.elementFlags[i] & ElementFlags.Variadic ? t : unknownType)) ? - mapType(elementTypes[unionIndex], t => createNormalizedTupleType(target, replaceElement(elementTypes, unionIndex, t))) : - errorType; + return checkCrossProductUnion( + map( + elementTypes, + (t, i) => target.elementFlags[i] & ElementFlags.Variadic ? t : unknownType, + ), + ) + ? mapType( + elementTypes[unionIndex], + t => createNormalizedTupleType(target, replaceElement(elementTypes, unionIndex, t)), + ) + : errorType; } } // We have optional, rest, or variadic elements that may need normalizing. Normalization ensures that all variadic @@ -14915,11 +19451,19 @@ namespace ts { return errorType; } // Spread variadic elements with tuple types into the resulting tuple. - forEach(elements, (t, n) => addElement(t, type.target.elementFlags[n], type.target.labeledElementDeclarations?.[n])); + forEach( + elements, + (t, n) => + addElement(t, type.target.elementFlags[n], type.target.labeledElementDeclarations?.[n]), + ); } else { // Treat everything else as an array type and create a rest element. - addElement(isArrayLikeType(type) && getIndexTypeOfType(type, numberType) || errorType, ElementFlags.Rest, target.labeledElementDeclarations?.[i]); + addElement( + isArrayLikeType(type) && getIndexTypeOfType(type, numberType) || errorType, + ElementFlags.Rest, + target.labeledElementDeclarations?.[i], + ); } } else { @@ -14933,17 +19477,29 @@ namespace ts { } if (firstRestIndex >= 0 && firstRestIndex < lastOptionalOrRestIndex) { // Turn elements between first rest and last optional/rest into a single rest element - expandedTypes[firstRestIndex] = getUnionType(sameMap(expandedTypes.slice(firstRestIndex, lastOptionalOrRestIndex + 1), (t, i) => expandedFlags[firstRestIndex + i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t)); + expandedTypes[firstRestIndex] = getUnionType( + sameMap( + expandedTypes.slice(firstRestIndex, lastOptionalOrRestIndex + 1), + (t, i) => + expandedFlags[firstRestIndex + i] & ElementFlags.Variadic + ? getIndexedAccessType(t, numberType) + : t, + ), + ); expandedTypes.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); expandedFlags.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); expandedDeclarations?.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); } const tupleTarget = getTupleTargetType(expandedFlags, target.readonly, expandedDeclarations); - return tupleTarget === emptyGenericType ? emptyObjectType : - expandedFlags.length ? createTypeReference(tupleTarget, expandedTypes) : - tupleTarget; - - function addElement(type: Type, flags: ElementFlags, declaration: NamedTupleMember | ParameterDeclaration | undefined) { + return tupleTarget === emptyGenericType ? emptyObjectType + : expandedFlags.length ? createTypeReference(tupleTarget, expandedTypes) + : tupleTarget; + + function addElement( + type: Type, + flags: ElementFlags, + declaration: NamedTupleMember | ParameterDeclaration | undefined, + ) { if (flags & ElementFlags.Required) { lastRequiredIndex = expandedFlags.length; } @@ -14967,12 +19523,22 @@ namespace ts { function sliceTupleType(type: TupleTypeReference, index: number, endSkipCount = 0) { const target = type.target; const endIndex = getTypeReferenceArity(type) - endSkipCount; - return index > target.fixedLength ? getRestArrayTypeOfTupleType(type) || createTupleType(emptyArray) : - createTupleType(getTypeArguments(type).slice(index, endIndex), target.elementFlags.slice(index, endIndex), /*readonly*/ false, target.labeledElementDeclarations && target.labeledElementDeclarations.slice(index, endIndex)); + return index > target.fixedLength ? getRestArrayTypeOfTupleType(type) || createTupleType(emptyArray) + : createTupleType( + getTypeArguments(type).slice(index, endIndex), + target.elementFlags.slice(index, endIndex), + /*readonly*/ false, + target.labeledElementDeclarations && target.labeledElementDeclarations.slice(index, endIndex), + ); } function getKnownKeysOfTupleType(type: TupleTypeReference) { - return getUnionType(append(arrayOf(type.target.fixedLength, i => getStringLiteralType("" + i)), getIndexType(type.target.readonly ? globalReadonlyArrayType : globalArrayType))); + return getUnionType( + append( + arrayOf(type.target.fixedLength, i => getStringLiteralType("" + i)), + getIndexType(type.target.readonly ? globalReadonlyArrayType : globalArrayType), + ), + ); } // Return count of starting consecutive tuple elements of the given kind(s) @@ -15010,7 +19576,11 @@ namespace ts { function addTypeToUnion(typeSet: Type[], includes: TypeFlags, type: Type) { const flags = type.flags; if (flags & TypeFlags.Union) { - return addTypesToUnion(typeSet, includes | (isNamedUnionType(type) ? TypeFlags.Union : 0), (type as UnionType).types); + return addTypesToUnion( + typeSet, + includes | (isNamedUnionType(type) ? TypeFlags.Union : 0), + (type as UnionType).types, + ); } // We ignore 'never' types in unions if (!(flags & TypeFlags.Never)) { @@ -15018,11 +19588,14 @@ namespace ts { if (flags & TypeFlags.Instantiable) includes |= TypeFlags.IncludesInstantiable; if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; if (!strictNullChecks && flags & TypeFlags.Nullable) { - if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType; + if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) { + includes |= TypeFlags.IncludesNonWideningType; + } } else { const len = typeSet.length; - const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues); + const index = len && type.id > typeSet[len - 1].id ? ~len + : binarySearch(typeSet, type, getTypeId, compareValues); if (index < 0) { typeSet.splice(~index, 0, type); } @@ -15055,7 +19628,12 @@ namespace ts { // We assume that redundant primitive types have already been removed from the types array and that there // are no any and unknown types in the array. Thus, the only possible supertypes for primitive types are empty // object types, and if none of those are present we can exclude primitive types from the subtype check. - const hasEmptyObject = hasObjectTypes && some(types, t => !!(t.flags & TypeFlags.Object) && !isGenericMappedType(t) && isEmptyResolvedType(resolveStructuredTypeMembers(t as ObjectType))); + const hasEmptyObject = hasObjectTypes + && some( + types, + t => !!(t.flags & TypeFlags.Object) && !isGenericMappedType(t) + && isEmptyResolvedType(resolveStructuredTypeMembers(t as ObjectType)), + ); const len = types.length; let i = len; let count = 0; @@ -15066,9 +19644,10 @@ namespace ts { // Find the first property with a unit type, if any. When constituents have a property by the same name // but of a different unit type, we can quickly disqualify them from subtype checks. This helps subtype // reduction of large discriminated union types. - const keyProperty = source.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive) ? - find(getPropertiesOfType(source), p => isUnitType(getTypeOfSymbol(p))) : - undefined; + const keyProperty = + source.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive) + ? find(getPropertiesOfType(source), p => isUnitType(getTypeOfSymbol(p))) + : undefined; const keyPropertyType = keyProperty && getRegularTypeOfLiteralType(getTypeOfSymbol(keyProperty)); for (const target of types) { if (source !== target) { @@ -15079,13 +19658,22 @@ namespace ts { // caps union types at 1000 unique object types. const estimatedCount = (count / (len - i)) * len; if (estimatedCount > 1000000) { - tracing?.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) }); - error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); + tracing?.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { + typeIds: types.map(t => t.id), + }); + error( + currentNode, + Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent, + ); return undefined; } } count++; - if (keyProperty && target.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive)) { + if ( + keyProperty + && target.flags + & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive) + ) { const t = getTypeOfPropertyOfType(target, keyProperty.escapedName); if (t && isUnitType(t) && getRegularTypeOfLiteralType(t) !== keyPropertyType) { continue; @@ -15093,9 +19681,9 @@ namespace ts { } if ( isTypeRelatedTo(source, target, strictSubtypeRelation) && ( - !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) || - !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) || - isTypeDerivedFrom(source, target) + !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) + || !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) + || isTypeDerivedFrom(source, target) ) ) { orderedRemoveItemAt(types, i); @@ -15115,12 +19703,13 @@ namespace ts { i--; const t = types[i]; const flags = t.flags; - const remove = flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && includes & TypeFlags.String || - flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number || - flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt || - flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol || - reduceVoidUndefined && flags & TypeFlags.Undefined && includes & TypeFlags.Void || - isFreshLiteralType(t) && containsType(types, (t as LiteralType).regularType); + const remove = flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + && includes & TypeFlags.String + || flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number + || flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt + || flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol + || reduceVoidUndefined && flags & TypeFlags.Undefined && includes & TypeFlags.Void + || isFreshLiteralType(t) && containsType(types, (t as LiteralType).regularType); if (remove) { orderedRemoveItemAt(types, i); } @@ -15134,7 +19723,10 @@ namespace ts { while (i > 0) { i--; const t = types[i]; - if (t.flags & TypeFlags.StringLiteral && some(templates, template => isTypeMatchedByTemplateLiteralType(t, template))) { + if ( + t.flags & TypeFlags.StringLiteral + && some(templates, template => isTypeMatchedByTemplateLiteralType(t, template)) + ) { orderedRemoveItemAt(types, i); } } @@ -15172,7 +19764,13 @@ namespace ts { // expression constructs such as array literals and the || and ?: operators). Named types can // circularly reference themselves and therefore cannot be subtype reduced during their declaration. // For example, "type Item = string | (() => Item" is a named type that circularly references itself. - function getUnionType(types: readonly Type[], unionReduction: UnionReduction = UnionReduction.Literal, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type { + function getUnionType( + types: readonly Type[], + unionReduction: UnionReduction = UnionReduction.Literal, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + origin?: Type, + ): Type { if (types.length === 0) { return neverType; } @@ -15183,9 +19781,10 @@ namespace ts { const includes = addTypesToUnion(typeSet, 0, types); if (unionReduction !== UnionReduction.None) { if (includes & TypeFlags.AnyOrUnknown) { - return includes & TypeFlags.Any ? - includes & TypeFlags.IncludesWildcard ? wildcardType : anyType : - includes & TypeFlags.Null || containsType(typeSet, unknownType) ? unknownType : nonNullUnknownType; + return includes & TypeFlags.Any + ? includes & TypeFlags.IncludesWildcard ? wildcardType : anyType + : includes & TypeFlags.Null || containsType(typeSet, unknownType) ? unknownType + : nonNullUnknownType; } if (exactOptionalPropertyTypes && includes & TypeFlags.Undefined) { const missingIndex = binarySearch(typeSet, missingType, getTypeId, compareValues); @@ -15193,7 +19792,11 @@ namespace ts { orderedRemoveItemAt(typeSet, missingIndex); } } - if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || includes & TypeFlags.Void && includes & TypeFlags.Undefined) { + if ( + includes + & (TypeFlags.Literal | TypeFlags.UniqueESSymbol | TypeFlags.TemplateLiteral + | TypeFlags.StringMapping) || includes & TypeFlags.Void && includes & TypeFlags.Undefined + ) { removeRedundantLiteralTypes(typeSet, includes, !!(unionReduction & UnionReduction.Subtype)); } if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) { @@ -15206,9 +19809,11 @@ namespace ts { } } if (typeSet.length === 0) { - return includes & TypeFlags.Null ? includes & TypeFlags.IncludesNonWideningType ? nullType : nullWideningType : - includes & TypeFlags.Undefined ? includes & TypeFlags.IncludesNonWideningType ? undefinedType : undefinedWideningType : - neverType; + return includes & TypeFlags.Null + ? includes & TypeFlags.IncludesNonWideningType ? nullType : nullWideningType + : includes & TypeFlags.Undefined + ? includes & TypeFlags.IncludesNonWideningType ? undefinedType : undefinedWideningType + : neverType; } } if (!origin && includes & TypeFlags.Union) { @@ -15225,7 +19830,11 @@ namespace ts { } // We create a denormalized origin type only when the union was created from one or more named unions // (unions with alias symbols or origins) and when there is no overlap between those named unions. - const namedTypesCount = reduceLeft(namedUnions, (sum, union) => sum + (union as UnionType).types.length, 0); + const namedTypesCount = reduceLeft( + namedUnions, + (sum, union) => sum + (union as UnionType).types.length, + 0, + ); if (namedTypesCount + reducedTypes.length === typeSet.length) { for (const t of namedUnions) { insertType(reducedTypes, t); @@ -15233,17 +19842,23 @@ namespace ts { origin = createOriginUnionOrIntersectionType(TypeFlags.Union, reducedTypes); } } - const objectFlags = (includes & TypeFlags.NotPrimitiveUnion ? 0 : ObjectFlags.PrimitiveUnion) | - (includes & TypeFlags.Intersection ? ObjectFlags.ContainsIntersections : 0); + const objectFlags = (includes & TypeFlags.NotPrimitiveUnion ? 0 : ObjectFlags.PrimitiveUnion) + | (includes & TypeFlags.Intersection ? ObjectFlags.ContainsIntersections : 0); return getUnionTypeFromSortedList(typeSet, objectFlags, aliasSymbol, aliasTypeArguments, origin); } - function getUnionOrIntersectionTypePredicate(signatures: readonly Signature[], kind: TypeFlags | undefined): TypePredicate | undefined { + function getUnionOrIntersectionTypePredicate( + signatures: readonly Signature[], + kind: TypeFlags | undefined, + ): TypePredicate | undefined { let first: TypePredicate | undefined; const types: Type[] = []; for (const sig of signatures) { const pred = getTypePredicateOfSignature(sig); - if (!pred || pred.kind === TypePredicateKind.AssertsThis || pred.kind === TypePredicateKind.AssertsIdentifier) { + if ( + !pred || pred.kind === TypePredicateKind.AssertsThis + || pred.kind === TypePredicateKind.AssertsIdentifier + ) { if (kind !== TypeFlags.Intersection) { continue; } @@ -15276,17 +19891,23 @@ namespace ts { } // This function assumes the constituent type list is sorted and deduplicated. - function getUnionTypeFromSortedList(types: Type[], objectFlags: ObjectFlags, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type { + function getUnionTypeFromSortedList( + types: Type[], + objectFlags: ObjectFlags, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + origin?: Type, + ): Type { if (types.length === 0) { return neverType; } if (types.length === 1) { return types[0]; } - const typeKey = !origin ? getTypeListId(types) : - origin.flags & TypeFlags.Union ? `|${getTypeListId((origin as UnionType).types)}` : - origin.flags & TypeFlags.Intersection ? `&${getTypeListId((origin as IntersectionType).types)}` : - `#${(origin as IndexType).type.id}|${getTypeListId(types)}`; // origin type id alone is insufficient, as `keyof x` may resolve to multiple WIP values while `x` is still resolving + const typeKey = !origin ? getTypeListId(types) + : origin.flags & TypeFlags.Union ? `|${getTypeListId((origin as UnionType).types)}` + : origin.flags & TypeFlags.Intersection ? `&${getTypeListId((origin as IntersectionType).types)}` + : `#${(origin as IndexType).type.id}|${getTypeListId(types)}`; // origin type id alone is insufficient, as `keyof x` may resolve to multiple WIP values while `x` is still resolving const id = typeKey + getAliasId(aliasSymbol, aliasTypeArguments); let type = unionTypes.get(id); if (!type) { @@ -15296,7 +19917,10 @@ namespace ts { type.origin = origin; type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = aliasTypeArguments; - if (types.length === 2 && types[0].flags & TypeFlags.BooleanLiteral && types[1].flags & TypeFlags.BooleanLiteral) { + if ( + types.length === 2 && types[0].flags & TypeFlags.BooleanLiteral + && types[1].flags & TypeFlags.BooleanLiteral + ) { type.flags |= TypeFlags.Boolean; (type as UnionType & IntrinsicType).intrinsicName = "boolean"; } @@ -15309,7 +19933,12 @@ namespace ts { const links = getNodeLinks(node); if (!links.resolvedType) { const aliasSymbol = getAliasSymbolForTypeNode(node); - links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), UnionReduction.Literal, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol)); + links.resolvedType = getUnionType( + map(node.types, getTypeFromTypeNode), + UnionReduction.Literal, + aliasSymbol, + getTypeArgumentsForAliasSymbol(aliasSymbol), + ); } return links.resolvedType; } @@ -15362,12 +19991,13 @@ namespace ts { while (i > 0) { i--; const t = types[i]; - const remove = t.flags & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || - t.flags & TypeFlags.Number && includes & TypeFlags.NumberLiteral || - t.flags & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || - t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || - t.flags & TypeFlags.Void && includes & TypeFlags.Undefined || - isEmptyAnonymousObjectType(t) && includes & TypeFlags.DefinitelyNonNullable; + const remove = t.flags & TypeFlags.String + && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + || t.flags & TypeFlags.Number && includes & TypeFlags.NumberLiteral + || t.flags & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral + || t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol + || t.flags & TypeFlags.Void && includes & TypeFlags.Undefined + || isEmptyAnonymousObjectType(t) && includes & TypeFlags.DefinitelyNonNullable; if (remove) { orderedRemoveItemAt(types, i); } @@ -15380,11 +20010,11 @@ namespace ts { function eachUnionContains(unionTypes: UnionType[], type: Type) { for (const u of unionTypes) { if (!containsType(u.types, type)) { - const primitive = type.flags & TypeFlags.StringLiteral ? stringType : - type.flags & TypeFlags.NumberLiteral ? numberType : - type.flags & TypeFlags.BigIntLiteral ? bigintType : - type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : - undefined; + const primitive = type.flags & TypeFlags.StringLiteral ? stringType + : type.flags & TypeFlags.NumberLiteral ? numberType + : type.flags & TypeFlags.BigIntLiteral ? bigintType + : type.flags & TypeFlags.UniqueESSymbol ? esSymbolType + : undefined; if (!primitive || !containsType(u.types, primitive)) { return false; } @@ -15418,7 +20048,10 @@ namespace ts { } function eachIsUnionContaining(types: Type[], flag: TypeFlags) { - return every(types, t => !!(t.flags & TypeFlags.Union) && some((t as UnionType).types, tt => !!(tt.flags & flag))); + return every( + types, + t => !!(t.flags & TypeFlags.Union) && some((t as UnionType).types, tt => !!(tt.flags & flag)), + ); } function removeFromEach(types: Type[], flag: TypeFlags) { @@ -15491,7 +20124,12 @@ namespace ts { // a type alias of the form "type List = T & { next: List }" cannot be reduced during its declaration. // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution // for intersections of types with signatures can be deterministic. - function getIntersectionType(types: readonly Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], noSupertypeReduction?: boolean): Type { + function getIntersectionType( + types: readonly Type[], + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + noSupertypeReduction?: boolean, + ): Type { const typeMembershipMap: ESMap = new Map(); const includes = addTypesToIntersection(typeMembershipMap, 0, types); const typeSet: Type[] = arrayFrom(typeMembershipMap.values()); @@ -15508,32 +20146,38 @@ namespace ts { return contains(typeSet, silentNeverType) ? silentNeverType : neverType; } if ( - strictNullChecks && includes & TypeFlags.Nullable && includes & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.IncludesEmptyObject) || - includes & TypeFlags.NonPrimitive && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive) || - includes & TypeFlags.StringLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.StringLike) || - includes & TypeFlags.NumberLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike) || - includes & TypeFlags.BigIntLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike) || - includes & TypeFlags.ESSymbolLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike) || - includes & TypeFlags.VoidLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike) + strictNullChecks && includes & TypeFlags.Nullable + && includes & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.IncludesEmptyObject) + || includes & TypeFlags.NonPrimitive && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive) + || includes & TypeFlags.StringLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.StringLike) + || includes & TypeFlags.NumberLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike) + || includes & TypeFlags.BigIntLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike) + || includes & TypeFlags.ESSymbolLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike) + || includes & TypeFlags.VoidLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike) ) { return neverType; } - if (includes & TypeFlags.TemplateLiteral && includes & TypeFlags.StringLiteral && extractRedundantTemplateLiterals(typeSet)) { + if ( + includes & TypeFlags.TemplateLiteral && includes & TypeFlags.StringLiteral + && extractRedundantTemplateLiterals(typeSet) + ) { return neverType; } if (includes & TypeFlags.Any) { return includes & TypeFlags.IncludesWildcard ? wildcardType : anyType; } if (!strictNullChecks && includes & TypeFlags.Nullable) { - return includes & TypeFlags.IncludesEmptyObject ? neverType : includes & TypeFlags.Undefined ? undefinedType : nullType; + return includes & TypeFlags.IncludesEmptyObject ? neverType + : includes & TypeFlags.Undefined ? undefinedType : nullType; } if ( - includes & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || - includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral || - includes & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || - includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || - includes & TypeFlags.Void && includes & TypeFlags.Undefined || - includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.DefinitelyNonNullable + includes & TypeFlags.String + && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + || includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral + || includes & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral + || includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol + || includes & TypeFlags.Void && includes & TypeFlags.Undefined + || includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.DefinitelyNonNullable ) { if (!noSupertypeReduction) removeRedundantSupertypes(typeSet, includes); } @@ -15557,13 +20201,24 @@ namespace ts { result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments); } else if (eachIsUnionContaining(typeSet, TypeFlags.Undefined)) { - const undefinedOrMissingType = exactOptionalPropertyTypes && some(typeSet, t => containsType((t as UnionType).types, missingType)) ? missingType : undefinedType; + const undefinedOrMissingType = exactOptionalPropertyTypes && some(typeSet, t => + containsType((t as UnionType).types, missingType)) ? missingType : undefinedType; removeFromEach(typeSet, TypeFlags.Undefined); - result = getUnionType([getIntersectionType(typeSet), undefinedOrMissingType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments); + result = getUnionType( + [getIntersectionType(typeSet), undefinedOrMissingType], + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments, + ); } else if (eachIsUnionContaining(typeSet, TypeFlags.Null)) { removeFromEach(typeSet, TypeFlags.Null); - result = getUnionType([getIntersectionType(typeSet), nullType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments); + result = getUnionType( + [getIntersectionType(typeSet), nullType], + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments, + ); } else { // We are attempting to construct a type of the form X & (A | B) & (C | D). Transform this into a type of @@ -15576,8 +20231,16 @@ namespace ts { // We attach a denormalized origin type when at least one constituent of the cross-product union is an // intersection (i.e. when the intersection didn't just reduce one or more unions to smaller unions) and // the denormalized origin has fewer constituents than the union itself. - const origin = some(constituents, t => !!(t.flags & TypeFlags.Intersection)) && getConstituentCountOfTypes(constituents) > getConstituentCountOfTypes(typeSet) ? createOriginUnionOrIntersectionType(TypeFlags.Intersection, typeSet) : undefined; - result = getUnionType(constituents, UnionReduction.Literal, aliasSymbol, aliasTypeArguments, origin); + const origin = some(constituents, t => !!(t.flags & TypeFlags.Intersection)) + && getConstituentCountOfTypes(constituents) > getConstituentCountOfTypes(typeSet) + ? createOriginUnionOrIntersectionType(TypeFlags.Intersection, typeSet) : undefined; + result = getUnionType( + constituents, + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments, + origin, + ); } } else { @@ -15589,13 +20252,21 @@ namespace ts { } function getCrossProductUnionSize(types: readonly Type[]) { - return reduceLeft(types, (n, t) => t.flags & TypeFlags.Union ? n * (t as UnionType).types.length : t.flags & TypeFlags.Never ? 0 : n, 1); + return reduceLeft( + types, + (n, t) => + t.flags & TypeFlags.Union ? n * (t as UnionType).types.length : t.flags & TypeFlags.Never ? 0 : n, + 1, + ); } function checkCrossProductUnion(types: readonly Type[]) { const size = getCrossProductUnionSize(types); if (size >= 100000) { - tracing?.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_DepthLimit", { typeIds: types.map(t => t.id), size }); + tracing?.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_DepthLimit", { + typeIds: types.map(t => t.id), + size, + }); error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); return false; } @@ -15623,9 +20294,10 @@ namespace ts { } function getConstituentCount(type: Type): number { - return !(type.flags & TypeFlags.UnionOrIntersection) || type.aliasSymbol ? 1 : - type.flags & TypeFlags.Union && (type as UnionType).origin ? getConstituentCount((type as UnionType).origin!) : - getConstituentCountOfTypes((type as UnionOrIntersectionType).types); + return !(type.flags & TypeFlags.UnionOrIntersection) || type.aliasSymbol ? 1 + : type.flags & TypeFlags.Union && (type as UnionType).origin + ? getConstituentCount((type as UnionType).origin!) + : getConstituentCountOfTypes((type as UnionOrIntersectionType).types); } function getConstituentCountOfTypes(types: Type[]): number { @@ -15637,8 +20309,15 @@ namespace ts { if (!links.resolvedType) { const aliasSymbol = getAliasSymbolForTypeNode(node); const types = map(node.types, getTypeFromTypeNode); - const noSupertypeReduction = types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) && types[1] === emptyTypeLiteralType; - links.resolvedType = getIntersectionType(types, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol), noSupertypeReduction); + const noSupertypeReduction = types.length === 2 + && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) + && types[1] === emptyTypeLiteralType; + links.resolvedType = getIntersectionType( + types, + aliasSymbol, + getTypeArgumentsForAliasSymbol(aliasSymbol), + noSupertypeReduction, + ); } return links.resolvedType; } @@ -15657,9 +20336,10 @@ namespace ts { } function getIndexTypeForGenericType(type: InstantiableType | UnionOrIntersectionType, stringsOnly: boolean) { - return stringsOnly ? - type.resolvedStringIndexType || (type.resolvedStringIndexType = createIndexType(type, /*stringsOnly*/ true)) : - type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, /*stringsOnly*/ false)); + return stringsOnly + ? type.resolvedStringIndexType + || (type.resolvedStringIndexType = createIndexType(type, /*stringsOnly*/ true)) + : type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, /*stringsOnly*/ false)); } /** @@ -15669,7 +20349,11 @@ namespace ts { * reduction in the constraintType) when possible. * @param noIndexSignatures Indicates if _string_ index signatures should be elided. (other index signatures are always reported) */ - function getIndexTypeForMappedType(type: MappedType, stringsOnly: boolean, noIndexSignatures: boolean | undefined) { + function getIndexTypeForMappedType( + type: MappedType, + stringsOnly: boolean, + noIndexSignatures: boolean | undefined, + ) { const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); const nameType = getNameTypeFromMappedType(type.target as MappedType || type); @@ -15686,7 +20370,12 @@ namespace ts { // so we only eagerly manifest the keys if the constraint is nongeneric if (!isGenericIndexType(constraintType)) { const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' - forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(modifiersType, TypeFlags.StringOrNumberLiteralOrUnique, stringsOnly, addMemberForKeyType); + forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( + modifiersType, + TypeFlags.StringOrNumberLiteralOrUnique, + stringsOnly, + addMemberForKeyType, + ); } else { // we have a generic index and a homomorphic mapping (but a distributive key remapping) - we need to defer the whole `keyof whatever` for later @@ -15702,14 +20391,20 @@ namespace ts { } // we had to pick apart the constraintType to potentially map/filter it - compare the final resulting list with the original constraintType, // so we can return the union that preserves aliases/origin data if possible - const result = noIndexSignatures ? filterType(getUnionType(keyTypes), t => !(t.flags & (TypeFlags.Any | TypeFlags.String))) : getUnionType(keyTypes); - if (result.flags & TypeFlags.Union && constraintType.flags & TypeFlags.Union && getTypeListId((result as UnionType).types) === getTypeListId((constraintType as UnionType).types)) { + const result = noIndexSignatures + ? filterType(getUnionType(keyTypes), t => !(t.flags & (TypeFlags.Any | TypeFlags.String))) + : getUnionType(keyTypes); + if ( + result.flags & TypeFlags.Union && constraintType.flags & TypeFlags.Union + && getTypeListId((result as UnionType).types) === getTypeListId((constraintType as UnionType).types) + ) { return constraintType; } return result; function addMemberForKeyType(keyType: Type) { - const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; + const propNameType = nameType + ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; // `keyof` currently always returns `string | number` for concrete `string` index signatures - the below ternary keeps that behavior for mapped types // See `getLiteralTypeFromProperties` where there's a similar ternary to cause the same behavior. keyTypes.push(propNameType === stringType ? stringOrNumberType : propNameType); @@ -15725,13 +20420,22 @@ namespace ts { const typeVariable = getTypeParameterFromMappedType(mappedType); return isDistributive(getNameTypeFromMappedType(mappedType) || typeVariable); function isDistributive(type: Type): boolean { - return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.NonPrimitive) ? true : - type.flags & TypeFlags.Conditional ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable : - type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) : - type.flags & TypeFlags.IndexedAccess ? isDistributive((type as IndexedAccessType).objectType) && isDistributive((type as IndexedAccessType).indexType) : - type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).baseType) && isDistributive((type as SubstitutionType).constraint) : - type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) : - false; + return type.flags + & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter + | TypeFlags.Object | TypeFlags.NonPrimitive) ? true + : type.flags & TypeFlags.Conditional + ? (type as ConditionalType).root.isDistributive + && (type as ConditionalType).checkType === typeVariable + : type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) + ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) + : type.flags & TypeFlags.IndexedAccess + ? isDistributive((type as IndexedAccessType).objectType) + && isDistributive((type as IndexedAccessType).indexType) + : type.flags & TypeFlags.Substitution + ? isDistributive((type as SubstitutionType).baseType) + && isDistributive((type as SubstitutionType).constraint) + : type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) + : false; } } @@ -15739,17 +20443,23 @@ namespace ts { if (isPrivateIdentifier(name)) { return neverType; } - return isIdentifier(name) ? getStringLiteralType(unescapeLeadingUnderscores(name.escapedText)) : - getRegularTypeOfLiteralType(isComputedPropertyName(name) ? checkComputedPropertyName(name) : checkExpression(name)); + return isIdentifier(name) ? getStringLiteralType(unescapeLeadingUnderscores(name.escapedText)) + : getRegularTypeOfLiteralType( + isComputedPropertyName(name) ? checkComputedPropertyName(name) : checkExpression(name), + ); } function getLiteralTypeFromProperty(prop: Symbol, include: TypeFlags, includeNonPublic?: boolean) { - if (includeNonPublic || !(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) { + if ( + includeNonPublic + || !(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier) + ) { let type = getSymbolLinks(getLateBoundSymbol(prop)).nameType; if (!type) { const name = getNameOfDeclaration(prop.valueDeclaration) as PropertyName; - type = prop.escapedName === InternalSymbolName.Default ? getStringLiteralType("default") : - name && getLiteralTypeFromPropertyName(name) || (!isKnownSymbol(prop) ? getStringLiteralType(symbolName(prop)) : undefined); + type = prop.escapedName === InternalSymbolName.Default ? getStringLiteralType("default") + : name && getLiteralTypeFromPropertyName(name) + || (!isKnownSymbol(prop) ? getStringLiteralType(symbolName(prop)) : undefined); } if (type && type.flags & include) { return type; @@ -15759,16 +20469,30 @@ namespace ts { } function isKeyTypeIncluded(keyType: Type, include: TypeFlags): boolean { - return !!(keyType.flags & include || keyType.flags & TypeFlags.Intersection && some((keyType as IntersectionType).types, t => isKeyTypeIncluded(t, include))); + return !!(keyType.flags & include + || keyType.flags & TypeFlags.Intersection + && some((keyType as IntersectionType).types, t => isKeyTypeIncluded(t, include))); } function getLiteralTypeFromProperties(type: Type, include: TypeFlags, includeOrigin: boolean) { - const origin = includeOrigin && (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) || type.aliasSymbol) ? createOriginIndexType(type) : undefined; + const origin = includeOrigin + && (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) + || type.aliasSymbol) ? createOriginIndexType(type) : undefined; const propertyTypes = map(getPropertiesOfType(type), prop => getLiteralTypeFromProperty(prop, include)); - const indexKeyTypes = map(getIndexInfosOfType(type), info => - info !== enumNumberIndexInfo && isKeyTypeIncluded(info.keyType, include) ? - info.keyType === stringType && include & TypeFlags.Number ? stringOrNumberType : info.keyType : neverType); - return getUnionType(concatenate(propertyTypes, indexKeyTypes), UnionReduction.Literal, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, origin); + const indexKeyTypes = map( + getIndexInfosOfType(type), + info => + info !== enumNumberIndexInfo && isKeyTypeIncluded(info.keyType, include) + ? info.keyType === stringType && include & TypeFlags.Number ? stringOrNumberType : info.keyType + : neverType, + ); + return getUnionType( + concatenate(propertyTypes, indexKeyTypes), + UnionReduction.Literal, + /*aliasSymbol*/ undefined, + /*aliasTypeArguments*/ undefined, + origin, + ); } /** @@ -15783,23 +20507,37 @@ namespace ts { } function shouldDeferIndexType(type: Type) { - return !!(type.flags & TypeFlags.InstantiableNonPrimitive || - isGenericTupleType(type) || - isGenericMappedType(type) && !hasDistributiveNameType(type) || - type.flags & TypeFlags.Union && some((type as UnionType).types, isPossiblyReducibleByInstantiation) || - type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) && some((type as IntersectionType).types, isEmptyAnonymousObjectType)); + return !!(type.flags & TypeFlags.InstantiableNonPrimitive + || isGenericTupleType(type) + || isGenericMappedType(type) && !hasDistributiveNameType(type) + || type.flags & TypeFlags.Union && some((type as UnionType).types, isPossiblyReducibleByInstantiation) + || type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) + && some((type as IntersectionType).types, isEmptyAnonymousObjectType)); } function getIndexType(type: Type, stringsOnly = keyofStringsOnly, noIndexSignatures?: boolean): Type { type = getReducedType(type); - return shouldDeferIndexType(type) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, stringsOnly) : - type.flags & TypeFlags.Union ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : - type.flags & TypeFlags.Intersection ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : - getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, stringsOnly, noIndexSignatures) : - type === wildcardType ? wildcardType : - type.flags & TypeFlags.Unknown ? neverType : - type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType : - getLiteralTypeFromProperties(type, (noIndexSignatures ? TypeFlags.StringLiteral : TypeFlags.StringLike) | (stringsOnly ? 0 : TypeFlags.NumberLike | TypeFlags.ESSymbolLike), stringsOnly === keyofStringsOnly && !noIndexSignatures); + return shouldDeferIndexType(type) + ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, stringsOnly) + : type.flags & TypeFlags.Union + ? getIntersectionType( + map((type as UnionType).types, t => getIndexType(t, stringsOnly, noIndexSignatures)), + ) + : type.flags & TypeFlags.Intersection + ? getUnionType( + map((type as IntersectionType).types, t => getIndexType(t, stringsOnly, noIndexSignatures)), + ) + : getObjectFlags(type) & ObjectFlags.Mapped + ? getIndexTypeForMappedType(type as MappedType, stringsOnly, noIndexSignatures) + : type === wildcardType ? wildcardType + : type.flags & TypeFlags.Unknown ? neverType + : type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType + : getLiteralTypeFromProperties( + type, + (noIndexSignatures ? TypeFlags.StringLiteral : TypeFlags.StringLike) + | (stringsOnly ? 0 : TypeFlags.NumberLike | TypeFlags.ESSymbolLike), + stringsOnly === keyofStringsOnly && !noIndexSignatures, + ); } function getExtractStringType(type: Type) { @@ -15851,9 +20589,12 @@ namespace ts { function getTemplateLiteralType(texts: readonly string[], types: readonly Type[]): Type { const unionIndex = findIndex(types, t => !!(t.flags & (TypeFlags.Never | TypeFlags.Union))); if (unionIndex >= 0) { - return checkCrossProductUnion(types) ? - mapType(types[unionIndex], t => getTemplateLiteralType(texts, replaceElement(types, unionIndex, t))) : - errorType; + return checkCrossProductUnion(types) + ? mapType( + types[unionIndex], + t => getTemplateLiteralType(texts, replaceElement(types, unionIndex, t)), + ) + : errorType; } if (contains(types, wildcardType)) { return wildcardType; @@ -15918,11 +20659,11 @@ namespace ts { } function getTemplateStringForType(type: Type) { - return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value : - type.flags & TypeFlags.NumberLiteral ? "" + (type as NumberLiteralType).value : - type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((type as BigIntLiteralType).value) : - type.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) ? (type as IntrinsicType).intrinsicName : - undefined; + return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value + : type.flags & TypeFlags.NumberLiteral ? "" + (type as NumberLiteralType).value + : type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((type as BigIntLiteralType).value) + : type.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) ? (type as IntrinsicType).intrinsicName + : undefined; } function createTemplateLiteralType(texts: readonly string[], types: readonly Type[]) { @@ -15933,15 +20674,26 @@ namespace ts { } function getStringMappingType(symbol: Symbol, type: Type): Type { - return type.flags & (TypeFlags.Union | TypeFlags.Never) ? mapType(type, t => getStringMappingType(symbol, t)) : - type.flags & TypeFlags.StringLiteral ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) : - type.flags & TypeFlags.TemplateLiteral ? getTemplateLiteralType(...applyTemplateStringMapping(symbol, (type as TemplateLiteralType).texts, (type as TemplateLiteralType).types)) : + return type.flags & (TypeFlags.Union | TypeFlags.Never) + ? mapType(type, t => getStringMappingType(symbol, t)) + : type.flags & TypeFlags.StringLiteral + ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) + : type.flags & TypeFlags.TemplateLiteral + ? getTemplateLiteralType( + ...applyTemplateStringMapping( + symbol, + (type as TemplateLiteralType).texts, + (type as TemplateLiteralType).types, + ), + ) // Mapping> === Mapping - type.flags & TypeFlags.StringMapping && symbol === type.symbol ? type : - type.flags & (TypeFlags.Any | TypeFlags.String || type.flags & TypeFlags.StringMapping) || isGenericIndexType(type) ? getStringMappingTypeForGenericType(symbol, type) : + : type.flags & TypeFlags.StringMapping && symbol === type.symbol ? type + : type.flags & (TypeFlags.Any | TypeFlags.String || type.flags & TypeFlags.StringMapping) + || isGenericIndexType(type) ? getStringMappingTypeForGenericType(symbol, type) // This handles Mapping<`${number}`> and Mapping<`${bigint}`> - isPatternLiteralPlaceholderType(type) ? getStringMappingTypeForGenericType(symbol, getTemplateLiteralType(["", ""], [type])) : - type; + : isPatternLiteralPlaceholderType(type) + ? getStringMappingTypeForGenericType(symbol, getTemplateLiteralType(["", ""], [type])) + : type; } function applyStringMapping(symbol: Symbol, str: string) { @@ -15958,16 +20710,28 @@ namespace ts { return str; } - function applyTemplateStringMapping(symbol: Symbol, texts: readonly string[], types: readonly Type[]): [texts: readonly string[], types: readonly Type[]] { + function applyTemplateStringMapping( + symbol: Symbol, + texts: readonly string[], + types: readonly Type[], + ): [texts: readonly string[], types: readonly Type[]] { switch (intrinsicTypeKinds.get(symbol.escapedName as string)) { case IntrinsicTypeKind.Uppercase: return [texts.map(t => t.toUpperCase()), types.map(t => getStringMappingType(symbol, t))]; case IntrinsicTypeKind.Lowercase: return [texts.map(t => t.toLowerCase()), types.map(t => getStringMappingType(symbol, t))]; case IntrinsicTypeKind.Capitalize: - return [texts[0] === "" ? texts : [texts[0].charAt(0).toUpperCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types]; + return [ + texts[0] === "" ? texts + : [texts[0].charAt(0).toUpperCase() + texts[0].slice(1), ...texts.slice(1)], + texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types, + ]; case IntrinsicTypeKind.Uncapitalize: - return [texts[0] === "" ? texts : [texts[0].charAt(0).toLowerCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types]; + return [ + texts[0] === "" ? texts + : [texts[0].charAt(0).toLowerCase() + texts[0].slice(1), ...texts.slice(1)], + texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types, + ]; } return [texts, types]; } @@ -15988,7 +20752,13 @@ namespace ts { return result; } - function createIndexedAccessType(objectType: Type, indexType: Type, accessFlags: AccessFlags, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { + function createIndexedAccessType( + objectType: Type, + indexType: Type, + accessFlags: AccessFlags, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + ) { const type = createType(TypeFlags.IndexedAccess) as IndexedAccessType; type.objectType = objectType; type.indexType = indexType; @@ -16027,13 +20797,27 @@ namespace ts { return false; } - function getPropertyNameFromIndex(indexType: Type, accessNode: StringLiteral | Identifier | PrivateIdentifier | ObjectBindingPattern | ArrayBindingPattern | ComputedPropertyName | NumericLiteral | IndexedAccessTypeNode | ElementAccessExpression | SyntheticExpression | undefined) { - return isTypeUsableAsPropertyName(indexType) ? - getPropertyNameFromType(indexType) : - accessNode && isPropertyName(accessNode) ? + function getPropertyNameFromIndex( + indexType: Type, + accessNode: + | StringLiteral + | Identifier + | PrivateIdentifier + | ObjectBindingPattern + | ArrayBindingPattern + | ComputedPropertyName + | NumericLiteral + | IndexedAccessTypeNode + | ElementAccessExpression + | SyntheticExpression + | undefined, + ) { + return isTypeUsableAsPropertyName(indexType) + ? getPropertyNameFromType(indexType) + : accessNode && isPropertyName(accessNode) // late bound names are handled in the first branch, so here we only need to handle normal names - getPropertyNameForPropertyNameNode(accessNode) : - undefined; + ? getPropertyNameForPropertyNameNode(accessNode) + : undefined; } function isUncalledFunctionReference(node: Node, symbol: Symbol) { @@ -16042,14 +20826,32 @@ namespace ts { if (isCallLikeExpression(parent)) { return isCallOrNewExpression(parent) && isIdentifier(node) && hasMatchingArgument(parent, node); } - return every(symbol.declarations, d => !isFunctionLike(d) || !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated)); + return every( + symbol.declarations, + d => !isFunctionLike(d) || !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated), + ); } return true; } - function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { - const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; - const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined : getPropertyNameFromIndex(indexType, accessNode); + function getPropertyTypeForIndexType( + originalObjectType: Type, + objectType: Type, + indexType: Type, + fullIndexType: Type, + accessNode: + | ElementAccessExpression + | IndexedAccessTypeNode + | PropertyName + | BindingName + | SyntheticExpression + | undefined, + accessFlags: AccessFlags, + ) { + const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode + : undefined; + const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined + : getPropertyNameFromIndex(indexType, accessNode); if (propName !== undefined) { if (accessFlags & AccessFlags.Contextual) { @@ -16057,14 +20859,32 @@ namespace ts { } const prop = getPropertyOfType(objectType, propName); if (prop) { - if (accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations && isDeprecatedSymbol(prop) && isUncalledFunctionReference(accessNode, prop)) { - const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); + if ( + accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations + && isDeprecatedSymbol(prop) && isUncalledFunctionReference(accessNode, prop) + ) { + const deprecatedNode = accessExpression?.argumentExpression + ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string); } if (accessExpression) { - markPropertyAsReferenced(prop, accessExpression, isSelfTypeAccess(accessExpression.expression, objectType.symbol)); - if (isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression))) { - error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop)); + markPropertyAsReferenced( + prop, + accessExpression, + isSelfTypeAccess(accessExpression.expression, objectType.symbol), + ); + if ( + isAssignmentToReadonlyEntity( + accessExpression, + prop, + getAssignmentTargetKind(accessExpression), + ) + ) { + error( + accessExpression.argumentExpression, + Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, + symbolToString(prop), + ); return undefined; } if (accessFlags & AccessFlags.CacheSymbol) { @@ -16075,64 +20895,95 @@ namespace ts { } } const propType = getTypeOfSymbol(prop); - return accessExpression && getAssignmentTargetKind(accessExpression) !== AssignmentKind.Definite ? - getFlowTypeOfReference(accessExpression, propType) : - propType; + return accessExpression && getAssignmentTargetKind(accessExpression) !== AssignmentKind.Definite + ? getFlowTypeOfReference(accessExpression, propType) + : propType; } if (everyType(objectType, isTupleType) && isNumericLiteralName(propName)) { const index = +propName; - if (accessNode && everyType(objectType, t => !(t as TupleTypeReference).target.hasRestElement) && !(accessFlags & AccessFlags.NoTupleBoundsCheck)) { + if ( + accessNode && everyType(objectType, t => !(t as TupleTypeReference).target.hasRestElement) + && !(accessFlags & AccessFlags.NoTupleBoundsCheck) + ) { const indexNode = getIndexNodeForAccessExpression(accessNode); if (isTupleType(objectType)) { if (index < 0) { error(indexNode, Diagnostics.A_tuple_type_cannot_be_indexed_with_a_negative_value); return undefinedType; } - error(indexNode, Diagnostics.Tuple_type_0_of_length_1_has_no_element_at_index_2, typeToString(objectType), getTypeReferenceArity(objectType), unescapeLeadingUnderscores(propName)); + error( + indexNode, + Diagnostics.Tuple_type_0_of_length_1_has_no_element_at_index_2, + typeToString(objectType), + getTypeReferenceArity(objectType), + unescapeLeadingUnderscores(propName), + ); } else { - error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); + error( + indexNode, + Diagnostics.Property_0_does_not_exist_on_type_1, + unescapeLeadingUnderscores(propName), + typeToString(objectType), + ); } } if (index >= 0) { errorIfWritingToReadonlyIndex(getIndexInfoOfType(objectType, numberType)); return mapType(objectType, t => { const restType = getRestTypeOfTupleType(t as TupleTypeReference) || undefinedType; - return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([restType, undefinedType]) : restType; + return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([restType, undefinedType]) + : restType; }); } } } - if (!(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike)) { + if ( + !(indexType.flags & TypeFlags.Nullable) + && isTypeAssignableToKind( + indexType, + TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike, + ) + ) { if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) { return objectType; } // If no index signature is applicable, we default to the string index signature. In effect, this means the string // index signature applies even when accessing with a symbol-like type. - const indexInfo = getApplicableIndexInfo(objectType, indexType) || getIndexInfoOfType(objectType, stringType); + const indexInfo = getApplicableIndexInfo(objectType, indexType) + || getIndexInfoOfType(objectType, stringType); if (indexInfo) { if (accessFlags & AccessFlags.NoIndexSignatures && indexInfo.keyType !== numberType) { if (accessExpression) { - error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType)); + error( + accessExpression, + Diagnostics.Type_0_cannot_be_used_to_index_type_1, + typeToString(indexType), + typeToString(originalObjectType), + ); } return undefined; } - if (accessNode && indexInfo.keyType === stringType && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) { + if ( + accessNode && indexInfo.keyType === stringType + && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number) + ) { const indexNode = getIndexNodeForAccessExpression(accessNode); error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType)); - return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type; + return accessFlags & AccessFlags.IncludeUndefined + ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type; } errorIfWritingToReadonlyIndex(indexInfo); // When accessing an enum object with its own type, // e.g. E[E.A] for enum E { A }, undefined shouldn't // be included in the result type if ( - (accessFlags & AccessFlags.IncludeUndefined) && - !(objectType.symbol && - objectType.symbol.flags & (SymbolFlags.RegularEnum | SymbolFlags.ConstEnum) && - (indexType.symbol && - indexType.flags & TypeFlags.EnumLiteral && - getParentOfSymbol(indexType.symbol) === objectType.symbol)) + (accessFlags & AccessFlags.IncludeUndefined) + && !(objectType.symbol + && objectType.symbol.flags & (SymbolFlags.RegularEnum | SymbolFlags.ConstEnum) + && (indexType.symbol + && indexType.flags & TypeFlags.EnumLiteral + && getParentOfSymbol(indexType.symbol) === objectType.symbol)) ) { return getUnionType([indexInfo.type, undefinedType]); } @@ -16147,7 +20998,14 @@ namespace ts { if (accessExpression && !isConstEnumObjectType(objectType)) { if (isObjectLiteralType(objectType)) { if (noImplicitAny && indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { - diagnostics.add(createDiagnosticForNode(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType))); + diagnostics.add( + createDiagnosticForNode( + accessExpression, + Diagnostics.Property_0_does_not_exist_on_type_1, + (indexType as StringLiteralType).value, + typeToString(objectType), + ), + ); return undefinedType; } else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { @@ -16158,55 +21016,129 @@ namespace ts { } } - if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports!.has(propName) && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped)) { - error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); + if ( + objectType.symbol === globalThisSymbol && propName !== undefined + && globalThisSymbol.exports!.has(propName) + && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped) + ) { + error( + accessExpression, + Diagnostics.Property_0_does_not_exist_on_type_1, + unescapeLeadingUnderscores(propName), + typeToString(objectType), + ); } - else if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !(accessFlags & AccessFlags.SuppressNoImplicitAnyError)) { + else if ( + noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors + && !(accessFlags & AccessFlags.SuppressNoImplicitAnyError) + ) { if (propName !== undefined && typeHasStaticProperty(propName, objectType)) { const typeName = typeToString(objectType); - error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName as string, typeName, typeName + "[" + getTextOfNode(accessExpression.argumentExpression) + "]"); + error( + accessExpression, + Diagnostics + .Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, + propName as string, + typeName, + typeName + "[" + getTextOfNode(accessExpression.argumentExpression) + "]", + ); } else if (getIndexTypeOfType(objectType, numberType)) { - error(accessExpression.argumentExpression, Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number); + error( + accessExpression.argumentExpression, + Diagnostics + .Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number, + ); } else { let suggestion: string | undefined; - if (propName !== undefined && (suggestion = getSuggestionForNonexistentProperty(propName as string, objectType))) { + if ( + propName !== undefined + && (suggestion = getSuggestionForNonexistentProperty(propName as string, objectType)) + ) { if (suggestion !== undefined) { - error(accessExpression.argumentExpression, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName as string, typeToString(objectType), suggestion); + error( + accessExpression.argumentExpression, + Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, + propName as string, + typeToString(objectType), + suggestion, + ); } } else { - const suggestion = getSuggestionForNonexistentIndexSignature(objectType, accessExpression, indexType); + const suggestion = getSuggestionForNonexistentIndexSignature( + objectType, + accessExpression, + indexType, + ); if (suggestion !== undefined) { - error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, typeToString(objectType), suggestion); + error( + accessExpression, + Diagnostics + .Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, + typeToString(objectType), + suggestion, + ); } else { let errorInfo: DiagnosticMessageChain | undefined; if (indexType.flags & TypeFlags.EnumLiteral) { - errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + typeToString(indexType) + "]", typeToString(objectType)); + errorInfo = chainDiagnosticMessages( + /* details */ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + "[" + typeToString(indexType) + "]", + typeToString(objectType), + ); } else if (indexType.flags & TypeFlags.UniqueESSymbol) { - const symbolName = getFullyQualifiedName((indexType as UniqueESSymbolType).symbol, accessExpression); - errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + symbolName + "]", typeToString(objectType)); + const symbolName = getFullyQualifiedName( + (indexType as UniqueESSymbolType).symbol, + accessExpression, + ); + errorInfo = chainDiagnosticMessages( + /* details */ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + "[" + symbolName + "]", + typeToString(objectType), + ); } else if (indexType.flags & TypeFlags.StringLiteral) { - errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType)); + errorInfo = chainDiagnosticMessages( + /* details */ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + (indexType as StringLiteralType).value, + typeToString(objectType), + ); } else if (indexType.flags & TypeFlags.NumberLiteral) { - errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as NumberLiteralType).value, typeToString(objectType)); + errorInfo = chainDiagnosticMessages( + /* details */ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + (indexType as NumberLiteralType).value, + typeToString(objectType), + ); } else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { - errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.No_index_signature_with_a_parameter_of_type_0_was_found_on_type_1, typeToString(indexType), typeToString(objectType)); + errorInfo = chainDiagnosticMessages( + /* details */ undefined, + Diagnostics + .No_index_signature_with_a_parameter_of_type_0_was_found_on_type_1, + typeToString(indexType), + typeToString(objectType), + ); } errorInfo = chainDiagnosticMessages( errorInfo, - Diagnostics.Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1, + Diagnostics + .Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1, typeToString(fullIndexType), typeToString(objectType), ); - diagnostics.add(createDiagnosticForNodeFromMessageChain(accessExpression, errorInfo)); + diagnostics.add( + createDiagnosticForNodeFromMessageChain(accessExpression, errorInfo), + ); } } } @@ -16220,10 +21152,20 @@ namespace ts { if (accessNode) { const indexNode = getIndexNodeForAccessExpression(accessNode); if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { - error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, "" + (indexType as StringLiteralType | NumberLiteralType).value, typeToString(objectType)); + error( + indexNode, + Diagnostics.Property_0_does_not_exist_on_type_1, + "" + (indexType as StringLiteralType | NumberLiteralType).value, + typeToString(objectType), + ); } else if (indexType.flags & (TypeFlags.String | TypeFlags.Number)) { - error(indexNode, Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, typeToString(objectType), typeToString(indexType)); + error( + indexNode, + Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, + typeToString(objectType), + typeToString(indexType), + ); } else { error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType)); @@ -16235,26 +21177,43 @@ namespace ts { return undefined; function errorIfWritingToReadonlyIndex(indexInfo: IndexInfo | undefined): void { - if (indexInfo && indexInfo.isReadonly && accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) { - error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); + if ( + indexInfo && indexInfo.isReadonly && accessExpression + && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression)) + ) { + error( + accessExpression, + Diagnostics.Index_signature_in_type_0_only_permits_reading, + typeToString(objectType), + ); } } } - function getIndexNodeForAccessExpression(accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression) { - return accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode.argumentExpression : - accessNode.kind === SyntaxKind.IndexedAccessType ? accessNode.indexType : - accessNode.kind === SyntaxKind.ComputedPropertyName ? accessNode.expression : - accessNode; + function getIndexNodeForAccessExpression( + accessNode: + | ElementAccessExpression + | IndexedAccessTypeNode + | PropertyName + | BindingName + | SyntheticExpression, + ) { + return accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode.argumentExpression + : accessNode.kind === SyntaxKind.IndexedAccessType ? accessNode.indexType + : accessNode.kind === SyntaxKind.ComputedPropertyName ? accessNode.expression + : accessNode; } function isPatternLiteralPlaceholderType(type: Type): boolean { - return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || isPatternLiteralType(type); + return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) + || isPatternLiteralType(type); } function isPatternLiteralType(type: Type) { - return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) || - !!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type); + return !!(type.flags & TypeFlags.TemplateLiteral) + && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) + || !!(type.flags & TypeFlags.StringMapping) + && isPatternLiteralPlaceholderType((type as StringMappingType).type); } function isGenericType(type: Type): boolean { @@ -16272,35 +21231,52 @@ namespace ts { function getGenericObjectFlags(type: Type): ObjectFlags { if (type.flags & TypeFlags.UnionOrIntersection) { if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { - (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | - reduceLeft((type as UnionOrIntersectionType).types, (flags, t) => flags | getGenericObjectFlags(t), 0); + (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericTypeComputed + | reduceLeft( + (type as UnionOrIntersectionType).types, + (flags, t) => flags | getGenericObjectFlags(t), + 0, + ); } return (type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericType; } if (type.flags & TypeFlags.Substitution) { if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { - (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | - getGenericObjectFlags((type as SubstitutionType).baseType) | getGenericObjectFlags((type as SubstitutionType).constraint); + (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericTypeComputed + | getGenericObjectFlags((type as SubstitutionType).baseType) + | getGenericObjectFlags((type as SubstitutionType).constraint); } return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType; } - return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) | - (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); + return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) + || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) + | (type.flags + & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral + | TypeFlags.StringMapping) && !isPatternLiteralType(type) + ? ObjectFlags.IsGenericIndexType : 0); } function getSimplifiedType(type: Type, writing: boolean): Type { - return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) : - type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) : - type; + return type.flags & TypeFlags.IndexedAccess + ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) + : type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) + : type; } function distributeIndexOverObjectType(objectType: Type, indexType: Type, writing: boolean) { // (T | U)[K] -> T[K] | U[K] (reading) // (T | U)[K] -> T[K] & U[K] (writing) // (T & U)[K] -> T[K] & U[K] - if (objectType.flags & TypeFlags.Union || objectType.flags & TypeFlags.Intersection && !shouldDeferIndexType(objectType)) { - const types = map((objectType as UnionOrIntersectionType).types, t => getSimplifiedType(getIndexedAccessType(t, indexType), writing)); - return objectType.flags & TypeFlags.Intersection || writing ? getIntersectionType(types) : getUnionType(types); + if ( + objectType.flags & TypeFlags.Union + || objectType.flags & TypeFlags.Intersection && !shouldDeferIndexType(objectType) + ) { + const types = map( + (objectType as UnionOrIntersectionType).types, + t => getSimplifiedType(getIndexedAccessType(t, indexType), writing), + ); + return objectType.flags & TypeFlags.Intersection || writing ? getIntersectionType(types) + : getUnionType(types); } } @@ -16308,7 +21284,10 @@ namespace ts { // T[A | B] -> T[A] | T[B] (reading) // T[A | B] -> T[A] & T[B] (writing) if (indexType.flags & TypeFlags.Union) { - const types = map((indexType as UnionType).types, t => getSimplifiedType(getIndexedAccessType(objectType, t), writing)); + const types = map( + (indexType as UnionType).types, + t => getSimplifiedType(getIndexedAccessType(objectType, t), writing), + ); return writing ? getIntersectionType(types) : getUnionType(types); } } @@ -16349,7 +21328,12 @@ namespace ts { // fixed element. We simplify to either the combined type of all elements (when the index type // the actual number type) or to the combined type of all non-fixed elements. if (isGenericTupleType(objectType) && indexType.flags & TypeFlags.NumberLike) { - const elementType = getElementTypeOfSliceOfTupleType(objectType, indexType.flags & TypeFlags.Number ? 0 : objectType.target.fixedLength, /*endSkipCount*/ 0, writing); + const elementType = getElementTypeOfSliceOfTupleType( + objectType, + indexType.flags & TypeFlags.Number ? 0 : objectType.target.fixedLength, + /*endSkipCount*/ 0, + writing, + ); if (elementType) { return type[cache] = elementType; } @@ -16360,7 +21344,10 @@ namespace ts { if (isGenericMappedType(objectType)) { const nameType = getNameTypeFromMappedType(objectType); if (!nameType || isTypeAssignableTo(nameType, getTypeParameterFromMappedType(objectType))) { - return type[cache] = mapType(substituteIndexedMappedType(objectType, type.indexType), t => getSimplifiedType(t, writing)); + return type[cache] = mapType( + substituteIndexedMappedType(objectType, type.indexType), + t => getSimplifiedType(t, writing), + ); } } return type[cache] = type; @@ -16372,16 +21359,34 @@ namespace ts { const trueType = getTrueTypeFromConditionalType(type); const falseType = getFalseTypeFromConditionalType(type); // Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`. - if (falseType.flags & TypeFlags.Never && getActualTypeVariable(trueType) === getActualTypeVariable(checkType)) { - if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true + if ( + falseType.flags & TypeFlags.Never + && getActualTypeVariable(trueType) === getActualTypeVariable(checkType) + ) { + if ( + checkType.flags & TypeFlags.Any + || isTypeAssignableTo( + getRestrictiveInstantiation(checkType), + getRestrictiveInstantiation(extendsType), + ) + ) { // Always true return getSimplifiedType(trueType, writing); } else if (isIntersectionEmpty(checkType, extendsType)) { // Always false return neverType; } } - else if (trueType.flags & TypeFlags.Never && getActualTypeVariable(falseType) === getActualTypeVariable(checkType)) { - if (!(checkType.flags & TypeFlags.Any) && isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true + else if ( + trueType.flags & TypeFlags.Never + && getActualTypeVariable(falseType) === getActualTypeVariable(checkType) + ) { + if ( + !(checkType.flags & TypeFlags.Any) + && isTypeAssignableTo( + getRestrictiveInstantiation(checkType), + getRestrictiveInstantiation(extendsType), + ) + ) { // Always true return neverType; } else if (checkType.flags & TypeFlags.Any || isIntersectionEmpty(checkType, extendsType)) { // Always false @@ -16401,11 +21406,33 @@ namespace ts { function substituteIndexedMappedType(objectType: MappedType, index: Type) { const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [index]); const templateMapper = combineTypeMappers(objectType.mapper, mapper); - return instantiateType(getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), templateMapper); + return instantiateType( + getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), + templateMapper, + ); } - function getIndexedAccessType(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { - return getIndexedAccessTypeOrUndefined(objectType, indexType, accessFlags, accessNode, aliasSymbol, aliasTypeArguments) || (accessNode ? errorType : unknownType); + function getIndexedAccessType( + objectType: Type, + indexType: Type, + accessFlags = AccessFlags.None, + accessNode?: + | ElementAccessExpression + | IndexedAccessTypeNode + | PropertyName + | BindingName + | SyntheticExpression, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { + return getIndexedAccessTypeOrUndefined( + objectType, + indexType, + accessFlags, + accessNode, + aliasSymbol, + aliasTypeArguments, + ) || (accessNode ? errorType : unknownType); } function indexTypeLessThan(indexType: Type, limit: number) { @@ -16421,18 +21448,35 @@ namespace ts { }); } - function getIndexedAccessTypeOrUndefined(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type | undefined { + function getIndexedAccessTypeOrUndefined( + objectType: Type, + indexType: Type, + accessFlags = AccessFlags.None, + accessNode?: + | ElementAccessExpression + | IndexedAccessTypeNode + | PropertyName + | BindingName + | SyntheticExpression, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type | undefined { if (objectType === wildcardType || indexType === wildcardType) { return wildcardType; } // If the object type has a string index signature and no other members we know that the result will // always be the type of that index signature and we can simplify accordingly. - if (isStringIndexSignatureOnlyType(objectType) && !(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) { + if ( + isStringIndexSignatureOnlyType(objectType) && !(indexType.flags & TypeFlags.Nullable) + && isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number) + ) { indexType = stringType; } // In noUncheckedIndexedAccess mode, indexed access operations that occur in an expression in a read position and resolve to // an index signature have 'undefined' included in their type. - if (compilerOptions.noUncheckedIndexedAccess && accessFlags & AccessFlags.ExpressionPosition) accessFlags |= AccessFlags.IncludeUndefined; + if (compilerOptions.noUncheckedIndexedAccess && accessFlags & AccessFlags.ExpressionPosition) { + accessFlags |= AccessFlags.IncludeUndefined; + } // If the index type is generic, or if the object type is generic and doesn't originate in an expression and // the operation isn't exclusively indexing the fixed (non-variadic) portion of a tuple type, we are performing // a higher-order index access where we cannot meaningfully access the properties of the object type. Note that @@ -16440,19 +21484,30 @@ namespace ts { // preserve backwards compatibility. For example, an element access 'this["foo"]' has always been resolved // eagerly using the constraint type of 'this' at the given location. if ( - isGenericIndexType(indexType) || (accessNode && accessNode.kind !== SyntaxKind.IndexedAccessType ? - isGenericTupleType(objectType) && !indexTypeLessThan(indexType, objectType.target.fixedLength) : - isGenericObjectType(objectType) && !(isTupleType(objectType) && indexTypeLessThan(indexType, objectType.target.fixedLength))) + isGenericIndexType(indexType) || (accessNode && accessNode.kind !== SyntaxKind.IndexedAccessType + ? isGenericTupleType(objectType) && !indexTypeLessThan(indexType, objectType.target.fixedLength) + : isGenericObjectType(objectType) + && !(isTupleType(objectType) && indexTypeLessThan(indexType, objectType.target.fixedLength))) ) { if (objectType.flags & TypeFlags.AnyOrUnknown) { return objectType; } // Defer the operation by creating an indexed access type. const persistentAccessFlags = accessFlags & AccessFlags.Persistent; - const id = objectType.id + "," + indexType.id + "," + persistentAccessFlags + getAliasId(aliasSymbol, aliasTypeArguments); + const id = objectType.id + "," + indexType.id + "," + persistentAccessFlags + + getAliasId(aliasSymbol, aliasTypeArguments); let type = indexedAccessTypes.get(id); if (!type) { - indexedAccessTypes.set(id, type = createIndexedAccessType(objectType, indexType, persistentAccessFlags, aliasSymbol, aliasTypeArguments)); + indexedAccessTypes.set( + id, + type = createIndexedAccessType( + objectType, + indexType, + persistentAccessFlags, + aliasSymbol, + aliasTypeArguments, + ), + ); } return type; @@ -16465,7 +21520,14 @@ namespace ts { const propTypes: Type[] = []; let wasMissingProp = false; for (const t of (indexType as UnionType).types) { - const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, indexType, accessNode, accessFlags | (wasMissingProp ? AccessFlags.SuppressNoImplicitAnyError : 0)); + const propType = getPropertyTypeForIndexType( + objectType, + apparentObjectType, + t, + indexType, + accessNode, + accessFlags | (wasMissingProp ? AccessFlags.SuppressNoImplicitAnyError : 0), + ); if (propType) { propTypes.push(propType); } @@ -16485,7 +21547,14 @@ namespace ts { ? getIntersectionType(propTypes, aliasSymbol, aliasTypeArguments) : getUnionType(propTypes, UnionReduction.Literal, aliasSymbol, aliasTypeArguments); } - return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated); + return getPropertyTypeForIndexType( + objectType, + apparentObjectType, + indexType, + indexType, + accessNode, + accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated, + ); } function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) { @@ -16494,7 +21563,14 @@ namespace ts { const objectType = getTypeFromTypeNode(node.objectType); const indexType = getTypeFromTypeNode(node.indexType); const potentialAlias = getAliasSymbolForTypeNode(node); - links.resolvedType = getIndexedAccessType(objectType, indexType, AccessFlags.None, node, potentialAlias, getTypeArgumentsForAliasSymbol(potentialAlias)); + links.resolvedType = getIndexedAccessType( + objectType, + indexType, + AccessFlags.None, + node, + potentialAlias, + getTypeArgumentsForAliasSymbol(potentialAlias), + ); } return links.resolvedType; } @@ -16520,30 +21596,36 @@ namespace ts { } if ( type.flags & TypeFlags.IndexedAccess && ( - (type as IndexedAccessType).objectType.flags & TypeFlags.Substitution || - (type as IndexedAccessType).indexType.flags & TypeFlags.Substitution + (type as IndexedAccessType).objectType.flags & TypeFlags.Substitution + || (type as IndexedAccessType).indexType.flags & TypeFlags.Substitution ) ) { - return getIndexedAccessType(getActualTypeVariable((type as IndexedAccessType).objectType), getActualTypeVariable((type as IndexedAccessType).indexType)); + return getIndexedAccessType( + getActualTypeVariable((type as IndexedAccessType).objectType), + getActualTypeVariable((type as IndexedAccessType).indexType), + ); } return type; } function maybeCloneTypeParameter(p: TypeParameter) { const constraint = getConstraintOfTypeParameter(p); - return constraint && (isGenericObjectType(constraint) || isGenericIndexType(constraint)) ? cloneTypeParameter(p) : p; + return constraint && (isGenericObjectType(constraint) || isGenericIndexType(constraint)) + ? cloneTypeParameter(p) : p; } function isTypicalNondistributiveConditional(root: ConditionalRoot) { - return !root.isDistributive && isSingletonTupleType(root.node.checkType) && isSingletonTupleType(root.node.extendsType); + return !root.isDistributive && isSingletonTupleType(root.node.checkType) + && isSingletonTupleType(root.node.extendsType); } function isSingletonTupleType(node: TypeNode) { - return isTupleTypeNode(node) && - length(node.elements) === 1 && - !isOptionalTypeNode(node.elements[0]) && - !isRestTypeNode(node.elements[0]) && - !(isNamedTupleMember(node.elements[0]) && (node.elements[0].questionToken || node.elements[0].dotDotDotToken)); + return isTupleTypeNode(node) + && length(node.elements) === 1 + && !isOptionalTypeNode(node.elements[0]) + && !isRestTypeNode(node.elements[0]) + && !(isNamedTupleMember(node.elements[0]) + && (node.elements[0].questionToken || node.elements[0].dotDotDotToken)); } /** @@ -16555,7 +21637,12 @@ namespace ts { return isTypicalNondistributiveConditional(root) && isTupleType(type) ? getTypeArguments(type)[0] : type; } - function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getConditionalType( + root: ConditionalRoot, + mapper: TypeMapper | undefined, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { let result; let extraTypes: Type[] | undefined; let tailCount = 0; @@ -16571,9 +21658,15 @@ namespace ts { break; } const isUnwrapped = isTypicalNondistributiveConditional(root); - const checkType = instantiateType(unwrapNondistributiveConditionalTuple(root, getActualTypeVariable(root.checkType)), mapper); + const checkType = instantiateType( + unwrapNondistributiveConditionalTuple(root, getActualTypeVariable(root.checkType)), + mapper, + ); const checkTypeInstantiable = isGenericType(checkType); - const extendsType = instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), mapper); + const extendsType = instantiateType( + unwrapNondistributiveConditionalTuple(root, root.extendsType), + mapper, + ); if (checkType === wildcardType || extendsType === wildcardType) { return wildcardType; } @@ -16597,7 +21690,8 @@ namespace ts { // * The mapper that maps the old root type parameter to the clone (`freshMapper`) // * The mapper that maps the clone to its inference result (`context.mapper`) const freshParams = sameMap(root.inferTypeParameters, maybeCloneTypeParameter); - const freshMapper = freshParams !== root.inferTypeParameters ? createTypeMapper(root.inferTypeParameters, freshParams) : undefined; + const freshMapper = freshParams !== root.inferTypeParameters + ? createTypeMapper(root.inferTypeParameters, freshParams) : undefined; const context = createInferenceContext(freshParams, /*signature*/ undefined, InferenceFlags.None); if (freshMapper) { const freshCombinedMapper = combineTypeMappers(mapper, freshMapper); @@ -16611,7 +21705,12 @@ namespace ts { // We don't want inferences from constraints as they may cause us to eagerly resolve the // conditional type instead of deferring resolution. Also, we always want strict function // types rules (i.e. proper contravariance) for inferences. - inferTypes(context.inferences, checkType, instantiateType(extendsType, freshMapper), InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); + inferTypes( + context.inferences, + checkType, + instantiateType(extendsType, freshMapper), + InferencePriority.NoConstraints | InferencePriority.AlwaysStrict, + ); } const innerMapper = combineTypeMappers(freshMapper, context.mapper); // It's possible for 'infer T' type paramteters to be given uninstantiated constraints when the @@ -16620,24 +21719,38 @@ namespace ts { combinedMapper = mapper ? combineTypeMappers(innerMapper, mapper) : innerMapper; } // Instantiate the extends type including inferences for 'infer T' type parameters - const inferredExtendsType = combinedMapper ? instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), combinedMapper) : extendsType; + const inferredExtendsType = combinedMapper + ? instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), combinedMapper) + : extendsType; // We attempt to resolve the conditional type only when the check and extends types are non-generic if (!checkTypeInstantiable && !isGenericType(inferredExtendsType)) { // Return falseType for a definitely false extends check. We check an instantiations of the two // types with type parameters mapped to the wildcard type, the most permissive instantiations // possible (the wildcard type is assignable to and from all types). If those are not related, // then no instantiations will be and we can just return the false branch type. - if (!(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && ((checkType.flags & TypeFlags.Any && !isUnwrapped) || !isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType)))) { + if ( + !(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) + && ((checkType.flags & TypeFlags.Any && !isUnwrapped) + || !isTypeAssignableTo( + getPermissiveInstantiation(checkType), + getPermissiveInstantiation(inferredExtendsType), + )) + ) { // Return union of trueType and falseType for 'any' since it matches anything if (checkType.flags & TypeFlags.Any && !isUnwrapped) { - (extraTypes || (extraTypes = [])).push(instantiateType(getTypeFromTypeNode(root.node.trueType), combinedMapper || mapper)); + (extraTypes || (extraTypes = [])).push( + instantiateType(getTypeFromTypeNode(root.node.trueType), combinedMapper || mapper), + ); } // If falseType is an immediately nested conditional type that isn't distributive or has an // identical checkType, switch to that type and loop. const falseType = getTypeFromTypeNode(root.node.falseType); if (falseType.flags & TypeFlags.Conditional) { const newRoot = (falseType as ConditionalType).root; - if (newRoot.node.parent === root.node && (!newRoot.isDistributive || newRoot.checkType === root.checkType)) { + if ( + newRoot.node.parent === root.node + && (!newRoot.isDistributive || newRoot.checkType === root.checkType) + ) { root = newRoot; continue; } @@ -16653,7 +21766,13 @@ namespace ts { // that has no constraint. This ensures that, for example, the type // type Foo = T extends { x: string } ? string : number // doesn't immediately resolve to 'string' instead of being deferred. - if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) { + if ( + inferredExtendsType.flags & TypeFlags.AnyOrUnknown + || isTypeAssignableTo( + getRestrictiveInstantiation(checkType), + getRestrictiveInstantiation(inferredExtendsType), + ) + ) { const trueType = getTypeFromTypeNode(root.node.trueType); const trueMapper = combinedMapper || mapper; if (canTailRecurse(trueType, trueMapper)) { @@ -16671,7 +21790,8 @@ namespace ts { result.mapper = mapper; result.combinedMapper = combinedMapper; result.aliasSymbol = aliasSymbol || root.aliasSymbol; - result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217 + result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217 break; } return extraTypes ? getUnionType(append(extraTypes, result)) : result; @@ -16686,8 +21806,12 @@ namespace ts { const typeParamMapper = combineTypeMappers((newType as ConditionalType).mapper, newMapper); const typeArguments = map(newRoot.outerTypeParameters, t => getMappedType(t, typeParamMapper)); const newRootMapper = createTypeMapper(newRoot.outerTypeParameters, typeArguments); - const newCheckType = newRoot.isDistributive ? getMappedType(newRoot.checkType, newRootMapper) : undefined; - if (!newCheckType || newCheckType === newRoot.checkType || !(newCheckType.flags & (TypeFlags.Union | TypeFlags.Never))) { + const newCheckType = newRoot.isDistributive ? getMappedType(newRoot.checkType, newRootMapper) + : undefined; + if ( + !newCheckType || newCheckType === newRoot.checkType + || !(newCheckType.flags & (TypeFlags.Union | TypeFlags.Never)) + ) { root = newRoot; mapper = newRootMapper; aliasSymbol = undefined; @@ -16704,15 +21828,23 @@ namespace ts { } function getTrueTypeFromConditionalType(type: ConditionalType) { - return type.resolvedTrueType || (type.resolvedTrueType = instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.mapper)); + return type.resolvedTrueType + || (type.resolvedTrueType = instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.mapper)); } function getFalseTypeFromConditionalType(type: ConditionalType) { - return type.resolvedFalseType || (type.resolvedFalseType = instantiateType(getTypeFromTypeNode(type.root.node.falseType), type.mapper)); + return type.resolvedFalseType + || (type.resolvedFalseType = instantiateType( + getTypeFromTypeNode(type.root.node.falseType), + type.mapper, + )); } function getInferredTrueTypeFromConditionalType(type: ConditionalType) { - return type.resolvedInferredTrueType || (type.resolvedInferredTrueType = type.combinedMapper ? instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.combinedMapper) : getTrueTypeFromConditionalType(type)); + return type.resolvedInferredTrueType + || (type.resolvedInferredTrueType = type.combinedMapper + ? instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.combinedMapper) + : getTrueTypeFromConditionalType(type)); } function getInferTypeParameters(node: ConditionalTypeNode): TypeParameter[] | undefined { @@ -16729,8 +21861,8 @@ namespace ts { function isDistributionDependent(root: ConditionalRoot) { return root.isDistributive && ( - isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.trueType) || - isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.falseType) + isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.trueType) + || isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.falseType) ); } @@ -16741,7 +21873,8 @@ namespace ts { const aliasSymbol = getAliasSymbolForTypeNode(node); const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true); - const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, node)); + const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters + : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, node)); const root: ConditionalRoot = { node, checkType, @@ -16792,7 +21925,8 @@ namespace ts { links.resolvedSymbol = unknownSymbol; return links.resolvedType = errorType; } - const targetMeaning = node.isTypeOf ? SymbolFlags.Value : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type : SymbolFlags.Type; + const targetMeaning = node.isTypeOf ? SymbolFlags.Value + : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type : SymbolFlags.Type; // TODO: Future work: support unions/generics/whatever via a deferred import-type const innerModuleSymbol = resolveExternalModuleName(node, node.argument.literal); if (!innerModuleSymbol) { @@ -16812,12 +21946,23 @@ namespace ts { // the `exports` lookup process that only looks up namespace members which is used for most type references const mergedResolvedSymbol = getMergedSymbol(resolveSymbol(currentNamespace)); const symbolFromVariable = node.isTypeOf || isInJSFile(node) && isExportEquals - ? getPropertyOfType(getTypeOfSymbol(mergedResolvedSymbol), current.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ true) + ? getPropertyOfType( + getTypeOfSymbol(mergedResolvedSymbol), + current.escapedText, + /*skipObjectFunctionPropertyAugment*/ false, + /*includeTypeOnlyMembers*/ true, + ) : undefined; - const symbolFromModule = node.isTypeOf ? undefined : getSymbol(getExportsOfSymbol(mergedResolvedSymbol), current.escapedText, meaning); + const symbolFromModule = node.isTypeOf ? undefined + : getSymbol(getExportsOfSymbol(mergedResolvedSymbol), current.escapedText, meaning); const next = symbolFromModule ?? symbolFromVariable; if (!next) { - error(current, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(currentNamespace), declarationNameToString(current)); + error( + current, + Diagnostics.Namespace_0_has_no_exported_member_1, + getFullyQualifiedName(currentNamespace), + declarationNameToString(current), + ); return links.resolvedType = errorType; } getNodeLinks(current).resolvedSymbol = next; @@ -16833,7 +21978,8 @@ namespace ts { else { const errorMessage = targetMeaning === SymbolFlags.Value ? Diagnostics.Module_0_does_not_refer_to_a_value_but_is_used_as_a_value_here - : Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0; + : Diagnostics + .Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0; error(node, errorMessage, node.argument.literal.text); @@ -16879,7 +22025,10 @@ namespace ts { function getAliasSymbolForTypeNode(node: Node) { let host = node.parent; - while (isParenthesizedTypeNode(host) || isJSDocTypeExpression(host) || isTypeOperatorNode(host) && host.operator === SyntaxKind.ReadonlyKeyword) { + while ( + isParenthesizedTypeNode(host) || isJSDocTypeExpression(host) + || isTypeOperatorNode(host) && host.operator === SyntaxKind.ReadonlyKeyword + ) { host = host.parent; } return isTypeAlias(host) ? getSymbolOfNode(host) : undefined; @@ -16894,7 +22043,11 @@ namespace ts { } function isEmptyObjectTypeOrSpreadsIntoEmptyObject(type: Type) { - return isEmptyObjectType(type) || !!(type.flags & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)); + return isEmptyObjectType(type) + || !!(type.flags + & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike + | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive + | TypeFlags.Index)); } function tryMergeUnionOfObjectTypeAndEmptyObject(type: Type, readonly: boolean): Type { @@ -16908,7 +22061,10 @@ namespace ts { if (!firstType) { return type; } - const secondType = find((type as UnionType).types, t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); + const secondType = find( + (type as UnionType).types, + t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t), + ); if (secondType) { return type; } @@ -16918,21 +22074,35 @@ namespace ts { // gets the type as if it had been spread, but where everything in the spread is made optional const members = createSymbolTable(); for (const prop of getPropertiesOfType(type)) { - if (getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) { + if ( + getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected) + ) { // do nothing, skip privates } else if (isSpreadableProperty(prop)) { - const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); + const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor + && !(prop.flags & SymbolFlags.GetAccessor); const flags = SymbolFlags.Property | SymbolFlags.Optional; - const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0)); - result.type = isSetonlyAccessor ? undefinedType : addOptionality(getTypeOfSymbol(prop), /*isProperty*/ true); + const result = createSymbol( + flags, + prop.escapedName, + getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0), + ); + result.type = isSetonlyAccessor ? undefinedType + : addOptionality(getTypeOfSymbol(prop), /*isProperty*/ true); result.declarations = prop.declarations; result.nameType = getSymbolLinks(prop).nameType; result.syntheticOrigin = prop; members.set(prop.escapedName, result); } } - const spread = createAnonymousType(type.symbol, members, emptyArray, emptyArray, getIndexInfosOfType(type)); + const spread = createAnonymousType( + type.symbol, + members, + emptyArray, + emptyArray, + getIndexInfosOfType(type), + ); spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; return spread; } @@ -16943,7 +22113,13 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, objectFlags: ObjectFlags, readonly: boolean): Type { + function getSpreadType( + left: Type, + right: Type, + symbol: Symbol | undefined, + objectFlags: ObjectFlags, + readonly: boolean, + ): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -16968,7 +22144,11 @@ namespace ts { ? mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly)) : errorType; } - if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { + if ( + right.flags + & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike + | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index) + ) { return left; } @@ -16983,7 +22163,11 @@ namespace ts { const types = (left as IntersectionType).types; const lastLeft = types[types.length - 1]; if (isNonGenericObjectType(lastLeft) && isNonGenericObjectType(right)) { - return getIntersectionType(concatenate(types.slice(0, types.length - 1), [getSpreadType(lastLeft, right, symbol, objectFlags, readonly)])); + return getIntersectionType( + concatenate(types.slice(0, types.length - 1), [ + getSpreadType(lastLeft, right, symbol, objectFlags, readonly), + ]), + ); } } return getIntersectionType([left, right]); @@ -16991,10 +22175,13 @@ namespace ts { const members = createSymbolTable(); const skippedPrivateMembers = new Set<__String>(); - const indexInfos = left === emptyObjectType ? getIndexInfosOfType(right) : getUnionIndexInfos([left, right]); + const indexInfos = left === emptyObjectType ? getIndexInfosOfType(right) + : getUnionIndexInfos([left, right]); for (const rightProp of getPropertiesOfType(right)) { - if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) { + if ( + getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected) + ) { skippedPrivateMembers.add(rightProp.escapedName); } else if (isSpreadableProperty(rightProp)) { @@ -17013,7 +22200,10 @@ namespace ts { const declarations = concatenate(leftProp.declarations, rightProp.declarations); const flags = SymbolFlags.Property | (leftProp.flags & SymbolFlags.Optional); const result = createSymbol(flags, leftProp.escapedName); - result.type = getUnionType([getTypeOfSymbol(leftProp), removeMissingOrUndefinedType(rightType)], UnionReduction.Subtype); + result.type = getUnionType( + [getTypeOfSymbol(leftProp), removeMissingOrUndefinedType(rightType)], + UnionReduction.Subtype, + ); result.leftSpread = leftProp; result.rightSpread = rightProp; result.declarations = declarations; @@ -17026,16 +22216,23 @@ namespace ts { } } - const spread = createAnonymousType(symbol, members, emptyArray, emptyArray, sameMap(indexInfos, info => getIndexInfoWithReadonly(info, readonly))); - spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral | ObjectFlags.ContainsSpread | objectFlags; + const spread = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + sameMap(indexInfos, info => getIndexInfoWithReadonly(info, readonly)), + ); + spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral + | ObjectFlags.ContainsSpread | objectFlags; return spread; } /** We approximate own properties as non-methods plus methods that are inside the object literal */ function isSpreadableProperty(prop: Symbol): boolean { - return !some(prop.declarations, isPrivateIdentifierClassElementDeclaration) && - (!(prop.flags & (SymbolFlags.Method | SymbolFlags.GetAccessor | SymbolFlags.SetAccessor)) || - !prop.declarations?.some(decl => isClassLike(decl.parent))); + return !some(prop.declarations, isPrivateIdentifierClassElementDeclaration) + && (!(prop.flags & (SymbolFlags.Method | SymbolFlags.GetAccessor | SymbolFlags.SetAccessor)) + || !prop.declarations?.some(decl => isClassLike(decl.parent))); } function getSpreadSymbol(prop: Symbol, readonly: boolean) { @@ -17044,7 +22241,11 @@ namespace ts { return prop; } const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional); - const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0)); + const result = createSymbol( + flags, + prop.escapedName, + getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0), + ); result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop); result.declarations = prop.declarations; result.nameType = getSymbolLinks(prop).nameType; @@ -17053,10 +22254,16 @@ namespace ts { } function getIndexInfoWithReadonly(info: IndexInfo, readonly: boolean) { - return info.isReadonly !== readonly ? createIndexInfo(info.keyType, info.type, readonly, info.declaration) : info; + return info.isReadonly !== readonly ? createIndexInfo(info.keyType, info.type, readonly, info.declaration) + : info; } - function createLiteralType(flags: TypeFlags, value: string | number | PseudoBigInt, symbol?: Symbol, regularType?: LiteralType) { + function createLiteralType( + flags: TypeFlags, + value: string | number | PseudoBigInt, + symbol?: Symbol, + regularType?: LiteralType, + ) { const type = createType(flags) as LiteralType; type.symbol = symbol!; type.value = value; @@ -17067,7 +22274,12 @@ namespace ts { function getFreshTypeOfLiteralType(type: Type): Type { if (type.flags & TypeFlags.Literal) { if (!(type as LiteralType).freshType) { - const freshType = createLiteralType(type.flags, (type as LiteralType).value, (type as LiteralType).symbol, type as LiteralType); + const freshType = createLiteralType( + type.flags, + (type as LiteralType).value, + (type as LiteralType).symbol, + type as LiteralType, + ); freshType.freshType = freshType; (type as LiteralType).freshType = freshType; } @@ -17077,9 +22289,11 @@ namespace ts { } function getRegularTypeOfLiteralType(type: Type): Type { - return type.flags & TypeFlags.Literal ? (type as LiteralType).regularType : - type.flags & TypeFlags.Union ? ((type as UnionType).regularType || ((type as UnionType).regularType = mapType(type, getRegularTypeOfLiteralType) as UnionType)) : - type; + return type.flags & TypeFlags.Literal ? (type as LiteralType).regularType + : type.flags & TypeFlags.Union + ? ((type as UnionType).regularType + || ((type as UnionType).regularType = mapType(type, getRegularTypeOfLiteralType) as UnionType)) + : type; } function isFreshLiteralType(type: Type) { @@ -17088,30 +22302,43 @@ namespace ts { function getStringLiteralType(value: string): StringLiteralType { let type; - return stringLiteralTypes.get(value) || - (stringLiteralTypes.set(value, type = createLiteralType(TypeFlags.StringLiteral, value) as StringLiteralType), type); + return stringLiteralTypes.get(value) + || (stringLiteralTypes.set( + value, + type = createLiteralType(TypeFlags.StringLiteral, value) as StringLiteralType, + ), + type); } function getNumberLiteralType(value: number): NumberLiteralType { let type; - return numberLiteralTypes.get(value) || - (numberLiteralTypes.set(value, type = createLiteralType(TypeFlags.NumberLiteral, value) as NumberLiteralType), type); + return numberLiteralTypes.get(value) + || (numberLiteralTypes.set( + value, + type = createLiteralType(TypeFlags.NumberLiteral, value) as NumberLiteralType, + ), + type); } function getBigIntLiteralType(value: PseudoBigInt): BigIntLiteralType { let type; const key = pseudoBigIntToString(value); - return bigIntLiteralTypes.get(key) || - (bigIntLiteralTypes.set(key, type = createLiteralType(TypeFlags.BigIntLiteral, value) as BigIntLiteralType), type); + return bigIntLiteralTypes.get(key) + || (bigIntLiteralTypes.set( + key, + type = createLiteralType(TypeFlags.BigIntLiteral, value) as BigIntLiteralType, + ), + type); } function getEnumLiteralType(value: string | number, enumId: number, symbol: Symbol): LiteralType { let type; const qualifier = typeof value === "string" ? "@" : "#"; const key = enumId + qualifier + value; - const flags = TypeFlags.EnumLiteral | (typeof value === "string" ? TypeFlags.StringLiteral : TypeFlags.NumberLiteral); - return enumLiteralTypes.get(key) || - (enumLiteralTypes.set(key, type = createLiteralType(flags, value, symbol)), type); + const flags = TypeFlags.EnumLiteral + | (typeof value === "string" ? TypeFlags.StringLiteral : TypeFlags.NumberLiteral); + return enumLiteralTypes.get(key) + || (enumLiteralTypes.set(key, type = createLiteralType(flags, value, symbol)), type); } function getTypeFromLiteralTypeNode(node: LiteralTypeNode): Type { @@ -17134,7 +22361,8 @@ namespace ts { function getESSymbolLikeTypeForNode(node: Node) { if (isValidESSymbolDeclaration(node)) { - const symbol = isCommonJsExportPropertyAssignment(node) ? getSymbolOfNode((node as BinaryExpression).left) : getSymbolOfNode(node); + const symbol = isCommonJsExportPropertyAssignment(node) + ? getSymbolOfNode((node as BinaryExpression).left) : getSymbolOfNode(node); if (symbol) { const links = getSymbolLinks(symbol); return links.uniqueESSymbolType || (links.uniqueESSymbolType = createUniqueESSymbolType(symbol)); @@ -17148,21 +22376,29 @@ namespace ts { const parent = container && container.parent; if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) { if ( - !isStatic(container) && - (!isConstructorDeclaration(container) || isNodeDescendantOf(node, container.body)) + !isStatic(container) + && (!isConstructorDeclaration(container) || isNodeDescendantOf(node, container.body)) ) { - return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent as ClassLikeDeclaration | InterfaceDeclaration)).thisType!; + return getDeclaredTypeOfClassOrInterface( + getSymbolOfNode(parent as ClassLikeDeclaration | InterfaceDeclaration), + ).thisType!; } } // inside x.prototype = { ... } - if (parent && isObjectLiteralExpression(parent) && isBinaryExpression(parent.parent) && getAssignmentDeclarationKind(parent.parent) === AssignmentDeclarationKind.Prototype) { + if ( + parent && isObjectLiteralExpression(parent) && isBinaryExpression(parent.parent) + && getAssignmentDeclarationKind(parent.parent) === AssignmentDeclarationKind.Prototype + ) { return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent.parent.left)!.parent!).thisType!; } // /** @return {this} */ // x.prototype.m = function() { ... } const host = node.flags & NodeFlags.JSDoc ? getHostSignatureFromJSDoc(node) : undefined; - if (host && isFunctionExpression(host) && isBinaryExpression(host.parent) && getAssignmentDeclarationKind(host.parent) === AssignmentDeclarationKind.PrototypeProperty) { + if ( + host && isFunctionExpression(host) && isBinaryExpression(host.parent) + && getAssignmentDeclarationKind(host.parent) === AssignmentDeclarationKind.PrototypeProperty + ) { return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(host.parent.left)!.parent!).thisType!; } // inside constructor function C() { ... } @@ -17192,7 +22428,10 @@ namespace ts { case SyntaxKind.TupleType: if ((node as TupleTypeNode).elements.length === 1) { node = (node as TupleTypeNode).elements[0]; - if (node.kind === SyntaxKind.RestType || node.kind === SyntaxKind.NamedTupleMember && (node as NamedTupleMember).dotDotDotToken) { + if ( + node.kind === SyntaxKind.RestType + || node.kind === SyntaxKind.NamedTupleMember && (node as NamedTupleMember).dotDotDotToken + ) { return getArrayElementTypeNode((node as RestTypeNode | NamedTupleMember).type); } } @@ -17205,8 +22444,8 @@ namespace ts { function getTypeFromNamedTupleTypeNode(node: NamedTupleMember): Type { const links = getNodeLinks(node); - return links.resolvedType || (links.resolvedType = node.dotDotDotToken ? getTypeFromRestTypeNode(node) : - addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true, !!node.questionToken)); + return links.resolvedType || (links.resolvedType = node.dotDotDotToken ? getTypeFromRestTypeNode(node) + : addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true, !!node.questionToken)); } function getTypeFromTypeNode(node: TypeNode): Type { @@ -17276,7 +22515,13 @@ namespace ts { case SyntaxKind.ParenthesizedType: case SyntaxKind.JSDocNonNullableType: case SyntaxKind.JSDocTypeExpression: - return getTypeFromTypeNode((node as ParenthesizedTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression | NamedTupleMember).type); + return getTypeFromTypeNode( + (node as + | ParenthesizedTypeNode + | JSDocTypeReferencingNode + | JSDocTypeExpression + | NamedTupleMember).type, + ); case SyntaxKind.RestType: return getTypeFromRestTypeNode(node as RestTypeNode); case SyntaxKind.JSDocVariadicType: @@ -17315,9 +22560,21 @@ namespace ts { } } - function instantiateList(items: readonly T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[]; - function instantiateList(items: readonly T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[] | undefined; - function instantiateList(items: readonly T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[] | undefined { + function instantiateList( + items: readonly T[], + mapper: TypeMapper, + instantiator: (item: T, mapper: TypeMapper) => T, + ): readonly T[]; + function instantiateList( + items: readonly T[] | undefined, + mapper: TypeMapper, + instantiator: (item: T, mapper: TypeMapper) => T, + ): readonly T[] | undefined; + function instantiateList( + items: readonly T[] | undefined, + mapper: TypeMapper, + instantiator: (item: T, mapper: TypeMapper) => T, + ): readonly T[] | undefined { if (items && items.length) { for (let i = 0; i < items.length; i++) { const item = items[i]; @@ -17350,7 +22607,8 @@ namespace ts { } function createTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper { - return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) : makeArrayTypeMapper(sources, targets); + return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) + : makeArrayTypeMapper(sources, targets); } function getMappedType(type: Type, mapper: TypeMapper): Type { @@ -17382,7 +22640,8 @@ namespace ts { case TypeMapKind.Composite: case TypeMapKind.Merged: const t1 = getMappedType(type, mapper.mapper1); - return t1 !== type && mapper.kind === TypeMapKind.Composite ? instantiateType(t1, mapper.mapper2) : getMappedType(t1, mapper.mapper2); + return t1 !== type && mapper.kind === TypeMapKind.Composite ? instantiateType(t1, mapper.mapper2) + : getMappedType(t1, mapper.mapper2); } } @@ -17390,19 +22649,30 @@ namespace ts { return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Simple, source, target }); } - function makeArrayTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper { + function makeArrayTypeMapper( + sources: readonly TypeParameter[], + targets: readonly Type[] | undefined, + ): TypeMapper { return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Array, sources, targets }); } function makeFunctionTypeMapper(func: (t: Type) => Type, debugInfo: () => string): TypeMapper { - return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Function, func, debugInfo: Debug.isDebugging ? debugInfo : undefined }); + return Debug.attachDebugPrototypeIfDebug({ + kind: TypeMapKind.Function, + func, + debugInfo: Debug.isDebugging ? debugInfo : undefined, + }); } function makeDeferredTypeMapper(sources: readonly TypeParameter[], targets: (() => Type)[]) { return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Deferred, sources, targets }); } - function makeCompositeTypeMapper(kind: TypeMapKind.Composite | TypeMapKind.Merged, mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper { + function makeCompositeTypeMapper( + kind: TypeMapKind.Composite | TypeMapKind.Merged, + mapper1: TypeMapper, + mapper2: TypeMapper, + ): TypeMapper { return Debug.attachDebugPrototypeIfDebug({ kind, mapper1, mapper2 }); } @@ -17416,7 +22686,10 @@ namespace ts { */ function createBackreferenceMapper(context: InferenceContext, index: number): TypeMapper { const forwardInferences = context.inferences.slice(index); - return createTypeMapper(map(forwardInferences, i => i.typeParameter), map(forwardInferences, () => unknownType)); + return createTypeMapper( + map(forwardInferences, i => i.typeParameter), + map(forwardInferences, () => unknownType), + ); } function combineTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper { @@ -17428,17 +22701,22 @@ namespace ts { } function prependTypeMapping(source: Type, target: Type, mapper: TypeMapper | undefined) { - return !mapper ? makeUnaryTypeMapper(source, target) : makeCompositeTypeMapper(TypeMapKind.Merged, makeUnaryTypeMapper(source, target), mapper); + return !mapper ? makeUnaryTypeMapper(source, target) + : makeCompositeTypeMapper(TypeMapKind.Merged, makeUnaryTypeMapper(source, target), mapper); } function appendTypeMapping(mapper: TypeMapper | undefined, source: Type, target: Type) { - return !mapper ? makeUnaryTypeMapper(source, target) : makeCompositeTypeMapper(TypeMapKind.Merged, mapper, makeUnaryTypeMapper(source, target)); + return !mapper ? makeUnaryTypeMapper(source, target) + : makeCompositeTypeMapper(TypeMapKind.Merged, mapper, makeUnaryTypeMapper(source, target)); } function getRestrictiveTypeParameter(tp: TypeParameter) { - return !tp.constraint && !getConstraintDeclaration(tp) || tp.constraint === noConstraintType ? tp : tp.restrictiveInstantiation || ( - tp.restrictiveInstantiation = createTypeParameter(tp.symbol), (tp.restrictiveInstantiation as TypeParameter).constraint = noConstraintType, tp.restrictiveInstantiation - ); + return !tp.constraint && !getConstraintDeclaration(tp) || tp.constraint === noConstraintType ? tp + : tp.restrictiveInstantiation || ( + tp.restrictiveInstantiation = createTypeParameter(tp.symbol), + (tp.restrictiveInstantiation as TypeParameter).constraint = noConstraintType, + tp.restrictiveInstantiation + ); } function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter { @@ -17448,10 +22726,19 @@ namespace ts { } function instantiateTypePredicate(predicate: TypePredicate, mapper: TypeMapper): TypePredicate { - return createTypePredicate(predicate.kind, predicate.parameterName, predicate.parameterIndex, instantiateType(predicate.type, mapper)); + return createTypePredicate( + predicate.kind, + predicate.parameterName, + predicate.parameterIndex, + instantiateType(predicate.type, mapper), + ); } - function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { + function instantiateSignature( + signature: Signature, + mapper: TypeMapper, + eraseTypeParameters?: boolean, + ): Signature { let freshTypeParameters: TypeParameter[] | undefined; if (signature.typeParameters && !eraseTypeParameters) { // First create a fresh set of type parameters, then include a mapping from the old to the @@ -17466,7 +22753,16 @@ namespace ts { // Don't compute resolvedReturnType and resolvedTypePredicate now, // because using `mapper` now could trigger inferences to become fixed. (See `createInferenceContext`.) // See GH#17600. - const result = createSignature(signature.declaration, freshTypeParameters, signature.thisParameter && instantiateSymbol(signature.thisParameter, mapper), instantiateList(signature.parameters, mapper, instantiateSymbol), /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, signature.minArgumentCount, signature.flags & SignatureFlags.PropagatingFlags); + const result = createSignature( + signature.declaration, + freshTypeParameters, + signature.thisParameter && instantiateSymbol(signature.thisParameter, mapper), + instantiateList(signature.parameters, mapper, instantiateSymbol), + /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, + signature.minArgumentCount, + signature.flags & SignatureFlags.PropagatingFlags, + ); result.target = signature; result.mapper = mapper; return result; @@ -17488,7 +22784,14 @@ namespace ts { } // Keep the flags from the symbol we're instantiating. Mark that is instantiated, and // also transient so that we can just store data on it directly. - const result = createSymbol(symbol.flags, symbol.escapedName, CheckFlags.Instantiated | getCheckFlags(symbol) & (CheckFlags.Readonly | CheckFlags.Late | CheckFlags.OptionalParameter | CheckFlags.RestParameter)); + const result = createSymbol( + symbol.flags, + symbol.escapedName, + CheckFlags.Instantiated + | getCheckFlags(symbol) + & (CheckFlags.Readonly | CheckFlags.Late | CheckFlags.OptionalParameter + | CheckFlags.RestParameter), + ); result.declarations = symbol.declarations; result.parent = symbol.parent; result.target = symbol; @@ -17502,13 +22805,19 @@ namespace ts { return result; } - function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) { - const declaration = type.objectFlags & ObjectFlags.Reference ? (type as TypeReference).node! : - type.objectFlags & ObjectFlags.InstantiationExpressionType ? (type as InstantiationExpressionType).node : - type.symbol.declarations![0]; + function getObjectTypeInstantiation( + type: AnonymousType | DeferredTypeReference, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ) { + const declaration = type.objectFlags & ObjectFlags.Reference ? (type as TypeReference).node! + : type.objectFlags & ObjectFlags.InstantiationExpressionType + ? (type as InstantiationExpressionType).node + : type.symbol.declarations![0]; const links = getNodeLinks(declaration); - const target = type.objectFlags & ObjectFlags.Reference ? links.resolvedType! as DeferredTypeReference : - type.objectFlags & ObjectFlags.Instantiated ? type.target! : type; + const target = type.objectFlags & ObjectFlags.Reference ? links.resolvedType! as DeferredTypeReference + : type.objectFlags & ObjectFlags.Instantiated ? type.target! : type; let typeParameters = links.outerTypeParameters; if (!typeParameters) { // The first time an anonymous type is instantiated we compute and store a list of the type @@ -17517,14 +22826,23 @@ namespace ts { // set of type parameters to those that are possibly referenced in the literal. let outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true); if (isJSConstructor(declaration)) { - const templateTagParameters = getTypeParametersFromDeclaration(declaration as DeclarationWithTypeParameters); + const templateTagParameters = getTypeParametersFromDeclaration( + declaration as DeclarationWithTypeParameters, + ); outerTypeParameters = addRange(outerTypeParameters, templateTagParameters); } typeParameters = outerTypeParameters || emptyArray; - const allDeclarations = type.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) ? [declaration] : type.symbol.declarations!; - typeParameters = (target.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) || target.symbol.flags & SymbolFlags.Method || target.symbol.flags & SymbolFlags.TypeLiteral) && !target.aliasTypeArguments ? - filter(typeParameters, tp => some(allDeclarations, d => isTypeParameterPossiblyReferenced(tp, d))) : - typeParameters; + const allDeclarations = + type.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) ? [declaration] + : type.symbol.declarations!; + typeParameters = (target.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) + || target.symbol.flags & SymbolFlags.Method + || target.symbol.flags & SymbolFlags.TypeLiteral) && !target.aliasTypeArguments + ? filter( + typeParameters, + tp => some(allDeclarations, d => isTypeParameterPossiblyReferenced(tp, d)), + ) + : typeParameters; links.outerTypeParameters = typeParameters; } if (typeParameters.length) { @@ -17534,18 +22852,30 @@ namespace ts { const combinedMapper = combineTypeMappers(type.mapper, mapper); const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper)); const newAliasSymbol = aliasSymbol || type.aliasSymbol; - const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); + const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); const id = getTypeListId(typeArguments) + getAliasId(newAliasSymbol, newAliasTypeArguments); if (!target.instantiations) { target.instantiations = new Map(); - target.instantiations.set(getTypeListId(typeParameters) + getAliasId(target.aliasSymbol, target.aliasTypeArguments), target); + target.instantiations.set( + getTypeListId(typeParameters) + getAliasId(target.aliasSymbol, target.aliasTypeArguments), + target, + ); } let result = target.instantiations.get(id); if (!result) { const newMapper = createTypeMapper(typeParameters, typeArguments); - result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((type as DeferredTypeReference).target, (type as DeferredTypeReference).node, newMapper, newAliasSymbol, newAliasTypeArguments) : - target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target as MappedType, newMapper, newAliasSymbol, newAliasTypeArguments) : - instantiateAnonymousType(target, newMapper, newAliasSymbol, newAliasTypeArguments); + result = target.objectFlags & ObjectFlags.Reference + ? createDeferredTypeReference( + (type as DeferredTypeReference).target, + (type as DeferredTypeReference).node, + newMapper, + newAliasSymbol, + newAliasTypeArguments, + ) + : target.objectFlags & ObjectFlags.Mapped + ? instantiateMappedType(target as MappedType, newMapper, newAliasSymbol, newAliasTypeArguments) + : instantiateAnonymousType(target, newMapper, newAliasSymbol, newAliasTypeArguments); target.instantiations.set(id, result); } return result; @@ -17554,8 +22884,10 @@ namespace ts { } function maybeTypeParameterReference(node: Node) { - return !(node.parent.kind === SyntaxKind.TypeReference && (node.parent as TypeReferenceNode).typeArguments && node === (node.parent as TypeReferenceNode).typeName || - node.parent.kind === SyntaxKind.ImportType && (node.parent as ImportTypeNode).typeArguments && node === (node.parent as ImportTypeNode).qualifier); + return !(node.parent.kind === SyntaxKind.TypeReference && (node.parent as TypeReferenceNode).typeArguments + && node === (node.parent as TypeReferenceNode).typeName + || node.parent.kind === SyntaxKind.ImportType && (node.parent as ImportTypeNode).typeArguments + && node === (node.parent as ImportTypeNode).qualifier); } function isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node) { @@ -17566,7 +22898,11 @@ namespace ts { if (tp.symbol && tp.symbol.declarations && tp.symbol.declarations.length === 1) { const container = tp.symbol.declarations[0].parent; for (let n = node; n !== container; n = n.parent) { - if (!n || n.kind === SyntaxKind.Block || n.kind === SyntaxKind.ConditionalType && forEachChild((n as ConditionalTypeNode).extendsType, containsReference)) { + if ( + !n || n.kind === SyntaxKind.Block + || n.kind === SyntaxKind.ConditionalType + && forEachChild((n as ConditionalTypeNode).extendsType, containsReference) + ) { return true; } } @@ -17578,8 +22914,8 @@ namespace ts { case SyntaxKind.ThisType: return !!tp.isThisType; case SyntaxKind.Identifier: - return !tp.isThisType && isPartOfTypeNode(node) && maybeTypeParameterReference(node) && - getTypeFromTypeNodeWorker(node as TypeNode) === tp; // use worker because we're looking for === equality + return !tp.isThisType && isPartOfTypeNode(node) && maybeTypeParameterReference(node) + && getTypeFromTypeNodeWorker(node as TypeNode) === tp; // use worker because we're looking for === equality case SyntaxKind.TypeQuery: const entityName = (node as TypeQueryNode).exprName; const firstIdentifier = getFirstIdentifier(entityName); @@ -17600,16 +22936,20 @@ namespace ts { } if (firstIdentifierSymbol.declarations) { - return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpScope)) || - some((node as TypeQueryNode).typeArguments, containsReference); + return some( + firstIdentifierSymbol.declarations, + idDecl => isNodeDescendantOf(idDecl, tpScope), + ) + || some((node as TypeQueryNode).typeArguments, containsReference); } return true; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - return !(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body || - some((node as FunctionLikeDeclaration).typeParameters, containsReference) || - some((node as FunctionLikeDeclaration).parameters, containsReference) || - !!(node as FunctionLikeDeclaration).type && containsReference((node as FunctionLikeDeclaration).type!); + return !(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body + || some((node as FunctionLikeDeclaration).typeParameters, containsReference) + || some((node as FunctionLikeDeclaration).parameters, containsReference) + || !!(node as FunctionLikeDeclaration).type + && containsReference((node as FunctionLikeDeclaration).type!); } return !!forEachChild(node, containsReference); } @@ -17626,7 +22966,12 @@ namespace ts { return undefined; } - function instantiateMappedType(type: MappedType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function instantiateMappedType( + type: MappedType, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { // For a homomorphic mapped type { [P in keyof T]: X }, where T is some type variable, the mapping // operation depends on T as follows: // * If T is a primitive type no mapping is performed and the result is simply T. @@ -17644,20 +22989,38 @@ namespace ts { return mapTypeWithAlias( getReducedType(mappedTypeVariable), t => { - if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t)) { + if ( + t.flags + & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object + | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t) + ) { if (!type.declaration.nameType) { let constraint; if ( - isArrayType(t) || t.flags & TypeFlags.Any && findResolutionCycleStartIndex(typeVariable, TypeSystemPropertyName.ImmediateBaseConstraint) < 0 && - (constraint = getConstraintOfTypeParameter(typeVariable)) && everyType(constraint, isArrayOrTupleType) + isArrayType(t) + || t.flags & TypeFlags.Any + && findResolutionCycleStartIndex( + typeVariable, + TypeSystemPropertyName.ImmediateBaseConstraint, + ) < 0 + && (constraint = getConstraintOfTypeParameter(typeVariable)) + && everyType(constraint, isArrayOrTupleType) ) { - return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper)); + return instantiateMappedArrayType( + t, + type, + prependTypeMapping(typeVariable, t, mapper), + ); } if (isGenericTupleType(t)) { return instantiateMappedGenericTupleType(t, type, typeVariable, mapper); } if (isTupleType(t)) { - return instantiateMappedTupleType(t, type, prependTypeMapping(typeVariable, t, mapper)); + return instantiateMappedTupleType( + t, + type, + prependTypeMapping(typeVariable, t, mapper), + ); } } return instantiateAnonymousType(type, prependTypeMapping(typeVariable, t, mapper)); @@ -17670,23 +23033,30 @@ namespace ts { } } // If the constraint type of the instantiation is the wildcard type, return the wildcard type. - return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments); + return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType + : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments); } function getModifiedReadonlyState(state: boolean, modifiers: MappedTypeModifiers) { - return modifiers & MappedTypeModifiers.IncludeReadonly ? true : modifiers & MappedTypeModifiers.ExcludeReadonly ? false : state; + return modifiers & MappedTypeModifiers.IncludeReadonly ? true + : modifiers & MappedTypeModifiers.ExcludeReadonly ? false : state; } - function instantiateMappedGenericTupleType(tupleType: TupleTypeReference, mappedType: MappedType, typeVariable: TypeVariable, mapper: TypeMapper) { + function instantiateMappedGenericTupleType( + tupleType: TupleTypeReference, + mappedType: MappedType, + typeVariable: TypeVariable, + mapper: TypeMapper, + ) { // When a tuple type is generic (i.e. when it contains variadic elements), we want to eagerly map the // non-generic elements and defer mapping the generic elements. In order to facilitate this, we transform // M<[A, B?, ...T, ...C[]] into [...M<[A]>, ...M<[B?]>, ...M, ...M] and then rely on tuple type // normalization to resolve the non-generic parts of the resulting tuple. const elementFlags = tupleType.target.elementFlags; const elementTypes = map(getTypeArguments(tupleType), (t, i) => { - const singleton = elementFlags[i] & ElementFlags.Variadic ? t : - elementFlags[i] & ElementFlags.Rest ? createArrayType(t) : - createTupleType([t], [elementFlags[i]]); + const singleton = elementFlags[i] & ElementFlags.Variadic ? t + : elementFlags[i] & ElementFlags.Rest ? createArrayType(t) + : createTupleType([t], [elementFlags[i]]); // The singleton is never a generic tuple type, so it is safe to recurse here. return instantiateMappedType(mappedType, prependTypeMapping(typeVariable, singleton, mapper)); }); @@ -17696,32 +23066,62 @@ namespace ts { function instantiateMappedArrayType(arrayType: Type, mappedType: MappedType, mapper: TypeMapper) { const elementType = instantiateMappedTypeTemplate(mappedType, numberType, /*isOptional*/ true, mapper); - return isErrorType(elementType) ? errorType : - createArrayType(elementType, getModifiedReadonlyState(isReadonlyArrayType(arrayType), getMappedTypeModifiers(mappedType))); + return isErrorType(elementType) ? errorType + : createArrayType( + elementType, + getModifiedReadonlyState(isReadonlyArrayType(arrayType), getMappedTypeModifiers(mappedType)), + ); } function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) { const elementFlags = tupleType.target.elementFlags; - const elementTypes = map(getTypeArguments(tupleType), (_, i) => instantiateMappedTypeTemplate(mappedType, getStringLiteralType("" + i), !!(elementFlags[i] & ElementFlags.Optional), mapper)); + const elementTypes = map( + getTypeArguments(tupleType), + (_, i) => + instantiateMappedTypeTemplate( + mappedType, + getStringLiteralType("" + i), + !!(elementFlags[i] & ElementFlags.Optional), + mapper, + ), + ); const modifiers = getMappedTypeModifiers(mappedType); - const newTupleModifiers = modifiers & MappedTypeModifiers.IncludeOptional ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) : - modifiers & MappedTypeModifiers.ExcludeOptional ? map(elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) : - elementFlags; + const newTupleModifiers = modifiers & MappedTypeModifiers.IncludeOptional + ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) + : modifiers & MappedTypeModifiers.ExcludeOptional + ? map(elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) + : elementFlags; const newReadonly = getModifiedReadonlyState(tupleType.target.readonly, modifiers); - return contains(elementTypes, errorType) ? errorType : - createTupleType(elementTypes, newTupleModifiers, newReadonly, tupleType.target.labeledElementDeclarations); + return contains(elementTypes, errorType) ? errorType + : createTupleType( + elementTypes, + newTupleModifiers, + newReadonly, + tupleType.target.labeledElementDeclarations, + ); } function instantiateMappedTypeTemplate(type: MappedType, key: Type, isOptional: boolean, mapper: TypeMapper) { const templateMapper = appendTypeMapping(mapper, getTypeParameterFromMappedType(type), key); - const propType = instantiateType(getTemplateTypeFromMappedType(type.target as MappedType || type), templateMapper); + const propType = instantiateType( + getTemplateTypeFromMappedType(type.target as MappedType || type), + templateMapper, + ); const modifiers = getMappedTypeModifiers(type); - return strictNullChecks && modifiers & MappedTypeModifiers.IncludeOptional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType, /*isProperty*/ true) : - strictNullChecks && modifiers & MappedTypeModifiers.ExcludeOptional && isOptional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) : - propType; - } - - function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): AnonymousType { + return strictNullChecks && modifiers & MappedTypeModifiers.IncludeOptional + && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) + ? getOptionalType(propType, /*isProperty*/ true) + : strictNullChecks && modifiers & MappedTypeModifiers.ExcludeOptional && isOptional + ? getTypeWithFacts(propType, TypeFacts.NEUndefined) + : propType; + } + + function instantiateAnonymousType( + type: AnonymousType, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): AnonymousType { const result = createObjectType(type.objectFlags | ObjectFlags.Instantiated, type.symbol) as AnonymousType; if (type.objectFlags & ObjectFlags.Mapped) { (result as MappedType).declaration = (type as MappedType).declaration; @@ -17738,12 +23138,18 @@ namespace ts { result.target = type; result.mapper = mapper; result.aliasSymbol = aliasSymbol || type.aliasSymbol; - result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); + result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); result.objectFlags |= result.aliasTypeArguments ? getPropagatingFlagsOfTypes(result.aliasTypeArguments) : 0; return result; } - function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getConditionalTypeInstantiation( + type: ConditionalType, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { const root = type.root; if (root.outerTypeParameters) { // We are instantiating a conditional type that has one or more type parameters in scope. Apply the @@ -17759,9 +23165,15 @@ namespace ts { // Distributive conditional types are distributed over union types. For example, when the // distributive conditional type T extends U ? X : Y is instantiated with A | B for T, the // result is (A extends U ? X : Y) | (B extends U ? X : Y). - result = distributionType && checkType !== distributionType && distributionType.flags & (TypeFlags.Union | TypeFlags.Never) ? - mapTypeWithAlias(getReducedType(distributionType), t => getConditionalType(root, prependTypeMapping(checkType, t, newMapper)), aliasSymbol, aliasTypeArguments) : - getConditionalType(root, newMapper, aliasSymbol, aliasTypeArguments); + result = distributionType && checkType !== distributionType + && distributionType.flags & (TypeFlags.Union | TypeFlags.Never) + ? mapTypeWithAlias( + getReducedType(distributionType), + t => getConditionalType(root, prependTypeMapping(checkType, t, newMapper)), + aliasSymbol, + aliasTypeArguments, + ) + : getConditionalType(root, newMapper, aliasSymbol, aliasTypeArguments); root.instantiations!.set(id, result); } return result; @@ -17772,10 +23184,17 @@ namespace ts { function instantiateType(type: Type, mapper: TypeMapper | undefined): Type; function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined; function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined { - return type && mapper ? instantiateTypeWithAlias(type, mapper, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined) : type; + return type && mapper + ? instantiateTypeWithAlias(type, mapper, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined) + : type; } - function instantiateTypeWithAlias(type: Type, mapper: TypeMapper, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined): Type { + function instantiateTypeWithAlias( + type: Type, + mapper: TypeMapper, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + ): Type { if (!couldContainTypeVariables(type)) { return type; } @@ -17783,7 +23202,11 @@ namespace ts { // We have reached 100 recursive type instantiations, or 5M type instantiations caused by the same statement // or expression. There is a very high likelyhood we're dealing with a combination of infinite generic types // that perpetually generate new type identities, so we stop the recursion here by yielding the error type. - tracing?.instant(tracing.Phase.CheckTypes, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount }); + tracing?.instant(tracing.Phase.CheckTypes, "instantiateType_DepthLimit", { + typeId: type.id, + instantiationDepth, + instantiationCount, + }); error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite); return errorType; } @@ -17795,7 +23218,12 @@ namespace ts { return result; } - function instantiateTypeWorker(type: Type, mapper: TypeMapper, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined): Type { + function instantiateTypeWorker( + type: Type, + mapper: TypeMapper, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + ): Type { const flags = type.flags; if (flags & TypeFlags.TypeParameter) { return getMappedType(type, mapper); @@ -17806,44 +23234,71 @@ namespace ts { if (objectFlags & ObjectFlags.Reference && !(type as TypeReference).node) { const resolvedTypeArguments = (type as TypeReference).resolvedTypeArguments; const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); - return newTypeArguments !== resolvedTypeArguments ? createNormalizedTypeReference((type as TypeReference).target, newTypeArguments) : type; + return newTypeArguments !== resolvedTypeArguments + ? createNormalizedTypeReference((type as TypeReference).target, newTypeArguments) : type; } if (objectFlags & ObjectFlags.ReverseMapped) { return instantiateReverseMappedType(type as ReverseMappedType, mapper); } - return getObjectTypeInstantiation(type as TypeReference | AnonymousType | MappedType, mapper, aliasSymbol, aliasTypeArguments); + return getObjectTypeInstantiation( + type as TypeReference | AnonymousType | MappedType, + mapper, + aliasSymbol, + aliasTypeArguments, + ); } return type; } if (flags & TypeFlags.UnionOrIntersection) { const origin = type.flags & TypeFlags.Union ? (type as UnionType).origin : undefined; - const types = origin && origin.flags & TypeFlags.UnionOrIntersection ? (origin as UnionOrIntersectionType).types : (type as UnionOrIntersectionType).types; + const types = origin && origin.flags & TypeFlags.UnionOrIntersection + ? (origin as UnionOrIntersectionType).types : (type as UnionOrIntersectionType).types; const newTypes = instantiateTypes(types, mapper); if (newTypes === types && aliasSymbol === type.aliasSymbol) { return type; } const newAliasSymbol = aliasSymbol || type.aliasSymbol; - const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - return flags & TypeFlags.Intersection || origin && origin.flags & TypeFlags.Intersection ? - getIntersectionType(newTypes, newAliasSymbol, newAliasTypeArguments) : - getUnionType(newTypes, UnionReduction.Literal, newAliasSymbol, newAliasTypeArguments); + const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); + return flags & TypeFlags.Intersection || origin && origin.flags & TypeFlags.Intersection + ? getIntersectionType(newTypes, newAliasSymbol, newAliasTypeArguments) + : getUnionType(newTypes, UnionReduction.Literal, newAliasSymbol, newAliasTypeArguments); } if (flags & TypeFlags.Index) { return getIndexType(instantiateType((type as IndexType).type, mapper)); } if (flags & TypeFlags.TemplateLiteral) { - return getTemplateLiteralType((type as TemplateLiteralType).texts, instantiateTypes((type as TemplateLiteralType).types, mapper)); + return getTemplateLiteralType( + (type as TemplateLiteralType).texts, + instantiateTypes((type as TemplateLiteralType).types, mapper), + ); } if (flags & TypeFlags.StringMapping) { - return getStringMappingType((type as StringMappingType).symbol, instantiateType((type as StringMappingType).type, mapper)); + return getStringMappingType( + (type as StringMappingType).symbol, + instantiateType((type as StringMappingType).type, mapper), + ); } if (flags & TypeFlags.IndexedAccess) { const newAliasSymbol = aliasSymbol || type.aliasSymbol; - const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - return getIndexedAccessType(instantiateType((type as IndexedAccessType).objectType, mapper), instantiateType((type as IndexedAccessType).indexType, mapper), (type as IndexedAccessType).accessFlags, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments); + const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); + return getIndexedAccessType( + instantiateType((type as IndexedAccessType).objectType, mapper), + instantiateType((type as IndexedAccessType).indexType, mapper), + (type as IndexedAccessType).accessFlags, + /*accessNode*/ undefined, + newAliasSymbol, + newAliasTypeArguments, + ); } if (flags & TypeFlags.Conditional) { - return getConditionalTypeInstantiation(type as ConditionalType, combineTypeMappers((type as ConditionalType).mapper, mapper), aliasSymbol, aliasTypeArguments); + return getConditionalTypeInstantiation( + type as ConditionalType, + combineTypeMappers((type as ConditionalType).mapper, mapper), + aliasSymbol, + aliasTypeArguments, + ); } if (flags & TypeFlags.Substitution) { const newBaseType = instantiateType((type as SubstitutionType).baseType, mapper); @@ -17854,10 +23309,17 @@ namespace ts { if (newBaseType.flags & TypeFlags.TypeVariable && isGenericType(newConstraint)) { return getSubstitutionType(newBaseType, newConstraint); } - if (newConstraint.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(newBaseType), getRestrictiveInstantiation(newConstraint))) { + if ( + newConstraint.flags & TypeFlags.AnyOrUnknown + || isTypeAssignableTo( + getRestrictiveInstantiation(newBaseType), + getRestrictiveInstantiation(newConstraint), + ) + ) { return newBaseType; } - return newBaseType.flags & TypeFlags.TypeVariable ? getSubstitutionType(newBaseType, newConstraint) : getIntersectionType([newConstraint, newBaseType]); + return newBaseType.flags & TypeFlags.TypeVariable ? getSubstitutionType(newBaseType, newConstraint) + : getIntersectionType([newConstraint, newBaseType]); } return type; } @@ -17883,13 +23345,15 @@ namespace ts { } function getUniqueLiteralFilledInstantiation(type: Type) { - return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type : - type.uniqueLiteralFilledInstantiation || (type.uniqueLiteralFilledInstantiation = instantiateType(type, uniqueLiteralMapper)); + return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type + : type.uniqueLiteralFilledInstantiation + || (type.uniqueLiteralFilledInstantiation = instantiateType(type, uniqueLiteralMapper)); } function getPermissiveInstantiation(type: Type) { - return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type : - type.permissiveInstantiation || (type.permissiveInstantiation = instantiateType(type, permissiveMapper)); + return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type + : type.permissiveInstantiation + || (type.permissiveInstantiation = instantiateType(type, permissiveMapper)); } function getRestrictiveInstantiation(type: Type) { @@ -17915,30 +23379,37 @@ namespace ts { // Returns true if the given expression contains (at any level of nesting) a function or arrow expression // that is subject to contextual typing. - function isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike | JsxChild): boolean { + function isContextSensitive( + node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike | JsxChild, + ): boolean { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); switch (node.kind) { case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: case SyntaxKind.MethodDeclaration: case SyntaxKind.FunctionDeclaration: // Function declarations can have context when annotated with a jsdoc @type - return isContextSensitiveFunctionLikeDeclaration(node as FunctionExpression | ArrowFunction | MethodDeclaration); + return isContextSensitiveFunctionLikeDeclaration( + node as FunctionExpression | ArrowFunction | MethodDeclaration, + ); case SyntaxKind.ObjectLiteralExpression: return some((node as ObjectLiteralExpression).properties, isContextSensitive); case SyntaxKind.ArrayLiteralExpression: return some((node as ArrayLiteralExpression).elements, isContextSensitive); case SyntaxKind.ConditionalExpression: - return isContextSensitive((node as ConditionalExpression).whenTrue) || - isContextSensitive((node as ConditionalExpression).whenFalse); + return isContextSensitive((node as ConditionalExpression).whenTrue) + || isContextSensitive((node as ConditionalExpression).whenFalse); case SyntaxKind.BinaryExpression: - return ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken || (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken) && - (isContextSensitive((node as BinaryExpression).left) || isContextSensitive((node as BinaryExpression).right)); + return ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken + || (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken) + && (isContextSensitive((node as BinaryExpression).left) + || isContextSensitive((node as BinaryExpression).right)); case SyntaxKind.PropertyAssignment: return isContextSensitive((node as PropertyAssignment).initializer); case SyntaxKind.ParenthesizedExpression: return isContextSensitive((node as ParenthesizedExpression).expression); case SyntaxKind.JsxAttributes: - return some((node as JsxAttributes).properties, isContextSensitive) || isJsxOpeningElement(node.parent) && some(node.parent.parent.children, isContextSensitive); + return some((node as JsxAttributes).properties, isContextSensitive) + || isJsxOpeningElement(node.parent) && some(node.parent.parent.children, isContextSensitive); case SyntaxKind.JsxAttribute: { // If there is no initializer, JSX attribute has a boolean value of true which is not context sensitive. const { initializer } = node as JsxAttribute; @@ -17960,12 +23431,15 @@ namespace ts { function hasContextSensitiveReturnExpression(node: FunctionLikeDeclaration) { // TODO(anhans): A block should be context-sensitive if it has a context-sensitive return value. - return !node.typeParameters && !getEffectiveReturnTypeNode(node) && !!node.body && node.body.kind !== SyntaxKind.Block && isContextSensitive(node.body); + return !node.typeParameters && !getEffectiveReturnTypeNode(node) && !!node.body + && node.body.kind !== SyntaxKind.Block && isContextSensitive(node.body); } - function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration { - return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) && - isContextSensitiveFunctionLikeDeclaration(func); + function isContextSensitiveFunctionOrObjectLiteralMethod( + func: Node, + ): func is FunctionExpression | ArrowFunction | MethodDeclaration { + return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) + && isContextSensitiveFunctionLikeDeclaration(func); } function getTypeWithoutSignatures(type: Type): Type { @@ -18022,12 +23496,17 @@ namespace ts { // Note that this check ignores type parameters and only considers the // inheritance hierarchy. function isTypeDerivedFrom(source: Type, target: Type): boolean { - return source.flags & TypeFlags.Union ? every((source as UnionType).types, t => isTypeDerivedFrom(t, target)) : - target.flags & TypeFlags.Union ? some((target as UnionType).types, t => isTypeDerivedFrom(source, t)) : - source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || unknownType, target) : - target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) : - target === globalFunctionType ? !!(source.flags & TypeFlags.Object) && isFunctionObjectType(source as ObjectType) : - hasBaseType(source, getTargetType(target)) || (isArrayType(target) && !isReadonlyArrayType(target) && isTypeDerivedFrom(source, globalReadonlyArrayType)); + return source.flags & TypeFlags.Union + ? every((source as UnionType).types, t => isTypeDerivedFrom(t, target)) + : target.flags & TypeFlags.Union ? some((target as UnionType).types, t => isTypeDerivedFrom(source, t)) + : source.flags & TypeFlags.InstantiableNonPrimitive + ? isTypeDerivedFrom(getBaseConstraintOfType(source) || unknownType, target) + : target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) + : target === globalFunctionType + ? !!(source.flags & TypeFlags.Object) && isFunctionObjectType(source as ObjectType) + : hasBaseType(source, getTargetType(target)) + || (isArrayType(target) && !isReadonlyArrayType(target) + && isTypeDerivedFrom(source, globalReadonlyArrayType)); } /** @@ -18048,16 +23527,47 @@ namespace ts { return isTypeComparableTo(type1, type2) || isTypeComparableTo(type2, type1); } - function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined, errorOutputObject?: { errors?: Diagnostic[]; }): boolean { - return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain, errorOutputObject); + function checkTypeAssignableTo( + source: Type, + target: Type, + errorNode: Node | undefined, + headMessage?: DiagnosticMessage, + containingMessageChain?: () => DiagnosticMessageChain | undefined, + errorOutputObject?: { errors?: Diagnostic[]; }, + ): boolean { + return checkTypeRelatedTo( + source, + target, + assignableRelation, + errorNode, + headMessage, + containingMessageChain, + errorOutputObject, + ); } /** * Like `checkTypeAssignableTo`, but if it would issue an error, instead performs structural comparisons of the types using the given expression node to * attempt to issue more specific errors on, for example, specific object literal properties or tuple members. */ - function checkTypeAssignableToAndOptionallyElaborate(source: Type, target: Type, errorNode: Node | undefined, expr: Expression | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean { - return checkTypeRelatedToAndOptionallyElaborate(source, target, assignableRelation, errorNode, expr, headMessage, containingMessageChain, /*errorOutputContainer*/ undefined); + function checkTypeAssignableToAndOptionallyElaborate( + source: Type, + target: Type, + errorNode: Node | undefined, + expr: Expression | undefined, + headMessage?: DiagnosticMessage, + containingMessageChain?: () => DiagnosticMessageChain | undefined, + ): boolean { + return checkTypeRelatedToAndOptionallyElaborate( + source, + target, + assignableRelation, + errorNode, + expr, + headMessage, + containingMessageChain, + /*errorOutputContainer*/ undefined, + ); } function checkTypeRelatedToAndOptionallyElaborate( @@ -18071,14 +23581,35 @@ namespace ts { errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ): boolean { if (isTypeRelatedTo(source, target, relation)) return true; - if (!errorNode || !elaborateError(expr, source, target, relation, headMessage, containingMessageChain, errorOutputContainer)) { - return checkTypeRelatedTo(source, target, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer); + if ( + !errorNode + || !elaborateError( + expr, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer, + ) + ) { + return checkTypeRelatedTo( + source, + target, + relation, + errorNode, + headMessage, + containingMessageChain, + errorOutputContainer, + ); } return false; } function isOrHasGenericConditional(type: Type): boolean { - return !!(type.flags & TypeFlags.Conditional || (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isOrHasGenericConditional))); + return !!(type.flags & TypeFlags.Conditional + || (type.flags & TypeFlags.Intersection + && some((type as IntersectionType).types, isOrHasGenericConditional))); } function elaborateError( @@ -18093,29 +23624,81 @@ namespace ts { if (!node || isOrHasGenericConditional(target)) return false; if ( !checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined) - && elaborateDidYouMeanToCallOrConstruct(node, source, target, relation, headMessage, containingMessageChain, errorOutputContainer) + && elaborateDidYouMeanToCallOrConstruct( + node, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer, + ) ) { return true; } switch (node.kind) { case SyntaxKind.JsxExpression: case SyntaxKind.ParenthesizedExpression: - return elaborateError((node as ParenthesizedExpression | JsxExpression).expression, source, target, relation, headMessage, containingMessageChain, errorOutputContainer); + return elaborateError( + (node as ParenthesizedExpression | JsxExpression).expression, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer, + ); case SyntaxKind.BinaryExpression: switch ((node as BinaryExpression).operatorToken.kind) { case SyntaxKind.EqualsToken: case SyntaxKind.CommaToken: - return elaborateError((node as BinaryExpression).right, source, target, relation, headMessage, containingMessageChain, errorOutputContainer); + return elaborateError( + (node as BinaryExpression).right, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer, + ); } break; case SyntaxKind.ObjectLiteralExpression: - return elaborateObjectLiteral(node as ObjectLiteralExpression, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateObjectLiteral( + node as ObjectLiteralExpression, + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); case SyntaxKind.ArrayLiteralExpression: - return elaborateArrayLiteral(node as ArrayLiteralExpression, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateArrayLiteral( + node as ArrayLiteralExpression, + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); case SyntaxKind.JsxAttributes: - return elaborateJsxComponents(node as JsxAttributes, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateJsxComponents( + node as JsxAttributes, + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); case SyntaxKind.ArrowFunction: - return elaborateArrowFunction(node as ArrowFunction, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateArrowFunction( + node as ArrowFunction, + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); } return false; } @@ -18135,7 +23718,8 @@ namespace ts { if ( some(signatures, s => { const returnType = getReturnTypeOfSignature(s); - return !(returnType.flags & (TypeFlags.Any | TypeFlags.Never)) && checkTypeRelatedTo(returnType, target, relation, /*errorNode*/ undefined); + return !(returnType.flags & (TypeFlags.Any | TypeFlags.Never)) + && checkTypeRelatedTo(returnType, target, relation, /*errorNode*/ undefined); }) ) { const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; @@ -18145,7 +23729,9 @@ namespace ts { diagnostic, createDiagnosticForNode( node, - signatures === constructSignatures ? Diagnostics.Did_you_mean_to_use_new_with_this_expression : Diagnostics.Did_you_mean_to_call_this_expression, + signatures === constructSignatures + ? Diagnostics.Did_you_mean_to_use_new_with_this_expression + : Diagnostics.Did_you_mean_to_call_this_expression, ), ); return true; @@ -18182,12 +23768,29 @@ namespace ts { const sourceReturn = getReturnTypeOfSignature(sourceSig); const targetReturn = getUnionType(map(targetSignatures, getReturnTypeOfSignature)); if (!checkTypeRelatedTo(sourceReturn, targetReturn, relation, /*errorNode*/ undefined)) { - const elaborated = returnExpression && elaborateError(returnExpression, sourceReturn, targetReturn, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); + const elaborated = returnExpression + && elaborateError( + returnExpression, + sourceReturn, + targetReturn, + relation, + /*headMessage*/ undefined, + containingMessageChain, + errorOutputContainer, + ); if (elaborated) { return elaborated; } const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; - checkTypeRelatedTo(sourceReturn, targetReturn, relation, returnExpression, /*message*/ undefined, containingMessageChain, resultObj); + checkTypeRelatedTo( + sourceReturn, + targetReturn, + relation, + returnExpression, + /*message*/ undefined, + containingMessageChain, + resultObj, + ); if (resultObj.errors) { if (target.symbol && length(target.symbol.declarations)) { addRelatedInfo( @@ -18203,7 +23806,12 @@ namespace ts { // exclude cases where source itself is promisy - this way we don't make a suggestion when relating // an IPromise and a Promise that are slightly different && !getTypeOfPropertyOfType(sourceReturn, "then" as __String) - && checkTypeRelatedTo(createPromiseType(sourceReturn), targetReturn, relation, /*errorNode*/ undefined) + && checkTypeRelatedTo( + createPromiseType(sourceReturn), + targetReturn, + relation, + /*errorNode*/ undefined, + ) ) { addRelatedInfo( resultObj.errors[resultObj.errors.length - 1], @@ -18242,7 +23850,14 @@ namespace ts { } } - type ElaborationIterator = IterableIterator<{ errorNode: Node; innerExpression: Expression | undefined; nameType: Type; errorMessage?: DiagnosticMessage | undefined; }>; + type ElaborationIterator = IterableIterator< + { + errorNode: Node; + innerExpression: Expression | undefined; + nameType: Type; + errorMessage?: DiagnosticMessage | undefined; + } + >; /** * For every element returned from the iterator, checks that element to issue an error on a property of that element's type * If that element would issue an error, we first attempt to dive into that element's inner expression and issue a more specific error by recuring into `elaborateError` @@ -18266,52 +23881,110 @@ namespace ts { if (!sourcePropType) continue; const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined); if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) { - const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); + const elaborated = next + && elaborateError( + next, + sourcePropType, + targetPropType, + relation, + /*headMessage*/ undefined, + containingMessageChain, + errorOutputContainer, + ); reportedError = true; if (!elaborated) { // Issue error on the prop itself, since the prop couldn't elaborate the error const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; // Use the expression type, if available - const specificSource = next ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType; - if (exactOptionalPropertyTypes && isExactOptionalPropertyMismatch(specificSource, targetPropType)) { - const diag = createDiagnosticForNode(prop, Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, typeToString(specificSource), typeToString(targetPropType)); + const specificSource = next + ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) + : sourcePropType; + if ( + exactOptionalPropertyTypes + && isExactOptionalPropertyMismatch(specificSource, targetPropType) + ) { + const diag = createDiagnosticForNode( + prop, + Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, + typeToString(specificSource), + typeToString(targetPropType), + ); diagnostics.add(diag); resultObj.errors = [diag]; } else { - const targetIsOptional = !!(propName && (getPropertyOfType(target, propName) || unknownSymbol).flags & SymbolFlags.Optional); - const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); + const targetIsOptional = !!(propName + && (getPropertyOfType(target, propName) || unknownSymbol).flags + & SymbolFlags.Optional); + const sourceIsOptional = !!(propName + && (getPropertyOfType(source, propName) || unknownSymbol).flags + & SymbolFlags.Optional); targetPropType = removeMissingType(targetPropType, targetIsOptional); sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional); - const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + const result = checkTypeRelatedTo( + specificSource, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj, + ); if (result && specificSource !== sourcePropType) { // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType - checkTypeRelatedTo(sourcePropType, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + checkTypeRelatedTo( + sourcePropType, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj, + ); } } if (resultObj.errors) { const reportedDiag = resultObj.errors[resultObj.errors.length - 1]; - const propertyName = isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) : undefined; - const targetProp = propertyName !== undefined ? getPropertyOfType(target, propertyName) : undefined; + const propertyName = isTypeUsableAsPropertyName(nameType) + ? getPropertyNameFromType(nameType) : undefined; + const targetProp = propertyName !== undefined ? getPropertyOfType(target, propertyName) + : undefined; let issuedElaboration = false; if (!targetProp) { const indexInfo = getApplicableIndexInfo(target, nameType); - if (indexInfo && indexInfo.declaration && !getSourceFileOfNode(indexInfo.declaration).hasNoDefaultLib) { + if ( + indexInfo && indexInfo.declaration + && !getSourceFileOfNode(indexInfo.declaration).hasNoDefaultLib + ) { issuedElaboration = true; - addRelatedInfo(reportedDiag, createDiagnosticForNode(indexInfo.declaration, Diagnostics.The_expected_type_comes_from_this_index_signature)); + addRelatedInfo( + reportedDiag, + createDiagnosticForNode( + indexInfo.declaration, + Diagnostics.The_expected_type_comes_from_this_index_signature, + ), + ); } } - if (!issuedElaboration && (targetProp && length(targetProp.declarations) || target.symbol && length(target.symbol.declarations))) { - const targetNode = targetProp && length(targetProp.declarations) ? targetProp.declarations![0] : target.symbol.declarations![0]; + if ( + !issuedElaboration + && (targetProp && length(targetProp.declarations) + || target.symbol && length(target.symbol.declarations)) + ) { + const targetNode = targetProp && length(targetProp.declarations) + ? targetProp.declarations![0] : target.symbol.declarations![0]; if (!getSourceFileOfNode(targetNode).hasNoDefaultLib) { addRelatedInfo( reportedDiag, createDiagnosticForNode( targetNode, - Diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1, - propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType), + Diagnostics + .The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1, + propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) + ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType), typeToString(target), ), ); @@ -18328,11 +24001,18 @@ namespace ts { if (!length(node.properties)) return; for (const prop of node.properties) { if (isJsxSpreadAttribute(prop) || isHyphenatedJsxName(idText(prop.name))) continue; - yield { errorNode: prop.name, innerExpression: prop.initializer, nameType: getStringLiteralType(idText(prop.name)) }; + yield { + errorNode: prop.name, + innerExpression: prop.initializer, + nameType: getStringLiteralType(idText(prop.name)), + }; } } - function* generateJsxChildren(node: JsxElement, getInvalidTextDiagnostic: () => DiagnosticMessage): ElaborationIterator { + function* generateJsxChildren( + node: JsxElement, + getInvalidTextDiagnostic: () => DiagnosticMessage, + ): ElaborationIterator { if (!length(node.children)) return; let memberOffset = 0; for (let i = 0; i < node.children.length; i++) { @@ -18348,7 +24028,11 @@ namespace ts { } } - function getElaborationElementForJsxChild(child: JsxChild, nameType: LiteralType, getInvalidTextDiagnostic: () => DiagnosticMessage) { + function getElaborationElementForJsxChild( + child: JsxChild, + nameType: LiteralType, + getInvalidTextDiagnostic: () => DiagnosticMessage, + ) { switch (child.kind) { case SyntaxKind.JsxExpression: // child is of the type of the expression @@ -18358,7 +24042,12 @@ namespace ts { break; // Whitespace only jsx text isn't real jsx text } // child is a string - return { errorNode: child, innerExpression: undefined, nameType, errorMessage: getInvalidTextDiagnostic() }; + return { + errorNode: child, + innerExpression: undefined, + nameType, + errorMessage: getInvalidTextDiagnostic(), + }; case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxFragment: @@ -18377,12 +24066,20 @@ namespace ts { containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ) { - let result = elaborateElementwise(generateJsxAttributes(node), source, target, relation, containingMessageChain, errorOutputContainer); + let result = elaborateElementwise( + generateJsxAttributes(node), + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); let invalidTextDiagnostic: DiagnosticMessage | undefined; if (isJsxOpeningElement(node.parent) && isJsxElement(node.parent.parent)) { const containingElement = node.parent.parent; const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName); + const childrenPropName = childPropName === undefined ? "children" + : unescapeLeadingUnderscores(childPropName); const childrenNameType = getStringLiteralType(childrenPropName); const childrenTargetType = getIndexedAccessType(target, childrenNameType); const validChildren = getSemanticJsxChildren(containingElement.children); @@ -18396,14 +24093,24 @@ namespace ts { if (arrayLikeTargetParts !== neverType) { const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal)); const children = generateJsxChildren(containingElement, getInvalidTextualChildDiagnostic); - result = elaborateElementwise(children, realSource, arrayLikeTargetParts, relation, containingMessageChain, errorOutputContainer) || result; + result = elaborateElementwise( + children, + realSource, + arrayLikeTargetParts, + relation, + containingMessageChain, + errorOutputContainer, + ) || result; } - else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) { + else if ( + !isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation) + ) { // arity mismatch result = true; const diag = error( containingElement.openingElement.tagName, - Diagnostics.This_JSX_tag_s_0_prop_expects_a_single_child_of_type_1_but_multiple_children_were_provided, + Diagnostics + .This_JSX_tag_s_0_prop_expects_a_single_child_of_type_1_but_multiple_children_were_provided, childrenPropName, typeToString(childrenTargetType), ); @@ -18415,7 +24122,11 @@ namespace ts { else { if (nonArrayLikeTargetParts !== neverType) { const child = validChildren[0]; - const elem = getElaborationElementForJsxChild(child, childrenNameType, getInvalidTextualChildDiagnostic); + const elem = getElaborationElementForJsxChild( + child, + childrenNameType, + getInvalidTextualChildDiagnostic, + ); if (elem) { result = elaborateElementwise( (function* () { @@ -18429,12 +24140,15 @@ namespace ts { ) || result; } } - else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) { + else if ( + !isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation) + ) { // arity mismatch result = true; const diag = error( containingElement.openingElement.tagName, - Diagnostics.This_JSX_tag_s_0_prop_expects_type_1_which_requires_multiple_children_but_only_a_single_child_was_provided, + Diagnostics + .This_JSX_tag_s_0_prop_expects_type_1_which_requires_multiple_children_but_only_a_single_child_was_provided, childrenPropName, typeToString(childrenTargetType), ); @@ -18450,10 +24164,22 @@ namespace ts { if (!invalidTextDiagnostic) { const tagNameText = getTextOfNode(node.parent.tagName); const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName); + const childrenPropName = childPropName === undefined ? "children" + : unescapeLeadingUnderscores(childPropName); const childrenTargetType = getIndexedAccessType(target, getStringLiteralType(childrenPropName)); - const diagnostic = Diagnostics._0_components_don_t_accept_text_as_child_elements_Text_in_JSX_has_the_type_string_but_the_expected_type_of_1_is_2; - invalidTextDiagnostic = { ...diagnostic, key: "!!ALREADY FORMATTED!!", message: formatMessage(/*_dummy*/ undefined, diagnostic, tagNameText, childrenPropName, typeToString(childrenTargetType)) }; + const diagnostic = Diagnostics + ._0_components_don_t_accept_text_as_child_elements_Text_in_JSX_has_the_type_string_but_the_expected_type_of_1_is_2; + invalidTextDiagnostic = { + ...diagnostic, + key: "!!ALREADY FORMATTED!!", + message: formatMessage( + /*_dummy*/ undefined, + diagnostic, + tagNameText, + childrenPropName, + typeToString(childrenTargetType), + ), + }; } return invalidTextDiagnostic; } @@ -18482,7 +24208,14 @@ namespace ts { ) { if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false; if (isTupleLikeType(source)) { - return elaborateElementwise(generateLimitedTupleElements(node, target), source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateElementwise( + generateLimitedTupleElements(node, target), + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); } // recreate a tuple from the elements, if possible // Since we're re-doing the expression type, we need to reapply the contextual type @@ -18492,7 +24225,14 @@ namespace ts { const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true); node.contextualType = oldContext; if (isTupleLikeType(tupleizedType)) { - return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation, containingMessageChain, errorOutputContainer); + return elaborateElementwise( + generateLimitedTupleElements(node, target), + tupleizedType, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); } return false; } @@ -18517,7 +24257,14 @@ namespace ts { yield { errorNode: prop.name, innerExpression: undefined, nameType: type }; break; case SyntaxKind.PropertyAssignment: - yield { errorNode: prop.name, innerExpression: prop.initializer, nameType: type, errorMessage: isComputedNonLiteralName(prop.name) ? Diagnostics.Type_of_computed_property_s_value_is_0_which_is_not_assignable_to_type_1 : undefined }; + yield { + errorNode: prop.name, + innerExpression: prop.initializer, + nameType: type, + errorMessage: isComputedNonLiteralName(prop.name) + ? Diagnostics.Type_of_computed_property_s_value_is_0_which_is_not_assignable_to_type_1 + : undefined, + }; break; default: Debug.assertNever(prop); @@ -18534,19 +24281,48 @@ namespace ts { errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ) { if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false; - return elaborateElementwise(generateObjectLiteralElements(node), source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateElementwise( + generateObjectLiteralElements(node), + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); } /** * This is *not* a bi-directional relationship. * If one needs to check both directions for comparability, use a second call to this function or 'isTypeComparableTo'. */ - function checkTypeComparableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean { - return checkTypeRelatedTo(source, target, comparableRelation, errorNode, headMessage, containingMessageChain); + function checkTypeComparableTo( + source: Type, + target: Type, + errorNode: Node, + headMessage?: DiagnosticMessage, + containingMessageChain?: () => DiagnosticMessageChain | undefined, + ): boolean { + return checkTypeRelatedTo( + source, + target, + comparableRelation, + errorNode, + headMessage, + containingMessageChain, + ); } function isSignatureAssignableTo(source: Signature, target: Signature, ignoreReturnTypes: boolean): boolean { - return compareSignaturesRelated(source, target, ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : 0, /*reportErrors*/ false, /*errorReporter*/ undefined, /*errorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False; + return compareSignaturesRelated( + source, + target, + ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : 0, + /*reportErrors*/ false, + /*errorReporter*/ undefined, + /*errorReporter*/ undefined, + compareTypesAssignable, + /*reportUnreliableMarkers*/ undefined, + ) !== Ternary.False; } type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void; @@ -18555,15 +24331,27 @@ namespace ts { * Returns true if `s` is `(...args: any[]) => any` or `(this: any, ...args: any[]) => any` */ function isAnySignature(s: Signature) { - return !s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) && s.parameters.length === 1 && - signatureHasRestParameter(s) && (getTypeOfParameter(s.parameters[0]) === anyArrayType || isTypeAny(getTypeOfParameter(s.parameters[0]))) && - isTypeAny(getReturnTypeOfSignature(s)); + return !s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) + && s.parameters.length === 1 + && signatureHasRestParameter(s) + && (getTypeOfParameter(s.parameters[0]) === anyArrayType + || isTypeAny(getTypeOfParameter(s.parameters[0]))) + && isTypeAny(getReturnTypeOfSignature(s)); } /** * See signatureRelatedTo, compareSignaturesIdentical */ - function compareSignaturesRelated(source: Signature, target: Signature, checkMode: SignatureCheckMode, reportErrors: boolean, errorReporter: ErrorReporter | undefined, incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined, compareTypes: TypeComparer, reportUnreliableMarkers: TypeMapper | undefined): Ternary { + function compareSignaturesRelated( + source: Signature, + target: Signature, + checkMode: SignatureCheckMode, + reportErrors: boolean, + errorReporter: ErrorReporter | undefined, + incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined, + compareTypes: TypeComparer, + reportUnreliableMarkers: TypeMapper | undefined, + ): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; @@ -18574,8 +24362,10 @@ namespace ts { } const targetCount = getParameterCount(target); - const sourceHasMoreParameters = !hasEffectiveRestParameter(target) && - (checkMode & SignatureCheckMode.StrictArity ? hasEffectiveRestParameter(source) || getParameterCount(source) > targetCount : getMinArgumentCount(source) > targetCount); + const sourceHasMoreParameters = !hasEffectiveRestParameter(target) + && (checkMode & SignatureCheckMode.StrictArity + ? hasEffectiveRestParameter(source) || getParameterCount(source) > targetCount + : getMinArgumentCount(source) > targetCount); if (sourceHasMoreParameters) { return Ternary.False; } @@ -18593,8 +24383,9 @@ namespace ts { } const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; - const strictVariance = !(checkMode & SignatureCheckMode.Callback) && strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration && - kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor; + const strictVariance = !(checkMode & SignatureCheckMode.Callback) && strictFunctionTypes + && kind !== SyntaxKind.MethodDeclaration + && kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor; let result = Ternary.True; const sourceThisType = getThisTypeOfSignature(source); @@ -18602,7 +24393,8 @@ namespace ts { const targetThisType = getThisTypeOfSignature(target); if (targetThisType) { // void sources are assignable to anything. - const related = !strictVariance && compareTypes(sourceThisType, targetThisType, /*reportErrors*/ false) + const related = + !strictVariance && compareTypes(sourceThisType, targetThisType, /*reportErrors*/ false) || compareTypes(targetThisType, sourceThisType, reportErrors); if (!related) { if (reportErrors) { @@ -18614,7 +24406,8 @@ namespace ts { } } - const paramCount = sourceRestType || targetRestType ? Math.min(sourceCount, targetCount) : Math.max(sourceCount, targetCount); + const paramCount = sourceRestType || targetRestType ? Math.min(sourceCount, targetCount) + : Math.max(sourceCount, targetCount); const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1; for (let i = 0; i < paramCount; i++) { @@ -18629,20 +24422,45 @@ namespace ts { // similar to return values, callback parameters are output positions. This means that a Promise, // where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant) // with respect to T. - const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); - const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType)); - const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && - (getTypeFacts(sourceType) & TypeFacts.IsUndefinedOrNull) === (getTypeFacts(targetType) & TypeFacts.IsUndefinedOrNull); - let related = callbacks ? - compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) : - !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); + const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined + : getSingleCallSignature(getNonNullableType(sourceType)); + const targetSig = checkMode & SignatureCheckMode.Callback ? undefined + : getSingleCallSignature(getNonNullableType(targetType)); + const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) + && !getTypePredicateOfSignature(targetSig) + && (getTypeFacts(sourceType) & TypeFacts.IsUndefinedOrNull) + === (getTypeFacts(targetType) & TypeFacts.IsUndefinedOrNull); + let related = callbacks + ? compareSignaturesRelated( + targetSig, + sourceSig, + (checkMode & SignatureCheckMode.StrictArity) + | (strictVariance ? SignatureCheckMode.StrictCallback + : SignatureCheckMode.BivariantCallback), + reportErrors, + errorReporter, + incompatibleErrorReporter, + compareTypes, + reportUnreliableMarkers, + ) + : !(checkMode & SignatureCheckMode.Callback) && !strictVariance + && compareTypes(sourceType, targetType, /*reportErrors*/ false) + || compareTypes(targetType, sourceType, reportErrors); // With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void - if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) { + if ( + related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) + && i < getMinArgumentCount(target) + && compareTypes(sourceType, targetType, /*reportErrors*/ false) + ) { related = Ternary.False; } if (!related) { if (reportErrors) { - errorReporter!(Diagnostics.Types_of_parameters_0_and_1_are_incompatible, unescapeLeadingUnderscores(getParameterNameAtPosition(source, i)), unescapeLeadingUnderscores(getParameterNameAtPosition(target, i))); + errorReporter!( + Diagnostics.Types_of_parameters_0_and_1_are_incompatible, + unescapeLeadingUnderscores(getParameterNameAtPosition(source, i)), + unescapeLeadingUnderscores(getParameterNameAtPosition(target, i)), + ); } return Ternary.False; } @@ -18654,13 +24472,15 @@ namespace ts { // If a signature resolution is already in-flight, skip issuing a circularity error // here and just use the `any` type directly const targetReturnType = isResolvingReturnTypeOfSignature(target) ? anyType - : target.declaration && isJSConstructor(target.declaration) ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(target.declaration.symbol)) + : target.declaration && isJSConstructor(target.declaration) + ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(target.declaration.symbol)) : getReturnTypeOfSignature(target); if (targetReturnType === voidType || targetReturnType === anyType) { return result; } const sourceReturnType = isResolvingReturnTypeOfSignature(source) ? anyType - : source.declaration && isJSConstructor(source.declaration) ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(source.declaration.symbol)) + : source.declaration && isJSConstructor(source.declaration) + ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(source.declaration.symbol)) : getReturnTypeOfSignature(source); // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions @@ -18668,7 +24488,13 @@ namespace ts { if (targetTypePredicate) { const sourceTypePredicate = getTypePredicateOfSignature(source); if (sourceTypePredicate) { - result &= compareTypePredicateRelatedTo(sourceTypePredicate, targetTypePredicate, reportErrors, errorReporter, compareTypes); + result &= compareTypePredicateRelatedTo( + sourceTypePredicate, + targetTypePredicate, + reportErrors, + errorReporter, + compareTypes, + ); } else if (isIdentifierTypePredicate(targetTypePredicate)) { if (reportErrors) { @@ -18681,8 +24507,9 @@ namespace ts { // When relating callback signatures, we still need to relate return types bi-variantly as otherwise // the containing type wouldn't be co-variant. For example, interface Foo { add(cb: () => T): void } // wouldn't be co-variant for T without this rule. - result &= checkMode & SignatureCheckMode.BivariantCallback && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) || - compareTypes(sourceReturnType, targetReturnType, reportErrors); + result &= checkMode & SignatureCheckMode.BivariantCallback + && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) + || compareTypes(sourceReturnType, targetReturnType, reportErrors); if (!result && reportErrors && incompatibleErrorReporter) { incompatibleErrorReporter(sourceReturnType, targetReturnType); } @@ -18701,8 +24528,14 @@ namespace ts { ): Ternary { if (source.kind !== target.kind) { if (reportErrors) { - errorReporter!(Diagnostics.A_this_based_type_guard_is_not_compatible_with_a_parameter_based_type_guard); - errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + errorReporter!( + Diagnostics.A_this_based_type_guard_is_not_compatible_with_a_parameter_based_type_guard, + ); + errorReporter!( + Diagnostics.Type_predicate_0_is_not_assignable_to_1, + typePredicateToString(source), + typePredicateToString(target), + ); } return Ternary.False; } @@ -18710,18 +24543,30 @@ namespace ts { if (source.kind === TypePredicateKind.Identifier || source.kind === TypePredicateKind.AssertsIdentifier) { if (source.parameterIndex !== (target as IdentifierTypePredicate).parameterIndex) { if (reportErrors) { - errorReporter!(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, source.parameterName, (target as IdentifierTypePredicate).parameterName); - errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + errorReporter!( + Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, + source.parameterName, + (target as IdentifierTypePredicate).parameterName, + ); + errorReporter!( + Diagnostics.Type_predicate_0_is_not_assignable_to_1, + typePredicateToString(source), + typePredicateToString(target), + ); } return Ternary.False; } } - const related = source.type === target.type ? Ternary.True : - source.type && target.type ? compareTypes(source.type, target.type, reportErrors) : - Ternary.False; + const related = source.type === target.type ? Ternary.True + : source.type && target.type ? compareTypes(source.type, target.type, reportErrors) + : Ternary.False; if (related === Ternary.False && reportErrors) { - errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + errorReporter!( + Diagnostics.Type_predicate_0_is_not_assignable_to_1, + typePredicateToString(source), + typePredicateToString(target), + ); } return related; } @@ -18745,25 +24590,27 @@ namespace ts { } function isEmptyResolvedType(t: ResolvedType) { - return t !== anyFunctionType && - t.properties.length === 0 && - t.callSignatures.length === 0 && - t.constructSignatures.length === 0 && - t.indexInfos.length === 0; + return t !== anyFunctionType + && t.properties.length === 0 + && t.callSignatures.length === 0 + && t.constructSignatures.length === 0 + && t.indexInfos.length === 0; } function isEmptyObjectType(type: Type): boolean { - return type.flags & TypeFlags.Object ? !isGenericMappedType(type) && isEmptyResolvedType(resolveStructuredTypeMembers(type as ObjectType)) : - type.flags & TypeFlags.NonPrimitive ? true : - type.flags & TypeFlags.Union ? some((type as UnionType).types, isEmptyObjectType) : - type.flags & TypeFlags.Intersection ? every((type as UnionType).types, isEmptyObjectType) : - false; + return type.flags & TypeFlags.Object + ? !isGenericMappedType(type) && isEmptyResolvedType(resolveStructuredTypeMembers(type as ObjectType)) + : type.flags & TypeFlags.NonPrimitive ? true + : type.flags & TypeFlags.Union ? some((type as UnionType).types, isEmptyObjectType) + : type.flags & TypeFlags.Intersection ? every((type as UnionType).types, isEmptyObjectType) + : false; } function isEmptyAnonymousObjectType(type: Type) { return !!(getObjectFlags(type) & ObjectFlags.Anonymous && ( - (type as ResolvedType).members && isEmptyResolvedType(type as ResolvedType) || - type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral && getMembersOfSymbol(type.symbol).size === 0 + (type as ResolvedType).members && isEmptyResolvedType(type as ResolvedType) + || type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral + && getMembersOfSymbol(type.symbol).size === 0 )); } @@ -18771,8 +24618,10 @@ namespace ts { if (strictNullChecks && type.flags & TypeFlags.Union) { if (!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnionComputed)) { const types = (type as UnionType).types; - (type as UnionType).objectFlags |= ObjectFlags.IsUnknownLikeUnionComputed | (types.length >= 3 && types[0].flags & TypeFlags.Undefined && - types[1].flags & TypeFlags.Null && some(types, isEmptyAnonymousObjectType) ? ObjectFlags.IsUnknownLikeUnion : 0); + (type as UnionType).objectFlags |= ObjectFlags.IsUnknownLikeUnionComputed + | (types.length >= 3 && types[0].flags & TypeFlags.Undefined + && types[1].flags & TypeFlags.Null && some(types, isEmptyAnonymousObjectType) + ? ObjectFlags.IsUnknownLikeUnion : 0); } return !!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnion); } @@ -18784,9 +24633,11 @@ namespace ts { } function isStringIndexSignatureOnlyType(type: Type): boolean { - return type.flags & TypeFlags.Object && !isGenericMappedType(type) && getPropertiesOfType(type).length === 0 && getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, stringType) || - type.flags & TypeFlags.UnionOrIntersection && every((type as UnionOrIntersectionType).types, isStringIndexSignatureOnlyType) || - false; + return type.flags & TypeFlags.Object && !isGenericMappedType(type) && getPropertiesOfType(type).length === 0 + && getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, stringType) + || type.flags & TypeFlags.UnionOrIntersection + && every((type as UnionOrIntersectionType).types, isStringIndexSignatureOnlyType) + || false; } function isEnumTypeRelatedTo(sourceSymbol: Symbol, targetSymbol: Symbol, errorReporter?: ErrorReporter) { @@ -18795,10 +24646,17 @@ namespace ts { } const id = getSymbolId(sourceSymbol) + "," + getSymbolId(targetSymbol); const entry = enumRelation.get(id); - if (entry !== undefined && !(!(entry & RelationComparisonResult.Reported) && entry & RelationComparisonResult.Failed && errorReporter)) { + if ( + entry !== undefined + && !(!(entry & RelationComparisonResult.Reported) && entry & RelationComparisonResult.Failed + && errorReporter) + ) { return !!(entry & RelationComparisonResult.Succeeded); } - if (sourceSymbol.escapedName !== targetSymbol.escapedName || !(sourceSymbol.flags & SymbolFlags.RegularEnum) || !(targetSymbol.flags & SymbolFlags.RegularEnum)) { + if ( + sourceSymbol.escapedName !== targetSymbol.escapedName || !(sourceSymbol.flags & SymbolFlags.RegularEnum) + || !(targetSymbol.flags & SymbolFlags.RegularEnum) + ) { enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported); return false; } @@ -18808,7 +24666,15 @@ namespace ts { const targetProperty = getPropertyOfType(targetEnumType, property.escapedName); if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) { if (errorReporter) { - errorReporter(Diagnostics.Property_0_is_missing_in_type_1, symbolName(property), typeToString(getDeclaredTypeOfSymbol(targetSymbol), /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType)); + errorReporter( + Diagnostics.Property_0_is_missing_in_type_1, + symbolName(property), + typeToString( + getDeclaredTypeOfSymbol(targetSymbol), + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.UseFullyQualifiedType, + ), + ); enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported); } else { @@ -18822,40 +24688,65 @@ namespace ts { return true; } - function isSimpleTypeRelatedTo(source: Type, target: Type, relation: ESMap, errorReporter?: ErrorReporter) { + function isSimpleTypeRelatedTo( + source: Type, + target: Type, + relation: ESMap, + errorReporter?: ErrorReporter, + ) { const s = source.flags; const t = target.flags; if (t & TypeFlags.AnyOrUnknown || s & TypeFlags.Never || source === wildcardType) return true; if (t & TypeFlags.Never) return false; if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; if ( - s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && - t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) && - (source as StringLiteralType).value === (target as StringLiteralType).value + s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral + && t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) + && (source as StringLiteralType).value === (target as StringLiteralType).value ) return true; if (s & TypeFlags.NumberLike && t & TypeFlags.Number) return true; if ( - s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral && - t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) && - (source as NumberLiteralType).value === (target as NumberLiteralType).value + s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral + && t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) + && (source as NumberLiteralType).value === (target as NumberLiteralType).value ) return true; if (s & TypeFlags.BigIntLike && t & TypeFlags.BigInt) return true; if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true; if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true; - if (s & TypeFlags.Enum && t & TypeFlags.Enum && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; + if ( + s & TypeFlags.Enum && t & TypeFlags.Enum + && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter) + ) return true; if (s & TypeFlags.EnumLiteral && t & TypeFlags.EnumLiteral) { - if (s & TypeFlags.Union && t & TypeFlags.Union && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; if ( - s & TypeFlags.Literal && t & TypeFlags.Literal && - (source as LiteralType).value === (target as LiteralType).value && - isEnumTypeRelatedTo(getParentOfSymbol(source.symbol)!, getParentOfSymbol(target.symbol)!, errorReporter) + s & TypeFlags.Union && t & TypeFlags.Union + && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter) + ) return true; + if ( + s & TypeFlags.Literal && t & TypeFlags.Literal + && (source as LiteralType).value === (target as LiteralType).value + && isEnumTypeRelatedTo( + getParentOfSymbol(source.symbol)!, + getParentOfSymbol(target.symbol)!, + errorReporter, + ) ) return true; } // In non-strictNullChecks mode, `undefined` and `null` are assignable to anything except `never`. // Since unions and intersections may reduce to `never`, we exclude them here. - if (s & TypeFlags.Undefined && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & (TypeFlags.Undefined | TypeFlags.Void))) return true; - if (s & TypeFlags.Null && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & TypeFlags.Null)) return true; - if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source) && !(getObjectFlags(source) & ObjectFlags.FreshLiteral))) return true; + if ( + s & TypeFlags.Undefined + && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) + || t & (TypeFlags.Undefined | TypeFlags.Void)) + ) return true; + if ( + s & TypeFlags.Null && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & TypeFlags.Null) + ) return true; + if ( + s & TypeFlags.Object && t & TypeFlags.NonPrimitive + && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source) + && !(getObjectFlags(source) & ObjectFlags.FreshLiteral)) + ) return true; if (relation === assignableRelation || relation === comparableRelation) { if (s & TypeFlags.Any) return true; // Type number or any numeric literal type is assignable to any numeric enum type or any @@ -18863,7 +24754,8 @@ namespace ts { // bit-flag enum types sometimes look like literal enum types with numeric literal values. if ( s & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(s & TypeFlags.EnumLiteral) && ( - t & TypeFlags.Enum || relation === assignableRelation && t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral + t & TypeFlags.Enum + || relation === assignableRelation && t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral ) ) return true; // Anything is assignable to a union containing undefined, null, and {} @@ -18883,22 +24775,34 @@ namespace ts { return true; } if (relation !== identityRelation) { - if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || isSimpleTypeRelatedTo(source, target, relation)) { + if ( + relation === comparableRelation && !(target.flags & TypeFlags.Never) + && isSimpleTypeRelatedTo(target, source, relation) + || isSimpleTypeRelatedTo(source, target, relation) + ) { return true; } } - else if (!((source.flags | target.flags) & (TypeFlags.UnionOrIntersection | TypeFlags.IndexedAccess | TypeFlags.Conditional | TypeFlags.Substitution))) { + else if ( + !((source.flags | target.flags) + & (TypeFlags.UnionOrIntersection | TypeFlags.IndexedAccess | TypeFlags.Conditional + | TypeFlags.Substitution)) + ) { // We have excluded types that may simplify to other forms, so types must have identical flags if (source.flags !== target.flags) return false; if (source.flags & TypeFlags.Singleton) return true; } if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { - const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false)); + const related = relation.get( + getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false), + ); if (related !== undefined) { return !!(related & RelationComparisonResult.Succeeded); } } - if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { + if ( + source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable + ) { return checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined); } return false; @@ -18910,12 +24814,18 @@ namespace ts { function getNormalizedType(type: Type, writing: boolean): Type { while (true) { - const t = isFreshLiteralType(type) ? (type as FreshableType).regularType : - getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : getSingleBaseForNonAugmentingSubtype(type) || type : - type.flags & TypeFlags.UnionOrIntersection ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) : - type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : getSubstitutionIntersection(type as SubstitutionType) : - type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) : - type; + const t = isFreshLiteralType(type) ? (type as FreshableType).regularType + : getObjectFlags(type) & ObjectFlags.Reference + ? (type as TypeReference).node + ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) + : getSingleBaseForNonAugmentingSubtype(type) || type + : type.flags & TypeFlags.UnionOrIntersection + ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) + : type.flags & TypeFlags.Substitution + ? writing ? (type as SubstitutionType).baseType + : getSubstitutionIntersection(type as SubstitutionType) + : type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) + : type; if (t === type) return t; type = t; } @@ -18926,7 +24836,10 @@ namespace ts { if (reduced !== type) { return reduced; } - if (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isEmptyAnonymousObjectType)) { + if ( + type.flags & TypeFlags.Intersection + && some((type as IntersectionType).types, isEmptyAnonymousObjectType) + ) { const normalizedTypes = sameMap(type.types, t => getNormalizedType(t, writing)); if (normalizedTypes !== type.types) { return getIntersectionType(normalizedTypes); @@ -18967,7 +24880,13 @@ namespace ts { let overflow = false; let overrideNextErrorInfo = 0; // How many `reportRelationError` calls should be skipped in the elaboration pyramid let lastSkippedInfo: [Type, Type] | undefined; - let incompatibleStack: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] | undefined; + let incompatibleStack: [ + DiagnosticMessage, + (string | number)?, + (string | number)?, + (string | number)?, + (string | number)?, + ][] | undefined; let inPropertyCheck = false; Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); @@ -18977,8 +24896,18 @@ namespace ts { reportIncompatibleStack(); } if (overflow) { - tracing?.instant(tracing.Phase.CheckTypes, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth: sourceDepth, targetDepth }); - const diag = error(errorNode || currentNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target)); + tracing?.instant(tracing.Phase.CheckTypes, "checkTypeRelatedTo_DepthLimit", { + sourceId: source.id, + targetId: target.id, + depth: sourceDepth, + targetDepth, + }); + const diag = error( + errorNode || currentNode, + Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, + typeToString(source), + typeToString(target), + ); if (errorOutputContainer) { (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); } @@ -18997,10 +24926,19 @@ namespace ts { if (headMessage && errorNode && !result && source.symbol) { const links = getSymbolLinks(source.symbol); if (links.originatingImport && !isImportCall(links.originatingImport)) { - const helpfulRetry = checkTypeRelatedTo(getTypeOfSymbol(links.target!), target, relation, /*errorNode*/ undefined); + const helpfulRetry = checkTypeRelatedTo( + getTypeOfSymbol(links.target!), + target, + relation, + /*errorNode*/ undefined, + ); if (helpfulRetry) { // Likely an incorrect import. Issue a helpful diagnostic to produce a quickfix to change the import - const diag = createDiagnosticForNode(links.originatingImport, Diagnostics.Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead); + const diag = createDiagnosticForNode( + links.originatingImport, + Diagnostics + .Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead, + ); relatedInformation = append(relatedInformation, diag); // Cause the error to appear with the error that triggered it } } @@ -19036,11 +24974,20 @@ namespace ts { lastSkippedInfo, incompatibleStack: incompatibleStack?.slice(), overrideNextErrorInfo, - relatedInfo: relatedInfo?.slice() as [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined, + relatedInfo: relatedInfo?.slice() as [ + DiagnosticRelatedInformation, + ...DiagnosticRelatedInformation[], + ] | undefined, }; } - function reportIncompatibleError(message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number) { + function reportIncompatibleError( + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ) { overrideNextErrorInfo++; // Suppress the next relation error lastSkippedInfo = undefined; // Reset skipped info cache (incompatibleStack ||= []).push([message, arg0, arg1, arg2, arg3]); @@ -19062,7 +25009,13 @@ namespace ts { // The first error will be the innermost, while the last will be the outermost - so by popping off the end, // we can build from left to right let path = ""; - const secondaryRootErrors: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] = []; + const secondaryRootErrors: [ + DiagnosticMessage, + (string | number)?, + (string | number)?, + (string | number)?, + (string | number)?, + ][] = []; while (stack.length) { const [msg, ...args] = stack.pop()!; switch (msg.code) { @@ -19093,38 +25046,74 @@ namespace ts { case Diagnostics.Call_signature_return_types_0_and_1_are_incompatible.code: case Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code: case Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code: - case Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code: { + case Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code: { if (path.length === 0) { // Don't flatten signature compatability errors at the start of a chain - instead prefer // to unify (the with no arguments bit is excessive for printback) and print them back let mappedMsg = msg; - if (msg.code === Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) { + if ( + msg.code + === Diagnostics + .Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code + ) { mappedMsg = Diagnostics.Call_signature_return_types_0_and_1_are_incompatible; } - else if (msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) { + else if ( + msg.code + === Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code + ) { mappedMsg = Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible; } secondaryRootErrors.unshift([mappedMsg, args[0], args[1]]); } else { - const prefix = (msg.code === Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code || - msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) + const prefix = (msg.code + === Diagnostics + .Construct_signature_return_types_0_and_1_are_incompatible.code + || msg.code + === Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code) ? "new " : ""; - const params = (msg.code === Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code || - msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) + const params = (msg.code + === Diagnostics + .Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code + || msg.code + === Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code) ? "" : "..."; path = `${prefix}${path}(${params})`; } break; } - case Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target.code: { - secondaryRootErrors.unshift([Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, args[0], args[1]]); + case Diagnostics + .Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target.code: { + secondaryRootErrors.unshift([ + Diagnostics + .Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, + args[0], + args[1], + ]); break; } - case Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target.code: { - secondaryRootErrors.unshift([Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, args[0], args[1], args[2]]); + case Diagnostics + .Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target + .code: { + secondaryRootErrors.unshift([ + Diagnostics + .Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, + args[0], + args[1], + args[2], + ]); break; } default: @@ -19155,7 +25144,13 @@ namespace ts { } } - function reportError(message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { + function reportError( + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): void { Debug.assert(!!errorNode); if (incompatibleStack) reportIncompatibleStack(); if (message.elidedInCompatabilityPyramid) return; @@ -19180,16 +25175,27 @@ namespace ts { if (isLiteralType(source) && !typeCouldHaveTopLevelSingletonTypes(target)) { generalizedSource = getBaseTypeOfLiteralType(source); - Debug.assert(!isTypeAssignableTo(generalizedSource, target), "generalized source shouldn't be assignable"); + Debug.assert( + !isTypeAssignableTo(generalizedSource, target), + "generalized source shouldn't be assignable", + ); generalizedSourceType = getTypeNameForErrorDisplay(generalizedSource); } - if (target.flags & TypeFlags.TypeParameter && target !== markerSuperTypeForCheck && target !== markerSubTypeForCheck) { + if ( + target.flags & TypeFlags.TypeParameter && target !== markerSuperTypeForCheck + && target !== markerSubTypeForCheck + ) { const constraint = getBaseConstraintOfType(target); let needsOriginalSource; - if (constraint && (isTypeAssignableTo(generalizedSource, constraint) || (needsOriginalSource = isTypeAssignableTo(source, constraint)))) { + if ( + constraint + && (isTypeAssignableTo(generalizedSource, constraint) + || (needsOriginalSource = isTypeAssignableTo(source, constraint))) + ) { reportError( - Diagnostics._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2, + Diagnostics + ._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2, needsOriginalSource ? sourceType : generalizedSourceType, targetType, typeToString(constraint), @@ -19210,16 +25216,28 @@ namespace ts { message = Diagnostics.Type_0_is_not_comparable_to_type_1; } else if (sourceType === targetType) { - message = Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated; + message = Diagnostics + .Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated; } - else if (exactOptionalPropertyTypes && getExactOptionalUnassignableProperties(source, target).length) { - message = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; + else if ( + exactOptionalPropertyTypes && getExactOptionalUnassignableProperties(source, target).length + ) { + message = Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; } else { if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.Union) { - const suggestedType = getSuggestedTypeForNonexistentStringLiteralType(source as StringLiteralType, target as UnionType); + const suggestedType = getSuggestedTypeForNonexistentStringLiteralType( + source as StringLiteralType, + target as UnionType, + ); if (suggestedType) { - reportError(Diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, generalizedSourceType, targetType, typeToString(suggestedType)); + reportError( + Diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, + generalizedSourceType, + targetType, + typeToString(suggestedType), + ); return; } } @@ -19231,23 +25249,30 @@ namespace ts { && exactOptionalPropertyTypes && getExactOptionalUnassignableProperties(source, target).length ) { - message = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; + message = Diagnostics + .Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; } reportError(message, generalizedSourceType, targetType); } function tryElaborateErrorsForPrimitivesAndObjects(source: Type, target: Type) { - const sourceType = symbolValueDeclarationIsContextSensitive(source.symbol) ? typeToString(source, source.symbol.valueDeclaration) : typeToString(source); - const targetType = symbolValueDeclarationIsContextSensitive(target.symbol) ? typeToString(target, target.symbol.valueDeclaration) : typeToString(target); + const sourceType = symbolValueDeclarationIsContextSensitive(source.symbol) + ? typeToString(source, source.symbol.valueDeclaration) : typeToString(source); + const targetType = symbolValueDeclarationIsContextSensitive(target.symbol) + ? typeToString(target, target.symbol.valueDeclaration) : typeToString(target); if ( - (globalStringType === source && stringType === target) || - (globalNumberType === source && numberType === target) || - (globalBooleanType === source && booleanType === target) || - (getGlobalESSymbolType() === source && esSymbolType === target) + (globalStringType === source && stringType === target) + || (globalNumberType === source && numberType === target) + || (globalBooleanType === source && booleanType === target) + || (getGlobalESSymbolType() === source && esSymbolType === target) ) { - reportError(Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, targetType, sourceType); + reportError( + Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, + targetType, + sourceType, + ); } } @@ -19268,7 +25293,11 @@ namespace ts { if (isTupleType(source)) { if (source.target.readonly && isMutableArrayOrTuple(target)) { if (reportErrors) { - reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target)); + reportError( + Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, + typeToString(source), + typeToString(target), + ); } return false; } @@ -19276,7 +25305,11 @@ namespace ts { } if (isReadonlyArrayType(source) && isMutableArrayOrTuple(target)) { if (reportErrors) { - reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target)); + reportError( + Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, + typeToString(source), + typeToString(target), + ); } return false; } @@ -19296,11 +25329,25 @@ namespace ts { * * Ternary.Maybe if they are related with assumptions of other relationships, or * * Ternary.False if they are not related. */ - function isRelatedTo(originalSource: Type, originalTarget: Type, recursionFlags: RecursionFlags = RecursionFlags.Both, reportErrors = false, headMessage?: DiagnosticMessage, intersectionState = IntersectionState.None): Ternary { + function isRelatedTo( + originalSource: Type, + originalTarget: Type, + recursionFlags: RecursionFlags = RecursionFlags.Both, + reportErrors = false, + headMessage?: DiagnosticMessage, + intersectionState = IntersectionState.None, + ): Ternary { // Before normalization: if `source` is type an object type, and `target` is primitive, // skip all the checks we don't need and just return `isSimpleTypeRelatedTo` result if (originalSource.flags & TypeFlags.Object && originalTarget.flags & TypeFlags.Primitive) { - if (isSimpleTypeRelatedTo(originalSource, originalTarget, relation, reportErrors ? reportError : undefined)) { + if ( + isSimpleTypeRelatedTo( + originalSource, + originalTarget, + relation, + reportErrors ? reportError : undefined, + ) + ) { return Ternary.True; } if (reportErrors) { @@ -19322,7 +25369,13 @@ namespace ts { if (source.flags !== target.flags) return Ternary.False; if (source.flags & TypeFlags.Singleton) return Ternary.True; traceUnionsOrIntersectionsTooLarge(source, target); - return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false, IntersectionState.None, recursionFlags); + return recursiveTypeRelatedTo( + source, + target, + /*reportErrors*/ false, + IntersectionState.None, + recursionFlags, + ); } // We fastpath comparing a type parameter to exactly its constraint, as this is _super_ common, @@ -19338,9 +25391,10 @@ namespace ts { // plus a single non-nullable type. If so, remove null and/or undefined from the target type. if (source.flags & TypeFlags.DefinitelyNonNullable && target.flags & TypeFlags.Union) { const types = (target as UnionType).types; - const candidate = types.length === 2 && types[0].flags & TypeFlags.Nullable ? types[1] : - types.length === 3 && types[0].flags & TypeFlags.Nullable && types[1].flags & TypeFlags.Nullable ? types[2] : - undefined; + const candidate = types.length === 2 && types[0].flags & TypeFlags.Nullable ? types[1] + : types.length === 3 && types[0].flags & TypeFlags.Nullable + && types[1].flags & TypeFlags.Nullable ? types[2] + : undefined; if (candidate && !(candidate.flags & TypeFlags.Nullable)) { target = getNormalizedType(candidate, /*writing*/ true); if (source === target) return Ternary.True; @@ -19348,41 +25402,75 @@ namespace ts { } if ( - relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || - isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined) + relation === comparableRelation && !(target.flags & TypeFlags.Never) + && isSimpleTypeRelatedTo(target, source, relation) + || isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined) ) return Ternary.True; - if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { - const isPerformingExcessPropertyChecks = !(intersectionState & IntersectionState.Target) && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral); + if ( + source.flags & TypeFlags.StructuredOrInstantiable + || target.flags & TypeFlags.StructuredOrInstantiable + ) { + const isPerformingExcessPropertyChecks = !(intersectionState & IntersectionState.Target) + && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral); if (isPerformingExcessPropertyChecks) { if (hasExcessProperties(source as FreshObjectLiteralType, target, reportErrors)) { if (reportErrors) { - reportRelationError(headMessage, source, originalTarget.aliasSymbol ? originalTarget : target); + reportRelationError( + headMessage, + source, + originalTarget.aliasSymbol ? originalTarget : target, + ); } return Ternary.False; } } - const isPerformingCommonPropertyChecks = (relation !== comparableRelation || isUnitType(source)) && - !(intersectionState & IntersectionState.Target) && - source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) && source !== globalObjectType && - target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) && - (getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source)); + const isPerformingCommonPropertyChecks = (relation !== comparableRelation || isUnitType(source)) + && !(intersectionState & IntersectionState.Target) + && source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) + && source !== globalObjectType + && target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) + && (getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source)); const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); - if (isPerformingCommonPropertyChecks && !hasCommonProperties(source, target, isComparingJsxAttributes)) { + if ( + isPerformingCommonPropertyChecks + && !hasCommonProperties(source, target, isComparingJsxAttributes) + ) { if (reportErrors) { const sourceString = typeToString(originalSource.aliasSymbol ? originalSource : source); const targetString = typeToString(originalTarget.aliasSymbol ? originalTarget : target); const calls = getSignaturesOfType(source, SignatureKind.Call); const constructs = getSignaturesOfType(source, SignatureKind.Construct); if ( - calls.length > 0 && isRelatedTo(getReturnTypeOfSignature(calls[0]), target, RecursionFlags.Source, /*reportErrors*/ false) || - constructs.length > 0 && isRelatedTo(getReturnTypeOfSignature(constructs[0]), target, RecursionFlags.Source, /*reportErrors*/ false) + calls.length > 0 + && isRelatedTo( + getReturnTypeOfSignature(calls[0]), + target, + RecursionFlags.Source, + /*reportErrors*/ false, + ) + || constructs.length > 0 + && isRelatedTo( + getReturnTypeOfSignature(constructs[0]), + target, + RecursionFlags.Source, + /*reportErrors*/ false, + ) ) { - reportError(Diagnostics.Value_of_type_0_has_no_properties_in_common_with_type_1_Did_you_mean_to_call_it, sourceString, targetString); + reportError( + Diagnostics + .Value_of_type_0_has_no_properties_in_common_with_type_1_Did_you_mean_to_call_it, + sourceString, + targetString, + ); } else { - reportError(Diagnostics.Type_0_has_no_properties_in_common_with_type_1, sourceString, targetString); + reportError( + Diagnostics.Type_0_has_no_properties_in_common_with_type_1, + sourceString, + targetString, + ); } } return Ternary.False; @@ -19390,11 +25478,13 @@ namespace ts { traceUnionsOrIntersectionsTooLarge(source, target); - const skipCaching = source.flags & TypeFlags.Union && (source as UnionType).types.length < 4 && !(target.flags & TypeFlags.Union) || - target.flags & TypeFlags.Union && (target as UnionType).types.length < 4 && !(source.flags & TypeFlags.StructuredOrInstantiable); - const result = skipCaching ? - unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState) : - recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags); + const skipCaching = source.flags & TypeFlags.Union && (source as UnionType).types.length < 4 + && !(target.flags & TypeFlags.Union) + || target.flags & TypeFlags.Union && (target as UnionType).types.length < 4 + && !(source.flags & TypeFlags.StructuredOrInstantiable); + const result = skipCaching + ? unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState) + : recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags); if (result) { return result; } @@ -19406,7 +25496,13 @@ namespace ts { return Ternary.False; } - function reportErrorResults(originalSource: Type, originalTarget: Type, source: Type, target: Type, headMessage: DiagnosticMessage | undefined) { + function reportErrorResults( + originalSource: Type, + originalTarget: Type, + source: Type, + target: Type, + headMessage: DiagnosticMessage | undefined, + ) { const sourceHasBase = !!getSingleBaseForNonAugmentingSubtype(originalSource); const targetHasBase = !!getSingleBaseForNonAugmentingSubtype(originalTarget); source = (originalSource.aliasSymbol || sourceHasBase) ? originalSource : source; @@ -19426,15 +25522,19 @@ namespace ts { tryElaborateErrorsForPrimitivesAndObjects(source, target); } else if (source.symbol && source.flags & TypeFlags.Object && globalObjectType === source) { - reportError(Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead); + reportError( + Diagnostics + .The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead, + ); } else if (getObjectFlags(source) & ObjectFlags.JsxAttributes && target.flags & TypeFlags.Intersection) { const targetTypes = (target as IntersectionType).types; const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, errorNode); const intrinsicClassAttributes = getJsxType(JsxNames.IntrinsicClassAttributes, errorNode); if ( - !isErrorType(intrinsicAttributes) && !isErrorType(intrinsicClassAttributes) && - (contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes)) + !isErrorType(intrinsicAttributes) && !isErrorType(intrinsicClassAttributes) + && (contains(targetTypes, intrinsicAttributes) + || contains(targetTypes, intrinsicClassAttributes)) ) { // do not report top error return; @@ -19449,12 +25549,21 @@ namespace ts { return; } reportRelationError(headMessage, source, target); - if (source.flags & TypeFlags.TypeParameter && source.symbol?.declarations?.[0] && !getConstraintOfType(source as TypeVariable)) { + if ( + source.flags & TypeFlags.TypeParameter && source.symbol?.declarations?.[0] + && !getConstraintOfType(source as TypeVariable) + ) { const syntheticParam = cloneTypeParameter(source as TypeParameter); syntheticParam.constraint = instantiateType(target, makeUnaryTypeMapper(source, syntheticParam)); if (hasNonCircularBaseConstraint(syntheticParam)) { const targetConstraintString = typeToString(target, source.symbol.declarations[0]); - associateRelatedInfo(createDiagnosticForNode(source.symbol.declarations[0], Diagnostics.This_type_parameter_might_need_an_extends_0_constraint, targetConstraintString)); + associateRelatedInfo( + createDiagnosticForNode( + source.symbol.declarations[0], + Diagnostics.This_type_parameter_might_need_an_extends_0_constraint, + targetConstraintString, + ), + ); } } } @@ -19468,7 +25577,10 @@ namespace ts { const sourceUnionOrIntersection = source as UnionOrIntersectionType; const targetUnionOrIntersection = target as UnionOrIntersectionType; - if (sourceUnionOrIntersection.objectFlags & targetUnionOrIntersection.objectFlags & ObjectFlags.PrimitiveUnion) { + if ( + sourceUnionOrIntersection.objectFlags & targetUnionOrIntersection.objectFlags + & ObjectFlags.PrimitiveUnion + ) { // There's a fast path for comparing primitive unions return; } @@ -19491,29 +25603,38 @@ namespace ts { function getTypeOfPropertyInTypes(types: Type[], name: __String) { const appendPropType = (propTypes: Type[] | undefined, type: Type) => { type = getApparentType(type); - const prop = type.flags & TypeFlags.UnionOrIntersection ? getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name) : getPropertyOfObjectType(type, name); - const propType = prop && getTypeOfSymbol(prop) || getApplicableIndexInfoForName(type, name)?.type || undefinedType; + const prop = type.flags & TypeFlags.UnionOrIntersection + ? getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name) + : getPropertyOfObjectType(type, name); + const propType = prop && getTypeOfSymbol(prop) || getApplicableIndexInfoForName(type, name)?.type + || undefinedType; return append(propTypes, propType); }; return getUnionType(reduceLeft(types, appendPropType, /*initial*/ undefined) || emptyArray); } function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { - if (!isExcessPropertyCheckTarget(target) || !noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral) { + if ( + !isExcessPropertyCheckTarget(target) + || !noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral + ) { return false; // Disable excess property checks on JS literals to simulate having an implicit "index signature" - but only outside of noImplicitAny } const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); if ( - (relation === assignableRelation || relation === comparableRelation) && - (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target))) + (relation === assignableRelation || relation === comparableRelation) + && (isTypeSubsetOf(globalObjectType, target) + || (!isComparingJsxAttributes && isEmptyObjectType(target))) ) { return false; } let reducedTarget = target; let checkTypes: Type[] | undefined; if (target.flags & TypeFlags.Union) { - reducedTarget = findMatchingDiscriminantType(source, target as UnionType, isRelatedTo) || filterPrimitivesIfContainsNonPrimitive(target as UnionType); - checkTypes = reducedTarget.flags & TypeFlags.Union ? (reducedTarget as UnionType).types : [reducedTarget]; + reducedTarget = findMatchingDiscriminantType(source, target as UnionType, isRelatedTo) + || filterPrimitivesIfContainsNonPrimitive(target as UnionType); + checkTypes = reducedTarget.flags & TypeFlags.Union ? (reducedTarget as UnionType).types + : [reducedTarget]; } for (const prop of getPropertiesOfType(source)) { if (shouldCheckAsExcessProperty(prop, source.symbol) && !isIgnoredJsxProperty(source, prop)) { @@ -19526,29 +25647,54 @@ namespace ts { // Use this property as the error node as this will be more helpful in // reasoning about what went wrong. if (!errorNode) return Debug.fail(); - if (isJsxAttributes(errorNode) || isJsxOpeningLikeElement(errorNode) || isJsxOpeningLikeElement(errorNode.parent)) { + if ( + isJsxAttributes(errorNode) || isJsxOpeningLikeElement(errorNode) + || isJsxOpeningLikeElement(errorNode.parent) + ) { // JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal. // However, using an object-literal error message will be very confusing to the users so we give different a message. - if (prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) && getSourceFileOfNode(errorNode) === getSourceFileOfNode(prop.valueDeclaration.name)) { + if ( + prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) + && getSourceFileOfNode(errorNode) + === getSourceFileOfNode(prop.valueDeclaration.name) + ) { // Note that extraneous children (as in `extra`) don't pass this check, // since `children` is a SyntaxKind.PropertySignature instead of a SyntaxKind.JsxAttribute. errorNode = prop.valueDeclaration.name; } const propName = symbolToString(prop); - const suggestionSymbol = getSuggestedSymbolForNonexistentJSXAttribute(propName, errorTarget); + const suggestionSymbol = getSuggestedSymbolForNonexistentJSXAttribute( + propName, + errorTarget, + ); const suggestion = suggestionSymbol ? symbolToString(suggestionSymbol) : undefined; if (suggestion) { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName, typeToString(errorTarget), suggestion); + reportError( + Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, + propName, + typeToString(errorTarget), + suggestion, + ); } else { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1, propName, typeToString(errorTarget)); + reportError( + Diagnostics.Property_0_does_not_exist_on_type_1, + propName, + typeToString(errorTarget), + ); } } else { // use the property's value declaration if the property is assigned inside the literal itself - const objectLiteralDeclaration = source.symbol?.declarations && firstOrUndefined(source.symbol.declarations); + const objectLiteralDeclaration = source.symbol?.declarations + && firstOrUndefined(source.symbol.declarations); let suggestion: string | undefined; - if (prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => d === objectLiteralDeclaration) && getSourceFileOfNode(objectLiteralDeclaration) === getSourceFileOfNode(errorNode)) { + if ( + prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => + d === objectLiteralDeclaration) + && getSourceFileOfNode(objectLiteralDeclaration) + === getSourceFileOfNode(errorNode) + ) { const propDeclaration = prop.valueDeclaration as ObjectLiteralElementLike; Debug.assertNode(propDeclaration, isObjectLiteralElementLike); @@ -19560,18 +25706,40 @@ namespace ts { } } if (suggestion !== undefined) { - reportError(Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2, symbolToString(prop), typeToString(errorTarget), suggestion); + reportError( + Diagnostics + .Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2, + symbolToString(prop), + typeToString(errorTarget), + suggestion, + ); } else { - reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, symbolToString(prop), typeToString(errorTarget)); + reportError( + Diagnostics + .Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, + symbolToString(prop), + typeToString(errorTarget), + ); } } } return true; } - if (checkTypes && !isRelatedTo(getTypeOfSymbol(prop), getTypeOfPropertyInTypes(checkTypes, prop.escapedName), RecursionFlags.Both, reportErrors)) { + if ( + checkTypes + && !isRelatedTo( + getTypeOfSymbol(prop), + getTypeOfPropertyInTypes(checkTypes, prop.escapedName), + RecursionFlags.Both, + reportErrors, + ) + ) { if (reportErrors) { - reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(prop)); + reportIncompatibleError( + Diagnostics.Types_of_property_0_are_incompatible, + symbolToString(prop), + ); } return true; } @@ -19581,23 +25749,48 @@ namespace ts { } function shouldCheckAsExcessProperty(prop: Symbol, container: Symbol) { - return prop.valueDeclaration && container.valueDeclaration && prop.valueDeclaration.parent === container.valueDeclaration; + return prop.valueDeclaration && container.valueDeclaration + && prop.valueDeclaration.parent === container.valueDeclaration; } - function unionOrIntersectionRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function unionOrIntersectionRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { // Note that these checks are specifically ordered to produce correct results. In particular, // we need to deconstruct unions before intersections (because unions are always at the top), // and we need to handle "each" relations before "some" relations for the same kind of type. if (source.flags & TypeFlags.Union) { - return relation === comparableRelation ? - someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState) : - eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState); + return relation === comparableRelation + ? someTypeRelatedToType( + source as UnionType, + target, + reportErrors && !(source.flags & TypeFlags.Primitive), + intersectionState, + ) + : eachTypeRelatedToType( + source as UnionType, + target, + reportErrors && !(source.flags & TypeFlags.Primitive), + intersectionState, + ); } if (target.flags & TypeFlags.Union) { - return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target as UnionType, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive)); + return typeRelatedToSomeType( + getRegularTypeOfObjectLiteral(source), + target as UnionType, + reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive), + ); } if (target.flags & TypeFlags.Intersection) { - return typeRelatedToEachType(source, target as IntersectionType, reportErrors, IntersectionState.Target); + return typeRelatedToEachType( + source, + target as IntersectionType, + reportErrors, + IntersectionState.Target, + ); } // Source is an intersection. For the comparable relation, if the target is a primitive type we hoist the // constraints of all non-primitive types in the source into a new intersection. We do this because the @@ -19605,15 +25798,18 @@ namespace ts { // parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't // appear to be comparable to '2'. if (relation === comparableRelation && target.flags & TypeFlags.Primitive) { - const constraints = sameMap((source as IntersectionType).types, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t); + const constraints = sameMap( + (source as IntersectionType).types, + t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t, + ); if (constraints !== (source as IntersectionType).types) { source = getIntersectionType(constraints); if (source.flags & TypeFlags.Never) { return Ternary.False; } if (!(source.flags & TypeFlags.Intersection)) { - return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false) || - isRelatedTo(target, source, RecursionFlags.Source, /*reportErrors*/ false); + return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false) + || isRelatedTo(target, source, RecursionFlags.Source, /*reportErrors*/ false); } } } @@ -19621,10 +25817,18 @@ namespace ts { // Don't report errors though. Elaborating on whether a source constituent is related to the target is // not actually useful and leads to some confusing error messages. Instead, we rely on the caller // checking whether the full intersection viewed as an object is related to the target. - return someTypeRelatedToType(source as IntersectionType, target, /*reportErrors*/ false, IntersectionState.Source); + return someTypeRelatedToType( + source as IntersectionType, + target, + /*reportErrors*/ false, + IntersectionState.Source, + ); } - function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary { + function eachTypeRelatedToSomeType( + source: UnionOrIntersectionType, + target: UnionOrIntersectionType, + ): Ternary { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { @@ -19637,7 +25841,11 @@ namespace ts { return result; } - function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { + function typeRelatedToSomeType( + source: Type, + target: UnionOrIntersectionType, + reportErrors: boolean, + ): Ternary { const targetTypes = target.types; if (target.flags & TypeFlags.Union) { if (containsType(targetTypes, source)) { @@ -19667,11 +25875,23 @@ namespace ts { return Ternary.False; } - function typeRelatedToEachType(source: Type, target: IntersectionType, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function typeRelatedToEachType( + source: Type, + target: IntersectionType, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { let result = Ternary.True; const targetTypes = target.types; for (const targetType of targetTypes) { - const related = isRelatedTo(source, targetType, RecursionFlags.Target, reportErrors, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + source, + targetType, + RecursionFlags.Target, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (!related) { return Ternary.False; } @@ -19680,14 +25900,26 @@ namespace ts { return result; } - function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function someTypeRelatedToType( + source: UnionOrIntersectionType, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { const sourceTypes = source.types; if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) { return Ternary.True; } const len = sourceTypes.length; for (let i = 0; i < len; i++) { - const related = isRelatedTo(sourceTypes[i], target, RecursionFlags.Source, reportErrors && i === len - 1, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + sourceTypes[i], + target, + RecursionFlags.Source, + reportErrors && i === len - 1, + /*headMessage*/ undefined, + intersectionState, + ); if (related) { return related; } @@ -19699,15 +25931,21 @@ namespace ts { // As a builtin type, `undefined` is a very low type ID - making it almsot always first, making this a very fast check to see // if we need to strip `undefined` from the target if ( - source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && - !((source as UnionType).types[0].flags & TypeFlags.Undefined) && (target as UnionType).types[0].flags & TypeFlags.Undefined + source.flags & TypeFlags.Union && target.flags & TypeFlags.Union + && !((source as UnionType).types[0].flags & TypeFlags.Undefined) + && (target as UnionType).types[0].flags & TypeFlags.Undefined ) { return extractTypesOfKind(target, ~TypeFlags.Undefined); } return target; } - function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function eachTypeRelatedToType( + source: UnionOrIntersectionType, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { let result = Ternary.True; const sourceTypes = source.types; // We strip `undefined` from the target if the `source` trivially doesn't contain it for our correspondence-checking fastpath @@ -19715,19 +25953,38 @@ namespace ts { const undefinedStrippedTarget = getUndefinedStrippedTargetIfNeeded(source, target as UnionType); for (let i = 0; i < sourceTypes.length; i++) { const sourceType = sourceTypes[i]; - if (undefinedStrippedTarget.flags & TypeFlags.Union && sourceTypes.length >= (undefinedStrippedTarget as UnionType).types.length && sourceTypes.length % (undefinedStrippedTarget as UnionType).types.length === 0) { + if ( + undefinedStrippedTarget.flags & TypeFlags.Union + && sourceTypes.length >= (undefinedStrippedTarget as UnionType).types.length + && sourceTypes.length % (undefinedStrippedTarget as UnionType).types.length === 0 + ) { // many unions are mappings of one another; in such cases, simply comparing members at the same index can shortcut the comparison // such unions will have identical lengths, and their corresponding elements will match up. Another common scenario is where a large // union has a union of objects intersected with it. In such cases, if the input was, eg `("a" | "b" | "c") & (string | boolean | {} | {whatever})`, // the result will have the structure `"a" | "b" | "c" | "a" & {} | "b" & {} | "c" & {} | "a" & {whatever} | "b" & {whatever} | "c" & {whatever}` // - the resulting union has a length which is a multiple of the original union, and the elements correspond modulo the length of the original union - const related = isRelatedTo(sourceType, (undefinedStrippedTarget as UnionType).types[i % (undefinedStrippedTarget as UnionType).types.length], RecursionFlags.Both, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + sourceType, + (undefinedStrippedTarget as UnionType) + .types[i % (undefinedStrippedTarget as UnionType).types.length], + RecursionFlags.Both, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ); if (related) { result &= related; continue; } } - const related = isRelatedTo(sourceType, target, RecursionFlags.Source, reportErrors, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + sourceType, + target, + RecursionFlags.Source, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (!related) { return Ternary.False; } @@ -19736,7 +25993,13 @@ namespace ts { return result; } - function typeArgumentsRelatedTo(sources: readonly Type[] = emptyArray, targets: readonly Type[] = emptyArray, variances: readonly VarianceFlags[] = emptyArray, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function typeArgumentsRelatedTo( + sources: readonly Type[] = emptyArray, + targets: readonly Type[] = emptyArray, + variances: readonly VarianceFlags[] = emptyArray, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { if (sources.length !== targets.length && relation === identityRelation) { return Ternary.False; } @@ -19757,13 +26020,29 @@ namespace ts { // Even an `Unmeasurable` variance works out without a structural check if the source and target are _identical_. // We can't simply assume invariance, because `Unmeasurable` marks nonlinear relations, for example, a relation tained by // the `-?` modifier in a mapped type (where, no matter how the inputs are related, the outputs still might not be) - related = relation === identityRelation ? isRelatedTo(s, t, RecursionFlags.Both, /*reportErrors*/ false) : compareTypesIdentical(s, t); + related = relation === identityRelation + ? isRelatedTo(s, t, RecursionFlags.Both, /*reportErrors*/ false) + : compareTypesIdentical(s, t); } else if (variance === VarianceFlags.Covariant) { - related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + s, + t, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } else if (variance === VarianceFlags.Contravariant) { - related = isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + t, + s, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } else if (variance === VarianceFlags.Bivariant) { // In the bivariant case we first compare contravariantly without reporting @@ -19772,16 +26051,37 @@ namespace ts { // which is generally easier to reason about. related = isRelatedTo(t, s, RecursionFlags.Both, /*reportErrors*/ false); if (!related) { - related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + s, + t, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } } else { // In the invariant case we first compare covariantly, and only when that // succeeds do we proceed to compare contravariantly. Thus, error elaboration // will typically be based on the covariant check. - related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + s, + t, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (related) { - related &= isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related &= isRelatedTo( + t, + s, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } } if (!related) { @@ -19798,14 +26098,23 @@ namespace ts { // Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are // equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion // and issue an error. Otherwise, actually compare the structure of the two types. - function recursiveTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, recursionFlags: RecursionFlags): Ternary { + function recursiveTypeRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + recursionFlags: RecursionFlags, + ): Ternary { if (overflow) { return Ternary.False; } const id = getRelationKey(source, target, intersectionState, relation, /*ingnoreConstraints*/ false); const entry = relation.get(id); if (entry !== undefined) { - if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) { + if ( + reportErrors && entry & RelationComparisonResult.Failed + && !(entry & RelationComparisonResult.Reported) + ) { // We are elaborating errors and the cached result is an unreported failure. The result will be reported // as a failure, and should be updated as a reported failure by the bottom of this function. } @@ -19832,7 +26141,9 @@ namespace ts { // A key that starts with "*" is an indication that we have type references that reference constrained // type parameters. For such keys we also check against the key we would have gotten if all type parameters // were unconstrained. - const broadestEquivalentId = id.startsWith("*") ? getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ true) : undefined; + const broadestEquivalentId = id.startsWith("*") + ? getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ true) + : undefined; for (let i = 0; i < maybeCount; i++) { // If source and target are already being compared, consider them related with assumptions if (id === maybeKeys[i] || broadestEquivalentId && broadestEquivalentId === maybeKeys[i]) { @@ -19851,19 +26162,26 @@ namespace ts { if (recursionFlags & RecursionFlags.Source) { sourceStack[sourceDepth] = source; sourceDepth++; - if (!(expandingFlags & ExpandingFlags.Source) && isDeeplyNestedType(source, sourceStack, sourceDepth)) expandingFlags |= ExpandingFlags.Source; + if ( + !(expandingFlags & ExpandingFlags.Source) + && isDeeplyNestedType(source, sourceStack, sourceDepth) + ) expandingFlags |= ExpandingFlags.Source; } if (recursionFlags & RecursionFlags.Target) { targetStack[targetDepth] = target; targetDepth++; - if (!(expandingFlags & ExpandingFlags.Target) && isDeeplyNestedType(target, targetStack, targetDepth)) expandingFlags |= ExpandingFlags.Target; + if ( + !(expandingFlags & ExpandingFlags.Target) + && isDeeplyNestedType(target, targetStack, targetDepth) + ) expandingFlags |= ExpandingFlags.Target; } let originalHandler: typeof outofbandVarianceMarkerHandler; let propagatingVarianceFlags: RelationComparisonResult = 0; if (outofbandVarianceMarkerHandler) { originalHandler = outofbandVarianceMarkerHandler; outofbandVarianceMarkerHandler = onlyUnreliable => { - propagatingVarianceFlags |= onlyUnreliable ? RelationComparisonResult.ReportsUnreliable : RelationComparisonResult.ReportsUnmeasurable; + propagatingVarianceFlags |= onlyUnreliable ? RelationComparisonResult.ReportsUnreliable + : RelationComparisonResult.ReportsUnmeasurable; return originalHandler!(onlyUnreliable); }; } @@ -19881,7 +26199,10 @@ namespace ts { result = Ternary.Maybe; } else { - tracing?.push(tracing.Phase.CheckTypes, "structuredTypeRelatedTo", { sourceId: source.id, targetId: target.id }); + tracing?.push(tracing.Phase.CheckTypes, "structuredTypeRelatedTo", { + sourceId: source.id, + targetId: target.id, + }); result = structuredTypeRelatedTo(source, target, reportErrors, intersectionState); tracing?.pop(); } @@ -19902,7 +26223,10 @@ namespace ts { // If result is definitely true, record all maybe keys as having succeeded. Also, record Ternary.Maybe // results as having succeeded once we reach depth 0, but never record Ternary.Unknown results. for (let i = maybeStart; i < maybeCount; i++) { - relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags); + relation.set( + maybeKeys[i], + RelationComparisonResult.Succeeded | propagatingVarianceFlags, + ); } } maybeCount = maybeStart; @@ -19911,15 +26235,30 @@ namespace ts { else { // A false result goes straight into global cache (when something is false under // assumptions it will also be false without assumptions) - relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags); + relation.set( + id, + (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed + | propagatingVarianceFlags, + ); maybeCount = maybeStart; } return result; } - function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function structuredTypeRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { const saveErrorInfo = captureErrorCalculationState(); - let result = structuredTypeRelatedToWorker(source, target, reportErrors, intersectionState, saveErrorInfo); + let result = structuredTypeRelatedToWorker( + source, + target, + reportErrors, + intersectionState, + saveErrorInfo, + ); if (relation !== identityRelation) { // The combined constraint of an intersection type is the intersection of the constraints of // the constituents. When an intersection type contains instantiable types with union type @@ -19934,11 +26273,28 @@ namespace ts { // needs to have its constraint hoisted into an intersection with said type parameter, this way // the type param can be compared with itself in the target (with the influence of its constraint to match other parts) // For example, if `T extends 1 | 2` and `U extends 2 | 3` and we compare `T & U` to `T & U & (1 | 2 | 3)` - if (!result && (source.flags & TypeFlags.Intersection || source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.Union)) { - const constraint = getEffectiveConstraintOfIntersection(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], !!(target.flags & TypeFlags.Union)); - if (constraint && !(constraint.flags & TypeFlags.Never) && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself + if ( + !result + && (source.flags & TypeFlags.Intersection + || source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.Union) + ) { + const constraint = getEffectiveConstraintOfIntersection( + source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], + !!(target.flags & TypeFlags.Union), + ); + if ( + constraint && !(constraint.flags & TypeFlags.Never) + && everyType(constraint, c => c !== source) + ) { // Skip comparison if expansion contains the source itself // TODO: Stack errors so we get a pyramid for the "normal" comparison above, _and_ a second for this - result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ); } } // For certain combinations involving intersections and optional, excess, or mismatched properties we need @@ -19958,12 +26314,25 @@ namespace ts { // recursive intersections that are structurally similar but not exactly identical. See #37854. if ( result && !inPropertyCheck && ( - target.flags & TypeFlags.Intersection && !isGenericObjectType(target) && source.flags & (TypeFlags.Object | TypeFlags.Intersection) || - isNonGenericObjectType(target) && !isArrayOrTupleType(target) && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && !some((source as IntersectionType).types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)) + target.flags & TypeFlags.Intersection && !isGenericObjectType(target) + && source.flags & (TypeFlags.Object | TypeFlags.Intersection) + || isNonGenericObjectType(target) && !isArrayOrTupleType(target) + && source.flags & TypeFlags.Intersection + && getApparentType(source).flags & TypeFlags.StructuredType + && !some( + (source as IntersectionType).types, + t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType), + ) ) ) { inPropertyCheck = true; - result &= propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None); + result &= propertiesRelatedTo( + source, + target, + reportErrors, + /*excludedProperties*/ undefined, + IntersectionState.None, + ); inPropertyCheck = false; } } @@ -19973,7 +26342,13 @@ namespace ts { return result; } - function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, saveErrorInfo: ReturnType): Ternary { + function structuredTypeRelatedToWorker( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + saveErrorInfo: ReturnType, + ): Ternary { let result: Ternary; let originalErrorInfo: DiagnosticMessageChain | undefined; let varianceCheckFailed = false; @@ -19982,28 +26357,84 @@ namespace ts { if (relation === identityRelation) { // We've already checked that source.flags and target.flags are identical if (sourceFlags & TypeFlags.UnionOrIntersection) { - let result = eachTypeRelatedToSomeType(source as UnionOrIntersectionType, target as UnionOrIntersectionType); + let result = eachTypeRelatedToSomeType( + source as UnionOrIntersectionType, + target as UnionOrIntersectionType, + ); if (result) { - result &= eachTypeRelatedToSomeType(target as UnionOrIntersectionType, source as UnionOrIntersectionType); + result &= eachTypeRelatedToSomeType( + target as UnionOrIntersectionType, + source as UnionOrIntersectionType, + ); } return result; } if (sourceFlags & TypeFlags.Index) { - return isRelatedTo((source as IndexType).type, (target as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false); + return isRelatedTo( + (source as IndexType).type, + (target as IndexType).type, + RecursionFlags.Both, + /*reportErrors*/ false, + ); } if (sourceFlags & TypeFlags.IndexedAccess) { - if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + result = isRelatedTo( + (source as IndexedAccessType).objectType, + (target as IndexedAccessType).objectType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + (source as IndexedAccessType).indexType, + (target as IndexedAccessType).indexType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { return result; } } } if (sourceFlags & TypeFlags.Conditional) { - if ((source as ConditionalType).root.isDistributive === (target as ConditionalType).root.isDistributive) { - if (result = isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as ConditionalType).extendsType, (target as ConditionalType).extendsType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + (source as ConditionalType).root.isDistributive + === (target as ConditionalType).root.isDistributive + ) { + if ( + result = isRelatedTo( + (source as ConditionalType).checkType, + (target as ConditionalType).checkType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + (source as ConditionalType).extendsType, + (target as ConditionalType).extendsType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + getTrueTypeFromConditionalType(source as ConditionalType), + getTrueTypeFromConditionalType(target as ConditionalType), + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + getFalseTypeFromConditionalType(source as ConditionalType), + getFalseTypeFromConditionalType(target as ConditionalType), + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { return result; } } @@ -20012,8 +26443,22 @@ namespace ts { } } if (sourceFlags & TypeFlags.Substitution) { - if (result = isRelatedTo((source as SubstitutionType).baseType, (target as SubstitutionType).baseType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as SubstitutionType).constraint, (target as SubstitutionType).constraint, RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + result = isRelatedTo( + (source as SubstitutionType).baseType, + (target as SubstitutionType).baseType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + (source as SubstitutionType).constraint, + (target as SubstitutionType).constraint, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { return result; } } @@ -20033,9 +26478,10 @@ namespace ts { // Source is an intersection, target is a union (e.g. { a } & { b: boolean } <=> { a, b: true } | { a, b: false }). // Source is an intersection, target instantiable (e.g. string & { tag } <=> T["a"] constrained to string & { tag }). if ( - !(sourceFlags & TypeFlags.Instantiable || - sourceFlags & TypeFlags.Object && targetFlags & TypeFlags.Union || - sourceFlags & TypeFlags.Intersection && targetFlags & (TypeFlags.Object | TypeFlags.Union | TypeFlags.Instantiable)) + !(sourceFlags & TypeFlags.Instantiable + || sourceFlags & TypeFlags.Object && targetFlags & TypeFlags.Union + || sourceFlags & TypeFlags.Intersection + && targetFlags & (TypeFlags.Object | TypeFlags.Union | TypeFlags.Instantiable)) ) { return Ternary.False; } @@ -20045,14 +26491,20 @@ namespace ts { // is more predictable than other, interned types, which may or may not have an alias depending on // the order in which things were checked. if ( - sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && - source.aliasSymbol === target.aliasSymbol && !(isMarkerType(source) || isMarkerType(target)) + sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol + && source.aliasTypeArguments + && source.aliasSymbol === target.aliasSymbol && !(isMarkerType(source) || isMarkerType(target)) ) { const variances = getAliasVariances(source.aliasSymbol); if (variances === emptyArray) { return Ternary.Unknown; } - const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances, intersectionState); + const varianceResult = relateVariances( + source.aliasTypeArguments, + target.aliasTypeArguments, + variances, + intersectionState, + ); if (varianceResult !== undefined) { return varianceResult; } @@ -20061,19 +26513,34 @@ namespace ts { // For a generic type T and a type U that is assignable to T, [...U] is assignable to T, U is assignable to readonly [...T], // and U is assignable to [...T] when U is constrained to a mutable array or tuple type. if ( - isSingleElementGenericTupleType(source) && !source.target.readonly && (result = isRelatedTo(getTypeArguments(source)[0], target, RecursionFlags.Source)) || - isSingleElementGenericTupleType(target) && (target.target.readonly || isMutableArrayOrTuple(getBaseConstraintOfType(source) || source)) && (result = isRelatedTo(source, getTypeArguments(target)[0], RecursionFlags.Target)) + isSingleElementGenericTupleType(source) && !source.target.readonly + && (result = isRelatedTo(getTypeArguments(source)[0], target, RecursionFlags.Source)) + || isSingleElementGenericTupleType(target) + && (target.target.readonly || isMutableArrayOrTuple(getBaseConstraintOfType(source) || source)) + && (result = isRelatedTo(source, getTypeArguments(target)[0], RecursionFlags.Target)) ) { return result; } if (targetFlags & TypeFlags.TypeParameter) { // A source type { [P in Q]: X } is related to a target type T if keyof T is related to Q and X is related to T[Q]. - if (getObjectFlags(source) & ObjectFlags.Mapped && !(source as MappedType).declaration.nameType && isRelatedTo(getIndexType(target), getConstraintTypeFromMappedType(source as MappedType), RecursionFlags.Both)) { + if ( + getObjectFlags(source) & ObjectFlags.Mapped && !(source as MappedType).declaration.nameType + && isRelatedTo( + getIndexType(target), + getConstraintTypeFromMappedType(source as MappedType), + RecursionFlags.Both, + ) + ) { if (!(getMappedTypeModifiers(source as MappedType) & MappedTypeModifiers.IncludeOptional)) { const templateType = getTemplateTypeFromMappedType(source as MappedType); - const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(source as MappedType)); - if (result = isRelatedTo(templateType, indexedAccessType, RecursionFlags.Both, reportErrors)) { + const indexedAccessType = getIndexedAccessType( + target, + getTypeParameterFromMappedType(source as MappedType), + ); + if ( + result = isRelatedTo(templateType, indexedAccessType, RecursionFlags.Both, reportErrors) + ) { return result; } } @@ -20084,7 +26551,14 @@ namespace ts { let constraint = getConstraintOfTypeParameter(source); if (constraint && hasNonCircularBaseConstraint(source)) { while (constraint && someType(constraint, c => !!(c.flags & TypeFlags.TypeParameter))) { - if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false)) { + if ( + result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + /*reportErrors*/ false, + ) + ) { return result; } constraint = getConstraintOfTypeParameter(constraint); @@ -20097,14 +26571,28 @@ namespace ts { const targetType = (target as IndexType).type; // A keyof S is related to a keyof T if T is related to S. if (sourceFlags & TypeFlags.Index) { - if (result = isRelatedTo(targetType, (source as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + result = isRelatedTo( + targetType, + (source as IndexType).type, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { return result; } } if (isTupleType(targetType)) { // An index type can have a tuple type target when the tuple type contains variadic elements. // Check if the source is related to the known keys of the tuple type. - if (result = isRelatedTo(source, getKnownKeysOfTupleType(targetType), RecursionFlags.Target, reportErrors)) { + if ( + result = isRelatedTo( + source, + getKnownKeysOfTupleType(targetType), + RecursionFlags.Target, + reportErrors, + ) + ) { return result; } } @@ -20117,7 +26605,14 @@ namespace ts { // false positives. For example, given 'T extends { [K in keyof T]: string }', // 'keyof T' has itself as its constraint and produces a Ternary.Maybe when // related to other types. - if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), RecursionFlags.Target, reportErrors) === Ternary.True) { + if ( + isRelatedTo( + source, + getIndexType(constraint, (target as IndexType).stringsOnly), + RecursionFlags.Target, + reportErrors, + ) === Ternary.True + ) { return Ternary.True; } } @@ -20138,7 +26633,16 @@ namespace ts { modifiersType, TypeFlags.StringOrNumberLiteralOrUnique, /*stringsOnly*/ false, - t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(targetType.mapper, getTypeParameterFromMappedType(targetType), t))), + t => void mappedKeys.push( + instantiateType( + nameType, + appendTypeMapping( + targetType.mapper, + getTypeParameterFromMappedType(targetType), + t, + ), + ), + ), ); // We still need to include the non-apparent (and thus still generic) keys in the target side of the comparison (in case they're in the source side) targetKeys = getUnionType([...mappedKeys, nameType]); @@ -20156,8 +26660,20 @@ namespace ts { if (sourceFlags & TypeFlags.IndexedAccess) { // Relate components directly before falling back to constraint relationships // A type S[K] is related to a type T[J] if S is related to T and K is related to J. - if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, reportErrors); + if ( + result = isRelatedTo( + (source as IndexedAccessType).objectType, + (target as IndexedAccessType).objectType, + RecursionFlags.Both, + reportErrors, + ) + ) { + result &= isRelatedTo( + (source as IndexedAccessType).indexType, + (target as IndexedAccessType).indexType, + RecursionFlags.Both, + reportErrors, + ); } if (result) { return result; @@ -20174,19 +26690,35 @@ namespace ts { const baseObjectType = getBaseConstraintOfType(objectType) || objectType; const baseIndexType = getBaseConstraintOfType(indexType) || indexType; if (!isGenericObjectType(baseObjectType) && !isGenericIndexType(baseIndexType)) { - const accessFlags = AccessFlags.Writing | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0); - const constraint = getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, accessFlags); + const accessFlags = AccessFlags.Writing + | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0); + const constraint = getIndexedAccessTypeOrUndefined( + baseObjectType, + baseIndexType, + accessFlags, + ); if (constraint) { if (reportErrors && originalErrorInfo) { // create a new chain for the constraint error resetErrorInfo(saveErrorInfo); } - if (result = isRelatedTo(source, constraint, RecursionFlags.Target, reportErrors, /* headMessage */ undefined, intersectionState)) { + if ( + result = isRelatedTo( + source, + constraint, + RecursionFlags.Target, + reportErrors, + /* headMessage */ undefined, + intersectionState, + ) + ) { return result; } // prefer the shorter chain of the constraint comparison chain, and the direct comparison chain if (reportErrors && originalErrorInfo && errorInfo) { - errorInfo = countMessageChainBreadth([originalErrorInfo]) <= countMessageChainBreadth([errorInfo]) ? originalErrorInfo : errorInfo; + errorInfo = countMessageChainBreadth([originalErrorInfo]) + <= countMessageChainBreadth([errorInfo]) ? originalErrorInfo + : errorInfo; } } } @@ -20204,19 +26736,26 @@ namespace ts { // If the mapped type has shape `{ [P in Q]: T[P] }`, // source `S` is related to target if `T` = `S`, i.e. `S` is related to `{ [P in Q]: S[P] }`. if ( - !keysRemapped && templateType.flags & TypeFlags.IndexedAccess && (templateType as IndexedAccessType).objectType === source && - (templateType as IndexedAccessType).indexType === getTypeParameterFromMappedType(target) + !keysRemapped && templateType.flags & TypeFlags.IndexedAccess + && (templateType as IndexedAccessType).objectType === source + && (templateType as IndexedAccessType).indexType === getTypeParameterFromMappedType(target) ) { return Ternary.True; } if (!isGenericMappedType(source)) { // If target has shape `{ [P in Q as R]: T}`, then its keys have type `R`. // If target has shape `{ [P in Q]: T }`, then its keys have type `Q`. - const targetKeys = keysRemapped ? getNameTypeFromMappedType(target)! : getConstraintTypeFromMappedType(target); + const targetKeys = keysRemapped ? getNameTypeFromMappedType(target)! + : getConstraintTypeFromMappedType(target); // Type of the keys of source type `S`, i.e. `keyof S`. - const sourceKeys = getIndexType(source, /*stringsOnly*/ undefined, /*noIndexSignatures*/ true); + const sourceKeys = getIndexType( + source, + /*stringsOnly*/ undefined, + /*noIndexSignatures*/ true, + ); const includeOptional = modifiers & MappedTypeModifiers.IncludeOptional; - const filteredByApplicability = includeOptional ? intersectTypes(targetKeys, sourceKeys) : undefined; + const filteredByApplicability = includeOptional ? intersectTypes(targetKeys, sourceKeys) + : undefined; // A source type `S` is related to a target type `{ [P in Q]: T }` if `Q` is related to `keyof S` and `S[Q]` is related to `T`. // A source type `S` is related to a target type `{ [P in Q as R]: T }` if `R` is related to `keyof S` and `S[R]` is related to `T. // A source type `S` is related to a target type `{ [P in Q]?: T }` if some constituent `Q'` of `Q` is related to `keyof S` and `S[Q']` is related to `T`. @@ -20232,8 +26771,18 @@ namespace ts { // Fastpath: When the template type has the form `Obj[P]` where `P` is the mapped type parameter, directly compare source `S` with `Obj` // to avoid creating the (potentially very large) number of new intermediate types made by manufacturing `S[P]`. const nonNullComponent = extractTypesOfKind(templateType, ~TypeFlags.Nullable); - if (!keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess && (nonNullComponent as IndexedAccessType).indexType === typeParameter) { - if (result = isRelatedTo(source, (nonNullComponent as IndexedAccessType).objectType, RecursionFlags.Target, reportErrors)) { + if ( + !keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess + && (nonNullComponent as IndexedAccessType).indexType === typeParameter + ) { + if ( + result = isRelatedTo( + source, + (nonNullComponent as IndexedAccessType).objectType, + RecursionFlags.Target, + reportErrors, + ) + ) { return result; } } @@ -20254,7 +26803,14 @@ namespace ts { : typeParameter; const indexedAccessType = getIndexedAccessType(source, indexingType); // Compare `S[indexingType]` to `T`, where `T` is the type of a property of the target type. - if (result = isRelatedTo(indexedAccessType, templateType, RecursionFlags.Both, reportErrors)) { + if ( + result = isRelatedTo( + indexedAccessType, + templateType, + RecursionFlags.Both, + reportErrors, + ) + ) { return result; } } @@ -20276,11 +26832,36 @@ namespace ts { // parameter in either of the result types. if (!c.root.inferTypeParameters && !isDistributionDependent(c.root)) { // Check if the conditional is always true or always false but still deferred for distribution purposes. - const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(c.checkType), getPermissiveInstantiation(c.extendsType)); - const skipFalse = !skipTrue && isTypeAssignableTo(getRestrictiveInstantiation(c.checkType), getRestrictiveInstantiation(c.extendsType)); + const skipTrue = !isTypeAssignableTo( + getPermissiveInstantiation(c.checkType), + getPermissiveInstantiation(c.extendsType), + ); + const skipFalse = !skipTrue + && isTypeAssignableTo( + getRestrictiveInstantiation(c.checkType), + getRestrictiveInstantiation(c.extendsType), + ); // TODO: Find a nice way to include potential conditional type breakdowns in error output, if they seem good (they usually don't) - if (result = skipTrue ? Ternary.True : isRelatedTo(source, getTrueTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { - result &= skipFalse ? Ternary.True : isRelatedTo(source, getFalseTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + if ( + result = skipTrue ? Ternary.True + : isRelatedTo( + source, + getTrueTypeFromConditionalType(c), + RecursionFlags.Target, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ) + ) { + result &= skipFalse ? Ternary.True + : isRelatedTo( + source, + getFalseTypeFromConditionalType(c), + RecursionFlags.Target, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ); if (result) { return result; } @@ -20290,7 +26871,10 @@ namespace ts { else if (targetFlags & TypeFlags.TemplateLiteral) { if (sourceFlags & TypeFlags.TemplateLiteral) { if (relation === comparableRelation) { - return templateLiteralTypesDefinitelyUnrelated(source as TemplateLiteralType, target as TemplateLiteralType) ? Ternary.False : Ternary.True; + return templateLiteralTypesDefinitelyUnrelated( + source as TemplateLiteralType, + target as TemplateLiteralType, + ) ? Ternary.False : Ternary.True; } // Report unreliable variance for type variables referenced in template literal type placeholders. // For example, `foo-${number}` is related to `foo-${string}` even though number isn't related to string. @@ -20313,11 +26897,30 @@ namespace ts { if (!(sourceFlags & TypeFlags.IndexedAccess && targetFlags & TypeFlags.IndexedAccess)) { const constraint = getConstraintOfType(source as TypeVariable) || unknownType; // hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed - if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { + if ( + result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ) + ) { return result; } // slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example - else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, RecursionFlags.Source, reportErrors && constraint !== unknownType && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), /*headMessage*/ undefined, intersectionState)) { + else if ( + result = isRelatedTo( + getTypeWithThisArgument(constraint, source), + target, + RecursionFlags.Source, + reportErrors && constraint !== unknownType + && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), + /*headMessage*/ undefined, + intersectionState, + ) + ) { return result; } if (isMappedTypeGenericIndexedAccess(source)) { @@ -20325,7 +26928,14 @@ namespace ts { // substituted for P. We also want to explore type { [P in K]: E }[C], where C is the constraint of X. const indexConstraint = getConstraintOfType((source as IndexedAccessType).indexType); if (indexConstraint) { - if (result = isRelatedTo(getIndexedAccessType((source as IndexedAccessType).objectType, indexConstraint), target, RecursionFlags.Source, reportErrors)) { + if ( + result = isRelatedTo( + getIndexedAccessType((source as IndexedAccessType).objectType, indexConstraint), + target, + RecursionFlags.Source, + reportErrors, + ) + ) { return result; } } @@ -20340,7 +26950,10 @@ namespace ts { else if (sourceFlags & TypeFlags.TemplateLiteral && !(targetFlags & TypeFlags.Object)) { if (!(targetFlags & TypeFlags.TemplateLiteral)) { const constraint = getBaseConstraintOfType(source); - if (constraint && constraint !== source && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors))) { + if ( + constraint && constraint !== source + && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors)) + ) { return result; } } @@ -20350,13 +26963,23 @@ namespace ts { if ((source as StringMappingType).symbol !== (target as StringMappingType).symbol) { return Ternary.False; } - if (result = isRelatedTo((source as StringMappingType).type, (target as StringMappingType).type, RecursionFlags.Both, reportErrors)) { + if ( + result = isRelatedTo( + (source as StringMappingType).type, + (target as StringMappingType).type, + RecursionFlags.Both, + reportErrors, + ) + ) { return result; } } else { const constraint = getBaseConstraintOfType(source); - if (constraint && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors))) { + if ( + constraint + && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors)) + ) { return result; } } @@ -20376,17 +26999,48 @@ namespace ts { let mapper: TypeMapper | undefined; if (sourceParams) { // If the source has infer type parameters, we instantiate them in the context of the target - const ctx = createInferenceContext(sourceParams, /*signature*/ undefined, InferenceFlags.None, isRelatedToWorker); - inferTypes(ctx.inferences, (target as ConditionalType).extendsType, sourceExtends, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); + const ctx = createInferenceContext( + sourceParams, + /*signature*/ undefined, + InferenceFlags.None, + isRelatedToWorker, + ); + inferTypes( + ctx.inferences, + (target as ConditionalType).extendsType, + sourceExtends, + InferencePriority.NoConstraints | InferencePriority.AlwaysStrict, + ); sourceExtends = instantiateType(sourceExtends, ctx.mapper); mapper = ctx.mapper; } if ( - isTypeIdenticalTo(sourceExtends, (target as ConditionalType).extendsType) && - (isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both) || isRelatedTo((target as ConditionalType).checkType, (source as ConditionalType).checkType, RecursionFlags.Both)) + isTypeIdenticalTo(sourceExtends, (target as ConditionalType).extendsType) + && (isRelatedTo( + (source as ConditionalType).checkType, + (target as ConditionalType).checkType, + RecursionFlags.Both, + ) + || isRelatedTo( + (target as ConditionalType).checkType, + (source as ConditionalType).checkType, + RecursionFlags.Both, + )) ) { - if (result = isRelatedTo(instantiateType(getTrueTypeFromConditionalType(source as ConditionalType), mapper), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors); + if ( + result = isRelatedTo( + instantiateType(getTrueTypeFromConditionalType(source as ConditionalType), mapper), + getTrueTypeFromConditionalType(target as ConditionalType), + RecursionFlags.Both, + reportErrors, + ) + ) { + result &= isRelatedTo( + getFalseTypeFromConditionalType(source as ConditionalType), + getFalseTypeFromConditionalType(target as ConditionalType), + RecursionFlags.Both, + reportErrors, + ); } if (result) { return result; @@ -20396,9 +27050,17 @@ namespace ts { else { // conditionals aren't related to one another via distributive constraint as it is much too inaccurate and allows way // more assignments than are desirable (since it maps the source check type to its constraint, it loses information) - const distributiveConstraint = hasNonCircularBaseConstraint(source) ? getConstraintOfDistributiveConditionalType(source as ConditionalType) : undefined; + const distributiveConstraint = hasNonCircularBaseConstraint(source) + ? getConstraintOfDistributiveConditionalType(source as ConditionalType) : undefined; if (distributiveConstraint) { - if (result = isRelatedTo(distributiveConstraint, target, RecursionFlags.Source, reportErrors)) { + if ( + result = isRelatedTo( + distributiveConstraint, + target, + RecursionFlags.Source, + reportErrors, + ) + ) { return result; } } @@ -20415,7 +27077,10 @@ namespace ts { } else { // An empty object type is related to any mapped type that includes a '?' modifier. - if (relation !== subtypeRelation && relation !== strictSubtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) { + if ( + relation !== subtypeRelation && relation !== strictSubtypeRelation + && isPartialMappedType(target) && isEmptyObjectType(source) + ) { return Ternary.True; } if (isGenericMappedType(target)) { @@ -20435,8 +27100,9 @@ namespace ts { return Ternary.False; } if ( - getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target && - !isTupleType(source) && !(isMarkerType(source) || isMarkerType(target)) + getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference + && (source as TypeReference).target === (target as TypeReference).target + && !isTupleType(source) && !(isMarkerType(source) || isMarkerType(target)) ) { // When strictNullChecks is disabled, the element type of the empty array literal is undefinedWideningType, // and an empty array literal wouldn't be assignable to a `never[]` without this check. @@ -20453,14 +27119,27 @@ namespace ts { if (variances === emptyArray) { return Ternary.Unknown; } - const varianceResult = relateVariances(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), variances, intersectionState); + const varianceResult = relateVariances( + getTypeArguments(source as TypeReference), + getTypeArguments(target as TypeReference), + variances, + intersectionState, + ); if (varianceResult !== undefined) { return varianceResult; } } - else if (isReadonlyArrayType(target) ? isArrayOrTupleType(source) : isArrayType(target) && isTupleType(source) && !source.target.readonly) { + else if ( + isReadonlyArrayType(target) ? isArrayOrTupleType(source) + : isArrayType(target) && isTupleType(source) && !source.target.readonly + ) { if (relation !== identityRelation) { - return isRelatedTo(getIndexTypeOfType(source, numberType) || anyType, getIndexTypeOfType(target, numberType) || anyType, RecursionFlags.Both, reportErrors); + return isRelatedTo( + getIndexTypeOfType(source, numberType) || anyType, + getIndexTypeOfType(target, numberType) || anyType, + RecursionFlags.Both, + reportErrors, + ); } else { // By flags alone, we know that the `target` is a readonly array while the source is a normal array or tuple @@ -20470,7 +27149,11 @@ namespace ts { } // Consider a fresh empty object literal type "closed" under the subtype relationship - this way `{} <- {[idx: string]: any} <- fresh({})` // and not `{} <- fresh({}) <- {[idx: string]: any}` - else if ((relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) { + else if ( + (relation === subtypeRelation || relation === strictSubtypeRelation) + && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral + && !isEmptyObjectType(source) + ) { return Ternary.False; } // Even if relationship doesn't hold for unions, intersections, or generic type references, @@ -20480,14 +27163,32 @@ namespace ts { // relates to X. Thus, we include intersection types on the source side here. if (sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && targetFlags & TypeFlags.Object) { // Report structural errors only if we haven't reported any errors yet - const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo.errorInfo && !sourceIsPrimitive; - result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined, intersectionState); + const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo.errorInfo + && !sourceIsPrimitive; + result = propertiesRelatedTo( + source, + target, + reportStructuralErrors, + /*excludedProperties*/ undefined, + intersectionState, + ); if (result) { result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors); if (result) { - result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportStructuralErrors); + result &= signaturesRelatedTo( + source, + target, + SignatureKind.Construct, + reportStructuralErrors, + ); if (result) { - result &= indexSignaturesRelatedTo(source, target, sourceIsPrimitive, reportStructuralErrors, intersectionState); + result &= indexSignaturesRelatedTo( + source, + target, + sourceIsPrimitive, + reportStructuralErrors, + intersectionState, + ); } } } @@ -20503,7 +27204,10 @@ namespace ts { // with respect to T. We do not report errors here, as we will use the existing // error result from checking each constituent of the union. if (sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && targetFlags & TypeFlags.Union) { - const objectOnlyTarget = extractTypesOfKind(target, TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Substitution); + const objectOnlyTarget = extractTypesOfKind( + target, + TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Substitution, + ); if (objectOnlyTarget.flags & TypeFlags.Union) { const result = typeRelatedToDiscriminatedType(source, objectOnlyTarget as UnionType); if (result) { @@ -20519,8 +27223,21 @@ namespace ts { return reduceLeft(info, (value, chain) => value + 1 + countMessageChainBreadth(chain.next), 0); } - function relateVariances(sourceTypeArguments: readonly Type[] | undefined, targetTypeArguments: readonly Type[] | undefined, variances: VarianceFlags[], intersectionState: IntersectionState) { - if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors, intersectionState)) { + function relateVariances( + sourceTypeArguments: readonly Type[] | undefined, + targetTypeArguments: readonly Type[] | undefined, + variances: VarianceFlags[], + intersectionState: IntersectionState, + ) { + if ( + result = typeArgumentsRelatedTo( + sourceTypeArguments, + targetTypeArguments, + variances, + reportErrors, + intersectionState, + ) + ) { return result; } if (some(variances, v => !!(v & VarianceFlags.AllowsStructuralFallback))) { @@ -20532,7 +27249,8 @@ namespace ts { resetErrorInfo(saveErrorInfo); return undefined; } - const allowStructuralFallback = targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances); + const allowStructuralFallback = targetTypeArguments + && hasCovariantVoidArgument(targetTypeArguments, variances); varianceCheckFailed = !allowStructuralFallback; // The type arguments did not relate appropriately, but it may be because we have no variance // information (in which case typeArgumentsRelatedTo defaulted to covariance for all type @@ -20550,7 +27268,11 @@ namespace ts { // reveal the reason). // We can switch on `reportErrors` here, since varianceCheckFailed guarantees we return `False`, // we can return `False` early here to skip calculating the structural error message we don't need. - if (varianceCheckFailed && !(reportErrors && some(variances, v => (v & VarianceFlags.VarianceMask) === VarianceFlags.Invariant))) { + if ( + varianceCheckFailed + && !(reportErrors + && some(variances, v => (v & VarianceFlags.VarianceMask) === VarianceFlags.Invariant)) + ) { return Ternary.False; } // We remember the original error information so we can restore it in case the structural @@ -20566,16 +27288,33 @@ namespace ts { // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice // that S and T are contra-variant whereas X and Y are co-variant. function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary { - const modifiersRelated = relation === comparableRelation || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) : - getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target)); + const modifiersRelated = relation === comparableRelation + || (relation === identityRelation + ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) + : getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target)); if (modifiersRelated) { let result: Ternary; const targetConstraint = getConstraintTypeFromMappedType(target); - const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMapper : reportUnreliableMapper); + const sourceConstraint = instantiateType( + getConstraintTypeFromMappedType(source), + getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMapper + : reportUnreliableMapper, + ); if (result = isRelatedTo(targetConstraint, sourceConstraint, RecursionFlags.Both, reportErrors)) { - const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]); - if (instantiateType(getNameTypeFromMappedType(source), mapper) === instantiateType(getNameTypeFromMappedType(target), mapper)) { - return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), RecursionFlags.Both, reportErrors); + const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [ + getTypeParameterFromMappedType(target), + ]); + if ( + instantiateType(getNameTypeFromMappedType(source), mapper) + === instantiateType(getNameTypeFromMappedType(target), mapper) + ) { + return result + & isRelatedTo( + instantiateType(getTemplateTypeFromMappedType(source), mapper), + getTemplateTypeFromMappedType(target), + RecursionFlags.Both, + reportErrors, + ); } } } @@ -20607,7 +27346,11 @@ namespace ts { numCombinations *= countTypes(getNonMissingTypeOfSymbol(sourceProperty)); if (numCombinations > 25) { // We've reached the complexity limit. - tracing?.instant(tracing.Phase.CheckTypes, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations }); + tracing?.instant(tracing.Phase.CheckTypes, "typeRelatedToDiscriminatedType_DepthLimit", { + sourceId: source.id, + targetId: target.id, + numCombinations, + }); return Ternary.False; } } @@ -20638,7 +27381,16 @@ namespace ts { if (!targetProperty) continue outer; if (sourceProperty === targetProperty) continue; // We compare the source property to the target in the context of a single discriminant type. - const related = propertyRelatedTo(source, target, sourceProperty, targetProperty, _ => combination[i], /*reportErrors*/ false, IntersectionState.None, /*skipOptional*/ strictNullChecks || relation === comparableRelation); + const related = propertyRelatedTo( + source, + target, + sourceProperty, + targetProperty, + _ => combination[i], + /*reportErrors*/ false, + IntersectionState.None, + /*skipOptional*/ strictNullChecks || relation === comparableRelation, + ); // If the target property could not be found, or if the properties were not related, // then this constituent is not a match. if (!related) { @@ -20657,17 +27409,39 @@ namespace ts { // Compare the remaining non-discriminant properties of each match. let result = Ternary.True; for (const type of matchingTypes) { - result &= propertiesRelatedTo(source, type, /*reportErrors*/ false, excludedProperties, IntersectionState.None); + result &= propertiesRelatedTo( + source, + type, + /*reportErrors*/ false, + excludedProperties, + IntersectionState.None, + ); if (result) { - result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportStructuralErrors*/ false); + result &= signaturesRelatedTo( + source, + type, + SignatureKind.Call, + /*reportStructuralErrors*/ false, + ); if (result) { - result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportStructuralErrors*/ false); + result &= signaturesRelatedTo( + source, + type, + SignatureKind.Construct, + /*reportStructuralErrors*/ false, + ); if (result && !(isTupleType(source) && isTupleType(type))) { // Comparing numeric index types when both `source` and `type` are tuples is unnecessary as the // element types should be sufficiently covered by `propertiesRelatedTo`. It also causes problems // with index type assignability as the types for the excluded discriminants are still included // in the index type. - result &= indexSignaturesRelatedTo(source, type, /*sourceIsPrimitive*/ false, /*reportStructuralErrors*/ false, IntersectionState.None); + result &= indexSignaturesRelatedTo( + source, + type, + /*sourceIsPrimitive*/ false, + /*reportStructuralErrors*/ false, + IntersectionState.None, + ); } } } @@ -20694,24 +27468,58 @@ namespace ts { return result || properties; } - function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function isPropertySymbolTypeRelated( + sourceProp: Symbol, + targetProp: Symbol, + getTypeOfSourceProperty: (sym: Symbol) => Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { const targetIsOptional = strictNullChecks && !!(getCheckFlags(targetProp) & CheckFlags.Partial); - const effectiveTarget = addOptionality(getNonMissingTypeOfSymbol(targetProp), /*isProperty*/ false, targetIsOptional); + const effectiveTarget = addOptionality( + getNonMissingTypeOfSymbol(targetProp), + /*isProperty*/ false, + targetIsOptional, + ); const effectiveSource = getTypeOfSourceProperty(sourceProp); - return isRelatedTo(effectiveSource, effectiveTarget, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + return isRelatedTo( + effectiveSource, + effectiveTarget, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } - function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState, skipOptional: boolean): Ternary { + function propertyRelatedTo( + source: Type, + target: Type, + sourceProp: Symbol, + targetProp: Symbol, + getTypeOfSourceProperty: (sym: Symbol) => Type, + reportErrors: boolean, + intersectionState: IntersectionState, + skipOptional: boolean, + ): Ternary { const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp); const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp); if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) { if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) { if (reportErrors) { if (sourcePropFlags & ModifierFlags.Private && targetPropFlags & ModifierFlags.Private) { - reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp)); + reportError( + Diagnostics.Types_have_separate_declarations_of_a_private_property_0, + symbolToString(targetProp), + ); } else { - reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp), typeToString(sourcePropFlags & ModifierFlags.Private ? source : target), typeToString(sourcePropFlags & ModifierFlags.Private ? target : source)); + reportError( + Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, + symbolToString(targetProp), + typeToString(sourcePropFlags & ModifierFlags.Private ? source : target), + typeToString(sourcePropFlags & ModifierFlags.Private ? target : source), + ); } } return Ternary.False; @@ -20720,14 +27528,24 @@ namespace ts { else if (targetPropFlags & ModifierFlags.Protected) { if (!isValidOverrideOf(sourceProp, targetProp)) { if (reportErrors) { - reportError(Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, symbolToString(targetProp), typeToString(getDeclaringClass(sourceProp) || source), typeToString(getDeclaringClass(targetProp) || target)); + reportError( + Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, + symbolToString(targetProp), + typeToString(getDeclaringClass(sourceProp) || source), + typeToString(getDeclaringClass(targetProp) || target), + ); } return Ternary.False; } } else if (sourcePropFlags & ModifierFlags.Protected) { if (reportErrors) { - reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, symbolToString(targetProp), typeToString(source), typeToString(target)); + reportError( + Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, + symbolToString(targetProp), + typeToString(source), + typeToString(target), + ); } return Ternary.False; } @@ -20739,21 +27557,33 @@ namespace ts { // They're still assignable to one another, since `readonly` doesn't affect assignability. // This is only applied during the strictSubtypeRelation -- currently used in subtype reduction if ( - relation === strictSubtypeRelation && - isReadonlySymbol(sourceProp) && !isReadonlySymbol(targetProp) + relation === strictSubtypeRelation + && isReadonlySymbol(sourceProp) && !isReadonlySymbol(targetProp) ) { return Ternary.False; } // If the target comes from a partial union prop, allow `undefined` in the target type - const related = isPropertySymbolTypeRelated(sourceProp, targetProp, getTypeOfSourceProperty, reportErrors, intersectionState); + const related = isPropertySymbolTypeRelated( + sourceProp, + targetProp, + getTypeOfSourceProperty, + reportErrors, + intersectionState, + ); if (!related) { if (reportErrors) { - reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp)); + reportIncompatibleError( + Diagnostics.Types_of_property_0_are_incompatible, + symbolToString(targetProp), + ); } return Ternary.False; } // When checking for comparability, be more lenient with optional properties. - if (!skipOptional && sourceProp.flags & SymbolFlags.Optional && targetProp.flags & SymbolFlags.ClassMember && !(targetProp.flags & SymbolFlags.Optional)) { + if ( + !skipOptional && sourceProp.flags & SymbolFlags.Optional + && targetProp.flags & SymbolFlags.ClassMember && !(targetProp.flags & SymbolFlags.Optional) + ) { // TypeScript 1.0 spec (April 2014): 3.8.3 // S is a subtype of a type T, and T is a supertype of S if ... // S' and T are object types and, for each member M in T.. @@ -20762,14 +27592,24 @@ namespace ts { // (M - property in T) // (N - property in S) if (reportErrors) { - reportError(Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2, symbolToString(targetProp), typeToString(source), typeToString(target)); + reportError( + Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2, + symbolToString(targetProp), + typeToString(source), + typeToString(target), + ); } return Ternary.False; } return related; } - function reportUnmatchedProperty(source: Type, target: Type, unmatchedProperty: Symbol, requireOptionalProperties: boolean) { + function reportUnmatchedProperty( + source: Type, + target: Type, + unmatchedProperty: Symbol, + requireOptionalProperties: boolean, + ) { let shouldSkipElaboration = false; // give specific error in case where private names have the same description if ( @@ -20780,12 +27620,16 @@ namespace ts { && source.symbol.flags & SymbolFlags.Class ) { const privateIdentifierDescription = unmatchedProperty.valueDeclaration.name.escapedText; - const symbolTableKey = getSymbolNameForPrivateIdentifier(source.symbol, privateIdentifierDescription); + const symbolTableKey = getSymbolNameForPrivateIdentifier( + source.symbol, + privateIdentifierDescription, + ); if (symbolTableKey && getPropertyOfType(source, symbolTableKey)) { const sourceName = factory.getDeclarationName(source.symbol.valueDeclaration); const targetName = factory.getDeclarationName(target.symbol.valueDeclaration); reportError( - Diagnostics.Property_0_in_type_1_refers_to_a_different_member_that_cannot_be_accessed_from_within_type_2, + Diagnostics + .Property_0_in_type_1_refers_to_a_different_member_that_cannot_be_accessed_from_within_type_2, diagnosticName(privateIdentifierDescription), diagnosticName(sourceName.escapedText === "" ? anon : sourceName), diagnosticName(targetName.escapedText === "" ? anon : targetName), @@ -20793,18 +27637,43 @@ namespace ts { return; } } - const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false)); + const props = arrayFrom( + getUnmatchedProperties( + source, + target, + requireOptionalProperties, + /*matchDiscriminantProperties*/ false, + ), + ); if ( - !headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code && - headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code) + !headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code + && headMessage.code + !== Diagnostics + .Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass + .code) ) { shouldSkipElaboration = true; // Retain top-level error for interface implementing issues, otherwise omit it } if (props.length === 1) { - const propName = symbolToString(unmatchedProperty, /*enclosingDeclaration*/ undefined, SymbolFlags.None, SymbolFormatFlags.AllowAnyNodeKind | SymbolFormatFlags.WriteComputedProps); - reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, ...getTypeNamesForErrorDisplay(source, target)); + const propName = symbolToString( + unmatchedProperty, + /*enclosingDeclaration*/ undefined, + SymbolFlags.None, + SymbolFormatFlags.AllowAnyNodeKind | SymbolFormatFlags.WriteComputedProps, + ); + reportError( + Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, + propName, + ...getTypeNamesForErrorDisplay(source, target), + ); if (length(unmatchedProperty.declarations)) { - associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations![0], Diagnostics._0_is_declared_here, propName)); + associateRelatedInfo( + createDiagnosticForNode( + unmatchedProperty.declarations![0], + Diagnostics._0_is_declared_here, + propName, + ), + ); } if (shouldSkipElaboration && errorInfo) { overrideNextErrorInfo++; @@ -20812,10 +27681,21 @@ namespace ts { } else if (tryElaborateArrayLikeErrors(source, target, /*reportErrors*/ false)) { if (props.length > 5) { // arbitrary cutoff for too-long list form - reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4); + reportError( + Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, + typeToString(source), + typeToString(target), + map(props.slice(0, 4), p => symbolToString(p)).join(", "), + props.length - 4, + ); } else { - reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", ")); + reportError( + Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, + typeToString(source), + typeToString(target), + map(props, p => symbolToString(p)).join(", "), + ); } if (shouldSkipElaboration && errorInfo) { overrideNextErrorInfo++; @@ -20824,69 +27704,113 @@ namespace ts { // No array like or unmatched property error - just issue top level error (errorInfo = undefined) } - function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean, excludedProperties: Set<__String> | undefined, intersectionState: IntersectionState): Ternary { + function propertiesRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + excludedProperties: Set<__String> | undefined, + intersectionState: IntersectionState, + ): Ternary { if (relation === identityRelation) { return propertiesIdenticalTo(source, target, excludedProperties); } let result = Ternary.True; if (isTupleType(target)) { if (isArrayOrTupleType(source)) { - if (!target.target.readonly && (isReadonlyArrayType(source) || isTupleType(source) && source.target.readonly)) { + if ( + !target.target.readonly + && (isReadonlyArrayType(source) || isTupleType(source) && source.target.readonly) + ) { return Ternary.False; } const sourceArity = getTypeReferenceArity(source); const targetArity = getTypeReferenceArity(target); - const sourceRestFlag = isTupleType(source) ? source.target.combinedFlags & ElementFlags.Rest : ElementFlags.Rest; + const sourceRestFlag = isTupleType(source) ? source.target.combinedFlags & ElementFlags.Rest + : ElementFlags.Rest; const targetRestFlag = target.target.combinedFlags & ElementFlags.Rest; const sourceMinLength = isTupleType(source) ? source.target.minLength : 0; const targetMinLength = target.target.minLength; if (!sourceRestFlag && sourceArity < targetMinLength) { if (reportErrors) { - reportError(Diagnostics.Source_has_0_element_s_but_target_requires_1, sourceArity, targetMinLength); + reportError( + Diagnostics.Source_has_0_element_s_but_target_requires_1, + sourceArity, + targetMinLength, + ); } return Ternary.False; } if (!targetRestFlag && targetArity < sourceMinLength) { if (reportErrors) { - reportError(Diagnostics.Source_has_0_element_s_but_target_allows_only_1, sourceMinLength, targetArity); + reportError( + Diagnostics.Source_has_0_element_s_but_target_allows_only_1, + sourceMinLength, + targetArity, + ); } return Ternary.False; } if (!targetRestFlag && (sourceRestFlag || targetArity < sourceArity)) { if (reportErrors) { if (sourceMinLength < targetMinLength) { - reportError(Diagnostics.Target_requires_0_element_s_but_source_may_have_fewer, targetMinLength); + reportError( + Diagnostics.Target_requires_0_element_s_but_source_may_have_fewer, + targetMinLength, + ); } else { - reportError(Diagnostics.Target_allows_only_0_element_s_but_source_may_have_more, targetArity); + reportError( + Diagnostics.Target_allows_only_0_element_s_but_source_may_have_more, + targetArity, + ); } } return Ternary.False; } const sourceTypeArguments = getTypeArguments(source); const targetTypeArguments = getTypeArguments(target); - const startCount = Math.min(isTupleType(source) ? getStartElementCount(source.target, ElementFlags.NonRest) : 0, getStartElementCount(target.target, ElementFlags.NonRest)); - const endCount = Math.min(isTupleType(source) ? getEndElementCount(source.target, ElementFlags.NonRest) : 0, targetRestFlag ? getEndElementCount(target.target, ElementFlags.NonRest) : 0); + const startCount = Math.min( + isTupleType(source) ? getStartElementCount(source.target, ElementFlags.NonRest) : 0, + getStartElementCount(target.target, ElementFlags.NonRest), + ); + const endCount = Math.min( + isTupleType(source) ? getEndElementCount(source.target, ElementFlags.NonRest) : 0, + targetRestFlag ? getEndElementCount(target.target, ElementFlags.NonRest) : 0, + ); let canExcludeDiscriminants = !!excludedProperties; for (let i = 0; i < targetArity; i++) { const sourceIndex = i < targetArity - endCount ? i : i + sourceArity - targetArity; - const sourceFlags = isTupleType(source) && (i < startCount || i >= targetArity - endCount) ? source.target.elementFlags[sourceIndex] : ElementFlags.Rest; + const sourceFlags = isTupleType(source) && (i < startCount || i >= targetArity - endCount) + ? source.target.elementFlags[sourceIndex] : ElementFlags.Rest; const targetFlags = target.target.elementFlags[i]; if (targetFlags & ElementFlags.Variadic && !(sourceFlags & ElementFlags.Variadic)) { if (reportErrors) { - reportError(Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, i); + reportError( + Diagnostics + .Source_provides_no_match_for_variadic_element_at_position_0_in_target, + i, + ); } return Ternary.False; } if (sourceFlags & ElementFlags.Variadic && !(targetFlags & ElementFlags.Variable)) { if (reportErrors) { - reportError(Diagnostics.Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, sourceIndex, i); + reportError( + Diagnostics + .Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, + sourceIndex, + i, + ); } return Ternary.False; } if (targetFlags & ElementFlags.Required && !(sourceFlags & ElementFlags.Required)) { if (reportErrors) { - reportError(Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, i); + reportError( + Diagnostics + .Source_provides_no_match_for_required_element_at_position_0_in_target, + i, + ); } return Ternary.False; } @@ -20899,20 +27823,47 @@ namespace ts { continue; } } - const sourceType = !isTupleType(source) ? sourceTypeArguments[0] : - i < startCount || i >= targetArity - endCount ? removeMissingType(sourceTypeArguments[sourceIndex], !!(sourceFlags & targetFlags & ElementFlags.Optional)) : - getElementTypeOfSliceOfTupleType(source, startCount, endCount) || neverType; + const sourceType = !isTupleType(source) ? sourceTypeArguments[0] + : i < startCount || i >= targetArity - endCount + ? removeMissingType( + sourceTypeArguments[sourceIndex], + !!(sourceFlags & targetFlags & ElementFlags.Optional), + ) + : getElementTypeOfSliceOfTupleType(source, startCount, endCount) || neverType; const targetType = targetTypeArguments[i]; - const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest ? createArrayType(targetType) : - removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional)); - const related = isRelatedTo(sourceType, targetCheckType, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + const targetCheckType = + sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest + ? createArrayType(targetType) + : removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional)); + const related = isRelatedTo( + sourceType, + targetCheckType, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (!related) { if (reportErrors && (targetArity > 1 || sourceArity > 1)) { - if (i < startCount || i >= targetArity - endCount || sourceArity - startCount - endCount === 1) { - reportIncompatibleError(Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, sourceIndex, i); + if ( + i < startCount || i >= targetArity - endCount + || sourceArity - startCount - endCount === 1 + ) { + reportIncompatibleError( + Diagnostics + .Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, + sourceIndex, + i, + ); } else { - reportIncompatibleError(Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, startCount, sourceArity - endCount - 1, i); + reportIncompatibleError( + Diagnostics + .Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, + startCount, + sourceArity - endCount - 1, + i, + ); } } return Ternary.False; @@ -20925,8 +27876,14 @@ namespace ts { return Ternary.False; } } - const requireOptionalProperties = (relation === subtypeRelation || relation === strictSubtypeRelation) && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source); - const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false); + const requireOptionalProperties = (relation === subtypeRelation || relation === strictSubtypeRelation) + && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source); + const unmatchedProperty = getUnmatchedProperty( + source, + target, + requireOptionalProperties, + /*matchDiscriminantProperties*/ false, + ); if (unmatchedProperty) { if (reportErrors && shouldReportUnmatchedPropertyError(source, target)) { reportUnmatchedProperty(source, target, unmatchedProperty, requireOptionalProperties); @@ -20939,7 +27896,11 @@ namespace ts { const sourceType = getTypeOfSymbol(sourceProp); if (!(sourceType.flags & TypeFlags.Undefined)) { if (reportErrors) { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(sourceProp), typeToString(target)); + reportError( + Diagnostics.Property_0_does_not_exist_on_type_1, + symbolToString(sourceProp), + typeToString(target), + ); } return Ternary.False; } @@ -20952,10 +27913,22 @@ namespace ts { const numericNamesOnly = isTupleType(source) && isTupleType(target); for (const targetProp of excludeProperties(properties, excludedProperties)) { const name = targetProp.escapedName; - if (!(targetProp.flags & SymbolFlags.Prototype) && (!numericNamesOnly || isNumericLiteralName(name) || name === "length")) { + if ( + !(targetProp.flags & SymbolFlags.Prototype) + && (!numericNamesOnly || isNumericLiteralName(name) || name === "length") + ) { const sourceProp = getPropertyOfType(source, name); if (sourceProp && sourceProp !== targetProp) { - const related = propertyRelatedTo(source, target, sourceProp, targetProp, getNonMissingTypeOfSymbol, reportErrors, intersectionState, relation === comparableRelation); + const related = propertyRelatedTo( + source, + target, + sourceProp, + targetProp, + getNonMissingTypeOfSymbol, + reportErrors, + intersectionState, + relation === comparableRelation, + ); if (!related) { return Ternary.False; } @@ -20966,7 +27939,11 @@ namespace ts { return result; } - function propertiesIdenticalTo(source: Type, target: Type, excludedProperties: Set<__String> | undefined): Ternary { + function propertiesIdenticalTo( + source: Type, + target: Type, + excludedProperties: Set<__String> | undefined, + ): Ternary { if (!(source.flags & TypeFlags.Object && target.flags & TypeFlags.Object)) { return Ternary.False; } @@ -20990,7 +27967,12 @@ namespace ts { return result; } - function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: boolean): Ternary { + function signaturesRelatedTo( + source: Type, + target: Type, + kind: SignatureKind, + reportErrors: boolean, + ): Ternary { if (relation === identityRelation) { return signaturesIdenticalTo(source, target, kind); } @@ -21003,13 +27985,13 @@ namespace ts { const sourceSignatures = getSignaturesOfType( source, - (sourceIsJSConstructor && kind === SignatureKind.Construct) ? - SignatureKind.Call : kind, + (sourceIsJSConstructor && kind === SignatureKind.Construct) + ? SignatureKind.Call : kind, ); const targetSignatures = getSignaturesOfType( target, - (targetIsJSConstructor && kind === SignatureKind.Construct) ? - SignatureKind.Call : kind, + (targetIsJSConstructor && kind === SignatureKind.Construct) + ? SignatureKind.Call : kind, ); if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length) { @@ -21021,7 +28003,10 @@ namespace ts { // check we perform for an extends clause excludes construct signatures from the target, // so this check never proceeds. if (reportErrors) { - reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); + reportError( + Diagnostics + .Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type, + ); } return Ternary.False; } @@ -21031,19 +28016,28 @@ namespace ts { } let result = Ternary.True; - const incompatibleReporter = kind === SignatureKind.Construct ? reportIncompatibleConstructSignatureReturn : reportIncompatibleCallSignatureReturn; + const incompatibleReporter = kind === SignatureKind.Construct + ? reportIncompatibleConstructSignatureReturn : reportIncompatibleCallSignatureReturn; const sourceObjectFlags = getObjectFlags(source); const targetObjectFlags = getObjectFlags(target); if ( - sourceObjectFlags & ObjectFlags.Instantiated && targetObjectFlags & ObjectFlags.Instantiated && source.symbol === target.symbol || - sourceObjectFlags & ObjectFlags.Reference && targetObjectFlags & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target + sourceObjectFlags & ObjectFlags.Instantiated && targetObjectFlags & ObjectFlags.Instantiated + && source.symbol === target.symbol + || sourceObjectFlags & ObjectFlags.Reference && targetObjectFlags & ObjectFlags.Reference + && (source as TypeReference).target === (target as TypeReference).target ) { // We have instantiations of the same anonymous type (which typically will be the type of a // method). Simply do a pairwise comparison of the signatures in the two signature lists instead // of the much more expensive N * M comparison matrix we explore below. We erase type parameters // as they are known to always be the same. for (let i = 0; i < targetSignatures.length; i++) { - const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, incompatibleReporter(sourceSignatures[i], targetSignatures[i])); + const related = signatureRelatedTo( + sourceSignatures[i], + targetSignatures[i], + /*erase*/ true, + reportErrors, + incompatibleReporter(sourceSignatures[i], targetSignatures[i]), + ); if (!related) { return Ternary.False; } @@ -21059,13 +28053,31 @@ namespace ts { const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks; const sourceSignature = first(sourceSignatures); const targetSignature = first(targetSignatures); - result = signatureRelatedTo(sourceSignature, targetSignature, eraseGenerics, reportErrors, incompatibleReporter(sourceSignature, targetSignature)); + result = signatureRelatedTo( + sourceSignature, + targetSignature, + eraseGenerics, + reportErrors, + incompatibleReporter(sourceSignature, targetSignature), + ); if ( - !result && reportErrors && kind === SignatureKind.Construct && (sourceObjectFlags & targetObjectFlags) && - (targetSignature.declaration?.kind === SyntaxKind.Constructor || sourceSignature.declaration?.kind === SyntaxKind.Constructor) + !result && reportErrors && kind === SignatureKind.Construct + && (sourceObjectFlags & targetObjectFlags) + && (targetSignature.declaration?.kind === SyntaxKind.Constructor + || sourceSignature.declaration?.kind === SyntaxKind.Constructor) ) { - const constructSignatureToString = (signature: Signature) => signatureToString(signature, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrowStyleSignature, kind); - reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, constructSignatureToString(sourceSignature), constructSignatureToString(targetSignature)); + const constructSignatureToString = (signature: Signature) => + signatureToString( + signature, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.WriteArrowStyleSignature, + kind, + ); + reportError( + Diagnostics.Type_0_is_not_assignable_to_type_1, + constructSignatureToString(sourceSignature), + constructSignatureToString(targetSignature), + ); reportError(Diagnostics.Types_of_construct_signatures_are_incompatible); return result; } @@ -21077,7 +28089,13 @@ namespace ts { // Only elaborate errors from the first failure let shouldElaborateErrors = reportErrors; for (const s of sourceSignatures) { - const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors, incompatibleReporter(s, t)); + const related = signatureRelatedTo( + s, + t, + /*erase*/ true, + shouldElaborateErrors, + incompatibleReporter(s, t), + ); if (related) { result &= related; resetErrorInfo(saveErrorInfo); @@ -21086,7 +28104,11 @@ namespace ts { shouldElaborateErrors = false; } if (shouldElaborateErrors) { - reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1, typeToString(source), signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind)); + reportError( + Diagnostics.Type_0_provides_no_match_for_the_signature_1, + typeToString(source), + signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind), + ); } return Ternary.False; } @@ -21100,8 +28122,9 @@ namespace ts { const typeProperties = getPropertiesOfObjectType(source); if ((typeCallSignatures.length || typeConstructSignatures.length) && !typeProperties.length) { if ( - (getSignaturesOfType(target, SignatureKind.Call).length && typeCallSignatures.length) || - (getSignaturesOfType(target, SignatureKind.Construct).length && typeConstructSignatures.length) + (getSignaturesOfType(target, SignatureKind.Call).length && typeCallSignatures.length) + || (getSignaturesOfType(target, SignatureKind.Construct).length + && typeConstructSignatures.length) ) { return true; // target has similar signature kinds to source, still focus on the unmatched property } @@ -21112,23 +28135,58 @@ namespace ts { function reportIncompatibleCallSignatureReturn(siga: Signature, sigb: Signature) { if (siga.parameters.length === 0 && sigb.parameters.length === 0) { - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, + typeToString(source), + typeToString(target), + ); } - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Call_signature_return_types_0_and_1_are_incompatible, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Call_signature_return_types_0_and_1_are_incompatible, + typeToString(source), + typeToString(target), + ); } function reportIncompatibleConstructSignatureReturn(siga: Signature, sigb: Signature) { if (siga.parameters.length === 0 && sigb.parameters.length === 0) { - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, + typeToString(source), + typeToString(target), + ); } - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible, + typeToString(source), + typeToString(target), + ); } /** * See signatureAssignableTo, compareSignaturesIdentical */ - function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary { - return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target, relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper); + function signatureRelatedTo( + source: Signature, + target: Signature, + erase: boolean, + reportErrors: boolean, + incompatibleReporter: (source: Type, target: Type) => void, + ): Ternary { + return compareSignaturesRelated( + erase ? getErasedSignature(source) : source, + erase ? getErasedSignature(target) : target, + relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, + reportErrors, + reportError, + incompatibleReporter, + isRelatedToWorker, + reportUnreliableMapper, + ); } function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary { @@ -21139,7 +28197,14 @@ namespace ts { } let result = Ternary.True; for (let i = 0; i < sourceSignatures.length; i++) { - const related = compareSignaturesIdentical(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, isRelatedTo); + const related = compareSignaturesIdentical( + sourceSignatures[i], + targetSignatures[i], + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ false, + isRelatedTo, + ); if (!related) { return Ternary.False; } @@ -21151,21 +28216,33 @@ namespace ts { function membersRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean): Ternary { let result = Ternary.True; const keyType = targetInfo.keyType; - const props = source.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(source as IntersectionType) : getPropertiesOfObjectType(source); + const props = source.flags & TypeFlags.Intersection + ? getPropertiesOfUnionOrIntersectionType(source as IntersectionType) + : getPropertiesOfObjectType(source); for (const prop of props) { // Skip over ignored JSX and symbol-named members if (isIgnoredJsxProperty(source, prop)) { continue; } - if (isApplicableIndexType(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), keyType)) { + if ( + isApplicableIndexType( + getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), + keyType, + ) + ) { const propType = getNonMissingTypeOfSymbol(prop); - const type = exactOptionalPropertyTypes || propType.flags & TypeFlags.Undefined || keyType === numberType || !(prop.flags & SymbolFlags.Optional) - ? propType - : getTypeWithFacts(propType, TypeFacts.NEUndefined); + const type = + exactOptionalPropertyTypes || propType.flags & TypeFlags.Undefined || keyType === numberType + || !(prop.flags & SymbolFlags.Optional) + ? propType + : getTypeWithFacts(propType, TypeFacts.NEUndefined); const related = isRelatedTo(type, targetInfo.type, RecursionFlags.Both, reportErrors); if (!related) { if (reportErrors) { - reportError(Diagnostics.Property_0_is_incompatible_with_index_signature, symbolToString(prop)); + reportError( + Diagnostics.Property_0_is_incompatible_with_index_signature, + symbolToString(prop), + ); } return Ternary.False; } @@ -21191,13 +28268,23 @@ namespace ts { reportError(Diagnostics._0_index_signatures_are_incompatible, typeToString(sourceInfo.keyType)); } else { - reportError(Diagnostics._0_and_1_index_signatures_are_incompatible, typeToString(sourceInfo.keyType), typeToString(targetInfo.keyType)); + reportError( + Diagnostics._0_and_1_index_signatures_are_incompatible, + typeToString(sourceInfo.keyType), + typeToString(targetInfo.keyType), + ); } } return related; } - function indexSignaturesRelatedTo(source: Type, target: Type, sourceIsPrimitive: boolean, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function indexSignaturesRelatedTo( + source: Type, + target: Type, + sourceIsPrimitive: boolean, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { if (relation === identityRelation) { return indexSignaturesIdenticalTo(source, target); } @@ -21205,9 +28292,16 @@ namespace ts { const targetHasStringIndex = some(indexInfos, info => info.keyType === stringType); let result = Ternary.True; for (const targetInfo of indexInfos) { - const related = !sourceIsPrimitive && targetHasStringIndex && targetInfo.type.flags & TypeFlags.Any ? Ternary.True : - isGenericMappedType(source) && targetHasStringIndex ? isRelatedTo(getTemplateTypeFromMappedType(source), targetInfo.type, RecursionFlags.Both, reportErrors) : - typeRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); + const related = !sourceIsPrimitive && targetHasStringIndex && targetInfo.type.flags & TypeFlags.Any + ? Ternary.True + : isGenericMappedType(source) && targetHasStringIndex + ? isRelatedTo( + getTemplateTypeFromMappedType(source), + targetInfo.type, + RecursionFlags.Both, + reportErrors, + ) + : typeRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); if (!related) { return Ternary.False; } @@ -21216,7 +28310,12 @@ namespace ts { return result; } - function typeRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function typeRelatedToIndexInfo( + source: Type, + targetInfo: IndexInfo, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { const sourceInfo = getApplicableIndexInfo(source, targetInfo.keyType); if (sourceInfo) { return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors); @@ -21226,7 +28325,11 @@ namespace ts { return membersRelatedToIndexInfo(source, targetInfo, reportErrors); } if (reportErrors) { - reportError(Diagnostics.Index_signature_for_type_0_is_missing_in_type_1, typeToString(targetInfo.keyType), typeToString(source)); + reportError( + Diagnostics.Index_signature_for_type_0_is_missing_in_type_1, + typeToString(targetInfo.keyType), + typeToString(source), + ); } return Ternary.False; } @@ -21239,20 +28342,33 @@ namespace ts { } for (const targetInfo of targetInfos) { const sourceInfo = getIndexInfoOfType(source, targetInfo.keyType); - if (!(sourceInfo && isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both) && sourceInfo.isReadonly === targetInfo.isReadonly)) { + if ( + !(sourceInfo && isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both) + && sourceInfo.isReadonly === targetInfo.isReadonly) + ) { return Ternary.False; } } return Ternary.True; } - function constructorVisibilitiesAreCompatible(sourceSignature: Signature, targetSignature: Signature, reportErrors: boolean) { + function constructorVisibilitiesAreCompatible( + sourceSignature: Signature, + targetSignature: Signature, + reportErrors: boolean, + ) { if (!sourceSignature.declaration || !targetSignature.declaration) { return true; } - const sourceAccessibility = getSelectedEffectiveModifierFlags(sourceSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier); - const targetAccessibility = getSelectedEffectiveModifierFlags(targetSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier); + const sourceAccessibility = getSelectedEffectiveModifierFlags( + sourceSignature.declaration, + ModifierFlags.NonPublicAccessibilityModifier, + ); + const targetAccessibility = getSelectedEffectiveModifierFlags( + targetSignature.declaration, + ModifierFlags.NonPublicAccessibilityModifier, + ); // A public, protected and private signature is assignable to a private signature. if (targetAccessibility === ModifierFlags.Private) { @@ -21270,7 +28386,11 @@ namespace ts { } if (reportErrors) { - reportError(Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, visibilityToString(sourceAccessibility), visibilityToString(targetAccessibility)); + reportError( + Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, + visibilityToString(sourceAccessibility), + visibilityToString(targetAccessibility), + ); } return false; @@ -21296,34 +28416,63 @@ namespace ts { } } - return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral) || !!(type.flags & TypeFlags.StringMapping); + return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral) + || !!(type.flags & TypeFlags.StringMapping); } function getExactOptionalUnassignableProperties(source: Type, target: Type) { if (isTupleType(source) && isTupleType(target)) return emptyArray; return getPropertiesOfType(target) - .filter(targetProp => isExactOptionalPropertyMismatch(getTypeOfPropertyOfType(source, targetProp.escapedName), getTypeOfSymbol(targetProp))); + .filter(targetProp => + isExactOptionalPropertyMismatch( + getTypeOfPropertyOfType(source, targetProp.escapedName), + getTypeOfSymbol(targetProp), + ) + ); } function isExactOptionalPropertyMismatch(source: Type | undefined, target: Type | undefined) { - return !!source && !!target && maybeTypeOfKind(source, TypeFlags.Undefined) && !!containsMissingType(target); + return !!source && !!target && maybeTypeOfKind(source, TypeFlags.Undefined) + && !!containsMissingType(target); } function getExactOptionalProperties(type: Type) { return getPropertiesOfType(type).filter(targetProp => containsMissingType(getTypeOfSymbol(targetProp))); } - function getBestMatchingType(source: Type, target: UnionOrIntersectionType, isRelatedTo = compareTypesAssignable) { - return findMatchingDiscriminantType(source, target, isRelatedTo, /*skipPartial*/ true) || - findMatchingTypeReferenceOrTypeAliasReference(source, target) || - findBestTypeForObjectLiteral(source, target) || - findBestTypeForInvokable(source, target) || - findMostOverlappyType(source, target); - } - - function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue?: undefined, skipPartial?: boolean): Type | undefined; - function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue: Type, skipPartial?: boolean): Type; - function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue?: Type, skipPartial?: boolean) { + function getBestMatchingType( + source: Type, + target: UnionOrIntersectionType, + isRelatedTo = compareTypesAssignable, + ) { + return findMatchingDiscriminantType(source, target, isRelatedTo, /*skipPartial*/ true) + || findMatchingTypeReferenceOrTypeAliasReference(source, target) + || findBestTypeForObjectLiteral(source, target) + || findBestTypeForInvokable(source, target) + || findMostOverlappyType(source, target); + } + + function discriminateTypeByDiscriminableItems( + target: UnionType, + discriminators: [() => Type, __String][], + related: (source: Type, target: Type) => boolean | Ternary, + defaultValue?: undefined, + skipPartial?: boolean, + ): Type | undefined; + function discriminateTypeByDiscriminableItems( + target: UnionType, + discriminators: [() => Type, __String][], + related: (source: Type, target: Type) => boolean | Ternary, + defaultValue: Type, + skipPartial?: boolean, + ): Type; + function discriminateTypeByDiscriminableItems( + target: UnionType, + discriminators: [() => Type, __String][], + related: (source: Type, target: Type) => boolean | Ternary, + defaultValue?: Type, + skipPartial?: boolean, + ) { // undefined=unknown, true=discriminated, false=not discriminated // The state of each type progresses from left to right. Discriminated types stop at 'true'. const discriminable = target.types.map(_ => undefined) as (boolean | undefined)[]; @@ -21366,8 +28515,10 @@ namespace ts { function isWeakType(type: Type): boolean { if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); - return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 && resolved.indexInfos.length === 0 && - resolved.properties.length > 0 && every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional)); + return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 + && resolved.indexInfos.length === 0 + && resolved.properties.length > 0 && every(resolved.properties, p => + !!(p.flags & SymbolFlags.Optional)); } if (type.flags & TypeFlags.Intersection) { return every((type as IntersectionType).types, isWeakType); @@ -21386,9 +28537,9 @@ namespace ts { function getVariances(type: GenericType): VarianceFlags[] { // Arrays and tuples are known to be covariant, no need to spend time computing this. - return type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple ? - arrayVariances : - getVariancesWorker(type.symbol, type.typeParameters); + return type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple + ? arrayVariances + : getVariancesWorker(type.symbol, type.typeParameters); } function getAliasVariances(symbol: Symbol) { @@ -21400,34 +28551,44 @@ namespace ts { // generic type are structurally compared. We infer the variance information by comparing // instantiations of the generic type for type arguments with known relations. The function // returns the emptyArray singleton when invoked recursively for the given generic type. - function getVariancesWorker(symbol: Symbol, typeParameters: readonly TypeParameter[] = emptyArray): VarianceFlags[] { + function getVariancesWorker( + symbol: Symbol, + typeParameters: readonly TypeParameter[] = emptyArray, + ): VarianceFlags[] { const links = getSymbolLinks(symbol); if (!links.variances) { - tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { arity: typeParameters.length, id: getTypeId(getDeclaredTypeOfSymbol(symbol)) }); + tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { + arity: typeParameters.length, + id: getTypeId(getDeclaredTypeOfSymbol(symbol)), + }); links.variances = emptyArray; const variances = []; for (const tp of typeParameters) { const modifiers = getVarianceModifiers(tp); - let variance = modifiers & ModifierFlags.Out ? - modifiers & ModifierFlags.In ? VarianceFlags.Invariant : VarianceFlags.Covariant : - modifiers & ModifierFlags.In ? VarianceFlags.Contravariant : undefined; + let variance = modifiers & ModifierFlags.Out + ? modifiers & ModifierFlags.In ? VarianceFlags.Invariant : VarianceFlags.Covariant + : modifiers & ModifierFlags.In ? VarianceFlags.Contravariant : undefined; if (variance === undefined) { let unmeasurable = false; let unreliable = false; const oldHandler = outofbandVarianceMarkerHandler; - outofbandVarianceMarkerHandler = onlyUnreliable => onlyUnreliable ? unreliable = true : unmeasurable = true; + outofbandVarianceMarkerHandler = onlyUnreliable => + onlyUnreliable ? unreliable = true : unmeasurable = true; // We first compare instantiations where the type parameter is replaced with // marker types that have a known subtype relationship. From this we can infer // invariance, covariance, contravariance or bivariance. const typeWithSuper = createMarkerType(symbol, tp, markerSuperType); const typeWithSub = createMarkerType(symbol, tp, markerSubType); - variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) | - (isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0); + variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) + | (isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0); // If the instantiations appear to be related bivariantly it may be because the // type parameter is independent (i.e. it isn't witnessed anywhere in the generic // type). To determine this we compare instantiations where the type parameter is // replaced with marker types that are known to be unrelated. - if (variance === VarianceFlags.Bivariant && isTypeAssignableTo(createMarkerType(symbol, tp, markerOtherType), typeWithSuper)) { + if ( + variance === VarianceFlags.Bivariant + && isTypeAssignableTo(createMarkerType(symbol, tp, markerOtherType), typeWithSuper) + ) { variance = VarianceFlags.Independent; } outofbandVarianceMarkerHandler = oldHandler; @@ -21454,9 +28615,12 @@ namespace ts { if (isErrorType(type)) { return type; } - const result = symbol.flags & SymbolFlags.TypeAlias ? - getTypeAliasInstantiation(symbol, instantiateTypes(getSymbolLinks(symbol).typeParameters!, mapper)) : - createTypeReference(type as GenericType, instantiateTypes((type as GenericType).typeParameters, mapper)); + const result = symbol.flags & SymbolFlags.TypeAlias + ? getTypeAliasInstantiation(symbol, instantiateTypes(getSymbolLinks(symbol).typeParameters!, mapper)) + : createTypeReference( + type as GenericType, + instantiateTypes((type as GenericType).typeParameters, mapper), + ); markerTypes.add(getTypeId(result)); return result; } @@ -21466,15 +28630,20 @@ namespace ts { } function getVarianceModifiers(tp: TypeParameter): ModifierFlags { - return (some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.In)) ? ModifierFlags.In : 0) | - (some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Out)) ? ModifierFlags.Out : 0); + return (some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.In)) ? ModifierFlags.In + : 0) + | (some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Out)) ? ModifierFlags.Out + : 0); } // Return true if the given type reference has a 'void' type argument for a covariant type parameter. // See comment at call in recursiveTypeRelatedTo for when this case matters. function hasCovariantVoidArgument(typeArguments: readonly Type[], variances: VarianceFlags[]): boolean { for (let i = 0; i < variances.length; i++) { - if ((variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Covariant && typeArguments[i].flags & TypeFlags.Void) { + if ( + (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Covariant + && typeArguments[i].flags & TypeFlags.Void + ) { return true; } } @@ -21490,10 +28659,19 @@ namespace ts { } function isTypeReferenceWithGenericArguments(type: Type): boolean { - return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t)); + return isNonDeferredTypeReference(type) + && some( + getTypeArguments(type), + t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t), + ); } - function getGenericTypeReferenceRelationKey(source: TypeReference, target: TypeReference, postFix: string, ignoreConstraints: boolean) { + function getGenericTypeReferenceRelationKey( + source: TypeReference, + target: TypeReference, + postFix: string, + ignoreConstraints: boolean, + ) { const typeParameters: Type[] = []; let constraintMarker = ""; const sourceId = getTypeReferenceId(source, 0); @@ -21532,16 +28710,27 @@ namespace ts { * To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters. * For other cases, the types ids are used. */ - function getRelationKey(source: Type, target: Type, intersectionState: IntersectionState, relation: ESMap, ignoreConstraints: boolean) { + function getRelationKey( + source: Type, + target: Type, + intersectionState: IntersectionState, + relation: ESMap, + ignoreConstraints: boolean, + ) { if (relation === identityRelation && source.id > target.id) { const temp = source; source = target; target = temp; } const postFix = intersectionState ? ":" + intersectionState : ""; - return isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target) ? - getGenericTypeReferenceRelationKey(source as TypeReference, target as TypeReference, postFix, ignoreConstraints) : - `${source.id},${target.id}${postFix}`; + return isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target) + ? getGenericTypeReferenceRelationKey( + source as TypeReference, + target as TypeReference, + postFix, + ignoreConstraints, + ) + : `${source.id},${target.id}${postFix}`; } // Invoke the callback for each underlying property symbol of the given symbol and return the first @@ -21562,7 +28751,8 @@ namespace ts { // Return the declaring class type of a property or undefined if property not declared in class function getDeclaringClass(prop: Symbol) { - return prop.parent && prop.parent.flags & SymbolFlags.Class ? getDeclaredTypeOfSymbol(getParentOfSymbol(prop)!) as InterfaceType : undefined; + return prop.parent && prop.parent.flags & SymbolFlags.Class + ? getDeclaredTypeOfSymbol(getParentOfSymbol(prop)!) as InterfaceType : undefined; } // Return the inherited type of the given property or undefined if property doesn't exist in a base class. @@ -21583,17 +28773,22 @@ namespace ts { // Return true if source property is a valid override of protected parts of target property. function isValidOverrideOf(sourceProp: Symbol, targetProp: Symbol) { - return !forEachProperty(targetProp, tp => - getDeclarationModifierFlagsFromSymbol(tp) & ModifierFlags.Protected ? - !isPropertyInClassDerivedFrom(sourceProp, getDeclaringClass(tp)) : false); + return !forEachProperty( + targetProp, + tp => + getDeclarationModifierFlagsFromSymbol(tp) & ModifierFlags.Protected + ? !isPropertyInClassDerivedFrom(sourceProp, getDeclaringClass(tp)) : false, + ); } // Return true if the given class derives from each of the declaring classes of the protected // constituents of the given property. function isClassDerivedFromDeclaringClasses(checkClass: T, prop: Symbol, writing: boolean) { - return forEachProperty(prop, p => - getDeclarationModifierFlagsFromSymbol(p, writing) & ModifierFlags.Protected ? - !hasBaseType(checkClass, getDeclaringClass(p)) : false) ? undefined : checkClass; + return forEachProperty( + prop, + p => getDeclarationModifierFlagsFromSymbol(p, writing) & ModifierFlags.Protected + ? !hasBaseType(checkClass, getDeclaringClass(p)) : false, + ) ? undefined : checkClass; } // Return true if the given type is deeply nested. We consider this to be the case when structural type comparisons @@ -21646,7 +28841,10 @@ namespace ts { // unique AST node. return (type as TypeReference).node!; } - if (type.symbol && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) { + if ( + type.symbol + && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class) + ) { // We track all object types that have an associated symbol (representing the origin of the type), but // exclude the static side of classes from this check since it shares its symbol with the instance side. return type.symbol; @@ -21678,15 +28876,21 @@ namespace ts { return compareProperties(sourceProp, targetProp, compareTypesIdentical) !== Ternary.False; } - function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary { + function compareProperties( + sourceProp: Symbol, + targetProp: Symbol, + compareTypes: (source: Type, target: Type) => Ternary, + ): Ternary { // Two members are considered identical when // - they are public properties with identical names, optionality, and types, // - they are private or protected properties originating in the same declaration and having identical types if (sourceProp === targetProp) { return Ternary.True; } - const sourcePropAccessibility = getDeclarationModifierFlagsFromSymbol(sourceProp) & ModifierFlags.NonPublicAccessibilityModifier; - const targetPropAccessibility = getDeclarationModifierFlagsFromSymbol(targetProp) & ModifierFlags.NonPublicAccessibilityModifier; + const sourcePropAccessibility = getDeclarationModifierFlagsFromSymbol(sourceProp) + & ModifierFlags.NonPublicAccessibilityModifier; + const targetPropAccessibility = getDeclarationModifierFlagsFromSymbol(targetProp) + & ModifierFlags.NonPublicAccessibilityModifier; if (sourcePropAccessibility !== targetPropAccessibility) { return Ternary.False; } @@ -21716,9 +28920,9 @@ namespace ts { // A source signature matches a target signature if the two signatures have the same number of required, // optional, and rest parameters. if ( - sourceParameterCount === targetParameterCount && - sourceMinArgumentCount === targetMinArgumentCount && - sourceHasRestParameter === targetHasRestParameter + sourceParameterCount === targetParameterCount + && sourceMinArgumentCount === targetMinArgumentCount + && sourceHasRestParameter === targetHasRestParameter ) { return true; } @@ -21733,7 +28937,14 @@ namespace ts { /** * See signatureRelatedTo, compareSignaturesIdentical */ - function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary { + function compareSignaturesIdentical( + source: Signature, + target: Signature, + partialMatch: boolean, + ignoreThisTypes: boolean, + ignoreReturnTypes: boolean, + compareTypes: (s: Type, t: Type) => Ternary, + ): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; @@ -21753,8 +28964,15 @@ namespace ts { const s = source.typeParameters![i]; const t = target.typeParameters[i]; if ( - !(s === t || compareTypes(instantiateType(getConstraintFromTypeParameter(s), mapper) || unknownType, getConstraintFromTypeParameter(t) || unknownType) && - compareTypes(instantiateType(getDefaultFromTypeParameter(s), mapper) || unknownType, getDefaultFromTypeParameter(t) || unknownType)) + !(s === t + || compareTypes( + instantiateType(getConstraintFromTypeParameter(s), mapper) || unknownType, + getConstraintFromTypeParameter(t) || unknownType, + ) + && compareTypes( + instantiateType(getDefaultFromTypeParameter(s), mapper) || unknownType, + getDefaultFromTypeParameter(t) || unknownType, + )) ) { return Ternary.False; } @@ -21788,18 +29006,22 @@ namespace ts { if (!ignoreReturnTypes) { const sourceTypePredicate = getTypePredicateOfSignature(source); const targetTypePredicate = getTypePredicateOfSignature(target); - result &= sourceTypePredicate || targetTypePredicate ? - compareTypePredicatesIdentical(sourceTypePredicate, targetTypePredicate, compareTypes) : - compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + result &= sourceTypePredicate || targetTypePredicate + ? compareTypePredicatesIdentical(sourceTypePredicate, targetTypePredicate, compareTypes) + : compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); } return result; } - function compareTypePredicatesIdentical(source: TypePredicate | undefined, target: TypePredicate | undefined, compareTypes: (s: Type, t: Type) => Ternary): Ternary { - return !(source && target && typePredicateKindsMatch(source, target)) ? Ternary.False : - source.type === target.type ? Ternary.True : - source.type && target.type ? compareTypes(source.type, target.type) : - Ternary.False; + function compareTypePredicatesIdentical( + source: TypePredicate | undefined, + target: TypePredicate | undefined, + compareTypes: (s: Type, t: Type) => Ternary, + ): Ternary { + return !(source && target && typePredicateKindsMatch(source, target)) ? Ternary.False + : source.type === target.type ? Ternary.True + : source.type && target.type ? compareTypes(source.type, target.type) + : Ternary.False; } function literalTypesWithSameBaseType(types: Type[]): boolean { @@ -21817,7 +29039,12 @@ namespace ts { } function getCombinedTypeFlags(types: Type[]): TypeFlags { - return reduceLeft(types, (flags, t) => flags | (t.flags & TypeFlags.Union ? getCombinedTypeFlags((t as UnionType).types) : t.flags), 0); + return reduceLeft( + types, + (flags, t) => + flags | (t.flags & TypeFlags.Union ? getCombinedTypeFlags((t as UnionType).types) : t.flags), + 0, + ); } function getCommonSupertype(types: Type[]): Type { @@ -21825,15 +29052,17 @@ namespace ts { return types[0]; } // Remove nullable types from each of the candidates. - const primaryTypes = strictNullChecks ? sameMap(types, t => filterType(t, u => !(u.flags & TypeFlags.Nullable))) : types; + const primaryTypes = strictNullChecks + ? sameMap(types, t => filterType(t, u => !(u.flags & TypeFlags.Nullable))) : types; // When the candidate types are all literal types with the same base type, return a union // of those literal types. Otherwise, return the leftmost type for which no type to the // right is a supertype. - const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) ? - getUnionType(primaryTypes) : - reduceLeft(primaryTypes, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!; + const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) + ? getUnionType(primaryTypes) + : reduceLeft(primaryTypes, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!; // Add any nullable types that occurred in the candidates back to the result. - return primaryTypes === types ? superTypeOrUnion : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable); + return primaryTypes === types ? superTypeOrUnion + : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable); } // Return the leftmost type for which no type to the right is a subtype. @@ -21842,11 +29071,14 @@ namespace ts { } function isArrayType(type: Type): type is TypeReference { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && ((type as TypeReference).target === globalArrayType || (type as TypeReference).target === globalReadonlyArrayType); + return !!(getObjectFlags(type) & ObjectFlags.Reference) + && ((type as TypeReference).target === globalArrayType + || (type as TypeReference).target === globalReadonlyArrayType); } function isReadonlyArrayType(type: Type): boolean { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && (type as TypeReference).target === globalReadonlyArrayType; + return !!(getObjectFlags(type) & ObjectFlags.Reference) + && (type as TypeReference).target === globalReadonlyArrayType; } function isArrayOrTupleType(type: Type): type is TypeReference { @@ -21864,15 +29096,20 @@ namespace ts { function isArrayLikeType(type: Type): boolean { // A type is array-like if it is a reference to the global Array or global ReadonlyArray type, // or if it is not the undefined or null type and if it is assignable to ReadonlyArray - return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType); + return isArrayType(type) + || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType); } function getSingleBaseForNonAugmentingSubtype(type: Type) { - if (!(getObjectFlags(type) & ObjectFlags.Reference) || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)) { + if ( + !(getObjectFlags(type) & ObjectFlags.Reference) + || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface) + ) { return undefined; } if (getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeCalculated) { - return getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeExists ? (type as TypeReference).cachedEquivalentBaseType : undefined; + return getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeExists + ? (type as TypeReference).cachedEquivalentBaseType : undefined; } (type as TypeReference).objectFlags |= ObjectFlags.IdenticalBaseTypeCalculated; const target = (type as TypeReference).target as InterfaceType; @@ -21880,7 +29117,10 @@ namespace ts { const baseTypeNode = getBaseTypeNodeOfClass(target); // A base type expression may circularly reference the class itself (e.g. as an argument to function call), so we only // check for base types specified as simple qualified names. - if (baseTypeNode && baseTypeNode.expression.kind !== SyntaxKind.Identifier && baseTypeNode.expression.kind !== SyntaxKind.PropertyAccessExpression) { + if ( + baseTypeNode && baseTypeNode.expression.kind !== SyntaxKind.Identifier + && baseTypeNode.expression.kind !== SyntaxKind.PropertyAccessExpression + ) { return undefined; } } @@ -21891,9 +29131,19 @@ namespace ts { if (getMembersOfSymbol(type.symbol).size) { return undefined; // If the interface has any members, they may subtype members in the base, so we should do a full structural comparison } - let instantiatedBase = !length(target.typeParameters) ? bases[0] : instantiateType(bases[0], createTypeMapper(target.typeParameters!, getTypeArguments(type as TypeReference).slice(0, target.typeParameters!.length))); + let instantiatedBase = !length(target.typeParameters) ? bases[0] + : instantiateType( + bases[0], + createTypeMapper( + target.typeParameters!, + getTypeArguments(type as TypeReference).slice(0, target.typeParameters!.length), + ), + ); if (length(getTypeArguments(type as TypeReference)) > length(target.typeParameters)) { - instantiatedBase = getTypeWithThisArgument(instantiatedBase, last(getTypeArguments(type as TypeReference))); + instantiatedBase = getTypeWithThisArgument( + instantiatedBase, + last(getTypeArguments(type as TypeReference)), + ); } (type as TypeReference).objectFlags |= ObjectFlags.IdenticalBaseTypeExists; return (type as TypeReference).cachedEquivalentBaseType = instantiatedBase; @@ -21936,28 +29186,31 @@ namespace ts { } function isUnitLikeType(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? some((type as IntersectionType).types, isUnitType) : - !!(type.flags & TypeFlags.Unit); + return type.flags & TypeFlags.Intersection ? some((type as IntersectionType).types, isUnitType) + : !!(type.flags & TypeFlags.Unit); } function extractUnitType(type: Type) { - return type.flags & TypeFlags.Intersection ? find((type as IntersectionType).types, isUnitType) || type : type; + return type.flags & TypeFlags.Intersection ? find((type as IntersectionType).types, isUnitType) || type + : type; } function isLiteralType(type: Type): boolean { - return type.flags & TypeFlags.Boolean ? true : - type.flags & TypeFlags.Union ? type.flags & TypeFlags.EnumLiteral ? true : every((type as UnionType).types, isUnitType) : - isUnitType(type); + return type.flags & TypeFlags.Boolean ? true + : type.flags & TypeFlags.Union + ? type.flags & TypeFlags.EnumLiteral ? true : every((type as UnionType).types, isUnitType) + : isUnitType(type); } function getBaseTypeOfLiteralType(type: Type): Type { - return type.flags & TypeFlags.EnumLiteral ? getBaseTypeOfEnumLiteralType(type as LiteralType) : - type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType : - type.flags & TypeFlags.NumberLiteral ? numberType : - type.flags & TypeFlags.BigIntLiteral ? bigintType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.Union ? getBaseTypeOfLiteralTypeUnion(type as UnionType) : - type; + return type.flags & TypeFlags.EnumLiteral ? getBaseTypeOfEnumLiteralType(type as LiteralType) + : type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + ? stringType + : type.flags & TypeFlags.NumberLiteral ? numberType + : type.flags & TypeFlags.BigIntLiteral ? bigintType + : type.flags & TypeFlags.BooleanLiteral ? booleanType + : type.flags & TypeFlags.Union ? getBaseTypeOfLiteralTypeUnion(type as UnionType) + : type; } function getBaseTypeOfLiteralTypeUnion(type: UnionType) { @@ -21966,19 +29219,20 @@ namespace ts { } function getWidenedLiteralType(type: Type): Type { - return type.flags & TypeFlags.EnumLiteral && isFreshLiteralType(type) ? getBaseTypeOfEnumLiteralType(type as LiteralType) : - type.flags & TypeFlags.StringLiteral && isFreshLiteralType(type) ? stringType : - type.flags & TypeFlags.NumberLiteral && isFreshLiteralType(type) ? numberType : - type.flags & TypeFlags.BigIntLiteral && isFreshLiteralType(type) ? bigintType : - type.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(type) ? booleanType : - type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedLiteralType) : - type; + return type.flags & TypeFlags.EnumLiteral && isFreshLiteralType(type) + ? getBaseTypeOfEnumLiteralType(type as LiteralType) + : type.flags & TypeFlags.StringLiteral && isFreshLiteralType(type) ? stringType + : type.flags & TypeFlags.NumberLiteral && isFreshLiteralType(type) ? numberType + : type.flags & TypeFlags.BigIntLiteral && isFreshLiteralType(type) ? bigintType + : type.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(type) ? booleanType + : type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedLiteralType) + : type; } function getWidenedUniqueESSymbolType(type: Type): Type { - return type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : - type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedUniqueESSymbolType) : - type; + return type.flags & TypeFlags.UniqueESSymbol ? esSymbolType + : type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedUniqueESSymbolType) + : type; } function getWidenedLiteralLikeTypeForContextualType(type: Type, contextualType: Type | undefined) { @@ -21988,20 +29242,33 @@ namespace ts { return getRegularTypeOfLiteralType(type); } - function getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded(type: Type | undefined, contextualSignatureReturnType: Type | undefined, isAsync: boolean) { + function getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded( + type: Type | undefined, + contextualSignatureReturnType: Type | undefined, + isAsync: boolean, + ) { if (type && isUnitType(type)) { - const contextualType = !contextualSignatureReturnType ? undefined : - isAsync ? getPromisedTypeOfPromise(contextualSignatureReturnType) : - contextualSignatureReturnType; + const contextualType = !contextualSignatureReturnType ? undefined + : isAsync ? getPromisedTypeOfPromise(contextualSignatureReturnType) + : contextualSignatureReturnType; type = getWidenedLiteralLikeTypeForContextualType(type, contextualType); } return type; } - function getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(type: Type | undefined, contextualSignatureReturnType: Type | undefined, kind: IterationTypeKind, isAsyncGenerator: boolean) { + function getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + type: Type | undefined, + contextualSignatureReturnType: Type | undefined, + kind: IterationTypeKind, + isAsyncGenerator: boolean, + ) { if (type && isUnitType(type)) { - const contextualType = !contextualSignatureReturnType ? undefined : - getIterationTypeOfGeneratorFunctionReturnType(kind, contextualSignatureReturnType, isAsyncGenerator); + const contextualType = !contextualSignatureReturnType ? undefined + : getIterationTypeOfGeneratorFunctionReturnType( + kind, + contextualSignatureReturnType, + isAsyncGenerator, + ); type = getWidenedLiteralLikeTypeForContextualType(type, contextualType); } return type; @@ -22012,7 +29279,8 @@ namespace ts { * Prefer using isTupleLikeType() unless the use of `elementTypes`/`getTypeArguments` is required. */ function isTupleType(type: Type): type is TupleTypeReference { - return !!(getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target.objectFlags & ObjectFlags.Tuple); + return !!(getObjectFlags(type) & ObjectFlags.Reference + && (type as TypeReference).target.objectFlags & ObjectFlags.Tuple); } function isGenericTupleType(type: Type): type is TupleTypeReference { @@ -22032,14 +29300,21 @@ namespace ts { return restType && createArrayType(restType); } - function getElementTypeOfSliceOfTupleType(type: TupleTypeReference, index: number, endSkipCount = 0, writing = false) { + function getElementTypeOfSliceOfTupleType( + type: TupleTypeReference, + index: number, + endSkipCount = 0, + writing = false, + ) { const length = getTypeReferenceArity(type) - endSkipCount; if (index < length) { const typeArguments = getTypeArguments(type); const elementTypes: Type[] = []; for (let i = index; i < length; i++) { const t = typeArguments[i]; - elementTypes.push(type.target.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t); + elementTypes.push( + type.target.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t, + ); } return writing ? getIntersectionType(elementTypes) : getUnionType(elementTypes); } @@ -22047,8 +29322,11 @@ namespace ts { } function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference) { - return getTypeReferenceArity(t1) === getTypeReferenceArity(t2) && - every(t1.target.elementFlags, (f, i) => (f & ElementFlags.Variable) === (t2.target.elementFlags[i] & ElementFlags.Variable)); + return getTypeReferenceArity(t1) === getTypeReferenceArity(t2) + && every( + t1.target.elementFlags, + (f, i) => (f & ElementFlags.Variable) === (t2.target.elementFlags[i] & ElementFlags.Variable), + ); } function isZeroBigInt({ value }: BigIntLiteralType) { @@ -22064,16 +29342,16 @@ namespace ts { } function getDefinitelyFalsyPartOfType(type: Type): Type { - return type.flags & TypeFlags.String ? emptyStringType : - type.flags & TypeFlags.Number ? zeroType : - type.flags & TypeFlags.BigInt ? zeroBigIntType : - type === regularFalseType || - type === falseType || - type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null | TypeFlags.AnyOrUnknown) || - type.flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === "" || - type.flags & TypeFlags.NumberLiteral && (type as NumberLiteralType).value === 0 || - type.flags & TypeFlags.BigIntLiteral && isZeroBigInt(type as BigIntLiteralType) ? type : - neverType; + return type.flags & TypeFlags.String ? emptyStringType + : type.flags & TypeFlags.Number ? zeroType + : type.flags & TypeFlags.BigInt ? zeroBigIntType + : type === regularFalseType + || type === falseType + || type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null | TypeFlags.AnyOrUnknown) + || type.flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === "" + || type.flags & TypeFlags.NumberLiteral && (type as NumberLiteralType).value === 0 + || type.flags & TypeFlags.BigIntLiteral && isZeroBigInt(type as BigIntLiteralType) ? type + : neverType; } /** @@ -22083,25 +29361,29 @@ namespace ts { */ function getNullableType(type: Type, flags: TypeFlags): Type { const missing = (flags & ~type.flags) & (TypeFlags.Undefined | TypeFlags.Null); - return missing === 0 ? type : - missing === TypeFlags.Undefined ? getUnionType([type, undefinedType]) : - missing === TypeFlags.Null ? getUnionType([type, nullType]) : - getUnionType([type, undefinedType, nullType]); + return missing === 0 ? type + : missing === TypeFlags.Undefined ? getUnionType([type, undefinedType]) + : missing === TypeFlags.Null ? getUnionType([type, nullType]) + : getUnionType([type, undefinedType, nullType]); } function getOptionalType(type: Type, isProperty = false): Type { Debug.assert(strictNullChecks); const missingOrUndefined = isProperty ? missingType : undefinedType; - return type.flags & TypeFlags.Undefined || type.flags & TypeFlags.Union && (type as UnionType).types[0] === missingOrUndefined ? type : getUnionType([type, missingOrUndefined]); + return type.flags & TypeFlags.Undefined + || type.flags & TypeFlags.Union && (type as UnionType).types[0] === missingOrUndefined ? type + : getUnionType([type, missingOrUndefined]); } function getGlobalNonNullableTypeInstantiation(type: Type) { if (!deferredGlobalNonNullableTypeAlias) { - deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable" as __String, SymbolFlags.TypeAlias, /*diagnostic*/ undefined) || unknownSymbol; + deferredGlobalNonNullableTypeAlias = + getGlobalSymbol("NonNullable" as __String, SymbolFlags.TypeAlias, /*diagnostic*/ undefined) + || unknownSymbol; } - return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? - getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]) : - getIntersectionType([type, emptyObjectType]); + return deferredGlobalNonNullableTypeAlias !== unknownSymbol + ? getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]) + : getIntersectionType([type, emptyObjectType]); } function getNonNullableType(type: Type): Type { @@ -22117,13 +29399,14 @@ namespace ts { } function propagateOptionalTypeMarker(type: Type, node: OptionalChain, wasOptional: boolean) { - return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) : type; + return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) + : type; } function getOptionalExpressionType(exprType: Type, expression: Expression) { - return isExpressionOfOptionalChainRoot(expression) ? getNonNullableType(exprType) : - isOptionalChain(expression) ? removeOptionalTypeMarker(exprType) : - exprType; + return isExpressionOfOptionalChainRoot(expression) ? getNonNullableType(exprType) + : isOptionalChain(expression) ? removeOptionalTypeMarker(exprType) + : exprType; } function removeMissingType(type: Type, isOptional: boolean) { @@ -22131,11 +29414,14 @@ namespace ts { } function containsMissingType(type: Type) { - return exactOptionalPropertyTypes && (type === missingType || type.flags & TypeFlags.Union && containsType((type as UnionType).types, missingType)); + return exactOptionalPropertyTypes + && (type === missingType + || type.flags & TypeFlags.Union && containsType((type as UnionType).types, missingType)); } function removeMissingOrUndefinedType(type: Type): Type { - return exactOptionalPropertyTypes ? removeType(type, missingType) : getTypeWithFacts(type, TypeFacts.NEUndefined); + return exactOptionalPropertyTypes ? removeType(type, missingType) + : getTypeWithFacts(type, TypeFacts.NEUndefined); } /** @@ -22173,12 +29459,16 @@ namespace ts { ? every((type as IntersectionType).types, isObjectTypeWithInferableIndex) : !!( type.symbol - && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 + && (type.symbol.flags + & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum + | SymbolFlags.ValueModule)) !== 0 && !(type.symbol.flags & SymbolFlags.Class) && !typeHasCallOrConstructSignatures(type) ) || !!( objectFlags & ObjectFlags.ObjectRestType - ) || !!(objectFlags & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source)); + ) + || !!(objectFlags & ObjectFlags.ReverseMapped + && isObjectTypeWithInferableIndex((type as ReverseMappedType).source)); } function createSymbolWithType(source: Symbol, type: Type | undefined) { @@ -22202,7 +29492,10 @@ namespace ts { for (const property of getPropertiesOfObjectType(type)) { const original = getTypeOfSymbol(property); const updated = f(original); - members.set(property.escapedName, updated === original ? property : createSymbolWithType(property, updated)); + members.set( + property.escapedName, + updated === original ? property : createSymbolWithType(property, updated), + ); } return members; } @@ -22223,14 +29516,24 @@ namespace ts { const resolved = type as ResolvedType; const members = transformTypeOfMembers(type, getRegularTypeOfObjectLiteral); - const regularNew = createAnonymousType(resolved.symbol, members, resolved.callSignatures, resolved.constructSignatures, resolved.indexInfos); + const regularNew = createAnonymousType( + resolved.symbol, + members, + resolved.callSignatures, + resolved.constructSignatures, + resolved.indexInfos, + ); regularNew.flags = resolved.flags; regularNew.objectFlags |= resolved.objectFlags & ~ObjectFlags.FreshLiteral; (type as FreshObjectLiteralType).regularType = regularNew; return regularNew; } - function createWideningContext(parent: WideningContext | undefined, propertyName: __String | undefined, siblings: Type[] | undefined): WideningContext { + function createWideningContext( + parent: WideningContext | undefined, + propertyName: __String | undefined, + siblings: Type[] | undefined, + ): WideningContext { return { parent, propertyName, siblings, resolvedProperties: undefined }; } @@ -22302,7 +29605,16 @@ namespace ts { } } } - const result = createAnonymousType(type.symbol, members, emptyArray, emptyArray, sameMap(getIndexInfosOfType(type), info => createIndexInfo(info.keyType, getWidenedType(info.type), info.isReadonly))); + const result = createAnonymousType( + type.symbol, + members, + emptyArray, + emptyArray, + sameMap( + getIndexInfosOfType(type), + info => createIndexInfo(info.keyType, getWidenedType(info.type), info.isReadonly), + ), + ); result.objectFlags |= getObjectFlags(type) & (ObjectFlags.JSLiteral | ObjectFlags.NonInferrableType); // Retain js literal flag through widening return result; } @@ -22324,12 +29636,23 @@ namespace ts { result = getWidenedTypeOfObjectLiteral(type, context); } else if (type.flags & TypeFlags.Union) { - const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (type as UnionType).types); - const widenedTypes = sameMap((type as UnionType).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext)); + const unionContext = context + || createWideningContext( + /*parent*/ undefined, + /*propertyName*/ undefined, + (type as UnionType).types, + ); + const widenedTypes = sameMap( + (type as UnionType).types, + t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext), + ); // Widening an empty object literal transitions from a highly restrictive type to // a highly inclusive one. For that reason we perform subtype reduction here if the // union includes empty object types (e.g. reducing {} | string to just {}). - result = getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal); + result = getUnionType( + widenedTypes, + some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal, + ); } else if (type.flags & TypeFlags.Intersection) { result = getIntersectionType(sameMap((type as IntersectionType).types, getWidenedType)); @@ -22383,7 +29706,12 @@ namespace ts { const t = getTypeOfSymbol(p); if (getObjectFlags(t) & ObjectFlags.ContainsWideningType) { if (!reportWideningErrorsInType(t)) { - error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolToString(p), typeToString(getWidenedType(t))); + error( + p.valueDeclaration, + Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, + symbolToString(p), + typeToString(getWidenedType(t)), + ); } errorReported = true; } @@ -22395,7 +29723,9 @@ namespace ts { function reportImplicitAny(declaration: Declaration, type: Type, wideningKind?: WideningKind) { const typeAsString = typeToString(getWidenedType(type)); - if (isInJSFile(declaration) && !isCheckJsEnabledForFile(getSourceFileOfNode(declaration), compilerOptions)) { + if ( + isInJSFile(declaration) && !isCheckJsEnabledForFile(getSourceFileOfNode(declaration), compilerOptions) + ) { // Only report implicit any errors/suggestions in TS and ts-check JS files return; } @@ -22404,25 +29734,43 @@ namespace ts { case SyntaxKind.BinaryExpression: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - diagnostic = noImplicitAny ? Diagnostics.Member_0_implicitly_has_an_1_type : Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; + diagnostic = noImplicitAny ? Diagnostics.Member_0_implicitly_has_an_1_type + : Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; break; case SyntaxKind.Parameter: const param = declaration as ParameterDeclaration; if ( - isIdentifier(param.name) && - (isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) && - param.parent.parameters.indexOf(param) > -1 && - (resolveName(param, param.name.escapedText, SymbolFlags.Type, undefined, param.name.escapedText, /*isUse*/ true) || - param.name.originalKeywordKind && isTypeNodeKind(param.name.originalKeywordKind)) + isIdentifier(param.name) + && (isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) + || isFunctionTypeNode(param.parent)) + && param.parent.parameters.indexOf(param) > -1 + && (resolveName( + param, + param.name.escapedText, + SymbolFlags.Type, + undefined, + param.name.escapedText, + /*isUse*/ true, + ) + || param.name.originalKeywordKind && isTypeNodeKind(param.name.originalKeywordKind)) ) { const newName = "arg" + param.parent.parameters.indexOf(param); const typeName = declarationNameToString(param.name) + (param.dotDotDotToken ? "[]" : ""); - errorOrSuggestion(noImplicitAny, declaration, Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, newName, typeName); + errorOrSuggestion( + noImplicitAny, + declaration, + Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, + newName, + typeName, + ); return; } - diagnostic = (declaration as ParameterDeclaration).dotDotDotToken ? - noImplicitAny ? Diagnostics.Rest_parameter_0_implicitly_has_an_any_type : Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage : - noImplicitAny ? Diagnostics.Parameter_0_implicitly_has_an_1_type : Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; + diagnostic = (declaration as ParameterDeclaration).dotDotDotToken + ? noImplicitAny ? Diagnostics.Rest_parameter_0_implicitly_has_an_any_type + : Diagnostics + .Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage + : noImplicitAny ? Diagnostics.Parameter_0_implicitly_has_an_1_type + : Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; break; case SyntaxKind.BindingElement: diagnostic = Diagnostics.Binding_element_0_implicitly_has_an_1_type; @@ -22432,7 +29780,11 @@ namespace ts { } break; case SyntaxKind.JSDocFunctionType: - error(declaration, Diagnostics.Function_type_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); + error( + declaration, + Diagnostics.Function_type_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, + typeAsString, + ); return; case SyntaxKind.FunctionDeclaration: case SyntaxKind.MethodDeclaration: @@ -22443,16 +29795,28 @@ namespace ts { case SyntaxKind.ArrowFunction: if (noImplicitAny && !(declaration as NamedDeclaration).name) { if (wideningKind === WideningKind.GeneratorYield) { - error(declaration, Diagnostics.Generator_implicitly_has_yield_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_type_annotation, typeAsString); + error( + declaration, + Diagnostics + .Generator_implicitly_has_yield_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_type_annotation, + typeAsString, + ); } else { - error(declaration, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); + error( + declaration, + Diagnostics + .Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, + typeAsString, + ); } return; } - diagnostic = !noImplicitAny ? Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage : - wideningKind === WideningKind.GeneratorYield ? Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_yield_type : - Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; + diagnostic = !noImplicitAny + ? Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage + : wideningKind === WideningKind.GeneratorYield + ? Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_yield_type + : Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; break; case SyntaxKind.MappedType: if (noImplicitAny) { @@ -22460,14 +29824,25 @@ namespace ts { } return; default: - diagnostic = noImplicitAny ? Diagnostics.Variable_0_implicitly_has_an_1_type : Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; + diagnostic = noImplicitAny ? Diagnostics.Variable_0_implicitly_has_an_1_type + : Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; } - errorOrSuggestion(noImplicitAny, declaration, diagnostic, declarationNameToString(getNameOfDeclaration(declaration)), typeAsString); + errorOrSuggestion( + noImplicitAny, + declaration, + diagnostic, + declarationNameToString(getNameOfDeclaration(declaration)), + typeAsString, + ); } function reportErrorsFromWidening(declaration: Declaration, type: Type, wideningKind?: WideningKind) { addLazyDiagnostic(() => { - if (noImplicitAny && getObjectFlags(type) & ObjectFlags.ContainsWideningType && (!wideningKind || !getContextualSignatureForFunctionLikeDeclaration(declaration as FunctionLikeDeclaration))) { + if ( + noImplicitAny && getObjectFlags(type) & ObjectFlags.ContainsWideningType + && (!wideningKind + || !getContextualSignatureForFunctionLikeDeclaration(declaration as FunctionLikeDeclaration)) + ) { // Report implicit any error within type if possible, otherwise report error on declaration if (!reportWideningErrorsInType(type)) { reportImplicitAny(declaration, type, wideningKind); @@ -22501,7 +29876,11 @@ namespace ts { function applyToReturnTypes(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { const sourceTypePredicate = getTypePredicateOfSignature(source); const targetTypePredicate = getTypePredicateOfSignature(target); - if (sourceTypePredicate && targetTypePredicate && typePredicateKindsMatch(sourceTypePredicate, targetTypePredicate) && sourceTypePredicate.type && targetTypePredicate.type) { + if ( + sourceTypePredicate && targetTypePredicate + && typePredicateKindsMatch(sourceTypePredicate, targetTypePredicate) && sourceTypePredicate.type + && targetTypePredicate.type + ) { callback(sourceTypePredicate.type, targetTypePredicate.type); } else { @@ -22509,15 +29888,39 @@ namespace ts { } } - function createInferenceContext(typeParameters: readonly TypeParameter[], signature: Signature | undefined, flags: InferenceFlags, compareTypes?: TypeComparer): InferenceContext { - return createInferenceContextWorker(typeParameters.map(createInferenceInfo), signature, flags, compareTypes || compareTypesAssignable); + function createInferenceContext( + typeParameters: readonly TypeParameter[], + signature: Signature | undefined, + flags: InferenceFlags, + compareTypes?: TypeComparer, + ): InferenceContext { + return createInferenceContextWorker( + typeParameters.map(createInferenceInfo), + signature, + flags, + compareTypes || compareTypesAssignable, + ); } - function cloneInferenceContext(context: T, extraFlags: InferenceFlags = 0): InferenceContext | T & undefined { - return context && createInferenceContextWorker(map(context.inferences, cloneInferenceInfo), context.signature, context.flags | extraFlags, context.compareTypes); + function cloneInferenceContext( + context: T, + extraFlags: InferenceFlags = 0, + ): InferenceContext | T & undefined { + return context + && createInferenceContextWorker( + map(context.inferences, cloneInferenceInfo), + context.signature, + context.flags | extraFlags, + context.compareTypes, + ); } - function createInferenceContextWorker(inferences: InferenceInfo[], signature: Signature | undefined, flags: InferenceFlags, compareTypes: TypeComparer): InferenceContext { + function createInferenceContextWorker( + inferences: InferenceInfo[], + signature: Signature | undefined, + flags: InferenceFlags, + compareTypes: TypeComparer, + ): InferenceContext { const context: InferenceContext = { inferences, signature, @@ -22564,7 +29967,11 @@ namespace ts { } } - function addIntraExpressionInferenceSite(context: InferenceContext, node: Expression | MethodDeclaration, type: Type) { + function addIntraExpressionInferenceSite( + context: InferenceContext, + node: Expression | MethodDeclaration, + type: Type, + ) { (context.intraExpressionInferenceSites ??= []).push({ node, type }); } @@ -22584,9 +29991,9 @@ namespace ts { function inferFromIntraExpressionSites(context: InferenceContext) { if (context.intraExpressionInferenceSites) { for (const { node, type } of context.intraExpressionInferenceSites) { - const contextualType = node.kind === SyntaxKind.MethodDeclaration ? - getContextualTypeForObjectLiteralMethod(node as MethodDeclaration, ContextFlags.NoConstraints) : - getContextualType(node, ContextFlags.NoConstraints); + const contextualType = node.kind === SyntaxKind.MethodDeclaration + ? getContextualTypeForObjectLiteralMethod(node as MethodDeclaration, ContextFlags.NoConstraints) + : getContextualType(node, ContextFlags.NoConstraints); if (contextualType) { inferTypes(context.inferences, type, contextualType); } @@ -22623,9 +30030,14 @@ namespace ts { function cloneInferredPartOfContext(context: InferenceContext): InferenceContext | undefined { const inferences = filter(context.inferences, hasInferenceCandidates); - return inferences.length ? - createInferenceContextWorker(map(inferences, cloneInferenceInfo), context.signature, context.flags, context.compareTypes) : - undefined; + return inferences.length + ? createInferenceContextWorker( + map(inferences, cloneInferenceInfo), + context.signature, + context.flags, + context.compareTypes, + ) + : undefined; } function getMapperFromContext(context: T): TypeMapper | T & undefined { @@ -22640,15 +30052,26 @@ namespace ts { if (objectFlags & ObjectFlags.CouldContainTypeVariablesComputed) { return !!(objectFlags & ObjectFlags.CouldContainTypeVariables); } - const result = !!(type.flags & TypeFlags.Instantiable || - type.flags & TypeFlags.Object && !isNonGenericTopLevelType(type) && ( - objectFlags & ObjectFlags.Reference && ((type as TypeReference).node || forEach(getTypeArguments(type as TypeReference), couldContainTypeVariables)) || - objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || - objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType | ObjectFlags.InstantiationExpressionType) - ) || - type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType).types, couldContainTypeVariables)); + const result = !!(type.flags & TypeFlags.Instantiable + || type.flags & TypeFlags.Object && !isNonGenericTopLevelType(type) && ( + objectFlags & ObjectFlags.Reference + && ((type as TypeReference).node + || forEach(getTypeArguments(type as TypeReference), couldContainTypeVariables)) + || objectFlags & ObjectFlags.Anonymous && type.symbol + && type.symbol.flags + & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class + | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) + && type.symbol.declarations + || objectFlags + & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType + | ObjectFlags.InstantiationExpressionType) + ) + || type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) + && !isNonGenericTopLevelType(type) + && some((type as UnionOrIntersectionType).types, couldContainTypeVariables)); if (type.flags & TypeFlags.ObjectFlagsType) { - (type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0); + (type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed + | (result ? ObjectFlags.CouldContainTypeVariables : 0); } return result; } @@ -22656,15 +30079,23 @@ namespace ts { function isNonGenericTopLevelType(type: Type) { if (type.aliasSymbol && !type.aliasTypeArguments) { const declaration = getDeclarationOfKind(type.aliasSymbol, SyntaxKind.TypeAliasDeclaration); - return !!(declaration && findAncestor(declaration.parent, n => n.kind === SyntaxKind.SourceFile ? true : n.kind === SyntaxKind.ModuleDeclaration ? false : "quit")); + return !!(declaration + && findAncestor( + declaration.parent, + n => n.kind === SyntaxKind.SourceFile ? true + : n.kind === SyntaxKind.ModuleDeclaration ? false : "quit", + )); } return false; } function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean { - return !!(type === typeParameter || - type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, t => isTypeParameterAtTopLevel(t, typeParameter)) || - type.flags & TypeFlags.Conditional && (getTrueTypeFromConditionalType(type as ConditionalType) === typeParameter || getFalseTypeFromConditionalType(type as ConditionalType) === typeParameter)); + return !!(type === typeParameter + || type.flags & TypeFlags.UnionOrIntersection + && some((type as UnionOrIntersectionType).types, t => isTypeParameterAtTopLevel(t, typeParameter)) + || type.flags & TypeFlags.Conditional + && (getTrueTypeFromConditionalType(type as ConditionalType) === typeParameter + || getFalseTypeFromConditionalType(type as ConditionalType) === typeParameter)); } /** Create an object with properties named in the string literal type. Every property has type `any` */ @@ -22683,7 +30114,8 @@ namespace ts { } members.set(name, literalProp); }); - const indexInfos = type.flags & TypeFlags.String ? [createIndexInfo(stringType, emptyObjectType, /*isReadonly*/ false)] : emptyArray; + const indexInfos = type.flags & TypeFlags.String + ? [createIndexInfo(stringType, emptyObjectType, /*isReadonly*/ false)] : emptyArray; return createAnonymousType(undefined, members, emptyArray, emptyArray, indexInfos); } @@ -22693,7 +30125,11 @@ namespace ts { * property is computed by inferring from the source property type to X for the type * variable T[P] (i.e. we treat the type T[P] as the type variable we're inferring for). */ - function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined { + function inferTypeForHomomorphicMappedType( + source: Type, + target: MappedType, + constraint: IndexType, + ): Type | undefined { if (inInferTypeForHomomorphicMappedType) { return undefined; } @@ -22713,32 +30149,47 @@ namespace ts { // literal { a: 123, b: x => true } is marked non-inferable because it contains a context sensitive // arrow function, but is considered partially inferable because property 'a' has an inferable type. function isPartiallyInferableType(type: Type): boolean { - return !(getObjectFlags(type) & ObjectFlags.NonInferrableType) || - isObjectLiteralType(type) && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop))) || - isTupleType(type) && some(getTypeArguments(type), isPartiallyInferableType); + return !(getObjectFlags(type) & ObjectFlags.NonInferrableType) + || isObjectLiteralType(type) + && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop))) + || isTupleType(type) && some(getTypeArguments(type), isPartiallyInferableType); } function createReverseMappedType(source: Type, target: MappedType, constraint: IndexType) { // We consider a source type reverse mappable if it has a string index signature or if // it has one or more properties and is of a partially inferable type. - if (!(getIndexInfoOfType(source, stringType) || getPropertiesOfType(source).length !== 0 && isPartiallyInferableType(source))) { + if ( + !(getIndexInfoOfType(source, stringType) + || getPropertiesOfType(source).length !== 0 && isPartiallyInferableType(source)) + ) { return undefined; } // For arrays and tuples we infer new arrays and tuples where the reverse mapping has been // applied to the element type(s). if (isArrayType(source)) { - return createArrayType(inferReverseMappedType(getTypeArguments(source)[0], target, constraint), isReadonlyArrayType(source)); + return createArrayType( + inferReverseMappedType(getTypeArguments(source)[0], target, constraint), + isReadonlyArrayType(source), + ); } if (isTupleType(source)) { const elementTypes = map(getTypeArguments(source), t => inferReverseMappedType(t, target, constraint)); - const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ? - sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) : - source.target.elementFlags; - return createTupleType(elementTypes, elementFlags, source.target.readonly, source.target.labeledElementDeclarations); + const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional + ? sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) + : source.target.elementFlags; + return createTupleType( + elementTypes, + elementFlags, + source.target.readonly, + source.target.labeledElementDeclarations, + ); } // For all other object types we infer a new object type where the reverse mapping has been // applied to the type of each property. - const reversed = createObjectType(ObjectFlags.ReverseMapped | ObjectFlags.Anonymous, /*symbol*/ undefined) as ReverseMappedType; + const reversed = createObjectType( + ObjectFlags.ReverseMapped | ObjectFlags.Anonymous, + /*symbol*/ undefined, + ) as ReverseMappedType; reversed.source = source; reversed.mappedType = target; reversed.constraintType = constraint; @@ -22754,21 +30205,32 @@ namespace ts { } function inferReverseMappedType(sourceType: Type, target: MappedType, constraint: IndexType): Type { - const typeParameter = getIndexedAccessType(constraint.type, getTypeParameterFromMappedType(target)) as TypeParameter; + const typeParameter = getIndexedAccessType( + constraint.type, + getTypeParameterFromMappedType(target), + ) as TypeParameter; const templateType = getTemplateTypeFromMappedType(target); const inference = createInferenceInfo(typeParameter); inferTypes([inference], sourceType, templateType); return getTypeFromInference(inference) || unknownType; } - function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator { + function* getUnmatchedProperties( + source: Type, + target: Type, + requireOptionalProperties: boolean, + matchDiscriminantProperties: boolean, + ): IterableIterator { const properties = getPropertiesOfType(target); for (const targetProp of properties) { // TODO: remove this when we support static private identifier fields and find other solutions to get privateNamesAndStaticFields test to pass if (isStaticPrivateIdentifierProperty(targetProp)) { continue; } - if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial)) { + if ( + requireOptionalProperties + || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial) + ) { const sourceProp = getPropertyOfType(source, targetProp.escapedName); if (!sourceProp) { yield targetProp; @@ -22777,7 +30239,11 @@ namespace ts { const targetType = getTypeOfSymbol(targetProp); if (targetType.flags & TypeFlags.Unit) { const sourceType = getTypeOfSymbol(sourceProp); - if (!(sourceType.flags & TypeFlags.Any || getRegularTypeOfLiteralType(sourceType) === getRegularTypeOfLiteralType(targetType))) { + if ( + !(sourceType.flags & TypeFlags.Any + || getRegularTypeOfLiteralType(sourceType) + === getRegularTypeOfLiteralType(targetType)) + ) { yield targetProp; } } @@ -22786,28 +30252,50 @@ namespace ts { } } - function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): Symbol | undefined { - const result = getUnmatchedProperties(source, target, requireOptionalProperties, matchDiscriminantProperties).next(); + function getUnmatchedProperty( + source: Type, + target: Type, + requireOptionalProperties: boolean, + matchDiscriminantProperties: boolean, + ): Symbol | undefined { + const result = getUnmatchedProperties( + source, + target, + requireOptionalProperties, + matchDiscriminantProperties, + ).next(); if (!result.done) return result.value; } function tupleTypesDefinitelyUnrelated(source: TupleTypeReference, target: TupleTypeReference) { - return !(target.target.combinedFlags & ElementFlags.Variadic) && target.target.minLength > source.target.minLength || - !target.target.hasRestElement && (source.target.hasRestElement || target.target.fixedLength < source.target.fixedLength); + return !(target.target.combinedFlags & ElementFlags.Variadic) + && target.target.minLength > source.target.minLength + || !target.target.hasRestElement + && (source.target.hasRestElement || target.target.fixedLength < source.target.fixedLength); } function typesDefinitelyUnrelated(source: Type, target: Type) { // Two tuple types with incompatible arities are definitely unrelated. // Two object types that each have a property that is unmatched in the other are definitely unrelated. - return isTupleType(source) && isTupleType(target) ? tupleTypesDefinitelyUnrelated(source, target) : - !!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ true) && - !!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false); + return isTupleType(source) && isTupleType(target) ? tupleTypesDefinitelyUnrelated(source, target) + : !!getUnmatchedProperty( + source, + target, + /*requireOptionalProperties*/ false, + /*matchDiscriminantProperties*/ true, + ) + && !!getUnmatchedProperty( + target, + source, + /*requireOptionalProperties*/ false, + /*matchDiscriminantProperties*/ false, + ); } function getTypeFromInference(inference: InferenceInfo) { - return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : - inference.contraCandidates ? getIntersectionType(inference.contraCandidates) : - undefined; + return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) + : inference.contraCandidates ? getIntersectionType(inference.contraCandidates) + : undefined; } function hasSkipDirectInferenceFlag(node: Node) { @@ -22826,8 +30314,8 @@ namespace ts { const targetEnd = target.texts[target.texts.length - 1]; const startLen = Math.min(sourceStart.length, targetStart.length); const endLen = Math.min(sourceEnd.length, targetEnd.length); - return sourceStart.slice(0, startLen) !== targetStart.slice(0, startLen) || - sourceEnd.slice(sourceEnd.length - endLen) !== targetEnd.slice(targetEnd.length - endLen); + return sourceStart.slice(0, startLen) !== targetStart.slice(0, startLen) + || sourceEnd.slice(sourceEnd.length - endLen) !== targetEnd.slice(targetEnd.length - endLen); } /** @@ -22872,8 +30360,14 @@ namespace ts { // * a bigint can be scanned, and that when it is scanned, it is // * the full length of the input string (so the scanner is one character beyond the augmented input length) // * it does not contain a numeric seperator (the `BigInt` constructor does not accept a numeric seperator in its input) - return success && result === SyntaxKind.BigIntLiteral && scanner.getTextPos() === (s.length + 1) && !(flags & TokenFlags.ContainsSeparator) - && (!roundTripOnly || s === pseudoBigIntToString({ negative, base10Value: parsePseudoBigInt(scanner.getTokenValue()) })); + return success && result === SyntaxKind.BigIntLiteral && scanner.getTextPos() === (s.length + 1) + && !(flags & TokenFlags.ContainsSeparator) + && (!roundTripOnly + || s + === pseudoBigIntToString({ + negative, + base10Value: parsePseudoBigInt(scanner.getTokenValue()), + })); } function isMemberOfStringMapping(source: Type, target: Type): boolean { @@ -22896,7 +30390,11 @@ namespace ts { mappingStack.unshift(target.symbol); target = (target as StringMappingType).type; } - const mappedSource = reduceLeft(mappingStack, (memo, value) => getStringMappingType(value, memo), source); + const mappedSource = reduceLeft( + mappingStack, + (memo, value) => getStringMappingType(value, memo), + source, + ); return mappedSource === source && isMemberOfStringMapping(source, target); } return false; @@ -22908,33 +30406,44 @@ namespace ts { } if (source.flags & TypeFlags.StringLiteral) { const value = (source as StringLiteralType).value; - return !!(target.flags & TypeFlags.Number && isValidNumberString(value, /*roundTripOnly*/ false) || - target.flags & TypeFlags.BigInt && isValidBigIntString(value, /*roundTripOnly*/ false) || - target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName || - target.flags & TypeFlags.StringMapping && isMemberOfStringMapping(getStringLiteralType(value), target)); + return !!(target.flags & TypeFlags.Number && isValidNumberString(value, /*roundTripOnly*/ false) + || target.flags & TypeFlags.BigInt && isValidBigIntString(value, /*roundTripOnly*/ false) + || target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) + && value === (target as IntrinsicType).intrinsicName + || target.flags & TypeFlags.StringMapping + && isMemberOfStringMapping(getStringLiteralType(value), target)); } if (source.flags & TypeFlags.TemplateLiteral) { const texts = (source as TemplateLiteralType).texts; - return texts.length === 2 && texts[0] === "" && texts[1] === "" && isTypeAssignableTo((source as TemplateLiteralType).types[0], target); + return texts.length === 2 && texts[0] === "" && texts[1] === "" + && isTypeAssignableTo((source as TemplateLiteralType).types[0], target); } return isTypeAssignableTo(source, target); } function inferTypesFromTemplateLiteralType(source: Type, target: TemplateLiteralType): Type[] | undefined { - return source.flags & TypeFlags.StringLiteral ? inferFromLiteralPartsToTemplateLiteral([(source as StringLiteralType).value], emptyArray, target) : - source.flags & TypeFlags.TemplateLiteral ? - arraysEqual((source as TemplateLiteralType).texts, target.texts) ? map((source as TemplateLiteralType).types, getStringLikeTypeForType) : - inferFromLiteralPartsToTemplateLiteral((source as TemplateLiteralType).texts, (source as TemplateLiteralType).types, target) : - undefined; + return source.flags & TypeFlags.StringLiteral + ? inferFromLiteralPartsToTemplateLiteral([(source as StringLiteralType).value], emptyArray, target) + : source.flags & TypeFlags.TemplateLiteral + ? arraysEqual((source as TemplateLiteralType).texts, target.texts) + ? map((source as TemplateLiteralType).types, getStringLikeTypeForType) + : inferFromLiteralPartsToTemplateLiteral( + (source as TemplateLiteralType).texts, + (source as TemplateLiteralType).types, + target, + ) + : undefined; } function isTypeMatchedByTemplateLiteralType(source: Type, target: TemplateLiteralType): boolean { const inferences = inferTypesFromTemplateLiteralType(source, target); - return !!inferences && every(inferences, (r, i) => isValidTypeForTemplateLiteralPlaceholder(r, target.types[i])); + return !!inferences + && every(inferences, (r, i) => isValidTypeForTemplateLiteralPlaceholder(r, target.types[i])); } function getStringLikeTypeForType(type: Type) { - return type.flags & (TypeFlags.Any | TypeFlags.StringLike) ? type : getTemplateLiteralType(["", ""], [type]); + return type.flags & (TypeFlags.Any | TypeFlags.StringLike) ? type + : getTemplateLiteralType(["", ""], [type]); } // This function infers from the text parts and type parts of a source literal to a target template literal. The number @@ -22956,7 +30465,11 @@ namespace ts { // the source. The first match for the '.' in target occurs at character 1 in the source text part at index 1, and thus // the first inference is the template literal type `<${string}>`. The remainder of the source makes up the second // inference, the template literal type `<${number}-${number}>`. - function inferFromLiteralPartsToTemplateLiteral(sourceTexts: readonly string[], sourceTypes: readonly Type[], target: TemplateLiteralType): Type[] | undefined { + function inferFromLiteralPartsToTemplateLiteral( + sourceTexts: readonly string[], + sourceTypes: readonly Type[], + target: TemplateLiteralType, + ): Type[] | undefined { const lastSourceIndex = sourceTexts.length - 1; const sourceStartText = sourceTexts[0]; const sourceEndText = sourceTexts[lastSourceIndex]; @@ -22965,8 +30478,8 @@ namespace ts { const targetStartText = targetTexts[0]; const targetEndText = targetTexts[lastTargetIndex]; if ( - lastSourceIndex === 0 && sourceStartText.length < targetStartText.length + targetEndText.length || - !sourceStartText.startsWith(targetStartText) || !sourceEndText.endsWith(targetEndText) + lastSourceIndex === 0 && sourceStartText.length < targetStartText.length + targetEndText.length + || !sourceStartText.startsWith(targetStartText) || !sourceEndText.endsWith(targetEndText) ) return undefined; const remainingEndText = sourceEndText.slice(0, sourceEndText.length - targetEndText.length); const matches: Type[] = []; @@ -23003,9 +30516,9 @@ namespace ts { return index < lastSourceIndex ? sourceTexts[index] : remainingEndText; } function addMatch(s: number, p: number) { - const matchType = s === seg ? - getStringLiteralType(getSourceText(s).slice(pos, p)) : - getTemplateLiteralType( + const matchType = s === seg + ? getStringLiteralType(getSourceText(s).slice(pos, p)) + : getTemplateLiteralType( [sourceTexts[seg].slice(pos), ...sourceTexts.slice(seg + 1, s), getSourceText(s).slice(0, p)], sourceTypes.slice(seg, s), ); @@ -23015,7 +30528,13 @@ namespace ts { } } - function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0, contravariant = false) { + function inferTypes( + inferences: InferenceInfo[], + originalSource: Type, + originalTarget: Type, + priority: InferencePriority = 0, + contravariant = false, + ) { let bivariant = false; let propagationType: Type; let inferencePriority = InferencePriority.MaxValue; @@ -23044,7 +30563,11 @@ namespace ts { if (source.aliasTypeArguments) { // Source and target are types originating in the same generic type alias declaration. // Simply infer from source type arguments to target type arguments. - inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol)); + inferFromTypeArguments( + source.aliasTypeArguments, + target.aliasTypeArguments!, + getAliasVariances(source.aliasSymbol), + ); } // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. return; @@ -23060,7 +30583,11 @@ namespace ts { if (target.flags & TypeFlags.Union) { // First, infer between identically matching source and target constituents and remove the // matching types. - const [tempSources, tempTargets] = inferFromMatchingTypes(source.flags & TypeFlags.Union ? (source as UnionType).types : [source], (target as UnionType).types, isTypeOrBaseIdenticalTo); + const [tempSources, tempTargets] = inferFromMatchingTypes( + source.flags & TypeFlags.Union ? (source as UnionType).types : [source], + (target as UnionType).types, + isTypeOrBaseIdenticalTo, + ); // Next, infer between closely matching source and target constituents and remove // the matching types. Types closely match when they are instantiations of the same // object type or instantiations of the same type alias. @@ -23080,7 +30607,13 @@ namespace ts { } source = getUnionType(sources); } - else if (target.flags & TypeFlags.Intersection && some((target as IntersectionType).types, t => !!getInferenceInfoForType(t) || (isGenericMappedType(t) && !!getInferenceInfoForType(getHomomorphicTypeVariable(t) || neverType)))) { + else if ( + target.flags & TypeFlags.Intersection + && some((target as IntersectionType).types, t => + !!getInferenceInfoForType(t) + || (isGenericMappedType(t) + && !!getInferenceInfoForType(getHomomorphicTypeVariable(t) || neverType))) + ) { // We reduce intersection types only when they contain naked type parameters. For example, when // inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and // infer { extra: any } for T. But when inferring to 'string[] & Iterable' we want to keep the @@ -23089,7 +30622,11 @@ namespace ts { // in such scenarios. if (!(source.flags & TypeFlags.Union)) { // Infer between identically matching source and target constituents and remove the matching types. - const [sources, targets] = inferFromMatchingTypes(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], (target as IntersectionType).types, isTypeIdenticalTo); + const [sources, targets] = inferFromMatchingTypes( + source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], + (target as IntersectionType).types, + isTypeIdenticalTo, + ); if (sources.length === 0 || targets.length === 0) { return; } @@ -23149,7 +30686,11 @@ namespace ts { clearCachedInferences(inferences); } } - if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && inference.topLevel && !isTypeParameterAtTopLevel(originalTarget, target as TypeParameter)) { + if ( + !(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter + && inference.topLevel + && !isTypeParameterAtTopLevel(originalTarget, target as TypeParameter) + ) { inference.topLevel = false; clearCachedInferences(inferences); } @@ -23167,7 +30708,11 @@ namespace ts { // Generally simplifications of instantiable indexes are avoided to keep relationship checking correct, however if our target is an access, we can consider // that key of that access to be "instantiated", since we're looking to find the infernce goal in any way we can. if (indexType.flags & TypeFlags.Instantiable) { - const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false); + const simplified = distributeIndexOverObjectType( + getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), + indexType, + /*writing*/ false, + ); if (simplified && simplified !== target) { inferFromTypes(source, simplified); } @@ -23175,20 +30720,30 @@ namespace ts { } } if ( - getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( - (source as TypeReference).target === (target as TypeReference).target || isArrayType(source) && isArrayType(target) - ) && - !((source as TypeReference).node && (target as TypeReference).node) + getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference + && ( + (source as TypeReference).target === (target as TypeReference).target + || isArrayType(source) && isArrayType(target) + ) + && !((source as TypeReference).node && (target as TypeReference).node) ) { // If source and target are references to the same generic type, infer from type arguments - inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); + inferFromTypeArguments( + getTypeArguments(source as TypeReference), + getTypeArguments(target as TypeReference), + getVariances((source as TypeReference).target), + ); } else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { inferFromContravariantTypes((source as IndexType).type, (target as IndexType).type); } else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) { const empty = createEmptyObjectTypeFromStringLiteral(source); - inferFromContravariantTypesWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof); + inferFromContravariantTypesWithPriority( + empty, + (target as IndexType).type, + InferencePriority.LiteralKeyof, + ); } else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) { inferFromTypes((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType); @@ -23201,7 +30756,11 @@ namespace ts { } else if (source.flags & TypeFlags.Substitution) { inferFromTypes((source as SubstitutionType).baseType, target); - inferWithPriority(getSubstitutionIntersection(source as SubstitutionType), target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority + inferWithPriority( + getSubstitutionIntersection(source as SubstitutionType), + target, + InferencePriority.SubstituteSource, + ); // Make substitute inference at a lower priority } else if (target.flags & TypeFlags.Conditional) { invokeOnce(source, target, inferToConditionalType); @@ -23221,12 +30780,18 @@ namespace ts { } else { source = getReducedType(source); - if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) { + if ( + !(priority & InferencePriority.NoConstraints + && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable)) + ) { const apparentSource = getApparentType(source); // getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type. // If that occurs and it doesn't simplify to an object or intersection, we'll need to restart `inferFromTypes` // with the simplified source. - if (apparentSource !== source && allowComplexConstraintInference && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) { + if ( + apparentSource !== source && allowComplexConstraintInference + && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection)) + ) { // TODO: The `allowComplexConstraintInference` flag is a hack! This forbids inference from complex constraints within constraints! // This isn't required algorithmically, but rather is used to lower the memory burden caused by performing inference // that is _too good_ in projects with complicated constraints (eg, fp-ts). In such cases, if we did not limit ourselves @@ -23252,14 +30817,23 @@ namespace ts { priority = savePriority; } - function inferFromContravariantTypesWithPriority(source: Type, target: Type, newPriority: InferencePriority) { + function inferFromContravariantTypesWithPriority( + source: Type, + target: Type, + newPriority: InferencePriority, + ) { const savePriority = priority; priority |= newPriority; inferFromContravariantTypes(source, target); priority = savePriority; } - function inferToMultipleTypesWithPriority(source: Type, targets: Type[], targetFlags: TypeFlags, newPriority: InferencePriority) { + function inferToMultipleTypesWithPriority( + source: Type, + targets: Type[], + targetFlags: TypeFlags, + newPriority: InferencePriority, + ) { const savePriority = priority; priority |= newPriority; inferToMultipleTypes(source, targets, targetFlags); @@ -23298,7 +30872,11 @@ namespace ts { inferencePriority = Math.min(inferencePriority, saveInferencePriority); } - function inferFromMatchingTypes(sources: Type[], targets: Type[], matches: (s: Type, t: Type) => boolean): [Type[], Type[]] { + function inferFromMatchingTypes( + sources: Type[], + targets: Type[], + matches: (s: Type, t: Type) => boolean, + ): [Type[], Type[]] { let matchedSources: Type[] | undefined; let matchedTargets: Type[] | undefined; for (const t of targets) { @@ -23316,10 +30894,17 @@ namespace ts { ]; } - function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) { + function inferFromTypeArguments( + sourceTypes: readonly Type[], + targetTypes: readonly Type[], + variances: readonly VarianceFlags[], + ) { const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length; for (let i = 0; i < count; i++) { - if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) { + if ( + i < variances.length + && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant + ) { inferFromContravariantTypes(sourceTypes[i], targetTypes[i]); } else { @@ -23357,7 +30942,8 @@ namespace ts { function getSingleTypeVariableFromIntersectionTypes(types: Type[]) { let typeVariable: Type | undefined; for (const type of types) { - const t = type.flags & TypeFlags.Intersection && find((type as IntersectionType).types, t => !!getInferenceInfoForType(t)); + const t = type.flags & TypeFlags.Intersection + && find((type as IntersectionType).types, t => !!getInferenceInfoForType(t)); if (!t || typeVariable && t !== typeVariable) { return undefined; } @@ -23388,7 +30974,8 @@ namespace ts { inferencePriority = InferencePriority.MaxValue; inferFromTypes(sources[i], t); if (inferencePriority === priority) matched[i] = true; - inferenceCircularity = inferenceCircularity || inferencePriority === InferencePriority.Circularity; + inferenceCircularity = inferenceCircularity + || inferencePriority === InferencePriority.Circularity; inferencePriority = Math.min(inferencePriority, saveInferencePriority); } } @@ -23456,7 +31043,11 @@ namespace ts { // such that direct inferences to T get priority over inferences to Partial, for example. const inference = getInferenceInfoForType((constraintType as IndexType).type); if (inference && !inference.isFixed && !isFromInferenceBlockedSource(source)) { - const inferredType = inferTypeForHomomorphicMappedType(source, target, constraintType as IndexType); + const inferredType = inferTypeForHomomorphicMappedType( + source, + target, + constraintType as IndexType, + ); if (inferredType) { // We assign a lower priority to inferences made from types containing non-inferrable // types because we may only have a partial result (i.e. we may have failed to make @@ -23464,9 +31055,9 @@ namespace ts { inferWithPriority( inferredType, inference.typeParameter, - getObjectFlags(source) & ObjectFlags.NonInferrableType ? - InferencePriority.PartialHomomorphicMappedType : - InferencePriority.HomomorphicMappedType, + getObjectFlags(source) & ObjectFlags.NonInferrableType + ? InferencePriority.PartialHomomorphicMappedType + : InferencePriority.HomomorphicMappedType, ); } } @@ -23487,8 +31078,14 @@ namespace ts { // If no inferences can be made to K's constraint, infer from a union of the property types // in the source to the template type X. const propTypes = map(getPropertiesOfType(source), getTypeOfSymbol); - const indexTypes = map(getIndexInfosOfType(source), info => info !== enumNumberIndexInfo ? info.type : neverType); - inferFromTypes(getUnionType(concatenate(propTypes, indexTypes)), getTemplateTypeFromMappedType(target)); + const indexTypes = map( + getIndexInfosOfType(source), + info => info !== enumNumberIndexInfo ? info.type : neverType, + ); + inferFromTypes( + getUnionType(concatenate(propTypes, indexTypes)), + getTemplateTypeFromMappedType(target), + ); return true; } return false; @@ -23498,12 +31095,26 @@ namespace ts { if (source.flags & TypeFlags.Conditional) { inferFromTypes((source as ConditionalType).checkType, target.checkType); inferFromTypes((source as ConditionalType).extendsType, target.extendsType); - inferFromTypes(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target)); - inferFromTypes(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target)); + inferFromTypes( + getTrueTypeFromConditionalType(source as ConditionalType), + getTrueTypeFromConditionalType(target), + ); + inferFromTypes( + getFalseTypeFromConditionalType(source as ConditionalType), + getFalseTypeFromConditionalType(target), + ); } else { - const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; - inferToMultipleTypesWithPriority(source, targetTypes, target.flags, contravariant ? InferencePriority.ContravariantConditional : 0); + const targetTypes = [ + getTrueTypeFromConditionalType(target), + getFalseTypeFromConditionalType(target), + ]; + inferToMultipleTypesWithPriority( + source, + targetTypes, + target.flags, + contravariant ? InferencePriority.ContravariantConditional : 0, + ); } } @@ -23525,42 +31136,84 @@ namespace ts { // allowed template literal placeholder types, infer from a literal type corresponding to the constraint. if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.TypeVariable) { const inferenceContext = getInferenceInfoForType(target); - const constraint = inferenceContext ? getBaseConstraintOfType(inferenceContext.typeParameter) : undefined; + const constraint = inferenceContext + ? getBaseConstraintOfType(inferenceContext.typeParameter) : undefined; if (constraint && !isTypeAny(constraint)) { - const constraintTypes = constraint.flags & TypeFlags.Union ? (constraint as UnionType).types : [constraint]; - let allTypeFlags: TypeFlags = reduceLeft(constraintTypes, (flags, t) => flags | t.flags, 0 as TypeFlags); + const constraintTypes = constraint.flags & TypeFlags.Union + ? (constraint as UnionType).types : [constraint]; + let allTypeFlags: TypeFlags = reduceLeft( + constraintTypes, + (flags, t) => flags | t.flags, + 0 as TypeFlags, + ); // If the constraint contains `string`, we don't need to look for a more preferred type if (!(allTypeFlags & TypeFlags.String)) { const str = (source as StringLiteralType).value; // If the type contains `number` or a number literal and the string isn't a valid number, exclude numbers - if (allTypeFlags & TypeFlags.NumberLike && !isValidNumberString(str, /*roundTripOnly*/ true)) { + if ( + allTypeFlags & TypeFlags.NumberLike + && !isValidNumberString(str, /*roundTripOnly*/ true) + ) { allTypeFlags &= ~TypeFlags.NumberLike; } // If the type contains `bigint` or a bigint literal and the string isn't a valid bigint, exclude bigints - if (allTypeFlags & TypeFlags.BigIntLike && !isValidBigIntString(str, /*roundTripOnly*/ true)) { + if ( + allTypeFlags & TypeFlags.BigIntLike + && !isValidBigIntString(str, /*roundTripOnly*/ true) + ) { allTypeFlags &= ~TypeFlags.BigIntLike; } // for each type in the constraint, find the highest priority matching type - const matchingType = reduceLeft(constraintTypes, (left, right) => - !(right.flags & allTypeFlags) ? left : - left.flags & TypeFlags.String ? left : right.flags & TypeFlags.String ? source : - left.flags & TypeFlags.TemplateLiteral ? left : right.flags & TypeFlags.TemplateLiteral && isTypeMatchedByTemplateLiteralType(source, right as TemplateLiteralType) ? source : - left.flags & TypeFlags.StringMapping ? left : right.flags & TypeFlags.StringMapping && str === applyStringMapping(right.symbol, str) ? source : - left.flags & TypeFlags.StringLiteral ? left : right.flags & TypeFlags.StringLiteral && (right as StringLiteralType).value === str ? right : - left.flags & TypeFlags.Number ? left : right.flags & TypeFlags.Number ? getNumberLiteralType(+str) : - left.flags & TypeFlags.Enum ? left : right.flags & TypeFlags.Enum ? getNumberLiteralType(+str) : - left.flags & TypeFlags.NumberLiteral ? left : right.flags & TypeFlags.NumberLiteral && (right as NumberLiteralType).value === +str ? right : - left.flags & TypeFlags.BigInt ? left : right.flags & TypeFlags.BigInt ? parseBigIntLiteralType(str) : - left.flags & TypeFlags.BigIntLiteral ? left : right.flags & TypeFlags.BigIntLiteral && pseudoBigIntToString((right as BigIntLiteralType).value) === str ? right : - left.flags & TypeFlags.Boolean ? left : right.flags & TypeFlags.Boolean ? str === "true" ? trueType : str === "false" ? falseType : booleanType : - left.flags & TypeFlags.BooleanLiteral ? left : right.flags & TypeFlags.BooleanLiteral && (right as IntrinsicType).intrinsicName === str ? right : - left.flags & TypeFlags.Undefined ? left : right.flags & TypeFlags.Undefined && (right as IntrinsicType).intrinsicName === str ? right : - left.flags & TypeFlags.Null ? left : right.flags & TypeFlags.Null && (right as IntrinsicType).intrinsicName === str ? right : - left, neverType as Type); + const matchingType = reduceLeft( + constraintTypes, + (left, right) => + !(right.flags & allTypeFlags) ? left + : left.flags & TypeFlags.String ? left + : right.flags & TypeFlags.String ? source + : left.flags & TypeFlags.TemplateLiteral ? left + : right.flags & TypeFlags.TemplateLiteral + && isTypeMatchedByTemplateLiteralType( + source, + right as TemplateLiteralType, + ) ? source + : left.flags & TypeFlags.StringMapping ? left + : right.flags & TypeFlags.StringMapping + && str === applyStringMapping(right.symbol, str) ? source + : left.flags & TypeFlags.StringLiteral ? left + : right.flags & TypeFlags.StringLiteral + && (right as StringLiteralType).value === str ? right + : left.flags & TypeFlags.Number ? left + : right.flags & TypeFlags.Number ? getNumberLiteralType(+str) + : left.flags & TypeFlags.Enum ? left + : right.flags & TypeFlags.Enum ? getNumberLiteralType(+str) + : left.flags & TypeFlags.NumberLiteral ? left + : right.flags & TypeFlags.NumberLiteral + && (right as NumberLiteralType).value === +str ? right + : left.flags & TypeFlags.BigInt ? left + : right.flags & TypeFlags.BigInt ? parseBigIntLiteralType(str) + : left.flags & TypeFlags.BigIntLiteral ? left + : right.flags & TypeFlags.BigIntLiteral + && pseudoBigIntToString((right as BigIntLiteralType).value) + === str ? right + : left.flags & TypeFlags.Boolean ? left + : right.flags & TypeFlags.Boolean + ? str === "true" ? trueType : str === "false" ? falseType : booleanType + : left.flags & TypeFlags.BooleanLiteral ? left + : right.flags & TypeFlags.BooleanLiteral + && (right as IntrinsicType).intrinsicName === str ? right + : left.flags & TypeFlags.Undefined ? left + : right.flags & TypeFlags.Undefined + && (right as IntrinsicType).intrinsicName === str ? right + : left.flags & TypeFlags.Null ? left + : right.flags & TypeFlags.Null + && (right as IntrinsicType).intrinsicName === str ? right + : left, + neverType as Type, + ); if (!(matchingType.flags & TypeFlags.Never)) { inferFromTypes(matchingType, target); @@ -23577,12 +31230,18 @@ namespace ts { function inferFromObjectTypes(source: Type, target: Type) { if ( - getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( - (source as TypeReference).target === (target as TypeReference).target || isArrayType(source) && isArrayType(target) + getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference + && ( + (source as TypeReference).target === (target as TypeReference).target + || isArrayType(source) && isArrayType(target) ) ) { // If source and target are references to the same generic type, infer from type arguments - inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); + inferFromTypeArguments( + getTypeArguments(source as TypeReference), + getTypeArguments(target as TypeReference), + getVariances((source as TypeReference).target), + ); return; } if (isGenericMappedType(source) && isGenericMappedType(target)) { @@ -23616,40 +31275,75 @@ namespace ts { } return; } - const startLength = isTupleType(source) ? Math.min(source.target.fixedLength, target.target.fixedLength) : 0; - const endLength = Math.min(isTupleType(source) ? getEndElementCount(source.target, ElementFlags.Fixed) : 0, target.target.hasRestElement ? getEndElementCount(target.target, ElementFlags.Fixed) : 0); + const startLength = isTupleType(source) + ? Math.min(source.target.fixedLength, target.target.fixedLength) : 0; + const endLength = Math.min( + isTupleType(source) ? getEndElementCount(source.target, ElementFlags.Fixed) : 0, + target.target.hasRestElement ? getEndElementCount(target.target, ElementFlags.Fixed) + : 0, + ); // Infer between starting fixed elements. for (let i = 0; i < startLength; i++) { inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); } - if (!isTupleType(source) || sourceArity - startLength - endLength === 1 && source.target.elementFlags[startLength] & ElementFlags.Rest) { + if ( + !isTupleType(source) + || sourceArity - startLength - endLength === 1 + && source.target.elementFlags[startLength] & ElementFlags.Rest + ) { // Single rest element remains in source, infer from that to every element in target const restType = getTypeArguments(source)[startLength]; for (let i = startLength; i < targetArity - endLength; i++) { - inferFromTypes(elementFlags[i] & ElementFlags.Variadic ? createArrayType(restType) : restType, elementTypes[i]); + inferFromTypes( + elementFlags[i] & ElementFlags.Variadic ? createArrayType(restType) : restType, + elementTypes[i], + ); } } else { const middleLength = targetArity - startLength - endLength; - if (middleLength === 2 && elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(source)) { + if ( + middleLength === 2 + && elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic + && isTupleType(source) + ) { // Middle of target is [...T, ...U] and source is tuple type const targetInfo = getInferenceInfoForType(elementTypes[startLength]); if (targetInfo && targetInfo.impliedArity !== undefined) { // Infer slices from source based on implied arity of T. - inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]); - inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); + inferFromTypes( + sliceTupleType( + source, + startLength, + endLength + sourceArity - targetInfo.impliedArity, + ), + elementTypes[startLength], + ); + inferFromTypes( + sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), + elementTypes[startLength + 1], + ); } } else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Variadic) { // Middle of target is exactly one variadic element. Infer the slice between the fixed parts in the source. // If target ends in optional element(s), make a lower priority a speculative inference. - const endsInOptional = target.target.elementFlags[targetArity - 1] & ElementFlags.Optional; - const sourceSlice = isTupleType(source) ? sliceTupleType(source, startLength, endLength) : createArrayType(getTypeArguments(source)[0]); - inferWithPriority(sourceSlice, elementTypes[startLength], endsInOptional ? InferencePriority.SpeculativeTuple : 0); + const endsInOptional = target.target.elementFlags[targetArity - 1] + & ElementFlags.Optional; + const sourceSlice = isTupleType(source) + ? sliceTupleType(source, startLength, endLength) + : createArrayType(getTypeArguments(source)[0]); + inferWithPriority( + sourceSlice, + elementTypes[startLength], + endsInOptional ? InferencePriority.SpeculativeTuple : 0, + ); } else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Rest) { // Middle of target is exactly one rest element. If middle of source is not empty, infer union of middle element types. - const restType = isTupleType(source) ? getElementTypeOfSliceOfTupleType(source, startLength, endLength) : getTypeArguments(source)[0]; + const restType = isTupleType(source) + ? getElementTypeOfSliceOfTupleType(source, startLength, endLength) + : getTypeArguments(source)[0]; if (restType) { inferFromTypes(restType, elementTypes[startLength]); } @@ -23657,7 +31351,10 @@ namespace ts { } // Infer between ending fixed elements for (let i = 0; i < endLength; i++) { - inferFromTypes(getTypeArguments(source)[sourceArity - i - 1], elementTypes[targetArity - i - 1]); + inferFromTypes( + getTypeArguments(source)[sourceArity - i - 1], + elementTypes[targetArity - i - 1], + ); } return; } @@ -23690,7 +31387,10 @@ namespace ts { const targetLen = targetSignatures.length; const len = sourceLen < targetLen ? sourceLen : targetLen; for (let i = 0; i < len; i++) { - inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i])); + inferFromSignature( + getBaseSignature(sourceSignatures[sourceLen - len + i]), + getErasedSignature(targetSignatures[targetLen - len + i]), + ); } } @@ -23698,7 +31398,8 @@ namespace ts { const saveBivariant = bivariant; const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; // Once we descend into a bivariant signature we remain bivariant for all nested inferences - bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor; + bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature + || kind === SyntaxKind.Constructor; applyToParameterTypes(source, target, inferFromContravariantTypesIfStrictFunctionTypes); bivariant = saveBivariant; applyToReturnTypes(source, target, inferFromTypes); @@ -23706,15 +31407,24 @@ namespace ts { function inferFromIndexTypes(source: Type, target: Type) { // Inferences across mapped type index signatures are pretty much the same a inferences to homomorphic variables - const priority = (getObjectFlags(source) & getObjectFlags(target) & ObjectFlags.Mapped) ? InferencePriority.HomomorphicMappedType : 0; + const priority = (getObjectFlags(source) & getObjectFlags(target) & ObjectFlags.Mapped) + ? InferencePriority.HomomorphicMappedType : 0; const indexInfos = getIndexInfosOfType(target); if (isObjectTypeWithInferableIndex(source)) { for (const targetInfo of indexInfos) { const propTypes: Type[] = []; for (const prop of getPropertiesOfType(source)) { - if (isApplicableIndexType(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), targetInfo.keyType)) { + if ( + isApplicableIndexType( + getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), + targetInfo.keyType, + ) + ) { const propType = getTypeOfSymbol(prop); - propTypes.push(prop.flags & SymbolFlags.Optional ? removeMissingOrUndefinedType(propType) : propType); + propTypes.push( + prop.flags & SymbolFlags.Optional ? removeMissingOrUndefinedType(propType) + : propType, + ); } } for (const info of getIndexInfosOfType(source)) { @@ -23737,18 +31447,25 @@ namespace ts { } function isTypeOrBaseIdenticalTo(s: Type, t: Type) { - return exactOptionalPropertyTypes && t === missingType ? s === t : - (isTypeIdenticalTo(s, t) || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral)); + return exactOptionalPropertyTypes && t === missingType ? s === t + : (isTypeIdenticalTo(s, t) + || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral + || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral)); } function isTypeCloselyMatchedBy(s: Type, t: Type) { - return !!(s.flags & TypeFlags.Object && t.flags & TypeFlags.Object && s.symbol && s.symbol === t.symbol || - s.aliasSymbol && s.aliasTypeArguments && s.aliasSymbol === t.aliasSymbol); + return !!(s.flags & TypeFlags.Object && t.flags & TypeFlags.Object && s.symbol && s.symbol === t.symbol + || s.aliasSymbol && s.aliasTypeArguments && s.aliasSymbol === t.aliasSymbol); } function hasPrimitiveConstraint(type: TypeParameter): boolean { const constraint = getConstraintOfTypeParameter(type); - return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); + return !!constraint + && maybeTypeOfKind( + constraint.flags & TypeFlags.Conditional + ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, + TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping, + ); } function isObjectLiteralType(type: Type) { @@ -23771,7 +31488,8 @@ namespace ts { } function getContravariantInference(inference: InferenceInfo) { - return inference.priority! & InferencePriority.PriorityImpliesCombination ? getIntersectionType(inference.contraCandidates!) : getCommonSubtype(inference.contraCandidates!); + return inference.priority! & InferencePriority.PriorityImpliesCombination + ? getIntersectionType(inference.contraCandidates!) : getCommonSubtype(inference.contraCandidates!); } function getCovariantInference(inference: InferenceInfo, signature: Signature) { @@ -23782,16 +31500,17 @@ namespace ts { // the type parameter has no constraint or its constraint includes no primitive or literal types, and // the type parameter was fixed during inference or does not occur at top-level in the return type. const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter); - const widenLiteralTypes = !primitiveConstraint && inference.topLevel && - (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); - const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) : - widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : - candidates; + const widenLiteralTypes = !primitiveConstraint && inference.topLevel + && (inference.isFixed + || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); + const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) + : widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) + : candidates; // If all inferences were made from a position that implies a combined result, infer a union type. // Otherwise, infer a common supertype. - const unwidenedType = inference.priority! & InferencePriority.PriorityImpliesCombination ? - getUnionType(baseCandidates, UnionReduction.Subtype) : - getCommonSupertype(baseCandidates); + const unwidenedType = inference.priority! & InferencePriority.PriorityImpliesCombination + ? getUnionType(baseCandidates, UnionReduction.Subtype) + : getCommonSupertype(baseCandidates); return getWidenedType(unwidenedType); } @@ -23801,13 +31520,14 @@ namespace ts { let inferredType: Type | undefined; const signature = context.signature; if (signature) { - const inferredCovariantType = inference.candidates ? getCovariantInference(inference, signature) : undefined; + const inferredCovariantType = inference.candidates ? getCovariantInference(inference, signature) + : undefined; if (inference.contraCandidates) { // If we have both co- and contra-variant inferences, we prefer the contra-variant inference // unless the co-variant inference is a subtype of some contra-variant inference and not 'never'. - inferredType = inferredCovariantType && !(inferredCovariantType.flags & TypeFlags.Never) && - some(inference.contraCandidates, t => isTypeSubtypeOf(inferredCovariantType, t)) ? - inferredCovariantType : getContravariantInference(inference); + inferredType = inferredCovariantType && !(inferredCovariantType.flags & TypeFlags.Never) + && some(inference.contraCandidates, t => isTypeSubtypeOf(inferredCovariantType, t)) + ? inferredCovariantType : getContravariantInference(inference); } else if (inferredCovariantType) { inferredType = inferredCovariantType; @@ -23826,7 +31546,10 @@ namespace ts { if (defaultType) { // Instantiate the default type. Any forward reference to a type // parameter should be instantiated to the empty object type. - inferredType = instantiateType(defaultType, mergeTypeMappers(createBackreferenceMapper(context, index), context.nonFixingMapper)); + inferredType = instantiateType( + defaultType, + mergeTypeMappers(createBackreferenceMapper(context, index), context.nonFixingMapper), + ); } } } @@ -23834,12 +31557,19 @@ namespace ts { inferredType = getTypeFromInference(inference); } - inference.inferredType = inferredType || getDefaultTypeArgumentType(!!(context.flags & InferenceFlags.AnyDefault)); + inference.inferredType = inferredType + || getDefaultTypeArgumentType(!!(context.flags & InferenceFlags.AnyDefault)); const constraint = getConstraintOfTypeParameter(inference.typeParameter); if (constraint) { const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper); - if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { + if ( + !inferredType + || !context.compareTypes( + inferredType, + getTypeWithThisArgument(instantiatedConstraint, inferredType), + ) + ) { inference.inferredType = inferredType = instantiatedConstraint; } } @@ -23866,25 +31596,32 @@ namespace ts { switch (node.escapedText) { case "document": case "console": - return Diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_include_dom; + return Diagnostics + .Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_include_dom; case "$": return compilerOptions.types - ? Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery_and_then_add_jquery_to_the_types_field_in_your_tsconfig - : Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery; + ? Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery_and_then_add_jquery_to_the_types_field_in_your_tsconfig + : Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery; case "describe": case "suite": case "it": case "test": return compilerOptions.types - ? Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha_and_then_add_jest_or_mocha_to_the_types_field_in_your_tsconfig - : Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha; + ? Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha_and_then_add_jest_or_mocha_to_the_types_field_in_your_tsconfig + : Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha; case "process": case "require": case "Buffer": case "module": return compilerOptions.types - ? Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode_and_then_add_node_to_the_types_field_in_your_tsconfig - : Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode; + ? Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode_and_then_add_node_to_the_types_field_in_your_tsconfig + : Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode; case "Map": case "Set": case "Promise": @@ -23903,7 +31640,8 @@ namespace ts { case "Reflect": case "BigInt64Array": case "BigUint64Array": - return Diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_1_or_later; + return Diagnostics + .Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_1_or_later; case "await": if (isCallExpression(node.parent)) { return Diagnostics.Cannot_find_name_0_Did_you_mean_to_write_this_in_an_async_function; @@ -23911,7 +31649,8 @@ namespace ts { // falls through default: if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { - return Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer; + return Diagnostics + .No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer; } else { return Diagnostics.Cannot_find_name_0; @@ -23922,8 +31661,8 @@ namespace ts { function getResolvedSymbol(node: Identifier): Symbol { const links = getNodeLinks(node); if (!links.resolvedSymbol) { - links.resolvedSymbol = !nodeIsMissing(node) && - resolveName( + links.resolvedSymbol = !nodeIsMissing(node) + && resolveName( node, node.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, @@ -23942,7 +31681,8 @@ namespace ts { // The expression is restricted to a single identifier or a sequence of identifiers separated by periods return !!findAncestor( node, - n => n.kind === SyntaxKind.TypeQuery ? true : n.kind === SyntaxKind.Identifier || n.kind === SyntaxKind.QualifiedName ? false : "quit", + n => n.kind === SyntaxKind.TypeQuery ? true + : n.kind === SyntaxKind.Identifier || n.kind === SyntaxKind.QualifiedName ? false : "quit", ); } @@ -23950,27 +31690,52 @@ namespace ts { // separated by dots). The key consists of the id of the symbol referenced by the // leftmost identifier followed by zero or more property names separated by dots. // The result is undefined if the reference isn't a dotted name. - function getFlowCacheKey(node: Node, declaredType: Type, initialType: Type, flowContainer: Node | undefined): string | undefined { + function getFlowCacheKey( + node: Node, + declaredType: Type, + initialType: Type, + flowContainer: Node | undefined, + ): string | undefined { switch (node.kind) { case SyntaxKind.Identifier: if (!isThisInTypeQuery(node)) { const symbol = getResolvedSymbol(node as Identifier); - return symbol !== unknownSymbol ? `${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}|${getSymbolId(symbol)}` : undefined; + return symbol !== unknownSymbol + ? `${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${ + getTypeId(initialType) + }|${getSymbolId(symbol)}` : undefined; } // falls through case SyntaxKind.ThisKeyword: - return `0|${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}`; + return `0|${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${ + getTypeId(initialType) + }`; case SyntaxKind.NonNullExpression: case SyntaxKind.ParenthesizedExpression: - return getFlowCacheKey((node as NonNullExpression | ParenthesizedExpression).expression, declaredType, initialType, flowContainer); + return getFlowCacheKey( + (node as NonNullExpression | ParenthesizedExpression).expression, + declaredType, + initialType, + flowContainer, + ); case SyntaxKind.QualifiedName: - const left = getFlowCacheKey((node as QualifiedName).left, declaredType, initialType, flowContainer); + const left = getFlowCacheKey( + (node as QualifiedName).left, + declaredType, + initialType, + flowContainer, + ); return left && left + "." + (node as QualifiedName).right.escapedText; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: const propName = getAccessedPropertyName(node as AccessExpression); if (propName !== undefined) { - const key = getFlowCacheKey((node as AccessExpression).expression, declaredType, initialType, flowContainer); + const key = getFlowCacheKey( + (node as AccessExpression).expression, + declaredType, + initialType, + flowContainer, + ); return key && key + "." + propName; } break; @@ -23990,10 +31755,14 @@ namespace ts { switch (target.kind) { case SyntaxKind.ParenthesizedExpression: case SyntaxKind.NonNullExpression: - return isMatchingReference(source, (target as NonNullExpression | ParenthesizedExpression).expression); + return isMatchingReference( + source, + (target as NonNullExpression | ParenthesizedExpression).expression, + ); case SyntaxKind.BinaryExpression: - return (isAssignmentExpression(target) && isMatchingReference(source, target.left)) || - (isBinaryExpression(target) && target.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source, target.right)); + return (isAssignmentExpression(target) && isMatchingReference(source, target.left)) + || (isBinaryExpression(target) && target.operatorToken.kind === SyntaxKind.CommaToken + && isMatchingReference(source, target.right)); } switch (source.kind) { case SyntaxKind.MetaProperty: @@ -24002,35 +31771,48 @@ namespace ts { && (source as MetaProperty).name.escapedText === (target as MetaProperty).name.escapedText; case SyntaxKind.Identifier: case SyntaxKind.PrivateIdentifier: - return isThisInTypeQuery(source) ? - target.kind === SyntaxKind.ThisKeyword : - target.kind === SyntaxKind.Identifier && getResolvedSymbol(source as Identifier) === getResolvedSymbol(target as Identifier) || - (target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) && - getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfNode(target); + return isThisInTypeQuery(source) + ? target.kind === SyntaxKind.ThisKeyword + : target.kind === SyntaxKind.Identifier + && getResolvedSymbol(source as Identifier) === getResolvedSymbol(target as Identifier) + || (target.kind === SyntaxKind.VariableDeclaration + || target.kind === SyntaxKind.BindingElement) + && getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) + === getSymbolOfNode(target); case SyntaxKind.ThisKeyword: return target.kind === SyntaxKind.ThisKeyword; case SyntaxKind.SuperKeyword: return target.kind === SyntaxKind.SuperKeyword; case SyntaxKind.NonNullExpression: case SyntaxKind.ParenthesizedExpression: - return isMatchingReference((source as NonNullExpression | ParenthesizedExpression).expression, target); + return isMatchingReference( + (source as NonNullExpression | ParenthesizedExpression).expression, + target, + ); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: const sourcePropertyName = getAccessedPropertyName(source as AccessExpression); const targetPropertyName = isAccessExpression(target) ? getAccessedPropertyName(target) : undefined; - return sourcePropertyName !== undefined && targetPropertyName !== undefined && targetPropertyName === sourcePropertyName && - isMatchingReference((source as AccessExpression).expression, (target as AccessExpression).expression); + return sourcePropertyName !== undefined && targetPropertyName !== undefined + && targetPropertyName === sourcePropertyName + && isMatchingReference( + (source as AccessExpression).expression, + (target as AccessExpression).expression, + ); case SyntaxKind.QualifiedName: - return isAccessExpression(target) && - (source as QualifiedName).right.escapedText === getAccessedPropertyName(target) && - isMatchingReference((source as QualifiedName).left, target.expression); + return isAccessExpression(target) + && (source as QualifiedName).right.escapedText === getAccessedPropertyName(target) + && isMatchingReference((source as QualifiedName).left, target.expression); case SyntaxKind.BinaryExpression: - return (isBinaryExpression(source) && source.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source.right, target)); + return (isBinaryExpression(source) && source.operatorToken.kind === SyntaxKind.CommaToken + && isMatchingReference(source.right, target)); } return false; } - function getAccessedPropertyName(access: AccessExpression | BindingElement | ParameterDeclaration): __String | undefined { + function getAccessedPropertyName( + access: AccessExpression | BindingElement | ParameterDeclaration, + ): __String | undefined { if (isPropertyAccessExpression(access)) { return access.name.escapedText; } @@ -24048,8 +31830,9 @@ namespace ts { } function tryGetNameFromType(type: Type) { - return type.flags & TypeFlags.UniqueESSymbol ? (type as UniqueESSymbolType).escapedName : - type.flags & TypeFlags.StringOrNumberLiteral ? escapeLeadingUnderscores("" + (type as StringLiteralType | NumberLiteralType).value) : undefined; + return type.flags & TypeFlags.UniqueESSymbol ? (type as UniqueESSymbolType).escapedName + : type.flags & TypeFlags.StringOrNumberLiteral + ? escapeLeadingUnderscores("" + (type as StringLiteralType | NumberLiteralType).value) : undefined; } function tryGetElementAccessExpressionName(node: ElementAccessExpression) { @@ -24071,7 +31854,10 @@ namespace ts { } } - if (hasOnlyExpressionInitializer(declaration) && isBlockScopedNameDeclaredBeforeUse(declaration, node.argumentExpression)) { + if ( + hasOnlyExpressionInitializer(declaration) + && isBlockScopedNameDeclaredBeforeUse(declaration, node.argumentExpression) + ) { const initializer = getEffectiveInitializer(declaration); if (initializer) { return tryGetNameFromType(getTypeOfExpression(initializer)); @@ -24109,8 +31895,9 @@ namespace ts { const prop = getUnionOrIntersectionProperty(type as UnionType, name); if (prop && getCheckFlags(prop) & CheckFlags.SyntheticProperty) { if ((prop as TransientSymbol).isDiscriminantProperty === undefined) { - (prop as TransientSymbol).isDiscriminantProperty = ((prop as TransientSymbol).checkFlags & CheckFlags.Discriminant) === CheckFlags.Discriminant && - !isGenericType(getTypeOfSymbol(prop)); + (prop as TransientSymbol).isDiscriminantProperty = + ((prop as TransientSymbol).checkFlags & CheckFlags.Discriminant) === CheckFlags.Discriminant + && !isGenericType(getTypeOfSymbol(prop)); } return !!(prop as TransientSymbol).isDiscriminantProperty; } @@ -24171,18 +31958,23 @@ namespace ts { const types = unionType.types; // We only construct maps for unions with many non-primitive constituents. if ( - types.length < 10 || getObjectFlags(unionType) & ObjectFlags.PrimitiveUnion || - countWhere(types, t => !!(t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive))) < 10 + types.length < 10 || getObjectFlags(unionType) & ObjectFlags.PrimitiveUnion + || countWhere(types, t => !!(t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive))) < 10 ) { return undefined; } if (unionType.keyPropertyName === undefined) { // The candidate key property name is the name of the first property with a unit type in one of the // constituent types. - const keyPropertyName = forEach(types, t => - t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) ? - forEach(getPropertiesOfType(t), p => isUnitType(getTypeOfSymbol(p)) ? p.escapedName : undefined) : - undefined); + const keyPropertyName = forEach( + types, + t => t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) + ? forEach( + getPropertiesOfType(t), + p => isUnitType(getTypeOfSymbol(p)) ? p.escapedName : undefined, + ) + : undefined, + ); const mapByKeyProperty = keyPropertyName && mapTypesByKeyProperty(types, keyPropertyName); unionType.keyPropertyName = mapByKeyProperty ? keyPropertyName : "" as __String; unionType.constituentMap = mapByKeyProperty; @@ -24205,9 +31997,10 @@ namespace ts { function getMatchingUnionConstituentForObjectLiteral(unionType: UnionType, node: ObjectLiteralExpression) { const keyPropertyName = getKeyPropertyName(unionType); - const propNode = keyPropertyName && find(node.properties, p => - p.symbol && p.kind === SyntaxKind.PropertyAssignment && - p.symbol.escapedName === keyPropertyName && isPossiblyDiscriminantValue(p.initializer)); + const propNode = keyPropertyName + && find(node.properties, p => + p.symbol && p.kind === SyntaxKind.PropertyAssignment + && p.symbol.escapedName === keyPropertyName && isPossiblyDiscriminantValue(p.initializer)); const propType = propNode && getContextFreeTypeOfExpression((propNode as PropertyAssignment).initializer); return propType && getConstituentTypeForKeyType(unionType, propType); } @@ -24225,8 +32018,11 @@ namespace ts { } } if ( - expression.expression.kind === SyntaxKind.PropertyAccessExpression && - isOrContainsMatchingReference(reference, (expression.expression as PropertyAccessExpression).expression) + expression.expression.kind === SyntaxKind.PropertyAccessExpression + && isOrContainsMatchingReference( + reference, + (expression.expression as PropertyAccessExpression).expression, + ) ) { return true; } @@ -24270,7 +32066,8 @@ namespace ts { function getAssignmentReducedTypeWorker(declaredType: UnionType, assignedType: Type) { const filteredType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t)); // Ensure that we narrow to fresh types if the assignment is a fresh boolean literal type. - const reducedType = assignedType.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(assignedType) ? mapType(filteredType, getFreshTypeOfLiteralType) : filteredType; + const reducedType = assignedType.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(assignedType) + ? mapType(filteredType, getFreshTypeOfLiteralType) : filteredType; // Our crude heuristic produces an invalid result in some cases: see GH#26130. // For now, when that happens, we give up and don't narrow at all. (This also // means we'll never narrow for erroneous assignments where the assigned type @@ -24282,8 +32079,8 @@ namespace ts { // We do a quick check for a "bind" property before performing the more expensive subtype // check. This gives us a quicker out in the common case where an object type is not a function. const resolved = resolveStructuredTypeMembers(type); - return !!(resolved.callSignatures.length || resolved.constructSignatures.length || - resolved.members.get("bind" as __String) && isTypeSubtypeOf(type, globalFunctionType)); + return !!(resolved.callSignatures.length || resolved.constructSignatures.length + || resolved.members.get("bind" as __String) && isTypeSubtypeOf(type, globalFunctionType)); } function getTypeFacts(type: Type): TypeFacts { @@ -24296,42 +32093,43 @@ namespace ts { } if (flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral)) { const isEmpty = flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === ""; - return strictNullChecks ? - isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : - isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; + return strictNullChecks + ? isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts + : isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; } if (flags & (TypeFlags.Number | TypeFlags.Enum)) { return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts; } if (flags & TypeFlags.NumberLiteral) { const isZero = (type as NumberLiteralType).value === 0; - return strictNullChecks ? - isZero ? TypeFacts.ZeroNumberStrictFacts : TypeFacts.NonZeroNumberStrictFacts : - isZero ? TypeFacts.ZeroNumberFacts : TypeFacts.NonZeroNumberFacts; + return strictNullChecks + ? isZero ? TypeFacts.ZeroNumberStrictFacts : TypeFacts.NonZeroNumberStrictFacts + : isZero ? TypeFacts.ZeroNumberFacts : TypeFacts.NonZeroNumberFacts; } if (flags & TypeFlags.BigInt) { return strictNullChecks ? TypeFacts.BigIntStrictFacts : TypeFacts.BigIntFacts; } if (flags & TypeFlags.BigIntLiteral) { const isZero = isZeroBigInt(type as BigIntLiteralType); - return strictNullChecks ? - isZero ? TypeFacts.ZeroBigIntStrictFacts : TypeFacts.NonZeroBigIntStrictFacts : - isZero ? TypeFacts.ZeroBigIntFacts : TypeFacts.NonZeroBigIntFacts; + return strictNullChecks + ? isZero ? TypeFacts.ZeroBigIntStrictFacts : TypeFacts.NonZeroBigIntStrictFacts + : isZero ? TypeFacts.ZeroBigIntFacts : TypeFacts.NonZeroBigIntFacts; } if (flags & TypeFlags.Boolean) { return strictNullChecks ? TypeFacts.BooleanStrictFacts : TypeFacts.BooleanFacts; } if (flags & TypeFlags.BooleanLike) { - return strictNullChecks ? - (type === falseType || type === regularFalseType) ? TypeFacts.FalseStrictFacts : TypeFacts.TrueStrictFacts : - (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; + return strictNullChecks + ? (type === falseType || type === regularFalseType) ? TypeFacts.FalseStrictFacts + : TypeFacts.TrueStrictFacts + : (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; } if (flags & TypeFlags.Object) { - return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) ? - strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts : - isFunctionObjectType(type as ObjectType) ? - strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : - strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; + return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) + ? strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts + : isFunctionObjectType(type as ObjectType) + ? strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts + : strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; } if (flags & TypeFlags.Void) { return TypeFacts.VoidFacts; @@ -24386,16 +32184,39 @@ namespace ts { // unknown with the union {} | null | undefined (and reduces that accordingly), and it intersects remaining // instantiable types with {}, {} | null, or {} | undefined in order to remove null and/or undefined. function getAdjustedTypeWithFacts(type: Type, facts: TypeFacts) { - const reduced = recombineUnknownType(getTypeWithFacts(strictNullChecks && type.flags & TypeFlags.Unknown ? unknownUnionType : type, facts)); + const reduced = recombineUnknownType( + getTypeWithFacts(strictNullChecks && type.flags & TypeFlags.Unknown ? unknownUnionType : type, facts), + ); if (strictNullChecks) { switch (facts) { case TypeFacts.NEUndefined: - return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefined ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQNull && !maybeTypeOfKind(reduced, TypeFlags.Null) ? getUnionType([emptyObjectType, nullType]) : emptyObjectType]) : t); + return mapType( + reduced, + t => getTypeFacts(t) & TypeFacts.EQUndefined + ? getIntersectionType([ + t, + getTypeFacts(t) & TypeFacts.EQNull && !maybeTypeOfKind(reduced, TypeFlags.Null) + ? getUnionType([emptyObjectType, nullType]) : emptyObjectType, + ]) : t, + ); case TypeFacts.NENull: - return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQNull ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQUndefined && !maybeTypeOfKind(reduced, TypeFlags.Undefined) ? getUnionType([emptyObjectType, undefinedType]) : emptyObjectType]) : t); + return mapType( + reduced, + t => getTypeFacts(t) & TypeFacts.EQNull + ? getIntersectionType([ + t, + getTypeFacts(t) & TypeFacts.EQUndefined + && !maybeTypeOfKind(reduced, TypeFlags.Undefined) + ? getUnionType([emptyObjectType, undefinedType]) : emptyObjectType, + ]) : t, + ); case TypeFacts.NEUndefinedOrNull: case TypeFacts.Truthy: - return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefinedOrNull ? getGlobalNonNullableTypeInstantiation(t) : t); + return mapType( + reduced, + t => getTypeFacts(t) & TypeFacts.EQUndefinedOrNull + ? getGlobalNonNullableTypeInstantiation(t) : t, + ); } } return reduced; @@ -24406,46 +32227,61 @@ namespace ts { } function getTypeWithDefault(type: Type, defaultExpression: Expression) { - return defaultExpression ? - getUnionType([getNonUndefinedType(type), getTypeOfExpression(defaultExpression)]) : - type; + return defaultExpression + ? getUnionType([getNonUndefinedType(type), getTypeOfExpression(defaultExpression)]) + : type; } function getTypeOfDestructuredProperty(type: Type, name: PropertyName) { const nameType = getLiteralTypeFromPropertyName(name); if (!isTypeUsableAsPropertyName(nameType)) return errorType; const text = getPropertyNameFromType(nameType); - return getTypeOfPropertyOfType(type, text) || includeUndefinedInIndexSignature(getApplicableIndexInfoForName(type, text)?.type) || errorType; + return getTypeOfPropertyOfType(type, text) + || includeUndefinedInIndexSignature(getApplicableIndexInfoForName(type, text)?.type) || errorType; } function getTypeOfDestructuredArrayElement(type: Type, index: number) { - return everyType(type, isTupleLikeType) && getTupleElementType(type, index) || - includeUndefinedInIndexSignature(checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined)) || - errorType; + return everyType(type, isTupleLikeType) && getTupleElementType(type, index) + || includeUndefinedInIndexSignature( + checkIteratedTypeOrElementType( + IterationUse.Destructuring, + type, + undefinedType, + /*errorNode*/ undefined, + ), + ) + || errorType; } function includeUndefinedInIndexSignature(type: Type | undefined): Type | undefined { if (!type) return type; - return compilerOptions.noUncheckedIndexedAccess ? - getUnionType([type, undefinedType]) : - type; + return compilerOptions.noUncheckedIndexedAccess + ? getUnionType([type, undefinedType]) + : type; } function getTypeOfDestructuredSpreadExpression(type: Type) { - return createArrayType(checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined) || errorType); + return createArrayType( + checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined) + || errorType, + ); } function getAssignedTypeOfBinaryExpression(node: BinaryExpression): Type { - const isDestructuringDefaultAssignment = node.parent.kind === SyntaxKind.ArrayLiteralExpression && isDestructuringAssignmentTarget(node.parent) || - node.parent.kind === SyntaxKind.PropertyAssignment && isDestructuringAssignmentTarget(node.parent.parent); - return isDestructuringDefaultAssignment ? - getTypeWithDefault(getAssignedType(node), node.right) : - getTypeOfExpression(node.right); + const isDestructuringDefaultAssignment = + node.parent.kind === SyntaxKind.ArrayLiteralExpression && isDestructuringAssignmentTarget(node.parent) + || node.parent.kind === SyntaxKind.PropertyAssignment + && isDestructuringAssignmentTarget(node.parent.parent); + return isDestructuringDefaultAssignment + ? getTypeWithDefault(getAssignedType(node), node.right) + : getTypeOfExpression(node.right); } function isDestructuringAssignmentTarget(parent: Node) { - return parent.parent.kind === SyntaxKind.BinaryExpression && (parent.parent as BinaryExpression).left === parent || - parent.parent.kind === SyntaxKind.ForOfStatement && (parent.parent as ForOfStatement).initializer === parent; + return parent.parent.kind === SyntaxKind.BinaryExpression + && (parent.parent as BinaryExpression).left === parent + || parent.parent.kind === SyntaxKind.ForOfStatement + && (parent.parent as ForOfStatement).initializer === parent; } function getAssignedTypeOfArrayLiteralElement(node: ArrayLiteralExpression, element: Expression): Type { @@ -24490,11 +32326,11 @@ namespace ts { function getInitialTypeOfBindingElement(node: BindingElement): Type { const pattern = node.parent; const parentType = getInitialType(pattern.parent as VariableDeclaration | BindingElement); - const type = pattern.kind === SyntaxKind.ObjectBindingPattern ? - getTypeOfDestructuredProperty(parentType, node.propertyName || node.name as Identifier) : - !node.dotDotDotToken ? - getTypeOfDestructuredArrayElement(parentType, pattern.elements.indexOf(node)) : - getTypeOfDestructuredSpreadExpression(parentType); + const type = pattern.kind === SyntaxKind.ObjectBindingPattern + ? getTypeOfDestructuredProperty(parentType, node.propertyName || node.name as Identifier) + : !node.dotDotDotToken + ? getTypeOfDestructuredArrayElement(parentType, pattern.elements.indexOf(node)) + : getTypeOfDestructuredSpreadExpression(parentType); return getTypeWithDefault(type, node.initializer!); } @@ -24520,16 +32356,16 @@ namespace ts { } function getInitialType(node: VariableDeclaration | BindingElement) { - return node.kind === SyntaxKind.VariableDeclaration ? - getInitialTypeOfVariableDeclaration(node) : - getInitialTypeOfBindingElement(node); + return node.kind === SyntaxKind.VariableDeclaration + ? getInitialTypeOfVariableDeclaration(node) + : getInitialTypeOfBindingElement(node); } function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) { - return node.kind === SyntaxKind.VariableDeclaration && (node as VariableDeclaration).initializer && - isEmptyArrayLiteral((node as VariableDeclaration).initializer!) || - node.kind !== SyntaxKind.BindingElement && node.parent.kind === SyntaxKind.BinaryExpression && - isEmptyArrayLiteral((node.parent as BinaryExpression).right); + return node.kind === SyntaxKind.VariableDeclaration && (node as VariableDeclaration).initializer + && isEmptyArrayLiteral((node as VariableDeclaration).initializer!) + || node.kind !== SyntaxKind.BindingElement && node.parent.kind === SyntaxKind.BinaryExpression + && isEmptyArrayLiteral((node.parent as BinaryExpression).right); } function getReferenceCandidate(node: Expression): Expression { @@ -24552,10 +32388,14 @@ namespace ts { function getReferenceRoot(node: Node): Node { const { parent } = node; - return parent.kind === SyntaxKind.ParenthesizedExpression || - parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && (parent as BinaryExpression).left === node || - parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken && (parent as BinaryExpression).right === node ? - getReferenceRoot(parent) : node; + return parent.kind === SyntaxKind.ParenthesizedExpression + || parent.kind === SyntaxKind.BinaryExpression + && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + && (parent as BinaryExpression).left === node + || parent.kind === SyntaxKind.BinaryExpression + && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken + && (parent as BinaryExpression).right === node + ? getReferenceRoot(parent) : node; } function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) { @@ -24579,23 +32419,31 @@ namespace ts { // Get the type names from all cases in a switch on `typeof`. The default clause and/or duplicate type names are // represented as undefined. Return undefined if one or more case clause expressions are not string literals. function getSwitchClauseTypeOfWitnesses(switchStatement: SwitchStatement): (string | undefined)[] | undefined { - if (some(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.CaseClause && !isStringLiteralLike(clause.expression))) { + if ( + some( + switchStatement.caseBlock.clauses, + clause => clause.kind === SyntaxKind.CaseClause && !isStringLiteralLike(clause.expression), + ) + ) { return undefined; } const witnesses: (string | undefined)[] = []; for (const clause of switchStatement.caseBlock.clauses) { - const text = clause.kind === SyntaxKind.CaseClause ? (clause.expression as StringLiteralLike).text : undefined; + const text = clause.kind === SyntaxKind.CaseClause ? (clause.expression as StringLiteralLike).text + : undefined; witnesses.push(text && !contains(witnesses, text) ? text : undefined); } return witnesses; } function eachTypeContainedIn(source: Type, types: Type[]) { - return source.flags & TypeFlags.Union ? !forEach((source as UnionType).types, t => !contains(types, t)) : contains(types, source); + return source.flags & TypeFlags.Union ? !forEach((source as UnionType).types, t => !contains(types, t)) + : contains(types, source); } function isTypeSubsetOf(source: Type, target: Type) { - return source === target || target.flags & TypeFlags.Union && isTypeSubsetOfUnion(source, target as UnionType); + return source === target + || target.flags & TypeFlags.Union && isTypeSubsetOfUnion(source, target as UnionType); } function isTypeSubsetOfUnion(source: Type, target: UnionType) { @@ -24607,7 +32455,9 @@ namespace ts { } return true; } - if (source.flags & TypeFlags.EnumLiteral && getBaseTypeOfEnumLiteralType(source as LiteralType) === target) { + if ( + source.flags & TypeFlags.EnumLiteral && getBaseTypeOfEnumLiteralType(source as LiteralType) === target + ) { return true; } return containsType(target.types, source); @@ -24626,7 +32476,8 @@ namespace ts { } function everyContainedType(type: Type, f: (t: Type) => boolean): boolean { - return type.flags & TypeFlags.UnionOrIntersection ? every((type as UnionOrIntersectionType).types, f) : f(type); + return type.flags & TypeFlags.UnionOrIntersection ? every((type as UnionOrIntersectionType).types, f) + : f(type); } function filterType(type: Type, f: (t: Type) => boolean): Type { @@ -24653,7 +32504,13 @@ namespace ts { newOrigin = createOriginUnionOrIntersectionType(TypeFlags.Union, originFiltered); } } - return getUnionTypeFromSortedList(filtered, (type as UnionType).objectFlags, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, newOrigin); + return getUnionTypeFromSortedList( + filtered, + (type as UnionType).objectFlags, + /*aliasSymbol*/ undefined, + /*aliasTypeArguments*/ undefined, + newOrigin, + ); } return type.flags & TypeFlags.Never || f(type) ? type : neverType; } @@ -24679,7 +32536,8 @@ namespace ts { return mapper(type); } const origin = (type as UnionType).origin; - const types = origin && origin.flags & TypeFlags.Union ? (origin as UnionType).types : (type as UnionType).types; + const types = origin && origin.flags & TypeFlags.Union ? (origin as UnionType).types + : (type as UnionType).types; let mappedTypes: Type[] | undefined; let changed = false; for (const t of types) { @@ -24694,13 +32552,25 @@ namespace ts { } } } - return changed ? mappedTypes && getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal) : type; + return changed + ? mappedTypes && getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal) + : type; } - function mapTypeWithAlias(type: Type, mapper: (t: Type) => Type, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { - return type.flags & TypeFlags.Union && aliasSymbol ? - getUnionType(map((type as UnionType).types, mapper), UnionReduction.Literal, aliasSymbol, aliasTypeArguments) : - mapType(type, mapper); + function mapTypeWithAlias( + type: Type, + mapper: (t: Type) => Type, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + ) { + return type.flags & TypeFlags.Union && aliasSymbol + ? getUnionType( + map((type as UnionType).types, mapper), + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments, + ) + : mapType(type, mapper); } function extractTypesOfKind(type: Type, kind: TypeFlags) { @@ -24714,14 +32584,34 @@ namespace ts { // types we don't actually care about. function replacePrimitivesWithLiterals(typeWithPrimitives: Type, typeWithLiterals: Type) { if ( - maybeTypeOfKind(typeWithPrimitives, TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.Number | TypeFlags.BigInt) && - maybeTypeOfKind(typeWithLiterals, TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.NumberLiteral | TypeFlags.BigIntLiteral) + maybeTypeOfKind( + typeWithPrimitives, + TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.Number | TypeFlags.BigInt, + ) + && maybeTypeOfKind( + typeWithLiterals, + TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping + | TypeFlags.NumberLiteral | TypeFlags.BigIntLiteral, + ) ) { - return mapType(typeWithPrimitives, t => - t.flags & TypeFlags.String ? extractTypesOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) : - isPatternLiteralType(t) && !maybeTypeOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? extractTypesOfKind(typeWithLiterals, TypeFlags.StringLiteral) : - t.flags & TypeFlags.Number ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) : - t.flags & TypeFlags.BigInt ? extractTypesOfKind(typeWithLiterals, TypeFlags.BigInt | TypeFlags.BigIntLiteral) : t); + return mapType( + typeWithPrimitives, + t => t.flags & TypeFlags.String + ? extractTypesOfKind( + typeWithLiterals, + TypeFlags.String | TypeFlags.StringLiteral | TypeFlags.TemplateLiteral + | TypeFlags.StringMapping, + ) + : isPatternLiteralType(t) + && !maybeTypeOfKind( + typeWithLiterals, + TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.StringMapping, + ) ? extractTypesOfKind(typeWithLiterals, TypeFlags.StringLiteral) + : t.flags & TypeFlags.Number + ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) + : t.flags & TypeFlags.BigInt + ? extractTypesOfKind(typeWithLiterals, TypeFlags.BigInt | TypeFlags.BigIntLiteral) : t, + ); } return typeWithPrimitives; } @@ -24749,38 +32639,48 @@ namespace ts { } function getEvolvingArrayType(elementType: Type): EvolvingArrayType { - return evolvingArrayTypes[elementType.id] || (evolvingArrayTypes[elementType.id] = createEvolvingArrayType(elementType)); + return evolvingArrayTypes[elementType.id] + || (evolvingArrayTypes[elementType.id] = createEvolvingArrayType(elementType)); } // When adding evolving array element types we do not perform subtype reduction. Instead, // we defer subtype reduction until the evolving array type is finalized into a manifest // array type. - function addEvolvingArrayElementType(evolvingArrayType: EvolvingArrayType, node: Expression): EvolvingArrayType { - const elementType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(getContextFreeTypeOfExpression(node))); - return isTypeSubsetOf(elementType, evolvingArrayType.elementType) ? evolvingArrayType : getEvolvingArrayType(getUnionType([evolvingArrayType.elementType, elementType])); + function addEvolvingArrayElementType( + evolvingArrayType: EvolvingArrayType, + node: Expression, + ): EvolvingArrayType { + const elementType = getRegularTypeOfObjectLiteral( + getBaseTypeOfLiteralType(getContextFreeTypeOfExpression(node)), + ); + return isTypeSubsetOf(elementType, evolvingArrayType.elementType) ? evolvingArrayType + : getEvolvingArrayType(getUnionType([evolvingArrayType.elementType, elementType])); } function createFinalArrayType(elementType: Type) { - return elementType.flags & TypeFlags.Never ? - autoArrayType : - createArrayType( - elementType.flags & TypeFlags.Union ? - getUnionType((elementType as UnionType).types, UnionReduction.Subtype) : - elementType, + return elementType.flags & TypeFlags.Never + ? autoArrayType + : createArrayType( + elementType.flags & TypeFlags.Union + ? getUnionType((elementType as UnionType).types, UnionReduction.Subtype) + : elementType, ); } // We perform subtype reduction upon obtaining the final array type from an evolving array type. function getFinalArrayType(evolvingArrayType: EvolvingArrayType): Type { - return evolvingArrayType.finalArrayType || (evolvingArrayType.finalArrayType = createFinalArrayType(evolvingArrayType.elementType)); + return evolvingArrayType.finalArrayType + || (evolvingArrayType.finalArrayType = createFinalArrayType(evolvingArrayType.elementType)); } function finalizeEvolvingArrayType(type: Type): Type { - return getObjectFlags(type) & ObjectFlags.EvolvingArray ? getFinalArrayType(type as EvolvingArrayType) : type; + return getObjectFlags(type) & ObjectFlags.EvolvingArray ? getFinalArrayType(type as EvolvingArrayType) + : type; } function getElementTypeOfEvolvingArrayType(type: Type) { - return getObjectFlags(type) & ObjectFlags.EvolvingArray ? (type as EvolvingArrayType).elementType : neverType; + return getObjectFlags(type) & ObjectFlags.EvolvingArray ? (type as EvolvingArrayType).elementType + : neverType; } function isEvolvingArrayTypeList(types: Type[]) { @@ -24802,29 +32702,37 @@ namespace ts { const root = getReferenceRoot(node); const parent = root.parent; const isLengthPushOrUnshift = isPropertyAccessExpression(parent) && ( - parent.name.escapedText === "length" || - parent.parent.kind === SyntaxKind.CallExpression + parent.name.escapedText === "length" + || parent.parent.kind === SyntaxKind.CallExpression && isIdentifier(parent.name) && isPushOrUnshiftIdentifier(parent.name) ); - const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression && - (parent as ElementAccessExpression).expression === root && - parent.parent.kind === SyntaxKind.BinaryExpression && - (parent.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && - (parent.parent as BinaryExpression).left === parent && - !isAssignmentTarget(parent.parent) && - isTypeAssignableToKind(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression), TypeFlags.NumberLike); + const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression + && (parent as ElementAccessExpression).expression === root + && parent.parent.kind === SyntaxKind.BinaryExpression + && (parent.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + && (parent.parent as BinaryExpression).left === parent + && !isAssignmentTarget(parent.parent) + && isTypeAssignableToKind( + getTypeOfExpression((parent as ElementAccessExpression).argumentExpression), + TypeFlags.NumberLike, + ); return isLengthPushOrUnshift || isElementAssignment; } function isDeclarationWithExplicitTypeAnnotation(node: Declaration) { - return (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isParameter(node)) && - !!(getEffectiveTypeAnnotationNode(node) || - isInJSFile(node) && hasInitializer(node) && node.initializer && isFunctionExpressionOrArrowFunction(node.initializer) && getEffectiveReturnTypeNode(node.initializer)); + return (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) + || isParameter(node)) + && !!(getEffectiveTypeAnnotationNode(node) + || isInJSFile(node) && hasInitializer(node) && node.initializer + && isFunctionExpressionOrArrowFunction(node.initializer) + && getEffectiveReturnTypeNode(node.initializer)); } function getExplicitTypeOfSymbol(symbol: Symbol, diagnostic?: Diagnostic) { - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule)) { + if ( + symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule) + ) { return getTypeOfSymbol(symbol); } if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { @@ -24839,16 +32747,31 @@ namespace ts { if (isDeclarationWithExplicitTypeAnnotation(declaration)) { return getTypeOfSymbol(symbol); } - if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { + if ( + isVariableDeclaration(declaration) + && declaration.parent.parent.kind === SyntaxKind.ForOfStatement + ) { const statement = declaration.parent.parent; const expressionType = getTypeOfDottedName(statement.expression, /*diagnostic*/ undefined); if (expressionType) { const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf; - return checkIteratedTypeOrElementType(use, expressionType, undefinedType, /*errorNode*/ undefined); + return checkIteratedTypeOrElementType( + use, + expressionType, + undefinedType, + /*errorNode*/ undefined, + ); } } if (diagnostic) { - addRelatedInfo(diagnostic, createDiagnosticForNode(declaration, Diagnostics._0_needs_an_explicit_type_annotation, symbolToString(symbol))); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + declaration, + Diagnostics._0_needs_an_explicit_type_annotation, + symbolToString(symbol), + ), + ); } } } @@ -24863,7 +32786,10 @@ namespace ts { switch (node.kind) { case SyntaxKind.Identifier: const symbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(node as Identifier)); - return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol, diagnostic); + return getExplicitTypeOfSymbol( + symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol, + diagnostic, + ); case SyntaxKind.ThisKeyword: return getExplicitThisType(node); case SyntaxKind.SuperKeyword: @@ -24877,7 +32803,10 @@ namespace ts { if (!type.symbol) { return undefined; } - prop = getPropertyOfType(type, getSymbolNameForPrivateIdentifier(type.symbol, name.escapedText)); + prop = getPropertyOfType( + type, + getSymbolNameForPrivateIdentifier(type.symbol, name.escapedText), + ); } else { prop = getPropertyOfType(type, name.escapedText); @@ -24915,22 +32844,30 @@ namespace ts { funcType = checkNonNullExpression(node.expression); } } - const signatures = getSignaturesOfType(funcType && getApparentType(funcType) || unknownType, SignatureKind.Call); - const candidate = signatures.length === 1 && !signatures[0].typeParameters ? signatures[0] : - some(signatures, hasTypePredicateOrNeverReturnType) ? getResolvedSignature(node) : - undefined; - signature = links.effectsSignature = candidate && hasTypePredicateOrNeverReturnType(candidate) ? candidate : unknownSignature; + const signatures = getSignaturesOfType( + funcType && getApparentType(funcType) || unknownType, + SignatureKind.Call, + ); + const candidate = signatures.length === 1 && !signatures[0].typeParameters ? signatures[0] + : some(signatures, hasTypePredicateOrNeverReturnType) ? getResolvedSignature(node) + : undefined; + signature = links.effectsSignature = candidate && hasTypePredicateOrNeverReturnType(candidate) + ? candidate : unknownSignature; } return signature === unknownSignature ? undefined : signature; } function hasTypePredicateOrNeverReturnType(signature: Signature) { - return !!(getTypePredicateOfSignature(signature) || - signature.declaration && (getReturnTypeFromAnnotation(signature.declaration) || unknownType).flags & TypeFlags.Never); + return !!(getTypePredicateOfSignature(signature) + || signature.declaration + && (getReturnTypeFromAnnotation(signature.declaration) || unknownType).flags & TypeFlags.Never); } function getTypePredicateArgument(predicate: TypePredicate, callExpression: CallExpression) { - if (predicate.kind === TypePredicateKind.Identifier || predicate.kind === TypePredicateKind.AssertsIdentifier) { + if ( + predicate.kind === TypePredicateKind.Identifier + || predicate.kind === TypePredicateKind.AssertsIdentifier + ) { return callExpression.arguments[predicate.parameterIndex]; } const invokedExpression = skipParentheses(callExpression.expression); @@ -24941,7 +32878,14 @@ namespace ts { const block = findAncestor(node, isFunctionOrModuleBlock) as Block | ModuleBlock | SourceFile; const sourceFile = getSourceFileOfNode(node); const span = getSpanOfTokenAtPosition(sourceFile, block.statements.pos); - diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis)); + diagnostics.add( + createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis, + ), + ); } function isReachableFlowNode(flow: FlowNode) { @@ -24954,8 +32898,12 @@ namespace ts { function isFalseExpression(expr: Expression): boolean { const node = skipParentheses(expr, /*excludeJSDocTypeAssertions*/ true); return node.kind === SyntaxKind.FalseKeyword || node.kind === SyntaxKind.BinaryExpression && ( - (node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken && (isFalseExpression((node as BinaryExpression).left) || isFalseExpression((node as BinaryExpression).right)) || - (node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken && isFalseExpression((node as BinaryExpression).left) && isFalseExpression((node as BinaryExpression).right) + (node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken + && (isFalseExpression((node as BinaryExpression).left) + || isFalseExpression((node as BinaryExpression).right)) + || (node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken + && isFalseExpression((node as BinaryExpression).left) + && isFalseExpression((node as BinaryExpression).right) ); } @@ -24969,7 +32917,8 @@ namespace ts { if (!noCacheCheck) { const id = getFlowNodeId(flow); const reachable = flowNodeReachable[id]; - return reachable !== undefined ? reachable : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*noCacheCheck*/ true)); + return reachable !== undefined ? reachable + : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*noCacheCheck*/ true)); } noCacheCheck = false; } @@ -24994,7 +32943,10 @@ namespace ts { } else if (flags & FlowFlags.BranchLabel) { // A branching point is reachable if any branch is reachable. - return some((flow as FlowLabel).antecedents, f => isReachableFlowNodeWorker(f, /*noCacheCheck*/ false)); + return some( + (flow as FlowLabel).antecedents, + f => isReachableFlowNodeWorker(f, /*noCacheCheck*/ false), + ); } else if (flags & FlowFlags.LoopLabel) { const antecedents = (flow as FlowLabel).antecedents; @@ -25007,7 +32959,10 @@ namespace ts { else if (flags & FlowFlags.SwitchClause) { // The control flow path representing an unmatched value in a switch statement with // no default clause is unreachable if the switch statement is exhaustive. - if ((flow as FlowSwitchClause).clauseStart === (flow as FlowSwitchClause).clauseEnd && isExhaustiveSwitchStatement((flow as FlowSwitchClause).switchStatement)) { + if ( + (flow as FlowSwitchClause).clauseStart === (flow as FlowSwitchClause).clauseEnd + && isExhaustiveSwitchStatement((flow as FlowSwitchClause).switchStatement) + ) { return false; } flow = (flow as FlowSwitchClause).antecedent; @@ -25018,7 +32973,10 @@ namespace ts { const target = (flow as FlowReduceLabel).target; const saveAntecedents = target.antecedents; target.antecedents = (flow as FlowReduceLabel).antecedents; - const result = isReachableFlowNodeWorker((flow as FlowReduceLabel).antecedent, /*noCacheCheck*/ false); + const result = isReachableFlowNodeWorker( + (flow as FlowReduceLabel).antecedent, + /*noCacheCheck*/ false, + ); target.antecedents = saveAntecedents; return result; } @@ -25037,11 +32995,15 @@ namespace ts { if (!noCacheCheck) { const id = getFlowNodeId(flow); const postSuper = flowNodePostSuper[id]; - return postSuper !== undefined ? postSuper : (flowNodePostSuper[id] = isPostSuperFlowNode(flow, /*noCacheCheck*/ true)); + return postSuper !== undefined ? postSuper + : (flowNodePostSuper[id] = isPostSuperFlowNode(flow, /*noCacheCheck*/ true)); } noCacheCheck = false; } - if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation | FlowFlags.SwitchClause)) { + if ( + flags + & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation | FlowFlags.SwitchClause) + ) { flow = (flow as FlowAssignment | FlowCondition | FlowArrayMutation | FlowSwitchClause).antecedent; } else if (flags & FlowFlags.Call) { @@ -25077,17 +33039,25 @@ namespace ts { switch (node.kind) { case SyntaxKind.Identifier: { const symbol = getResolvedSymbol(node as Identifier); - return isConstVariable(symbol) || isParameterOrCatchClauseVariable(symbol) && !isSymbolAssigned(symbol); + return isConstVariable(symbol) + || isParameterOrCatchClauseVariable(symbol) && !isSymbolAssigned(symbol); } case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: // The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here. - return isConstantReference((node as AccessExpression).expression) && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol); + return isConstantReference((node as AccessExpression).expression) + && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol); } return false; } - function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, flowNode = reference.flowNode) { + function getFlowTypeOfReference( + reference: Node, + declaredType: Type, + initialType = declaredType, + flowContainer?: Node, + flowNode = reference.flowNode, + ) { let key: string | undefined; let isKeySet = false; let flowDepth = 0; @@ -25105,8 +33075,15 @@ namespace ts { // we give type 'any[]' to 'x' instead of using the type determined by control flow analysis such that operations // on empty arrays are possible without implicit any errors and new element types can be inferred without // type mismatch errors. - const resultType = getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) ? autoArrayType : finalizeEvolvingArrayType(evolvedType); - if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && !(resultType.flags & TypeFlags.Never) && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) { + const resultType = + getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) + ? autoArrayType : finalizeEvolvingArrayType(evolvedType); + if ( + resultType === unreachableNeverType + || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression + && !(resultType.flags & TypeFlags.Never) + && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never + ) { return declaredType; } // The non-null unknown type should never escape control flow analysis. @@ -25171,9 +33148,9 @@ namespace ts { flow = (flow as FlowLabel).antecedents![0]; continue; } - type = flags & FlowFlags.BranchLabel ? - getTypeAtFlowBranchLabel(flow as FlowLabel) : - getTypeAtFlowLoopLabel(flow as FlowLabel); + type = flags & FlowFlags.BranchLabel + ? getTypeAtFlowBranchLabel(flow as FlowLabel) + : getTypeAtFlowLoopLabel(flow as FlowLabel); } else if (flags & FlowFlags.ArrayMutation) { type = getTypeAtFlowArrayMutation(flow as FlowArrayMutation); @@ -25193,10 +33170,10 @@ namespace ts { // Check if we should continue with the control flow of the containing function. const container = (flow as FlowStart).node; if ( - container && container !== flowContainer && - reference.kind !== SyntaxKind.PropertyAccessExpression && - reference.kind !== SyntaxKind.ElementAccessExpression && - reference.kind !== SyntaxKind.ThisKeyword + container && container !== flowContainer + && reference.kind !== SyntaxKind.PropertyAccessExpression + && reference.kind !== SyntaxKind.ElementAccessExpression + && reference.kind !== SyntaxKind.ThisKeyword ) { flow = container.flowNode!; continue; @@ -25223,9 +33200,9 @@ namespace ts { function getInitialOrAssignedType(flow: FlowAssignment) { const node = flow.node; return getNarrowableTypeForReference( - node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ? - getInitialType(node as VariableDeclaration | BindingElement) : - getAssignedType(node), + node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement + ? getInitialType(node as VariableDeclaration | BindingElement) + : getAssignedType(node), reference, ); } @@ -25240,7 +33217,10 @@ namespace ts { } if (getAssignmentTargetKind(node) === AssignmentKind.Compound) { const flowType = getTypeAtFlowNode(flow.antecedent); - return createFlowType(getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), isIncomplete(flowType)); + return createFlowType( + getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), + isIncomplete(flowType), + ); } if (declaredType === autoType || declaredType === autoArrayType) { if (isEmptyArrayAssignment(node)) { @@ -25266,15 +33246,23 @@ namespace ts { // in which case we continue control flow analysis back to the function's declaration if (isVariableDeclaration(node) && (isInJSFile(node) || isVarConst(node))) { const init = getDeclaredExpandoInitializer(node); - if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) { + if ( + init + && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction) + ) { return getTypeAtFlowNode(flow.antecedent); } } return declaredType; } // for (const _ in ref) acts as a nonnull on ref - if (isVariableDeclaration(node) && node.parent.parent.kind === SyntaxKind.ForInStatement && isMatchingReference(reference, node.parent.parent.expression)) { - return getNonNullableTypeIfNeeded(finalizeEvolvingArrayType(getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent)))); + if ( + isVariableDeclaration(node) && node.parent.parent.kind === SyntaxKind.ForInStatement + && isMatchingReference(reference, node.parent.parent.expression) + ) { + return getNonNullableTypeIfNeeded( + finalizeEvolvingArrayType(getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent))), + ); } // Assignment doesn't affect reference return undefined; @@ -25287,10 +33275,16 @@ namespace ts { } if (node.kind === SyntaxKind.BinaryExpression) { if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { - return narrowTypeByAssertion(narrowTypeByAssertion(type, (node as BinaryExpression).left), (node as BinaryExpression).right); + return narrowTypeByAssertion( + narrowTypeByAssertion(type, (node as BinaryExpression).left), + (node as BinaryExpression).right, + ); } if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken) { - return getUnionType([narrowTypeByAssertion(type, (node as BinaryExpression).left), narrowTypeByAssertion(type, (node as BinaryExpression).right)]); + return getUnionType([ + narrowTypeByAssertion(type, (node as BinaryExpression).left), + narrowTypeByAssertion(type, (node as BinaryExpression).right), + ]); } } return narrowType(type, node, /*assumeTrue*/ true); @@ -25300,12 +33294,19 @@ namespace ts { const signature = getEffectsSignature(flow.node); if (signature) { const predicate = getTypePredicateOfSignature(signature); - if (predicate && (predicate.kind === TypePredicateKind.AssertsThis || predicate.kind === TypePredicateKind.AssertsIdentifier)) { + if ( + predicate + && (predicate.kind === TypePredicateKind.AssertsThis + || predicate.kind === TypePredicateKind.AssertsIdentifier) + ) { const flowType = getTypeAtFlowNode(flow.antecedent); const type = finalizeEvolvingArrayType(getTypeFromFlowType(flowType)); - const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : - predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex >= 0 && predicate.parameterIndex < flow.node.arguments.length ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) : - type; + const narrowedType = predicate.type + ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) + : predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex >= 0 + && predicate.parameterIndex < flow.node.arguments.length + ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) + : type; return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); } if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { @@ -25318,9 +33319,9 @@ namespace ts { function getTypeAtFlowArrayMutation(flow: FlowArrayMutation): FlowType | undefined { if (declaredType === autoType || declaredType === autoArrayType) { const node = flow.node; - const expr = node.kind === SyntaxKind.CallExpression ? - (node.expression as PropertyAccessExpression).expression : - (node.left as ElementAccessExpression).expression; + const expr = node.kind === SyntaxKind.CallExpression + ? (node.expression as PropertyAccessExpression).expression + : (node.left as ElementAccessExpression).expression; if (isMatchingReference(reference, getReferenceCandidate(expr))) { const flowType = getTypeAtFlowNode(flow.antecedent); const type = getTypeFromFlowType(flowType); @@ -25333,12 +33334,15 @@ namespace ts { } else { // We must get the context free expression type so as to not recur in an uncached fashion on the LHS (which causes exponential blowup in compile time) - const indexType = getContextFreeTypeOfExpression((node.left as ElementAccessExpression).argumentExpression); + const indexType = getContextFreeTypeOfExpression( + (node.left as ElementAccessExpression).argumentExpression, + ); if (isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) { evolvedType = addEvolvingArrayElementType(evolvedType, node.right); } } - return evolvedType === type ? flowType : createFlowType(evolvedType, isIncomplete(flowType)); + return evolvedType === type ? flowType + : createFlowType(evolvedType, isIncomplete(flowType)); } return flowType; } @@ -25373,23 +33377,54 @@ namespace ts { const flowType = getTypeAtFlowNode(flow.antecedent); let type = getTypeFromFlowType(flowType); if (isMatchingReference(reference, expr)) { - type = narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd); + type = narrowTypeBySwitchOnDiscriminant( + type, + flow.switchStatement, + flow.clauseStart, + flow.clauseEnd, + ); } - else if (expr.kind === SyntaxKind.TypeOfExpression && isMatchingReference(reference, (expr as TypeOfExpression).expression)) { + else if ( + expr.kind === SyntaxKind.TypeOfExpression + && isMatchingReference(reference, (expr as TypeOfExpression).expression) + ) { type = narrowBySwitchOnTypeOf(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd); } else { if (strictNullChecks) { if (optionalChainContainsReference(expr, reference)) { - type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd, t => !(t.flags & (TypeFlags.Undefined | TypeFlags.Never))); + type = narrowTypeBySwitchOptionalChainContainment( + type, + flow.switchStatement, + flow.clauseStart, + flow.clauseEnd, + t => !(t.flags & (TypeFlags.Undefined | TypeFlags.Never)), + ); } - else if (expr.kind === SyntaxKind.TypeOfExpression && optionalChainContainsReference((expr as TypeOfExpression).expression, reference)) { - type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd, t => !(t.flags & TypeFlags.Never || t.flags & TypeFlags.StringLiteral && (t as StringLiteralType).value === "undefined")); + else if ( + expr.kind === SyntaxKind.TypeOfExpression + && optionalChainContainsReference((expr as TypeOfExpression).expression, reference) + ) { + type = narrowTypeBySwitchOptionalChainContainment( + type, + flow.switchStatement, + flow.clauseStart, + flow.clauseEnd, + t => !(t.flags & TypeFlags.Never + || t.flags & TypeFlags.StringLiteral + && (t as StringLiteralType).value === "undefined"), + ); } } const access = getDiscriminantPropertyAccess(expr, type); if (access) { - type = narrowTypeBySwitchOnDiscriminantProperty(type, access, flow.switchStatement, flow.clauseStart, flow.clauseEnd); + type = narrowTypeBySwitchOnDiscriminantProperty( + type, + access, + flow.switchStatement, + flow.clauseStart, + flow.clauseEnd, + ); } } return createFlowType(type, isIncomplete(flowType)); @@ -25401,7 +33436,10 @@ namespace ts { let seenIncomplete = false; let bypassFlow: FlowSwitchClause | undefined; for (const antecedent of flow.antecedents!) { - if (!bypassFlow && antecedent.flags & FlowFlags.SwitchClause && (antecedent as FlowSwitchClause).clauseStart === (antecedent as FlowSwitchClause).clauseEnd) { + if ( + !bypassFlow && antecedent.flags & FlowFlags.SwitchClause + && (antecedent as FlowSwitchClause).clauseStart === (antecedent as FlowSwitchClause).clauseEnd + ) { // The antecedent is the bypass branch of a potentially exhaustive switch statement. bypassFlow = antecedent as FlowSwitchClause; continue; @@ -25445,7 +33483,13 @@ namespace ts { } } } - return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete); + return createFlowType( + getUnionOrEvolvingArrayType( + antecedentTypes, + subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal, + ), + seenIncomplete, + ); } function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType { @@ -25472,7 +33516,10 @@ namespace ts { // path that leads to the top. for (let i = flowLoopStart; i < flowLoopCount; i++) { if (flowLoopNodes[i] === flow && flowLoopKeys[i] === key && flowLoopTypes[i].length) { - return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], UnionReduction.Literal), /*incomplete*/ true); + return createFlowType( + getUnionOrEvolvingArrayType(flowLoopTypes[i], UnionReduction.Literal), + /*incomplete*/ true, + ); } } // Add the flow loop junction and reference to the in-process stack and analyze @@ -25524,7 +33571,10 @@ namespace ts { } // The result is incomplete if the first antecedent (the non-looping control flow path) // is incomplete. - const result = getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal); + const result = getUnionOrEvolvingArrayType( + antecedentTypes, + subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal, + ); if (isIncomplete(firstAntecedentType!)) { return createFlowType(result, /*incomplete*/ true); } @@ -25539,22 +33589,34 @@ namespace ts { if (isEvolvingArrayTypeList(types)) { return getEvolvingArrayType(getUnionType(map(types, getElementTypeOfEvolvingArrayType))); } - const result = recombineUnknownType(getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction)); - if (result !== declaredType && result.flags & declaredType.flags & TypeFlags.Union && arraysEqual((result as UnionType).types, (declaredType as UnionType).types)) { + const result = recombineUnknownType( + getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction), + ); + if ( + result !== declaredType && result.flags & declaredType.flags & TypeFlags.Union + && arraysEqual((result as UnionType).types, (declaredType as UnionType).types) + ) { return declaredType; } return result; } function getCandidateDiscriminantPropertyAccess(expr: Expression) { - if (isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference) || isObjectLiteralMethod(reference)) { + if ( + isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference) + || isObjectLiteralMethod(reference) + ) { // When the reference is a binding pattern or function or arrow expression, we are narrowing a pesudo-reference in // getNarrowedTypeOfSymbol. An identifier for a destructuring variable declared in the same binding pattern or // parameter declared in the same parameter list is a candidate. if (isIdentifier(expr)) { const symbol = getResolvedSymbol(expr); const declaration = symbol.valueDeclaration; - if (declaration && (isBindingElement(declaration) || isParameter(declaration)) && reference === declaration.parent && !declaration.initializer && !declaration.dotDotDotToken) { + if ( + declaration && (isBindingElement(declaration) || isParameter(declaration)) + && reference === declaration.parent && !declaration.initializer + && !declaration.dotDotDotToken + ) { return declaration; } } @@ -25571,8 +33633,9 @@ namespace ts { const declaration = symbol.valueDeclaration!; // Given 'const x = obj.kind', allow 'x' as an alias for 'obj.kind' if ( - isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isAccessExpression(declaration.initializer) && - isMatchingReference(reference, declaration.initializer.expression) + isVariableDeclaration(declaration) && !declaration.type && declaration.initializer + && isAccessExpression(declaration.initializer) + && isMatchingReference(reference, declaration.initializer.expression) ) { return declaration.initializer; } @@ -25580,8 +33643,9 @@ namespace ts { if (isBindingElement(declaration) && !declaration.initializer) { const parent = declaration.parent.parent; if ( - isVariableDeclaration(parent) && !parent.type && parent.initializer && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) && - isMatchingReference(reference, parent.initializer) + isVariableDeclaration(parent) && !parent.type && parent.initializer + && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) + && isMatchingReference(reference, parent.initializer) ) { return declaration; } @@ -25605,13 +33669,21 @@ namespace ts { return undefined; } - function narrowTypeByDiscriminant(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, narrowType: (t: Type) => Type): Type { + function narrowTypeByDiscriminant( + type: Type, + access: AccessExpression | BindingElement | ParameterDeclaration, + narrowType: (t: Type) => Type, + ): Type { const propName = getAccessedPropertyName(access); if (propName === undefined) { return type; } - const removeNullable = strictNullChecks && isOptionalChain(access) && maybeTypeOfKind(type, TypeFlags.Nullable); - let propType = getTypeOfPropertyOfType(removeNullable ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type, propName); + const removeNullable = strictNullChecks && isOptionalChain(access) + && maybeTypeOfKind(type, TypeFlags.Nullable); + let propType = getTypeOfPropertyOfType( + removeNullable ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type, + propName, + ); if (!propType) { return type; } @@ -25619,34 +33691,66 @@ namespace ts { const narrowedPropType = narrowType(propType); return filterType(type, t => { const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName); - return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType); + return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) + && areTypesComparable(narrowedPropType, discriminantType); }); } - function narrowTypeByDiscriminantProperty(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, operator: SyntaxKind, value: Expression, assumeTrue: boolean) { - if ((operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) && type.flags & TypeFlags.Union) { + function narrowTypeByDiscriminantProperty( + type: Type, + access: AccessExpression | BindingElement | ParameterDeclaration, + operator: SyntaxKind, + value: Expression, + assumeTrue: boolean, + ) { + if ( + (operator === SyntaxKind.EqualsEqualsEqualsToken + || operator === SyntaxKind.ExclamationEqualsEqualsToken) && type.flags & TypeFlags.Union + ) { const keyPropertyName = getKeyPropertyName(type as UnionType); if (keyPropertyName && keyPropertyName === getAccessedPropertyName(access)) { const candidate = getConstituentTypeForKeyType(type as UnionType, getTypeOfExpression(value)); if (candidate) { - return operator === (assumeTrue ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken) ? candidate : - isUnitType(getTypeOfPropertyOfType(candidate, keyPropertyName) || unknownType) ? removeType(type, candidate) : - type; + return operator + === (assumeTrue ? SyntaxKind.EqualsEqualsEqualsToken + : SyntaxKind.ExclamationEqualsEqualsToken) ? candidate + : isUnitType(getTypeOfPropertyOfType(candidate, keyPropertyName) || unknownType) + ? removeType(type, candidate) + : type; } } } - return narrowTypeByDiscriminant(type, access, t => narrowTypeByEquality(t, operator, value, assumeTrue)); + return narrowTypeByDiscriminant( + type, + access, + t => narrowTypeByEquality(t, operator, value, assumeTrue), + ); } - function narrowTypeBySwitchOnDiscriminantProperty(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number) { - if (clauseStart < clauseEnd && type.flags & TypeFlags.Union && getKeyPropertyName(type as UnionType) === getAccessedPropertyName(access)) { + function narrowTypeBySwitchOnDiscriminantProperty( + type: Type, + access: AccessExpression | BindingElement | ParameterDeclaration, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + ) { + if ( + clauseStart < clauseEnd && type.flags & TypeFlags.Union + && getKeyPropertyName(type as UnionType) === getAccessedPropertyName(access) + ) { const clauseTypes = getSwitchClauseTypes(switchStatement).slice(clauseStart, clauseEnd); - const candidate = getUnionType(map(clauseTypes, t => getConstituentTypeForKeyType(type as UnionType, t) || unknownType)); + const candidate = getUnionType( + map(clauseTypes, t => getConstituentTypeForKeyType(type as UnionType, t) || unknownType), + ); if (candidate !== unknownType) { return candidate; } } - return narrowTypeByDiscriminant(type, access, t => narrowTypeBySwitchOnDiscriminant(t, switchStatement, clauseStart, clauseEnd)); + return narrowTypeByDiscriminant( + type, + access, + t => narrowTypeBySwitchOnDiscriminant(t, switchStatement, clauseStart, clauseEnd), + ); } function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type { @@ -25658,19 +33762,27 @@ namespace ts { } const access = getDiscriminantPropertyAccess(expr, type); if (access) { - return narrowTypeByDiscriminant(type, access, t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy)); + return narrowTypeByDiscriminant( + type, + access, + t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy), + ); } return type; } function isTypePresencePossible(type: Type, propName: __String, assumeTrue: boolean) { const prop = getPropertyOfType(type, propName); - return prop ? - !!(prop.flags & SymbolFlags.Optional) || assumeTrue : - !!getApplicableIndexInfoForName(type, propName) || !assumeTrue; + return prop + ? !!(prop.flags & SymbolFlags.Optional) || assumeTrue + : !!getApplicableIndexInfoForName(type, propName) || !assumeTrue; } - function narrowByInKeyword(type: Type, nameType: StringLiteralType | NumberLiteralType | UniqueESSymbolType, assumeTrue: boolean) { + function narrowByInKeyword( + type: Type, + nameType: StringLiteralType | NumberLiteralType | UniqueESSymbolType, + assumeTrue: boolean, + ) { const name = getPropertyNameFromType(nameType); const isKnownProperty = someType(type, t => isTypePresencePossible(t, name, /*assumeTrue*/ true)); if (isKnownProperty) { @@ -25683,7 +33795,10 @@ namespace ts { // where X is the name of the property. const recordSymbol = getGlobalRecordSymbol(); if (recordSymbol) { - return getIntersectionType([type, getTypeAliasInstantiation(recordSymbol, [nameType, unknownType])]); + return getIntersectionType([ + type, + getTypeAliasInstantiation(recordSymbol, [nameType, unknownType]), + ]); } } return type; @@ -25748,13 +33863,24 @@ namespace ts { const leftType = getTypeOfExpression(expr.left); if (leftType.flags & TypeFlags.StringOrNumberLiteralOrUnique) { if ( - containsMissingType(type) && isAccessExpression(reference) && isMatchingReference(reference.expression, target) && - getAccessedPropertyName(reference) === getPropertyNameFromType(leftType as StringLiteralType | NumberLiteralType | UniqueESSymbolType) + containsMissingType(type) && isAccessExpression(reference) + && isMatchingReference(reference.expression, target) + && getAccessedPropertyName(reference) + === getPropertyNameFromType( + leftType as StringLiteralType | NumberLiteralType | UniqueESSymbolType, + ) ) { - return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined); + return getTypeWithFacts( + type, + assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined, + ); } if (isMatchingReference(reference, target)) { - return narrowByInKeyword(type, leftType as StringLiteralType | NumberLiteralType | UniqueESSymbolType, assumeTrue); + return narrowByInKeyword( + type, + leftType as StringLiteralType | NumberLiteralType | UniqueESSymbolType, + assumeTrue, + ); } } break; @@ -25764,18 +33890,36 @@ namespace ts { // expressions down to individual conditional control flows. However, we may encounter them when analyzing // aliased conditional expressions. case SyntaxKind.AmpersandAmpersandToken: - return assumeTrue ? - narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ true) : - getUnionType([narrowType(type, expr.left, /*assumeTrue*/ false), narrowType(type, expr.right, /*assumeTrue*/ false)]); + return assumeTrue + ? narrowType( + narrowType(type, expr.left, /*assumeTrue*/ true), + expr.right, + /*assumeTrue*/ true, + ) + : getUnionType([ + narrowType(type, expr.left, /*assumeTrue*/ false), + narrowType(type, expr.right, /*assumeTrue*/ false), + ]); case SyntaxKind.BarBarToken: - return assumeTrue ? - getUnionType([narrowType(type, expr.left, /*assumeTrue*/ true), narrowType(type, expr.right, /*assumeTrue*/ true)]) : - narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ false); + return assumeTrue + ? getUnionType([ + narrowType(type, expr.left, /*assumeTrue*/ true), + narrowType(type, expr.right, /*assumeTrue*/ true), + ]) + : narrowType( + narrowType(type, expr.left, /*assumeTrue*/ false), + expr.right, + /*assumeTrue*/ false, + ); } return type; } - function narrowTypeByPrivateIdentifierInInExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { + function narrowTypeByPrivateIdentifierInInExpression( + type: Type, + expr: BinaryExpression, + assumeTrue: boolean, + ): Type { const target = getReferenceCandidate(expr.right); if (!isMatchingReference(reference, target)) { return type; @@ -25787,13 +33931,19 @@ namespace ts { return type; } const classSymbol = symbol.parent!; - const targetType = hasStaticModifier(Debug.checkDefined(symbol.valueDeclaration, "should always have a declaration")) - ? getTypeOfSymbol(classSymbol) as InterfaceType - : getDeclaredTypeOfSymbol(classSymbol); + const targetType = + hasStaticModifier(Debug.checkDefined(symbol.valueDeclaration, "should always have a declaration")) + ? getTypeOfSymbol(classSymbol) as InterfaceType + : getDeclaredTypeOfSymbol(classSymbol); return getNarrowedType(type, targetType, assumeTrue, /*checkDerived*/ true); } - function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { + function narrowTypeByOptionalChainContainment( + type: Type, + operator: SyntaxKind, + value: Expression, + assumeTrue: boolean, + ): Type { // We are in a branch of obj?.foo === value (or any one of the other equality operators). We narrow obj as follows: // When operator is === and type of value excludes undefined, null and undefined is removed from type of obj in true branch. // When operator is !== and type of value excludes undefined, null and undefined is removed from type of obj in false branch. @@ -25803,45 +33953,68 @@ namespace ts { // When operator is !== and type of value is undefined, null and undefined is removed from type of obj in true branch. // When operator is == and type of value is null or undefined, null and undefined is removed from type of obj in false branch. // When operator is != and type of value is null or undefined, null and undefined is removed from type of obj in true branch. - const equalsOperator = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; - const nullableFlags = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken ? TypeFlags.Nullable : TypeFlags.Undefined; + const equalsOperator = operator === SyntaxKind.EqualsEqualsToken + || operator === SyntaxKind.EqualsEqualsEqualsToken; + const nullableFlags = + operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken + ? TypeFlags.Nullable : TypeFlags.Undefined; const valueType = getTypeOfExpression(value); // Note that we include any and unknown in the exclusion test because their domain includes null and undefined. - const removeNullable = equalsOperator !== assumeTrue && everyType(valueType, t => !!(t.flags & nullableFlags)) || - equalsOperator === assumeTrue && everyType(valueType, t => !(t.flags & (TypeFlags.AnyOrUnknown | nullableFlags))); + const removeNullable = + equalsOperator !== assumeTrue && everyType(valueType, t => !!(t.flags & nullableFlags)) + || equalsOperator === assumeTrue + && everyType(valueType, t => !(t.flags & (TypeFlags.AnyOrUnknown | nullableFlags))); return removeNullable ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } - function narrowTypeByEquality(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { + function narrowTypeByEquality( + type: Type, + operator: SyntaxKind, + value: Expression, + assumeTrue: boolean, + ): Type { if (type.flags & TypeFlags.Any) { return type; } - if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { + if ( + operator === SyntaxKind.ExclamationEqualsToken + || operator === SyntaxKind.ExclamationEqualsEqualsToken + ) { assumeTrue = !assumeTrue; } const valueType = getTypeOfExpression(value); - const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken; + const doubleEquals = operator === SyntaxKind.EqualsEqualsToken + || operator === SyntaxKind.ExclamationEqualsToken; if (valueType.flags & TypeFlags.Nullable) { if (!strictNullChecks) { return type; } - const facts = doubleEquals ? - assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull : - valueType.flags & TypeFlags.Null ? - assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull : - assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; + const facts = doubleEquals + ? assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull + : valueType.flags & TypeFlags.Null + ? assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull + : assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; return getAdjustedTypeWithFacts(type, facts); } if (assumeTrue) { - if (!doubleEquals && (type.flags & TypeFlags.Unknown || someType(type, isEmptyAnonymousObjectType))) { - if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) || isEmptyAnonymousObjectType(valueType)) { + if ( + !doubleEquals && (type.flags & TypeFlags.Unknown || someType(type, isEmptyAnonymousObjectType)) + ) { + if ( + valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) + || isEmptyAnonymousObjectType(valueType) + ) { return valueType; } if (valueType.flags & TypeFlags.Object) { return nonPrimitiveType; } } - const filteredType = filterType(type, t => areTypesComparable(t, valueType) || doubleEquals && isCoercibleUnderDoubleEquals(t, valueType)); + const filteredType = filterType( + type, + t => areTypesComparable(t, valueType) + || doubleEquals && isCoercibleUnderDoubleEquals(t, valueType), + ); return replacePrimitivesWithLiterals(filteredType, valueType); } if (isUnitType(valueType)) { @@ -25850,18 +34023,34 @@ namespace ts { return type; } - function narrowTypeByTypeof(type: Type, typeOfExpr: TypeOfExpression, operator: SyntaxKind, literal: LiteralExpression, assumeTrue: boolean): Type { + function narrowTypeByTypeof( + type: Type, + typeOfExpr: TypeOfExpression, + operator: SyntaxKind, + literal: LiteralExpression, + assumeTrue: boolean, + ): Type { // We have '==', '!=', '===', or !==' operator with 'typeof xxx' and string literal operands - if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { + if ( + operator === SyntaxKind.ExclamationEqualsToken + || operator === SyntaxKind.ExclamationEqualsEqualsToken + ) { assumeTrue = !assumeTrue; } const target = getReferenceCandidate(typeOfExpr.expression); if (!isMatchingReference(reference, target)) { const propertyAccess = getDiscriminantPropertyAccess(typeOfExpr.expression, type); if (propertyAccess) { - return narrowTypeByDiscriminant(type, propertyAccess, t => narrowTypeByLiteralExpression(t, literal, assumeTrue)); + return narrowTypeByDiscriminant( + type, + propertyAccess, + t => narrowTypeByLiteralExpression(t, literal, assumeTrue), + ); } - if (strictNullChecks && optionalChainContainsReference(target, reference) && assumeTrue === (literal.text !== "undefined")) { + if ( + strictNullChecks && optionalChainContainsReference(target, reference) + && assumeTrue === (literal.text !== "undefined") + ) { return getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } return type; @@ -25870,17 +34059,29 @@ namespace ts { } function narrowTypeByLiteralExpression(type: Type, literal: LiteralExpression, assumeTrue: boolean) { - return assumeTrue ? - narrowTypeByTypeName(type, literal.text) : - getTypeWithFacts(type, typeofNEFacts.get(literal.text) || TypeFacts.TypeofNEHostObject); + return assumeTrue + ? narrowTypeByTypeName(type, literal.text) + : getTypeWithFacts(type, typeofNEFacts.get(literal.text) || TypeFacts.TypeofNEHostObject); } - function narrowTypeBySwitchOptionalChainContainment(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number, clauseCheck: (type: Type) => boolean) { - const everyClauseChecks = clauseStart !== clauseEnd && every(getSwitchClauseTypes(switchStatement).slice(clauseStart, clauseEnd), clauseCheck); + function narrowTypeBySwitchOptionalChainContainment( + type: Type, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + clauseCheck: (type: Type) => boolean, + ) { + const everyClauseChecks = clauseStart !== clauseEnd + && every(getSwitchClauseTypes(switchStatement).slice(clauseStart, clauseEnd), clauseCheck); return everyClauseChecks ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } - function narrowTypeBySwitchOnDiscriminant(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number) { + function narrowTypeBySwitchOnDiscriminant( + type: Type, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + ) { // We only narrow if all case expressions specify // values with unit types, except for the case where // `type` is unknown. In this instance we map object @@ -25913,12 +34114,18 @@ namespace ts { return getUnionType(groundClauseTypes === undefined ? clauseTypes : groundClauseTypes); } const discriminantType = getUnionType(clauseTypes); - const caseType = discriminantType.flags & TypeFlags.Never ? neverType : - replacePrimitivesWithLiterals(filterType(type, t => areTypesComparable(discriminantType, t)), discriminantType); + const caseType = discriminantType.flags & TypeFlags.Never ? neverType + : replacePrimitivesWithLiterals( + filterType(type, t => areTypesComparable(discriminantType, t)), + discriminantType, + ); if (!hasDefaultClause) { return caseType; } - const defaultType = filterType(type, t => !(isUnitLikeType(t) && contains(switchTypes, getRegularTypeOfLiteralType(extractUnitType(t))))); + const defaultType = filterType( + type, + t => !(isUnitLikeType(t) && contains(switchTypes, getRegularTypeOfLiteralType(extractUnitType(t)))), + ); return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]); } @@ -25935,9 +34142,14 @@ namespace ts { case "symbol": return narrowTypeByTypeFacts(type, esSymbolType, TypeFacts.TypeofEQSymbol); case "object": - return type.flags & TypeFlags.Any ? type : getUnionType([narrowTypeByTypeFacts(type, nonPrimitiveType, TypeFacts.TypeofEQObject), narrowTypeByTypeFacts(type, nullType, TypeFacts.EQNull)]); + return type.flags & TypeFlags.Any ? type + : getUnionType([ + narrowTypeByTypeFacts(type, nonPrimitiveType, TypeFacts.TypeofEQObject), + narrowTypeByTypeFacts(type, nullType, TypeFacts.EQNull), + ]); case "function": - return type.flags & TypeFlags.Any ? type : narrowTypeByTypeFacts(type, globalFunctionType, TypeFacts.TypeofEQFunction); + return type.flags & TypeFlags.Any ? type + : narrowTypeByTypeFacts(type, globalFunctionType, TypeFacts.TypeofEQFunction); case "undefined": return narrowTypeByTypeFacts(type, undefinedType, TypeFacts.EQUndefined); } @@ -25950,25 +34162,34 @@ namespace ts { // the constituent based on its type facts. We use the strict subtype relation because it treats `object` // as a subtype of `{}`, and we need the type facts check because function types are subtypes of `object`, // but are classified as "function" according to `typeof`. - isTypeRelatedTo(t, impliedType, strictSubtypeRelation) ? getTypeFacts(t) & facts ? t : neverType : + isTypeRelatedTo(t, impliedType, strictSubtypeRelation) ? getTypeFacts(t) & facts ? t : neverType // We next check if the consituent is a supertype of the implied type. If so, we substitute the implied // type. This handles top types like `unknown` and `{}`, and supertypes like `{ toString(): string }`. - isTypeSubtypeOf(impliedType, t) ? impliedType : + : isTypeSubtypeOf(impliedType, t) ? impliedType // Neither the constituent nor the implied type is a subtype of the other, however their domains may still // overlap. For example, an unconstrained type parameter and type `string`. If the type facts indicate // possible overlap, we form an intersection. Otherwise, we eliminate the constituent. - getTypeFacts(t) & facts ? getIntersectionType([t, impliedType]) : - neverType); + : getTypeFacts(t) & facts ? getIntersectionType([t, impliedType]) + : neverType); } - function narrowBySwitchOnTypeOf(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type { + function narrowBySwitchOnTypeOf( + type: Type, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + ): Type { const witnesses = getSwitchClauseTypeOfWitnesses(switchStatement); if (!witnesses) { return type; } // Equal start and end denotes implicit fallthrough; undefined marks explicit default clause. - const defaultIndex = findIndex(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.DefaultClause); - const hasDefaultClause = clauseStart === clauseEnd || (defaultIndex >= clauseStart && defaultIndex < clauseEnd); + const defaultIndex = findIndex( + switchStatement.caseBlock.clauses, + clause => clause.kind === SyntaxKind.DefaultClause, + ); + const hasDefaultClause = clauseStart === clauseEnd + || (defaultIndex >= clauseStart && defaultIndex < clauseEnd); if (hasDefaultClause) { // In the default clause we filter constituents down to those that are not-equal to all handled cases. const notEqualFacts = getNotEqualFactsFromTypeofSwitch(clauseStart, clauseEnd, witnesses); @@ -25980,14 +34201,25 @@ namespace ts { } function isMatchingConstructorReference(expr: Expression) { - return (isPropertyAccessExpression(expr) && idText(expr.name) === "constructor" || - isElementAccessExpression(expr) && isStringLiteralLike(expr.argumentExpression) && expr.argumentExpression.text === "constructor") && - isMatchingReference(reference, expr.expression); - } - - function narrowTypeByConstructor(type: Type, operator: SyntaxKind, identifier: Expression, assumeTrue: boolean): Type { + return (isPropertyAccessExpression(expr) && idText(expr.name) === "constructor" + || isElementAccessExpression(expr) && isStringLiteralLike(expr.argumentExpression) + && expr.argumentExpression.text === "constructor") + && isMatchingReference(reference, expr.expression); + } + + function narrowTypeByConstructor( + type: Type, + operator: SyntaxKind, + identifier: Expression, + assumeTrue: boolean, + ): Type { // Do not narrow when checking inequality. - if (assumeTrue ? (operator !== SyntaxKind.EqualsEqualsToken && operator !== SyntaxKind.EqualsEqualsEqualsToken) : (operator !== SyntaxKind.ExclamationEqualsToken && operator !== SyntaxKind.ExclamationEqualsEqualsToken)) { + if ( + assumeTrue + ? (operator !== SyntaxKind.EqualsEqualsToken && operator !== SyntaxKind.EqualsEqualsEqualsToken) + : (operator !== SyntaxKind.ExclamationEqualsToken + && operator !== SyntaxKind.ExclamationEqualsEqualsToken) + ) { return type; } @@ -26024,8 +34256,8 @@ namespace ts { // that defines the same set of properties as class `A`, in that case they are structurally the same // type, but when you do something like `instanceOfA.constructor === B` it will return false. if ( - source.flags & TypeFlags.Object && getObjectFlags(source) & ObjectFlags.Class || - target.flags & TypeFlags.Object && getObjectFlags(target) & ObjectFlags.Class + source.flags & TypeFlags.Object && getObjectFlags(source) & ObjectFlags.Class + || target.flags & TypeFlags.Object && getObjectFlags(target) & ObjectFlags.Class ) { return source.symbol === target.symbol; } @@ -26067,9 +34299,14 @@ namespace ts { if (!targetType) { const constructSignatures = getSignaturesOfType(rightType, SignatureKind.Construct); - targetType = constructSignatures.length ? - getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature)))) : - emptyObjectType; + targetType = constructSignatures.length + ? getUnionType( + map( + constructSignatures, + signature => getReturnTypeOfSignature(getErasedSignature(signature)), + ), + ) + : emptyObjectType; } // We can't narrow a union based off instanceof without negated types see #31576 for more info @@ -26082,8 +34319,11 @@ namespace ts { } function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) { - const key = type.flags & TypeFlags.Union ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0)}` : undefined; - return getCachedType(key) ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived)); + const key = type.flags & TypeFlags.Union + ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0)}` + : undefined; + return getCachedType(key) + ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived)); } function getNarrowedTypeWorker(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) { @@ -26096,7 +34336,8 @@ namespace ts { } // We first attempt to filter the current type, narrowing constituents as appropriate and removing // constituents that are unrelated to the candidate. - const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined; + const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) + : undefined; const narrowedType = mapType(candidate, c => { // If a discriminant property is available, use that to reduce the type. const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); @@ -26107,41 +34348,58 @@ namespace ts { // prototype object types. const directlyRelated = mapType( matching || type, - checkDerived ? - t => isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType : - t => isTypeSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : neverType, + checkDerived + ? t => isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType + : t => isTypeSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : neverType, ); // If no constituents are directly related, create intersections for any generic constituents that // are related by constraint. - return directlyRelated.flags & TypeFlags.Never ? - mapType(type, t => maybeTypeOfKind(t, TypeFlags.Instantiable) && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) : neverType) : - directlyRelated; + return directlyRelated.flags & TypeFlags.Never + ? mapType( + type, + t => maybeTypeOfKind(t, TypeFlags.Instantiable) + && isRelated(c, getBaseConstraintOfType(t) || unknownType) + ? getIntersectionType([t, c]) : neverType, + ) + : directlyRelated; }); // If filtering produced a non-empty type, return that. Otherwise, pick the most specific of the two // based on assignability, or as a last resort produce an intersection. - return !(narrowedType.flags & TypeFlags.Never) ? narrowedType : - isTypeSubtypeOf(candidate, type) ? candidate : - isTypeAssignableTo(type, candidate) ? type : - isTypeAssignableTo(candidate, type) ? candidate : - getIntersectionType([type, candidate]); + return !(narrowedType.flags & TypeFlags.Never) ? narrowedType + : isTypeSubtypeOf(candidate, type) ? candidate + : isTypeAssignableTo(type, candidate) ? type + : isTypeAssignableTo(candidate, type) ? candidate + : getIntersectionType([type, candidate]); } function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { if (hasMatchingArgument(callExpression, reference)) { - const signature = assumeTrue || !isCallChain(callExpression) ? getEffectsSignature(callExpression) : undefined; + const signature = assumeTrue || !isCallChain(callExpression) ? getEffectsSignature(callExpression) + : undefined; const predicate = signature && getTypePredicateOfSignature(signature); - if (predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier)) { + if ( + predicate + && (predicate.kind === TypePredicateKind.This + || predicate.kind === TypePredicateKind.Identifier) + ) { return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue); } } - if (containsMissingType(type) && isAccessExpression(reference) && isPropertyAccessExpression(callExpression.expression)) { + if ( + containsMissingType(type) && isAccessExpression(reference) + && isPropertyAccessExpression(callExpression.expression) + ) { const callAccess = callExpression.expression; if ( - isMatchingReference(reference.expression, getReferenceCandidate(callAccess.expression)) && - isIdentifier(callAccess.name) && callAccess.name.escapedText === "hasOwnProperty" && callExpression.arguments.length === 1 + isMatchingReference(reference.expression, getReferenceCandidate(callAccess.expression)) + && isIdentifier(callAccess.name) && callAccess.name.escapedText === "hasOwnProperty" + && callExpression.arguments.length === 1 ) { const argument = callExpression.arguments[0]; - if (isStringLiteralLike(argument) && getAccessedPropertyName(reference) === escapeLeadingUnderscores(argument.text)) { + if ( + isStringLiteralLike(argument) + && getAccessedPropertyName(reference) === escapeLeadingUnderscores(argument.text) + ) { return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined); } } @@ -26149,23 +34407,37 @@ namespace ts { return type; } - function narrowTypeByTypePredicate(type: Type, predicate: TypePredicate, callExpression: CallExpression, assumeTrue: boolean): Type { + function narrowTypeByTypePredicate( + type: Type, + predicate: TypePredicate, + callExpression: CallExpression, + assumeTrue: boolean, + ): Type { // Don't narrow from 'any' if the predicate type is exactly 'Object' or 'Function' - if (predicate.type && !(isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType))) { + if ( + predicate.type + && !(isTypeAny(type) + && (predicate.type === globalObjectType || predicate.type === globalFunctionType)) + ) { const predicateArgument = getTypePredicateArgument(predicate, callExpression); if (predicateArgument) { if (isMatchingReference(reference, predicateArgument)) { return getNarrowedType(type, predicate.type, assumeTrue, /*checkDerived*/ false); } if ( - strictNullChecks && assumeTrue && optionalChainContainsReference(predicateArgument, reference) && - !(getTypeFacts(predicate.type) & TypeFacts.EQUndefined) + strictNullChecks && assumeTrue + && optionalChainContainsReference(predicateArgument, reference) + && !(getTypeFacts(predicate.type) & TypeFacts.EQUndefined) ) { type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } const access = getDiscriminantPropertyAccess(predicateArgument, type); if (access) { - return narrowTypeByDiscriminant(type, access, t => getNarrowedType(t, predicate.type!, assumeTrue, /*checkDerived*/ false)); + return narrowTypeByDiscriminant( + type, + access, + t => getNarrowedType(t, predicate.type!, assumeTrue, /*checkDerived*/ false), + ); } } } @@ -26177,8 +34449,10 @@ namespace ts { function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type { // for `a?.b`, we emulate a synthetic `a !== null && a !== undefined` condition for `a` if ( - isExpressionOfOptionalChainRoot(expr) || - isBinaryExpression(expr.parent) && expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken && expr.parent.left === expr + isExpressionOfOptionalChainRoot(expr) + || isBinaryExpression(expr.parent) + && expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken + && expr.parent.left === expr ) { return narrowTypeByOptionality(type, expr, assumeTrue); } @@ -26190,7 +34464,10 @@ namespace ts { const symbol = getResolvedSymbol(expr as Identifier); if (isConstVariable(symbol)) { const declaration = symbol.valueDeclaration; - if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isConstantReference(reference)) { + if ( + declaration && isVariableDeclaration(declaration) && !declaration.type + && declaration.initializer && isConstantReference(reference) + ) { inlineLevel++; const result = narrowType(type, declaration.initializer, assumeTrue); inlineLevel--; @@ -26208,7 +34485,11 @@ namespace ts { return narrowTypeByCallExpression(type, expr as CallExpression, assumeTrue); case SyntaxKind.ParenthesizedExpression: case SyntaxKind.NonNullExpression: - return narrowType(type, (expr as ParenthesizedExpression | NonNullExpression).expression, assumeTrue); + return narrowType( + type, + (expr as ParenthesizedExpression | NonNullExpression).expression, + assumeTrue, + ); case SyntaxKind.BinaryExpression: return narrowTypeByBinaryExpression(type, expr as BinaryExpression, assumeTrue); case SyntaxKind.PrefixUnaryExpression: @@ -26222,11 +34503,21 @@ namespace ts { function narrowTypeByOptionality(type: Type, expr: Expression, assumePresent: boolean): Type { if (isMatchingReference(reference, expr)) { - return getAdjustedTypeWithFacts(type, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull); + return getAdjustedTypeWithFacts( + type, + assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull, + ); } const access = getDiscriminantPropertyAccess(expr, type); if (access) { - return narrowTypeByDiscriminant(type, access, t => getTypeWithFacts(t, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull)); + return narrowTypeByDiscriminant( + type, + access, + t => getTypeWithFacts( + t, + assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull, + ), + ); } return type; } @@ -26250,7 +34541,10 @@ namespace ts { } } } - if (isDeclarationName(location) && isSetAccessor(location.parent) && getAnnotatedAccessorTypeNode(location.parent)) { + if ( + isDeclarationName(location) && isSetAccessor(location.parent) + && getAnnotatedAccessorTypeNode(location.parent) + ) { return getWriteTypeOfAccessors(location.parent.symbol); } // The location isn't a reference to the given symbol, meaning we're being asked @@ -26262,11 +34556,14 @@ namespace ts { } function getControlFlowContainer(node: Node): Node { - return findAncestor(node.parent, node => - isFunctionLike(node) && !getImmediatelyInvokedFunctionExpression(node) || - node.kind === SyntaxKind.ModuleBlock || - node.kind === SyntaxKind.SourceFile || - node.kind === SyntaxKind.PropertyDeclaration)!; + return findAncestor( + node.parent, + node => + isFunctionLike(node) && !getImmediatelyInvokedFunctionExpression(node) + || node.kind === SyntaxKind.ModuleBlock + || node.kind === SyntaxKind.SourceFile + || node.kind === SyntaxKind.PropertyDeclaration, + )!; } // Check if a parameter or catch variable is assigned anywhere @@ -26286,7 +34583,12 @@ namespace ts { } function hasParentWithAssignmentsMarked(node: Node) { - return !!findAncestor(node.parent, node => (isFunctionLike(node) || isCatchClause(node)) && !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked)); + return !!findAncestor( + node.parent, + node => + (isFunctionLike(node) || isCatchClause(node)) + && !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked), + ); } function markNodeAssignments(node: Node) { @@ -26304,20 +34606,22 @@ namespace ts { } function isConstVariable(symbol: Symbol) { - return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0; + return symbol.flags & SymbolFlags.Variable + && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0; } /** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */ function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type { if (pushTypeResolution(declaration.symbol, TypeSystemPropertyName.DeclaredType)) { - const annotationIncludesUndefined = strictNullChecks && - declaration.kind === SyntaxKind.Parameter && - declaration.initializer && - getTypeFacts(declaredType) & TypeFacts.IsUndefined && - !(getTypeFacts(checkExpression(declaration.initializer)) & TypeFacts.IsUndefined); + const annotationIncludesUndefined = strictNullChecks + && declaration.kind === SyntaxKind.Parameter + && declaration.initializer + && getTypeFacts(declaredType) & TypeFacts.IsUndefined + && !(getTypeFacts(checkExpression(declaration.initializer)) & TypeFacts.IsUndefined); popTypeResolution(); - return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType; + return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) + : declaredType; } else { reportCircularityError(declaration.symbol); @@ -26330,23 +34634,29 @@ namespace ts { // In an element access obj[x], we consider obj to be in a constraint position, except when obj is of // a generic type without a nullable constraint and x is a generic type. This is because when both obj // and x are of generic types T and K, we want the resulting type to be T[K]. - return parent.kind === SyntaxKind.PropertyAccessExpression || - parent.kind === SyntaxKind.QualifiedName || - parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === node || - parent.kind === SyntaxKind.ElementAccessExpression && (parent as ElementAccessExpression).expression === node && - !(someType(type, isGenericTypeWithoutNullableConstraint) && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression))); + return parent.kind === SyntaxKind.PropertyAccessExpression + || parent.kind === SyntaxKind.QualifiedName + || parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === node + || parent.kind === SyntaxKind.ElementAccessExpression + && (parent as ElementAccessExpression).expression === node + && !(someType(type, isGenericTypeWithoutNullableConstraint) + && isGenericIndexType( + getTypeOfExpression((parent as ElementAccessExpression).argumentExpression), + )); } function isGenericTypeWithUnionConstraint(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? - some((type as IntersectionType).types, isGenericTypeWithUnionConstraint) : - !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); + return type.flags & TypeFlags.Intersection + ? some((type as IntersectionType).types, isGenericTypeWithUnionConstraint) + : !!(type.flags & TypeFlags.Instantiable + && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); } function isGenericTypeWithoutNullableConstraint(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? - some((type as IntersectionType).types, isGenericTypeWithoutNullableConstraint) : - !!(type.flags & TypeFlags.Instantiable && !maybeTypeOfKind(getBaseConstraintOrType(type), TypeFlags.Nullable)); + return type.flags & TypeFlags.Intersection + ? some((type as IntersectionType).types, isGenericTypeWithoutNullableConstraint) + : !!(type.flags & TypeFlags.Instantiable + && !maybeTypeOfKind(getBaseConstraintOrType(type), TypeFlags.Nullable)); } function hasContextualTypeWithNoGenericTypes(node: Node, checkMode: CheckMode | undefined) { @@ -26354,10 +34664,12 @@ namespace ts { // element's tag name, so we exclude that here to avoid circularities. // If check mode has `CheckMode.RestBindingElement`, we skip binding pattern contextual types, // as we want the type of a rest element to be generic when possible. - const contextualType = (isIdentifier(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node)) && - !((isJsxOpeningElement(node.parent) || isJsxSelfClosingElement(node.parent)) && node.parent.tagName === node) && - (checkMode && checkMode & CheckMode.RestBindingElement ? - getContextualType(node, ContextFlags.SkipBindingPatterns) + const contextualType = + (isIdentifier(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node)) + && !((isJsxOpeningElement(node.parent) || isJsxSelfClosingElement(node.parent)) + && node.parent.tagName === node) + && (checkMode && checkMode & CheckMode.RestBindingElement + ? getContextualType(node, ContextFlags.SkipBindingPatterns) : getContextualType(node, /*contextFlags*/ undefined)); return contextualType && !isGenericType(contextualType); } @@ -26370,9 +34682,9 @@ namespace ts { // control flow analysis an opportunity to narrow it further. For example, for a reference of a type // parameter type 'T extends string | undefined' with a contextual type 'string', we substitute // 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'. - const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) && - someType(type, isGenericTypeWithUnionConstraint) && - (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); + const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) + && someType(type, isGenericTypeWithUnionConstraint) + && (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); return substituteConstraints ? mapType(type, getBaseConstraintOrType) : type; } @@ -26393,16 +34705,19 @@ namespace ts { } function markAliasReferenced(symbol: Symbol, location: Node) { - if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)) { + if ( + isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) + && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value) + ) { const target = resolveAlias(symbol); if (getAllSymbolFlags(target) & SymbolFlags.Value) { // An alias resolving to a const enum cannot be elided if (1) 'isolatedModules' is enabled // (because the const enum value will not be inlined), or if (2) the alias is an export // of a const enum declaration that will be preserved. if ( - compilerOptions.isolatedModules || - shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(location) || - !isConstEnumOrConstEnumOnlyModule(target) + compilerOptions.isolatedModules + || shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(location) + || !isConstEnumOrConstEnumOnlyModule(target) ) { markAliasSymbolAsReferenced(symbol); } @@ -26439,18 +34754,34 @@ namespace ts { // the binding pattern AST instance for '{ kind, payload }' as a pseudo-reference and narrow this reference // as if it occurred in the specified location. We then recompute the narrowed binding element type by // destructuring from the narrowed parent type. - if (isBindingElement(declaration) && !declaration.initializer && !declaration.dotDotDotToken && declaration.parent.elements.length >= 2) { + if ( + isBindingElement(declaration) && !declaration.initializer && !declaration.dotDotDotToken + && declaration.parent.elements.length >= 2 + ) { const parent = declaration.parent.parent; - if (parent.kind === SyntaxKind.VariableDeclaration && getCombinedNodeFlags(declaration) & NodeFlags.Const || parent.kind === SyntaxKind.Parameter) { + if ( + parent.kind === SyntaxKind.VariableDeclaration + && getCombinedNodeFlags(declaration) & NodeFlags.Const + || parent.kind === SyntaxKind.Parameter + ) { const links = getNodeLinks(parent); if (!(links.flags & NodeCheckFlags.InCheckIdentifier)) { links.flags |= NodeCheckFlags.InCheckIdentifier; const parentType = getTypeForBindingElementParent(parent, CheckMode.Normal); const parentTypeConstraint = parentType && mapType(parentType, getBaseConstraintOrType); links.flags &= ~NodeCheckFlags.InCheckIdentifier; - if (parentTypeConstraint && parentTypeConstraint.flags & TypeFlags.Union && !(parent.kind === SyntaxKind.Parameter && isSymbolAssigned(symbol))) { + if ( + parentTypeConstraint && parentTypeConstraint.flags & TypeFlags.Union + && !(parent.kind === SyntaxKind.Parameter && isSymbolAssigned(symbol)) + ) { const pattern = declaration.parent; - const narrowedType = getFlowTypeOfReference(pattern, parentTypeConstraint, parentTypeConstraint, /*flowContainer*/ undefined, location.flowNode); + const narrowedType = getFlowTypeOfReference( + pattern, + parentTypeConstraint, + parentTypeConstraint, + /*flowContainer*/ undefined, + location.flowNode, + ); if (narrowedType.flags & TypeFlags.Never) { return neverType; } @@ -26479,14 +34810,29 @@ namespace ts { // the arrow function AST node for '(kind, payload) => ...' as a pseudo-reference and narrow this reference as // if it occurred in the specified location. We then recompute the narrowed parameter type by indexing into the // narrowed tuple type. - if (isParameter(declaration) && !declaration.type && !declaration.initializer && !declaration.dotDotDotToken) { + if ( + isParameter(declaration) && !declaration.type && !declaration.initializer + && !declaration.dotDotDotToken + ) { const func = declaration.parent; if (func.parameters.length >= 2 && isContextSensitiveFunctionOrObjectLiteralMethod(func)) { const contextualSignature = getContextualSignature(func); - if (contextualSignature && contextualSignature.parameters.length === 1 && signatureHasRestParameter(contextualSignature)) { + if ( + contextualSignature && contextualSignature.parameters.length === 1 + && signatureHasRestParameter(contextualSignature) + ) { const restType = getReducedApparentType(getTypeOfSymbol(contextualSignature.parameters[0])); - if (restType.flags & TypeFlags.Union && everyType(restType, isTupleType) && !isSymbolAssigned(symbol)) { - const narrowedType = getFlowTypeOfReference(func, restType, restType, /*flowContainer*/ undefined, location.flowNode); + if ( + restType.flags & TypeFlags.Union && everyType(restType, isTupleType) + && !isSymbolAssigned(symbol) + ) { + const narrowedType = getFlowTypeOfReference( + func, + restType, + restType, + /*flowContainer*/ undefined, + location.flowNode, + ); const index = func.parameters.indexOf(declaration) - (getThisParameter(func) ? 1 : 0); return getIndexedAccessType(narrowedType, getNumberLiteralType(index)); } @@ -26522,10 +34868,18 @@ namespace ts { const container = getContainingFunction(node)!; if (languageVersion < ScriptTarget.ES2015) { if (container.kind === SyntaxKind.ArrowFunction) { - error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression); + error( + node, + Diagnostics + .The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression, + ); } else if (hasSyntacticModifier(container, ModifierFlags.Async)) { - error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_async_function_or_method_in_ES3_and_ES5_Consider_using_a_standard_function_or_method); + error( + node, + Diagnostics + .The_arguments_object_cannot_be_referenced_in_an_async_function_or_method_in_ES3_and_ES5_Consider_using_a_standard_function_or_method, + ); } } @@ -26539,7 +34893,10 @@ namespace ts { const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); const targetSymbol = checkDeprecatedAliasedSymbol(localOrExportSymbol, node); - if (isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) && targetSymbol.declarations) { + if ( + isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) + && targetSymbol.declarations + ) { addDeprecatedSuggestion(node, targetSymbol.declarations, node.escapedText as string); } @@ -26570,7 +34927,10 @@ namespace ts { let container = getThisContainer(node, /*includeArrowFunctions*/ false); while (container.kind !== SyntaxKind.SourceFile) { if (container.parent === declaration) { - if (isPropertyDeclaration(container) && isStatic(container) || isClassStaticBlockDeclaration(container)) { + if ( + isPropertyDeclaration(container) && isStatic(container) + || isClassStaticBlockDeclaration(container) + ) { getNodeLinks(declaration).flags |= NodeCheckFlags.ClassWithConstructorReference; getNodeLinks(node).flags |= NodeCheckFlags.ConstructorReferenceInClass; } @@ -26589,14 +34949,19 @@ namespace ts { if (assignmentKind) { if ( - !(localOrExportSymbol.flags & SymbolFlags.Variable) && - !(isInJSFile(node) && localOrExportSymbol.flags & SymbolFlags.ValueModule) + !(localOrExportSymbol.flags & SymbolFlags.Variable) + && !(isInJSFile(node) && localOrExportSymbol.flags & SymbolFlags.ValueModule) ) { - const assignmentError = localOrExportSymbol.flags & SymbolFlags.Enum ? Diagnostics.Cannot_assign_to_0_because_it_is_an_enum - : localOrExportSymbol.flags & SymbolFlags.Class ? Diagnostics.Cannot_assign_to_0_because_it_is_a_class - : localOrExportSymbol.flags & SymbolFlags.Module ? Diagnostics.Cannot_assign_to_0_because_it_is_a_namespace - : localOrExportSymbol.flags & SymbolFlags.Function ? Diagnostics.Cannot_assign_to_0_because_it_is_a_function - : localOrExportSymbol.flags & SymbolFlags.Alias ? Diagnostics.Cannot_assign_to_0_because_it_is_an_import + const assignmentError = localOrExportSymbol.flags & SymbolFlags.Enum + ? Diagnostics.Cannot_assign_to_0_because_it_is_an_enum + : localOrExportSymbol.flags & SymbolFlags.Class + ? Diagnostics.Cannot_assign_to_0_because_it_is_a_class + : localOrExportSymbol.flags & SymbolFlags.Module + ? Diagnostics.Cannot_assign_to_0_because_it_is_a_namespace + : localOrExportSymbol.flags & SymbolFlags.Function + ? Diagnostics.Cannot_assign_to_0_because_it_is_a_function + : localOrExportSymbol.flags & SymbolFlags.Alias + ? Diagnostics.Cannot_assign_to_0_because_it_is_an_import : Diagnostics.Cannot_assign_to_0_because_it_is_not_a_variable; error(node, assignmentError, symbolToString(symbol)); @@ -26607,7 +34972,11 @@ namespace ts { error(node, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant, symbolToString(symbol)); } else { - error(node, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(symbol)); + error( + node, + Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, + symbolToString(symbol), + ); } return errorType; } @@ -26642,30 +35011,37 @@ namespace ts { const declarationContainer = getControlFlowContainer(declaration); let flowContainer = getControlFlowContainer(node); const isOuterVariable = flowContainer !== declarationContainer; - const isSpreadDestructuringAssignmentTarget = node.parent && node.parent.parent && isSpreadAssignment(node.parent) && isDestructuringAssignmentTarget(node.parent.parent); + const isSpreadDestructuringAssignmentTarget = node.parent && node.parent.parent + && isSpreadAssignment(node.parent) && isDestructuringAssignmentTarget(node.parent.parent); const isModuleExports = symbol.flags & SymbolFlags.ModuleExports; // When the control flow originates in a function expression or arrow function and we are referencing // a const variable or parameter from an outer function, we extend the origin of the control flow // analysis to include the immediately enclosing function. while ( - flowContainer !== declarationContainer && (flowContainer.kind === SyntaxKind.FunctionExpression || - flowContainer.kind === SyntaxKind.ArrowFunction || isObjectLiteralOrClassExpressionMethodOrAccessor(flowContainer)) && - (isConstVariable(localOrExportSymbol) && type !== autoArrayType || isParameter && !isSymbolAssigned(localOrExportSymbol)) + flowContainer !== declarationContainer && (flowContainer.kind === SyntaxKind.FunctionExpression + || flowContainer.kind === SyntaxKind.ArrowFunction + || isObjectLiteralOrClassExpressionMethodOrAccessor(flowContainer)) + && (isConstVariable(localOrExportSymbol) && type !== autoArrayType + || isParameter && !isSymbolAssigned(localOrExportSymbol)) ) { flowContainer = getControlFlowContainer(flowContainer); } // We only look for uninitialized variables in strict null checking mode, and only when we can analyze // the entire control flow graph from the variable's declaration (i.e. when the flow container and // declaration container are the same). - const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget || isModuleExports || isBindingElement(declaration) || - type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 || - isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || - node.parent.kind === SyntaxKind.NonNullExpression || - declaration.kind === SyntaxKind.VariableDeclaration && (declaration as VariableDeclaration).exclamationToken || - declaration.flags & NodeFlags.Ambient; - const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) : - type === autoType || type === autoArrayType ? undefinedType : - getOptionalType(type); + const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget + || isModuleExports || isBindingElement(declaration) + || type !== autoType && type !== autoArrayType + && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 + || isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) + || node.parent.kind === SyntaxKind.NonNullExpression + || declaration.kind === SyntaxKind.VariableDeclaration + && (declaration as VariableDeclaration).exclamationToken + || declaration.flags & NodeFlags.Ambient; + const initialType = assumeInitialized + ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) + : type === autoType || type === autoArrayType ? undefinedType + : getOptionalType(type); const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer); // A variable is considered uninitialized when it is possible to analyze the entire control flow graph // from declaration to use, and when the variable's declared type doesn't include undefined but the @@ -26673,8 +35049,19 @@ namespace ts { if (!isEvolvingArrayOperationTarget(node) && (type === autoType || type === autoArrayType)) { if (flowType === autoType || flowType === autoArrayType) { if (noImplicitAny) { - error(getNameOfDeclaration(declaration), Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol), typeToString(flowType)); - error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); + error( + getNameOfDeclaration(declaration), + Diagnostics + .Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, + symbolToString(symbol), + typeToString(flowType), + ); + error( + node, + Diagnostics.Variable_0_implicitly_has_an_1_type, + symbolToString(symbol), + typeToString(flowType), + ); } return convertAutoToAny(flowType); } @@ -26709,25 +35096,35 @@ namespace ts { function isInsideFunctionOrInstancePropertyInitializer(node: Node, threshold: Node): boolean { return !!findAncestor(node, n => n === threshold ? "quit" : isFunctionLike(n) || ( - n.parent && isPropertyDeclaration(n.parent) && !hasStaticModifier(n.parent) && n.parent.initializer === n + n.parent && isPropertyDeclaration(n.parent) && !hasStaticModifier(n.parent) + && n.parent.initializer === n )); } function getPartOfForStatementContainingNode(node: Node, container: ForStatement) { - return findAncestor(node, n => n === container ? "quit" : n === container.initializer || n === container.condition || n === container.incrementor || n === container.statement); + return findAncestor( + node, + n => n === container ? "quit" + : n === container.initializer || n === container.condition || n === container.incrementor + || n === container.statement, + ); } function getEnclosingIterationStatement(node: Node): Node | undefined { - return findAncestor(node, n => (!n || nodeStartsNewLexicalEnvironment(n)) ? "quit" : isIterationStatement(n, /*lookInLabeledStatements*/ false)); + return findAncestor( + node, + n => (!n || nodeStartsNewLexicalEnvironment(n)) ? "quit" + : isIterationStatement(n, /*lookInLabeledStatements*/ false), + ); } function checkNestedBlockScopedBinding(node: Identifier, symbol: Symbol): void { if ( - languageVersion >= ScriptTarget.ES2015 || - (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === 0 || - !symbol.valueDeclaration || - isSourceFile(symbol.valueDeclaration) || - symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause + languageVersion >= ScriptTarget.ES2015 + || (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === 0 + || !symbol.valueDeclaration + || isSourceFile(symbol.valueDeclaration) + || symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause ) { return; } @@ -26753,7 +35150,8 @@ namespace ts { const links = getNodeLinks(part); links.flags |= NodeCheckFlags.ContainsCapturedBlockScopeBinding; - const capturedBindings = links.capturedBlockScopeBindings || (links.capturedBlockScopeBindings = []); + const capturedBindings = links.capturedBlockScopeBindings + || (links.capturedBlockScopeBindings = []); pushIfUnique(capturedBindings, symbol); if (part === container.initializer) { @@ -26763,7 +35161,8 @@ namespace ts { } } if (capturesBlockScopeBindingInLoopBody) { - getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; + getNodeLinks(enclosingIterationStatement).flags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding; } } @@ -26771,7 +35170,10 @@ namespace ts { // if body of ForStatement will be converted to function then we'll need a extra machinery to propagate reassigned values back. if (isForStatement(container)) { const varDeclList = getAncestor(symbol.valueDeclaration, SyntaxKind.VariableDeclarationList); - if (varDeclList && varDeclList.parent === container && isAssignedInBodyOfForStatement(node, container)) { + if ( + varDeclList && varDeclList.parent === container + && isAssignedInBodyOfForStatement(node, container) + ) { getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.NeedsLoopOutParameter; } } @@ -26802,7 +35204,10 @@ namespace ts { if (isAssignmentTarget(current)) { isAssigned = true; } - else if ((current.parent.kind === SyntaxKind.PrefixUnaryExpression || current.parent.kind === SyntaxKind.PostfixUnaryExpression)) { + else if ( + (current.parent.kind === SyntaxKind.PrefixUnaryExpression + || current.parent.kind === SyntaxKind.PostfixUnaryExpression) + ) { const expr = current.parent as PrefixUnaryExpression | PostfixUnaryExpression; isAssigned = expr.operator === SyntaxKind.PlusPlusToken || expr.operator === SyntaxKind.MinusMinusToken; } @@ -26828,9 +35233,9 @@ namespace ts { } function findFirstSuperCall(node: Node): SuperCall | undefined { - return isSuperCall(node) ? node : - isFunctionLike(node) ? undefined : - forEachChild(node, findFirstSuperCall); + return isSuperCall(node) ? node + : isFunctionLike(node) ? undefined + : forEachChild(node, findFirstSuperCall); } /** @@ -26861,10 +35266,15 @@ namespace ts { function checkThisInStaticClassFieldInitializerInDecoratedClass(thisExpression: Node, container: Node) { if ( - isPropertyDeclaration(container) && hasStaticModifier(container) && - container.initializer && textRangeContainsPositionInclusive(container.initializer, thisExpression.pos) && hasDecorators(container.parent) + isPropertyDeclaration(container) && hasStaticModifier(container) + && container.initializer + && textRangeContainsPositionInclusive(container.initializer, thisExpression.pos) + && hasDecorators(container.parent) ) { - error(thisExpression, Diagnostics.Cannot_use_this_in_a_static_property_initializer_of_a_decorated_class); + error( + thisExpression, + Diagnostics.Cannot_use_this_in_a_static_property_initializer_of_a_decorated_class, + ); } } @@ -26876,7 +35286,11 @@ namespace ts { let capturedByArrowFunction = false; if (container.kind === SyntaxKind.Constructor) { - checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class); + checkThisBeforeSuper( + node, + container, + Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class, + ); } // Now skip arrow functions to get the "real" owner of 'this'. @@ -26919,11 +35333,20 @@ namespace ts { } else if (!type) { // With noImplicitThis, functions may not reference 'this' if it has type 'any' - const diag = error(node, Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation); + const diag = error( + node, + Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation, + ); if (!isSourceFile(container)) { const outsideThis = tryGetThisTypeAt(container); if (outsideThis && outsideThis !== globalThisType) { - addRelatedInfo(diag, createDiagnosticForNode(container, Diagnostics.An_outer_value_of_this_is_shadowed_by_this_container)); + addRelatedInfo( + diag, + createDiagnosticForNode( + container, + Diagnostics.An_outer_value_of_this_is_shadowed_by_this_container, + ), + ); } } } @@ -26931,13 +35354,18 @@ namespace ts { return type || anyType; } - function tryGetThisTypeAt(node: Node, includeGlobalThis = true, container = getThisContainer(node, /*includeArrowFunctions*/ false)): Type | undefined { + function tryGetThisTypeAt( + node: Node, + includeGlobalThis = true, + container = getThisContainer(node, /*includeArrowFunctions*/ false), + ): Type | undefined { const isInJS = isInJSFile(node); if ( - isFunctionLike(container) && - (!isInParameterInitializerBeforeContainingFunction(node) || getThisParameter(container)) + isFunctionLike(container) + && (!isInParameterInitializerBeforeContainingFunction(node) || getThisParameter(container)) ) { - let thisType = getThisTypeOfDeclaration(container) || isInJS && getTypeForThisExpressionFromJSDoc(container); + let thisType = getThisTypeOfDeclaration(container) + || isInJS && getTypeForThisExpressionFromJSDoc(container); // Note: a parameter initializer should refer to class-this unless function-this is explicitly annotated. // If this is a function in a JS file, it might be a class method. if (!thisType) { @@ -26949,7 +35377,8 @@ namespace ts { } } else if (isJSConstructor(container)) { - thisType = (getDeclaredTypeOfSymbol(getMergedSymbol(container.symbol)) as InterfaceType).thisType; + thisType = + (getDeclaredTypeOfSymbol(getMergedSymbol(container.symbol)) as InterfaceType).thisType; } thisType ||= getContextualThisParameterType(container); } @@ -26961,7 +35390,8 @@ namespace ts { if (isClassLike(container.parent)) { const symbol = getSymbolOfNode(container.parent); - const type = isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; + const type = isStatic(container) ? getTypeOfSymbol(symbol) + : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; return getFlowTypeOfReference(node, type); } @@ -26991,16 +35421,17 @@ namespace ts { } if (isClassLike(container.parent)) { const symbol = getSymbolOfNode(container.parent); - return isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; + return isStatic(container) ? getTypeOfSymbol(symbol) + : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; } } function getClassNameFromPrototypeMethod(container: Node) { // Check if it's the RHS of a x.prototype.y = function [name]() { .... } if ( - container.kind === SyntaxKind.FunctionExpression && - isBinaryExpression(container.parent) && - getAssignmentDeclarationKind(container.parent) === AssignmentDeclarationKind.PrototypeProperty + container.kind === SyntaxKind.FunctionExpression + && isBinaryExpression(container.parent) + && getAssignmentDeclarationKind(container.parent) === AssignmentDeclarationKind.PrototypeProperty ) { // Get the 'x' of 'x.prototype.y = container' return ((container.parent // x.prototype.y = container @@ -27010,20 +35441,20 @@ namespace ts { } // x.prototype = { method() { } } else if ( - container.kind === SyntaxKind.MethodDeclaration && - container.parent.kind === SyntaxKind.ObjectLiteralExpression && - isBinaryExpression(container.parent.parent) && - getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.Prototype + container.kind === SyntaxKind.MethodDeclaration + && container.parent.kind === SyntaxKind.ObjectLiteralExpression + && isBinaryExpression(container.parent.parent) + && getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.Prototype ) { return (container.parent.parent.left as PropertyAccessExpression).expression; } // x.prototype = { method: function() { } } else if ( - container.kind === SyntaxKind.FunctionExpression && - container.parent.kind === SyntaxKind.PropertyAssignment && - container.parent.parent.kind === SyntaxKind.ObjectLiteralExpression && - isBinaryExpression(container.parent.parent.parent) && - getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.Prototype + container.kind === SyntaxKind.FunctionExpression + && container.parent.kind === SyntaxKind.PropertyAssignment + && container.parent.parent.kind === SyntaxKind.ObjectLiteralExpression + && isBinaryExpression(container.parent.parent.parent) + && getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.Prototype ) { return (container.parent.parent.parent.left as PropertyAccessExpression).expression; } @@ -27031,14 +35462,16 @@ namespace ts { // Object.defineProperty(x, "method", { set: (x: () => void) => void }); // Object.defineProperty(x, "method", { get: () => function() { }) }); else if ( - container.kind === SyntaxKind.FunctionExpression && - isPropertyAssignment(container.parent) && - isIdentifier(container.parent.name) && - (container.parent.name.escapedText === "value" || container.parent.name.escapedText === "get" || container.parent.name.escapedText === "set") && - isObjectLiteralExpression(container.parent.parent) && - isCallExpression(container.parent.parent.parent) && - container.parent.parent.parent.arguments[2] === container.parent.parent && - getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty + container.kind === SyntaxKind.FunctionExpression + && isPropertyAssignment(container.parent) + && isIdentifier(container.parent.name) + && (container.parent.name.escapedText === "value" || container.parent.name.escapedText === "get" + || container.parent.name.escapedText === "set") + && isObjectLiteralExpression(container.parent.parent) + && isCallExpression(container.parent.parent.parent) + && container.parent.parent.parent.arguments[2] === container.parent.parent + && getAssignmentDeclarationKind(container.parent.parent.parent) + === AssignmentDeclarationKind.ObjectDefinePrototypeProperty ) { return (container.parent.parent.parent.arguments[0] as PropertyAccessExpression).expression; } @@ -27046,13 +35479,15 @@ namespace ts { // Object.defineProperty(x, "method", { set(x: () => void) {} }); // Object.defineProperty(x, "method", { get() { return () => {} } }); else if ( - isMethodDeclaration(container) && - isIdentifier(container.name) && - (container.name.escapedText === "value" || container.name.escapedText === "get" || container.name.escapedText === "set") && - isObjectLiteralExpression(container.parent) && - isCallExpression(container.parent.parent) && - container.parent.parent.arguments[2] === container.parent && - getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty + isMethodDeclaration(container) + && isIdentifier(container.name) + && (container.name.escapedText === "value" || container.name.escapedText === "get" + || container.name.escapedText === "set") + && isObjectLiteralExpression(container.parent) + && isCallExpression(container.parent.parent) + && container.parent.parent.arguments[2] === container.parent + && getAssignmentDeclarationKind(container.parent.parent) + === AssignmentDeclarationKind.ObjectDefinePrototypeProperty ) { return (container.parent.parent.arguments[0] as PropertyAccessExpression).expression; } @@ -27063,9 +35498,9 @@ namespace ts { if (jsdocType && jsdocType.kind === SyntaxKind.JSDocFunctionType) { const jsDocFunctionType = jsdocType as JSDocFunctionType; if ( - jsDocFunctionType.parameters.length > 0 && - jsDocFunctionType.parameters[0].name && - (jsDocFunctionType.parameters[0].name as Identifier).escapedText === InternalSymbolName.This + jsDocFunctionType.parameters.length > 0 + && jsDocFunctionType.parameters[0].name + && (jsDocFunctionType.parameters[0].name as Identifier).escapedText === InternalSymbolName.This ) { return getTypeFromTypeNode(jsDocFunctionType.parameters[0].type!); } @@ -27077,11 +35512,16 @@ namespace ts { } function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean { - return !!findAncestor(node, n => isFunctionLikeDeclaration(n) ? "quit" : n.kind === SyntaxKind.Parameter && n.parent === constructorDecl); + return !!findAncestor( + node, + n => isFunctionLikeDeclaration(n) ? "quit" + : n.kind === SyntaxKind.Parameter && n.parent === constructorDecl, + ); } function checkSuperExpression(node: Node): Type { - const isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (node.parent as CallExpression).expression === node; + const isCallExpression = node.parent.kind === SyntaxKind.CallExpression + && (node.parent as CallExpression).expression === node; const immediateContainer = getSuperContainer(node, /*stopOnFunctions*/ true); let container = immediateContainer; @@ -27104,32 +35544,55 @@ namespace ts { // class B { // [super.foo()]() {} // } - const current = findAncestor(node, n => n === container ? "quit" : n.kind === SyntaxKind.ComputedPropertyName); + const current = findAncestor( + node, + n => n === container ? "quit" : n.kind === SyntaxKind.ComputedPropertyName, + ); if (current && current.kind === SyntaxKind.ComputedPropertyName) { error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); } else if (isCallExpression) { - error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); + error( + node, + Diagnostics + .Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors, + ); } - else if (!container || !container.parent || !(isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression)) { - error(node, Diagnostics.super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions); + else if ( + !container || !container.parent + || !(isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) + ) { + error( + node, + Diagnostics + .super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions, + ); } else { - error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); + error( + node, + Diagnostics + .super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class, + ); } return errorType; } if (!isCallExpression && immediateContainer.kind === SyntaxKind.Constructor) { - checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class); + checkThisBeforeSuper( + node, + container, + Diagnostics + .super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class, + ); } if (isStatic(container) || isCallExpression) { nodeCheckFlag = NodeCheckFlags.SuperStatic; if ( - !isCallExpression && - languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 && - (isPropertyDeclaration(container) || isClassStaticBlockDeclaration(container)) + !isCallExpression + && languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 + && (isPropertyDeclaration(container) || isClassStaticBlockDeclaration(container)) ) { // for `super.x` or `super[x]` in a static initializer, mark all enclosing // block scope containers so that we can report potential collisions with @@ -27206,7 +35669,9 @@ namespace ts { // as a call expression cannot be used as the target of a destructuring assignment while a property access can. // // For element access expressions (`super[x]`), we emit a generic helper that forwards the element access in both situations. - if (container.kind === SyntaxKind.MethodDeclaration && hasSyntacticModifier(container, ModifierFlags.Async)) { + if ( + container.kind === SyntaxKind.MethodDeclaration && hasSyntacticModifier(container, ModifierFlags.Async) + ) { if (isSuperProperty(node.parent) && isAssignmentTarget(node.parent)) { getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuperBinding; } @@ -27224,7 +35689,11 @@ namespace ts { if (container.parent.kind === SyntaxKind.ObjectLiteralExpression) { if (languageVersion < ScriptTarget.ES2015) { - error(node, Diagnostics.super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher); + error( + node, + Diagnostics + .super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher, + ); return errorType; } else { @@ -27275,21 +35744,21 @@ namespace ts { // topmost container must be something that is directly nested in the class declaration\object literal expression if (isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) { if (isStatic(container)) { - return container.kind === SyntaxKind.MethodDeclaration || - container.kind === SyntaxKind.MethodSignature || - container.kind === SyntaxKind.GetAccessor || - container.kind === SyntaxKind.SetAccessor || - container.kind === SyntaxKind.PropertyDeclaration || - container.kind === SyntaxKind.ClassStaticBlockDeclaration; + return container.kind === SyntaxKind.MethodDeclaration + || container.kind === SyntaxKind.MethodSignature + || container.kind === SyntaxKind.GetAccessor + || container.kind === SyntaxKind.SetAccessor + || container.kind === SyntaxKind.PropertyDeclaration + || container.kind === SyntaxKind.ClassStaticBlockDeclaration; } else { - return container.kind === SyntaxKind.MethodDeclaration || - container.kind === SyntaxKind.MethodSignature || - container.kind === SyntaxKind.GetAccessor || - container.kind === SyntaxKind.SetAccessor || - container.kind === SyntaxKind.PropertyDeclaration || - container.kind === SyntaxKind.PropertySignature || - container.kind === SyntaxKind.Constructor; + return container.kind === SyntaxKind.MethodDeclaration + || container.kind === SyntaxKind.MethodSignature + || container.kind === SyntaxKind.GetAccessor + || container.kind === SyntaxKind.SetAccessor + || container.kind === SyntaxKind.PropertyDeclaration + || container.kind === SyntaxKind.PropertySignature + || container.kind === SyntaxKind.Constructor; } } } @@ -27299,20 +35768,24 @@ namespace ts { } function getContainingObjectLiteral(func: SignatureDeclaration): ObjectLiteralExpression | undefined { - return (func.kind === SyntaxKind.MethodDeclaration || - func.kind === SyntaxKind.GetAccessor || - func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression ? func.parent : - func.kind === SyntaxKind.FunctionExpression && func.parent.kind === SyntaxKind.PropertyAssignment ? func.parent.parent as ObjectLiteralExpression : - undefined; + return (func.kind === SyntaxKind.MethodDeclaration + || func.kind === SyntaxKind.GetAccessor + || func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression + ? func.parent + : func.kind === SyntaxKind.FunctionExpression && func.parent.kind === SyntaxKind.PropertyAssignment + ? func.parent.parent as ObjectLiteralExpression + : undefined; } function getThisTypeArgument(type: Type): Type | undefined { - return getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target === globalThisType ? getTypeArguments(type as TypeReference)[0] : undefined; + return getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target === globalThisType + ? getTypeArguments(type as TypeReference)[0] : undefined; } function getThisTypeFromContextualType(type: Type): Type | undefined { return mapType(type, t => { - return t.flags & TypeFlags.Intersection ? forEach((t as IntersectionType).types, getThisTypeArgument) : getThisTypeArgument(t); + return t.flags & TypeFlags.Intersection ? forEach((t as IntersectionType).types, getThisTypeArgument) + : getThisTypeArgument(t); }); } @@ -27336,13 +35809,19 @@ namespace ts { // We have an object literal method. Check if the containing object literal has a contextual type // that includes a ThisType. If so, T is the contextual type for 'this'. We continue looking in // any directly enclosing object literals. - const contextualType = getApparentTypeOfContextualType(containingLiteral, /*contextFlags*/ undefined); + const contextualType = getApparentTypeOfContextualType( + containingLiteral, + /*contextFlags*/ undefined, + ); let literal = containingLiteral; let type = contextualType; while (type) { const thisType = getThisTypeFromContextualType(type); if (thisType) { - return instantiateType(thisType, getMapperFromContext(getInferenceContext(containingLiteral))); + return instantiateType( + thisType, + getMapperFromContext(getInferenceContext(containingLiteral)), + ); } if (literal.parent.kind !== SyntaxKind.PropertyAssignment) { break; @@ -27353,19 +35832,27 @@ namespace ts { // There was no contextual ThisType for the containing object literal, so the contextual type // for 'this' is the non-null form of the contextual type for the containing object literal or // the type of the object literal itself. - return getWidenedType(contextualType ? getNonNullableType(contextualType) : checkExpressionCached(containingLiteral)); + return getWidenedType( + contextualType ? getNonNullableType(contextualType) : checkExpressionCached(containingLiteral), + ); } // In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the // contextual type for 'this' is 'obj'. const parent = walkUpParenthesizedExpressions(func.parent); - if (parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + parent.kind === SyntaxKind.BinaryExpression + && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { const target = (parent as BinaryExpression).left; if (isAccessExpression(target)) { const { expression } = target; // Don't contextually type `this` as `exports` in `exports.Point = function(x, y) { this.x = x; this.y = y; }` if (inJs && isIdentifier(expression)) { const sourceFile = getSourceFileOfNode(parent); - if (sourceFile.commonJsModuleIndicator && getResolvedSymbol(expression) === sourceFile.symbol) { + if ( + sourceFile.commonJsModuleIndicator + && getResolvedSymbol(expression) === sourceFile.symbol + ) { return undefined; } } @@ -27388,27 +35875,37 @@ namespace ts { const args = getEffectiveCallArguments(iife); const indexOfParameter = func.parameters.indexOf(parameter); if (parameter.dotDotDotToken) { - return getSpreadArgumentType(args, indexOfParameter, args.length, anyType, /*context*/ undefined, CheckMode.Normal); + return getSpreadArgumentType( + args, + indexOfParameter, + args.length, + anyType, + /*context*/ undefined, + CheckMode.Normal, + ); } const links = getNodeLinks(iife); const cached = links.resolvedSignature; links.resolvedSignature = anySignature; - const type = indexOfParameter < args.length ? - getWidenedLiteralType(checkExpression(args[indexOfParameter])) : - parameter.initializer ? undefined : undefinedWideningType; + const type = indexOfParameter < args.length + ? getWidenedLiteralType(checkExpression(args[indexOfParameter])) + : parameter.initializer ? undefined : undefinedWideningType; links.resolvedSignature = cached; return type; } const contextualSignature = getContextualSignature(func); if (contextualSignature) { const index = func.parameters.indexOf(parameter) - (getThisParameter(func) ? 1 : 0); - return parameter.dotDotDotToken && lastOrUndefined(func.parameters) === parameter ? - getRestTypeAtPosition(contextualSignature, index) : - tryGetTypeAtPosition(contextualSignature, index); + return parameter.dotDotDotToken && lastOrUndefined(func.parameters) === parameter + ? getRestTypeAtPosition(contextualSignature, index) + : tryGetTypeAtPosition(contextualSignature, index); } } - function getContextualTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForVariableLikeDeclaration( + declaration: VariableLikeDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const typeNode = getEffectiveTypeAnnotationNode(declaration); if (typeNode) { return getTypeFromTypeNode(typeNode); @@ -27426,11 +35923,18 @@ namespace ts { } } - function getContextualTypeForBindingElement(declaration: BindingElement, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForBindingElement( + declaration: BindingElement, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const parent = declaration.parent.parent; const name = declaration.propertyName || declaration.name; - const parentType = getContextualTypeForVariableLikeDeclaration(parent, contextFlags) || - parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent, declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal); + const parentType = getContextualTypeForVariableLikeDeclaration(parent, contextFlags) + || parent.kind !== SyntaxKind.BindingElement && parent.initializer + && checkDeclarationInitializer( + parent, + declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal, + ); if (!parentType || isBindingPattern(name) || isComputedNonLiteralName(name)) return undefined; if (parent.name.kind === SyntaxKind.ArrayBindingPattern) { const index = indexOfNode(declaration.parent.elements, declaration); @@ -27444,7 +35948,10 @@ namespace ts { } } - function getContextualTypeForStaticPropertyDeclaration(declaration: PropertyDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForStaticPropertyDeclaration( + declaration: PropertyDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const parentType = isExpression(declaration.parent) && getContextualType(declaration.parent, contextFlags); if (!parentType) return undefined; return getTypeOfPropertyOfContextualType(parentType, getSymbolOfNode(declaration).escapedName); @@ -27458,21 +35965,34 @@ namespace ts { // the contextual type of an initializer expression is the type implied by the binding pattern. // Otherwise, in a binding pattern inside a variable or parameter declaration, // the contextual type of an initializer expression is the type annotation of the containing declaration, if present. - function getContextualTypeForInitializerExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForInitializerExpression( + node: Expression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const declaration = node.parent as VariableLikeDeclaration; if (hasInitializer(declaration) && node === declaration.initializer) { const result = getContextualTypeForVariableLikeDeclaration(declaration, contextFlags); if (result) { return result; } - if (!(contextFlags! & ContextFlags.SkipBindingPatterns) && isBindingPattern(declaration.name) && declaration.name.elements.length > 0) { - return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false); + if ( + !(contextFlags! & ContextFlags.SkipBindingPatterns) && isBindingPattern(declaration.name) + && declaration.name.elements.length > 0 + ) { + return getTypeFromBindingPattern( + declaration.name, + /*includePatternInType*/ true, + /*reportErrors*/ false, + ); } } return undefined; } - function getContextualTypeForReturnExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForReturnExpression( + node: Expression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const func = getContainingFunction(node); if (func) { let contextualReturnType = getContextualReturnType(func, contextFlags); @@ -27481,9 +36001,21 @@ namespace ts { if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0; if (contextualReturnType.flags & TypeFlags.Union) { - contextualReturnType = filterType(contextualReturnType, type => !!getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator)); + contextualReturnType = filterType( + contextualReturnType, + type => + !!getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + type, + isAsyncGenerator, + ), + ); } - const iterationReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, contextualReturnType, (functionFlags & FunctionFlags.Async) !== 0); + const iterationReturnType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + contextualReturnType, + (functionFlags & FunctionFlags.Async) !== 0, + ); if (!iterationReturnType) { return undefined; } @@ -27494,7 +36026,8 @@ namespace ts { if (functionFlags & FunctionFlags.Async) { // Async function or AsyncGenerator function // Get the awaited type without the `Awaited` alias const contextualAwaitedType = mapType(contextualReturnType, getAwaitedTypeNoAlias); - return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); + return contextualAwaitedType + && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); } return contextualReturnType; // Regular function or Generator function @@ -27503,16 +36036,23 @@ namespace ts { return undefined; } - function getContextualTypeForAwaitOperand(node: AwaitExpression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForAwaitOperand( + node: AwaitExpression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const contextualType = getContextualType(node, contextFlags); if (contextualType) { const contextualAwaitedType = getAwaitedTypeNoAlias(contextualType); - return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); + return contextualAwaitedType + && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); } return undefined; } - function getContextualTypeForYieldOperand(node: YieldExpression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForYieldOperand( + node: YieldExpression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const func = getContainingFunction(node); if (func) { const functionFlags = getFunctionFlags(func); @@ -27520,11 +36060,23 @@ namespace ts { if (contextualReturnType) { const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0; if (!node.asteriskToken && contextualReturnType.flags & TypeFlags.Union) { - contextualReturnType = filterType(contextualReturnType, type => !!getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator)); + contextualReturnType = filterType( + contextualReturnType, + type => + !!getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + type, + isAsyncGenerator, + ), + ); } return node.asteriskToken ? contextualReturnType - : getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, contextualReturnType, isAsyncGenerator); + : getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Yield, + contextualReturnType, + isAsyncGenerator, + ); } } @@ -27547,7 +36099,10 @@ namespace ts { return false; } - function getContextualIterationType(kind: IterationTypeKind, functionDecl: SignatureDeclaration): Type | undefined { + function getContextualIterationType( + kind: IterationTypeKind, + functionDecl: SignatureDeclaration, + ): Type | undefined { const isAsync = !!(getFunctionFlags(functionDecl) & FunctionFlags.Async); const contextualReturnType = getContextualReturnType(functionDecl, /*contextFlags*/ undefined); if (contextualReturnType) { @@ -27558,7 +36113,10 @@ namespace ts { return undefined; } - function getContextualReturnType(functionDecl: SignatureDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualReturnType( + functionDecl: SignatureDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { // If the containing function has a return type annotation, is a constructor, or is a get accessor whose // corresponding set accessor has a type annotation, return statements in the function are contextually typed const returnType = getReturnTypeFromAnnotation(functionDecl); @@ -27587,33 +36145,47 @@ namespace ts { function getContextualTypeForArgumentAtIndex(callTarget: CallLikeExpression, argIndex: number): Type { if (isImportCall(callTarget)) { - return argIndex === 0 ? stringType : - argIndex === 1 ? getGlobalImportCallOptionsType(/*reportErrors*/ false) : - anyType; + return argIndex === 0 ? stringType + : argIndex === 1 ? getGlobalImportCallOptionsType(/*reportErrors*/ false) + : anyType; } // If we're already in the process of resolving the given signature, don't resolve again as // that could cause infinite recursion. Instead, return anySignature. - const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget); + const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature + : getResolvedSignature(callTarget); if (isJsxOpeningLikeElement(callTarget) && argIndex === 0) { return getEffectiveFirstArgumentForJsxSignature(signature, callTarget); } const restIndex = signature.parameters.length - 1; - return signatureHasRestParameter(signature) && argIndex >= restIndex ? - getIndexedAccessType(getTypeOfSymbol(signature.parameters[restIndex]), getNumberLiteralType(argIndex - restIndex), AccessFlags.Contextual) : - getTypeAtPosition(signature, argIndex); + return signatureHasRestParameter(signature) && argIndex >= restIndex + ? getIndexedAccessType( + getTypeOfSymbol(signature.parameters[restIndex]), + getNumberLiteralType(argIndex - restIndex), + AccessFlags.Contextual, + ) + : getTypeAtPosition(signature, argIndex); } - function getContextualTypeForSubstitutionExpression(template: TemplateExpression, substitutionExpression: Expression) { + function getContextualTypeForSubstitutionExpression( + template: TemplateExpression, + substitutionExpression: Expression, + ) { if (template.parent.kind === SyntaxKind.TaggedTemplateExpression) { - return getContextualTypeForArgument(template.parent as TaggedTemplateExpression, substitutionExpression); + return getContextualTypeForArgument( + template.parent as TaggedTemplateExpression, + substitutionExpression, + ); } return undefined; } - function getContextualTypeForBinaryOperand(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForBinaryOperand( + node: Expression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const binaryExpression = node.parent as BinaryExpression; const { left, operatorToken, right } = binaryExpression; switch (operatorToken.kind) { @@ -27630,8 +36202,9 @@ namespace ts { // by the type of the left operand, except for the special case of Javascript declarations of the form // `namespace.prop = namespace.prop || {}`. const type = getContextualType(binaryExpression, contextFlags); - return node === right && (type && type.pattern || !type && !isDefaultedExpandoInitializer(binaryExpression)) ? - getTypeOfExpression(left) : type; + return node === right + && (type && type.pattern || !type && !isDefaultedExpandoInitializer(binaryExpression)) + ? getTypeOfExpression(left) : type; case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.CommaToken: return node === right ? getContextualType(binaryExpression, contextFlags) : undefined; @@ -27653,7 +36226,8 @@ namespace ts { } if (isPropertyAccessExpression(e)) { const lhsType = getTypeOfExpression(e.expression); - return isPrivateIdentifier(e.name) ? tryGetPrivateIdentifierPropertyOfType(lhsType, e.name) : getPropertyOfType(lhsType, e.name.escapedText); + return isPrivateIdentifier(e.name) ? tryGetPrivateIdentifierPropertyOfType(lhsType, e.name) + : getPropertyOfType(lhsType, e.name.escapedText); } if (isElementAccessExpression(e)) { const propType = checkExpressionCached(e.argumentExpression); @@ -27684,8 +36258,13 @@ namespace ts { // We avoid calling back into `getTypeOfExpression` and reentering contextual typing to avoid a bogus circularity error in that case. if (decl && (isPropertyDeclaration(decl) || isPropertySignature(decl))) { const overallAnnotation = getEffectiveTypeAnnotationNode(decl); - return (overallAnnotation && instantiateType(getTypeFromTypeNode(overallAnnotation), getSymbolLinks(lhsSymbol).mapper)) || - (isPropertyDeclaration(decl) ? decl.initializer && getTypeOfExpression(binaryExpression.left) : undefined); + return (overallAnnotation + && instantiateType( + getTypeFromTypeNode(overallAnnotation), + getSymbolLinks(lhsSymbol).mapper, + )) + || (isPropertyDeclaration(decl) + ? decl.initializer && getTypeOfExpression(binaryExpression.left) : undefined); } if (kind === AssignmentDeclarationKind.None) { return getTypeOfExpression(binaryExpression.left); @@ -27712,13 +36291,24 @@ namespace ts { } else if (isIdentifier(lhs.expression)) { const id = lhs.expression; - const parentSymbol = resolveName(id, id.escapedText, SymbolFlags.Value, undefined, id.escapedText, /*isUse*/ true); + const parentSymbol = resolveName( + id, + id.escapedText, + SymbolFlags.Value, + undefined, + id.escapedText, + /*isUse*/ true, + ); if (parentSymbol) { - const annotated = parentSymbol.valueDeclaration && getEffectiveTypeAnnotationNode(parentSymbol.valueDeclaration); + const annotated = parentSymbol.valueDeclaration + && getEffectiveTypeAnnotationNode(parentSymbol.valueDeclaration); if (annotated) { const nameStr = getElementOrPropertyAccessName(lhs); if (nameStr !== undefined) { - return getTypeOfPropertyOfContextualType(getTypeFromTypeNode(annotated), nameStr); + return getTypeOfPropertyOfContextualType( + getTypeFromTypeNode(annotated), + nameStr, + ); } } return undefined; @@ -27746,15 +36336,29 @@ namespace ts { } } - function isPossiblyAliasedThisProperty(declaration: BinaryExpression, kind = getAssignmentDeclarationKind(declaration)) { + function isPossiblyAliasedThisProperty( + declaration: BinaryExpression, + kind = getAssignmentDeclarationKind(declaration), + ) { if (kind === AssignmentDeclarationKind.ThisProperty) { return true; } - if (!isInJSFile(declaration) || kind !== AssignmentDeclarationKind.Property || !isIdentifier((declaration.left as AccessExpression).expression)) { + if ( + !isInJSFile(declaration) || kind !== AssignmentDeclarationKind.Property + || !isIdentifier((declaration.left as AccessExpression).expression) + ) { return false; } const name = ((declaration.left as AccessExpression).expression as Identifier).escapedText; - const symbol = resolveName(declaration.left, name, SymbolFlags.Value, undefined, undefined, /*isUse*/ true, /*excludeGlobals*/ true); + const symbol = resolveName( + declaration.left, + name, + SymbolFlags.Value, + undefined, + undefined, + /*isUse*/ true, + /*excludeGlobals*/ true, + ); return isThisInitializedDeclaration(symbol?.valueDeclaration); } @@ -27779,7 +36383,8 @@ namespace ts { } function isCircularMappedProperty(symbol: Symbol) { - return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(symbol as MappedSymbol).type && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0); + return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(symbol as MappedSymbol).type + && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0); } function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) { @@ -27803,7 +36408,10 @@ namespace ts { return restType; } } - return findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType || getStringLiteralType(unescapeLeadingUnderscores(name)))?.type; + return findApplicableIndexInfo( + getIndexInfosOfStructuredType(t), + nameType || getStringLiteralType(unescapeLeadingUnderscores(name)), + )?.type; } return undefined; }, /*noReductions*/ true); @@ -27812,7 +36420,10 @@ namespace ts { // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of // the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one // exists. Otherwise, it is the type of the string index signature in T, if one exists. - function getContextualTypeForObjectLiteralMethod(node: MethodDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForObjectLiteralMethod( + node: MethodDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { Debug.assert(isObjectLiteralMethod(node)); if (node.flags & NodeFlags.InWithStatement) { // We cannot answer semantic questions within a with block, do not proceed any further @@ -27821,9 +36432,13 @@ namespace ts { return getContextualTypeForObjectLiteralElement(node, contextFlags); } - function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike, contextFlags: ContextFlags | undefined) { + function getContextualTypeForObjectLiteralElement( + element: ObjectLiteralElementLike, + contextFlags: ContextFlags | undefined, + ) { const objectLiteral = element.parent as ObjectLiteralExpression; - const propertyAssignmentType = isPropertyAssignment(element) && getContextualTypeForVariableLikeDeclaration(element, contextFlags); + const propertyAssignmentType = isPropertyAssignment(element) + && getContextualTypeForVariableLikeDeclaration(element, contextFlags); if (propertyAssignmentType) { return propertyAssignmentType; } @@ -27839,7 +36454,11 @@ namespace ts { if (element.name) { const nameType = getLiteralTypeFromPropertyName(element.name); // We avoid calling getApplicableIndexInfo here because it performs potentially expensive intersection reduction. - return mapType(type, t => findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType)?.type, /*noReductions*/ true); + return mapType( + type, + t => findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType)?.type, + /*noReductions*/ true, + ); } } return undefined; @@ -27849,28 +36468,48 @@ namespace ts { // the type of the property with the numeric name N in T, if one exists. Otherwise, if T has a numeric index signature, // it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated // type of T. - function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined { + function getContextualTypeForElementExpression( + arrayContextualType: Type | undefined, + index: number, + ): Type | undefined { return arrayContextualType && ( getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String) || mapType( arrayContextualType, - t => getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false), + t => getIteratedTypeOrElementType( + IterationUse.Element, + t, + undefinedType, + /*errorNode*/ undefined, + /*checkAssignability*/ false, + ), /*noReductions*/ true, ) ); } // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type. - function getContextualTypeForConditionalOperand(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForConditionalOperand( + node: Expression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const conditional = node.parent as ConditionalExpression; - return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional, contextFlags) : undefined; + return node === conditional.whenTrue || node === conditional.whenFalse + ? getContextualType(conditional, contextFlags) : undefined; } - function getContextualTypeForChildJsxExpression(node: JsxElement, child: JsxChild, contextFlags: ContextFlags | undefined) { + function getContextualTypeForChildJsxExpression( + node: JsxElement, + child: JsxChild, + contextFlags: ContextFlags | undefined, + ) { const attributesType = getApparentTypeOfContextualType(node.openingElement.tagName, contextFlags); // JSX expression is in children of JSX Element, we will look for an "children" attribute (we get the name from JSX.ElementAttributesProperty) const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - if (!(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "")) { + if ( + !(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName + && jsxChildrenPropertyName !== "") + ) { return undefined; } const realChildren = getSemanticJsxChildren(node.children); @@ -27886,7 +36525,10 @@ namespace ts { }, /*noReductions*/ true)); } - function getContextualTypeForJsxExpression(node: JsxExpression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForJsxExpression( + node: JsxExpression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const exprParent = node.parent; return isJsxAttributeLike(exprParent) ? getContextualType(node, contextFlags) @@ -27895,7 +36537,10 @@ namespace ts { : undefined; } - function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForJsxAttribute( + attribute: JsxAttribute | JsxSpreadAttribute, + contextFlags: ContextFlags | undefined, + ): Type | undefined { // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type // which is a type of the parameter of the signature we are trying out. // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName @@ -27928,29 +36573,46 @@ namespace ts { return true; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ParenthesizedExpression: - return isPossiblyDiscriminantValue((node as PropertyAccessExpression | ParenthesizedExpression).expression); + return isPossiblyDiscriminantValue( + (node as PropertyAccessExpression | ParenthesizedExpression).expression, + ); case SyntaxKind.JsxExpression: - return !(node as JsxExpression).expression || isPossiblyDiscriminantValue((node as JsxExpression).expression!); + return !(node as JsxExpression).expression + || isPossiblyDiscriminantValue((node as JsxExpression).expression!); } return false; } function discriminateContextualTypeByObjectMembers(node: ObjectLiteralExpression, contextualType: UnionType) { - return getMatchingUnionConstituentForObjectLiteral(contextualType, node) || discriminateTypeByDiscriminableItems( - contextualType, - concatenate( - map( - filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.PropertyAssignment && isPossiblyDiscriminantValue(p.initializer) && isDiscriminantProperty(contextualType, p.symbol.escapedName)), - prop => ([() => getContextFreeTypeOfExpression((prop as PropertyAssignment).initializer), prop.symbol.escapedName] as [() => Type, __String]), - ), - map( - filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), - s => [() => undefinedType, s.escapedName] as [() => Type, __String], + return getMatchingUnionConstituentForObjectLiteral(contextualType, node) + || discriminateTypeByDiscriminableItems( + contextualType, + concatenate( + map( + filter( + node.properties, + p => !!p.symbol && p.kind === SyntaxKind.PropertyAssignment + && isPossiblyDiscriminantValue(p.initializer) + && isDiscriminantProperty(contextualType, p.symbol.escapedName), + ), + prop => ([ + () => getContextFreeTypeOfExpression((prop as PropertyAssignment).initializer), + prop.symbol.escapedName, + ] as [() => Type, __String]), + ), + map( + filter( + getPropertiesOfType(contextualType), + s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members + && !node.symbol.members.has(s.escapedName) + && isDiscriminantProperty(contextualType, s.escapedName), + ), + s => [() => undefinedType, s.escapedName] as [() => Type, __String], + ), ), - ), - isTypeAssignableTo, - contextualType, - ); + isTypeAssignableTo, + contextualType, + ); } function discriminateContextualTypeByJSXAttributes(node: JsxAttributes, contextualType: UnionType) { @@ -27958,11 +36620,25 @@ namespace ts { contextualType, concatenate( map( - filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute && isDiscriminantProperty(contextualType, p.symbol.escapedName) && (!p.initializer || isPossiblyDiscriminantValue(p.initializer))), - prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as [() => Type, __String]), + filter( + node.properties, + p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute + && isDiscriminantProperty(contextualType, p.symbol.escapedName) + && (!p.initializer || isPossiblyDiscriminantValue(p.initializer)), + ), + prop => ([ + !(prop as JsxAttribute).initializer ? (() => trueType) + : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), + prop.symbol.escapedName, + ] as [() => Type, __String]), ), map( - filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), + filter( + getPropertiesOfType(contextualType), + s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members + && !node.symbol.members.has(s.escapedName) + && isDiscriminantProperty(contextualType, s.escapedName), + ), s => [() => undefinedType, s.escapedName] as [() => Type, __String], ), ), @@ -27973,28 +36649,44 @@ namespace ts { // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily // be "pushed" onto a node using the contextualType property. - function getApparentTypeOfContextualType(node: Expression | MethodDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { - const contextualType = isObjectLiteralMethod(node) ? - getContextualTypeForObjectLiteralMethod(node, contextFlags) : - getContextualType(node, contextFlags); + function getApparentTypeOfContextualType( + node: Expression | MethodDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { + const contextualType = isObjectLiteralMethod(node) + ? getContextualTypeForObjectLiteralMethod(node, contextFlags) + : getContextualType(node, contextFlags); const instantiatedType = instantiateContextualType(contextualType, node, contextFlags); - if (instantiatedType && !(contextFlags && contextFlags & ContextFlags.NoConstraints && instantiatedType.flags & TypeFlags.TypeVariable)) { + if ( + instantiatedType + && !(contextFlags && contextFlags & ContextFlags.NoConstraints + && instantiatedType.flags & TypeFlags.TypeVariable) + ) { const apparentType = mapType(instantiatedType, getApparentType, /*noReductions*/ true); - return apparentType.flags & TypeFlags.Union && isObjectLiteralExpression(node) ? discriminateContextualTypeByObjectMembers(node, apparentType as UnionType) : - apparentType.flags & TypeFlags.Union && isJsxAttributes(node) ? discriminateContextualTypeByJSXAttributes(node, apparentType as UnionType) : - apparentType; + return apparentType.flags & TypeFlags.Union && isObjectLiteralExpression(node) + ? discriminateContextualTypeByObjectMembers(node, apparentType as UnionType) + : apparentType.flags & TypeFlags.Union && isJsxAttributes(node) + ? discriminateContextualTypeByJSXAttributes(node, apparentType as UnionType) + : apparentType; } } // If the given contextual type contains instantiable types and if a mapper representing // return type inferences is available, instantiate those types using that mapper. - function instantiateContextualType(contextualType: Type | undefined, node: Node, contextFlags: ContextFlags | undefined): Type | undefined { + function instantiateContextualType( + contextualType: Type | undefined, + node: Node, + contextFlags: ContextFlags | undefined, + ): Type | undefined { if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) { const inferenceContext = getInferenceContext(node); // If no inferences have been made, and none of the type parameters for which we are inferring // specify default types, nothing is gained from instantiating as type parameters would just be // replaced with their constraints similar to the apparent type. - if (inferenceContext && contextFlags! & ContextFlags.Signature && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault)) { + if ( + inferenceContext && contextFlags! & ContextFlags.Signature + && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault) + ) { // For contextual signatures we incorporate all inferences made so far, e.g. from return // types as well as arguments to the left in a function call. return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); @@ -28005,9 +36697,10 @@ namespace ts { // the 'boolean' type from the contextual type such that contextually typed boolean // literals actually end up widening to 'boolean' (see #48363). const type = instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper); - return type.flags & TypeFlags.Union && containsType((type as UnionType).types, regularFalseType) && containsType((type as UnionType).types, regularTrueType) ? - filterType(type, t => t !== regularFalseType && t !== regularTrueType) : - type; + return type.flags & TypeFlags.Union && containsType((type as UnionType).types, regularFalseType) + && containsType((type as UnionType).types, regularTrueType) + ? filterType(type, t => t !== regularFalseType && t !== regularTrueType) + : type; } } return contextualType; @@ -28021,10 +36714,15 @@ namespace ts { return instantiateType(type, mapper); } if (type.flags & TypeFlags.Union) { - return getUnionType(map((type as UnionType).types, t => instantiateInstantiableTypes(t, mapper)), UnionReduction.None); + return getUnionType( + map((type as UnionType).types, t => instantiateInstantiableTypes(t, mapper)), + UnionReduction.None, + ); } if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(map((type as IntersectionType).types, t => instantiateInstantiableTypes(t, mapper))); + return getIntersectionType( + map((type as IntersectionType).types, t => instantiateInstantiableTypes(t, mapper)), + ); } return type; } @@ -28074,12 +36772,17 @@ namespace ts { return getContextualTypeForArgument(parent as CallExpression | NewExpression, node); case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: - return isConstTypeReference((parent as AssertionExpression).type) ? tryFindWhenConstTypeReference(parent as AssertionExpression) : getTypeFromTypeNode((parent as AssertionExpression).type); + return isConstTypeReference((parent as AssertionExpression).type) + ? tryFindWhenConstTypeReference(parent as AssertionExpression) + : getTypeFromTypeNode((parent as AssertionExpression).type); case SyntaxKind.BinaryExpression: return getContextualTypeForBinaryOperand(node, contextFlags); case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - return getContextualTypeForObjectLiteralElement(parent as PropertyAssignment | ShorthandPropertyAssignment, contextFlags); + return getContextualTypeForObjectLiteralElement( + parent as PropertyAssignment | ShorthandPropertyAssignment, + contextFlags, + ); case SyntaxKind.SpreadAssignment: return getContextualType(parent.parent as ObjectLiteralExpression, contextFlags); case SyntaxKind.ArrayLiteralExpression: { @@ -28095,9 +36798,10 @@ namespace ts { case SyntaxKind.ParenthesizedExpression: { // Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast. const tag = isInJSFile(parent) ? getJSDocTypeTag(parent) : undefined; - return !tag ? getContextualType(parent as ParenthesizedExpression, contextFlags) : - isJSDocTypeTag(tag) && isConstTypeReference(tag.typeExpression.type) ? tryFindWhenConstTypeReference(parent as ParenthesizedExpression) : - getTypeFromTypeNode(tag.typeExpression.type); + return !tag ? getContextualType(parent as ParenthesizedExpression, contextFlags) + : isJSDocTypeTag(tag) && isConstTypeReference(tag.typeExpression.type) + ? tryFindWhenConstTypeReference(parent as ParenthesizedExpression) + : getTypeFromTypeNode(tag.typeExpression.type); } case SyntaxKind.NonNullExpression: return getContextualType(parent as NonNullExpression, contextFlags); @@ -28126,7 +36830,10 @@ namespace ts { return ancestor && ancestor.inferenceContext!; } - function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) { + function getContextualJsxElementAttributesType( + node: JsxOpeningLikeElement, + contextFlags: ContextFlags | undefined, + ) { if (isJsxOpeningElement(node) && node.parent.contextualType && contextFlags !== ContextFlags.Completions) { // Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit // _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type @@ -28195,7 +36902,11 @@ namespace ts { return tagType; } - function getJsxManagedAttributesFromLocatedAttributes(context: JsxOpeningLikeElement, ns: Symbol, attributesType: Type) { + function getJsxManagedAttributesFromLocatedAttributes( + context: JsxOpeningLikeElement, + ns: Symbol, + attributesType: Type, + ) { const managedSym = getJsxLibraryManagedAttributes(ns); if (managedSym) { const declaredManagedType = getDeclaredTypeOfSymbol(managedSym); // fetches interface type, or initializes symbol links type parmaeters @@ -28203,12 +36914,22 @@ namespace ts { if (managedSym.flags & SymbolFlags.TypeAlias) { const params = getSymbolLinks(managedSym).typeParameters; if (length(params) >= 2) { - const args = fillMissingTypeArguments([ctorType, attributesType], params, 2, isInJSFile(context)); + const args = fillMissingTypeArguments( + [ctorType, attributesType], + params, + 2, + isInJSFile(context), + ); return getTypeAliasInstantiation(managedSym, args); } } if (length((declaredManagedType as GenericType).typeParameters) >= 2) { - const args = fillMissingTypeArguments([ctorType, attributesType], (declaredManagedType as GenericType).typeParameters, 2, isInJSFile(context)); + const args = fillMissingTypeArguments( + [ctorType, attributesType], + (declaredManagedType as GenericType).typeParameters, + 2, + isInJSFile(context), + ); return createTypeReference(declaredManagedType as GenericType, args); } } @@ -28230,7 +36951,11 @@ namespace ts { if (!attributesType) { // There is no property named 'props' on this instance type if (!!forcedLookupLocation && !!length(context.attributes.properties)) { - error(context, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(forcedLookupLocation)); + error( + context, + Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, + unescapeLeadingUnderscores(forcedLookupLocation), + ); } return unknownType; } @@ -28246,13 +36971,23 @@ namespace ts { let apparentAttributesType = attributesType; const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes, context); if (!isErrorType(intrinsicClassAttribs)) { - const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol); + const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias( + intrinsicClassAttribs.symbol, + ); const hostClassType = getReturnTypeOfSignature(sig); let libraryManagedAttributeType: Type; if (typeParams) { // apply JSX.IntrinsicClassElements - const inferredArgs = fillMissingTypeArguments([hostClassType], typeParams, getMinTypeArgumentCount(typeParams), isInJSFile(context)); - libraryManagedAttributeType = instantiateType(intrinsicClassAttribs, createTypeMapper(typeParams, inferredArgs)); + const inferredArgs = fillMissingTypeArguments( + [hostClassType], + typeParams, + getMinTypeArgumentCount(typeParams), + isInJSFile(context), + ); + libraryManagedAttributeType = instantiateType( + intrinsicClassAttribs, + createTypeMapper(typeParams, inferredArgs), + ); } // or JSX.IntrinsicClassElements has no generics. else libraryManagedAttributeType = intrinsicClassAttribs; @@ -28274,13 +37009,18 @@ namespace ts { signatures, (left, right) => left === right || !left ? left - : compareTypeParametersIdentical(left.typeParameters, right.typeParameters) ? combineSignaturesOfIntersectionMembers(left, right) + : compareTypeParametersIdentical(left.typeParameters, right.typeParameters) + ? combineSignaturesOfIntersectionMembers(left, right) : undefined, ) : undefined; } - function combineIntersectionThisParam(left: Symbol | undefined, right: Symbol | undefined, mapper: TypeMapper | undefined): Symbol | undefined { + function combineIntersectionThisParam( + left: Symbol | undefined, + right: Symbol | undefined, + mapper: TypeMapper | undefined, + ): Symbol | undefined { if (!left || !right) { return left || right; } @@ -28315,10 +37055,10 @@ namespace ts { const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); - const paramName = leftName === rightName ? leftName : - !leftName ? rightName : - !rightName ? leftName : - undefined; + const paramName = leftName === rightName ? leftName + : !leftName ? rightName + : !rightName ? leftName + : undefined; const paramSymbol = createSymbol( SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), paramName || `arg${i}` as __String, @@ -28359,9 +37099,13 @@ namespace ts { (left.flags | right.flags) & SignatureFlags.PropagatingFlags, ); result.compositeKind = TypeFlags.Intersection; - result.compositeSignatures = concatenate(left.compositeKind === TypeFlags.Intersection && left.compositeSignatures || [left], [right]); + result.compositeSignatures = concatenate( + left.compositeKind === TypeFlags.Intersection && left.compositeSignatures || [left], + [right], + ); if (paramMapper) { - result.mapper = left.compositeKind === TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; + result.mapper = left.compositeKind === TypeFlags.Intersection && left.mapper && left.compositeSignatures + ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; } return result; } @@ -28379,7 +37123,9 @@ namespace ts { let targetParameterCount = 0; for (; targetParameterCount < target.parameters.length; targetParameterCount++) { const param = target.parameters[targetParameterCount]; - if (param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param)) { + if ( + param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param) + ) { break; } } @@ -28389,7 +37135,9 @@ namespace ts { return !hasEffectiveRestParameter(signature) && getParameterCount(signature) < targetParameterCount; } - function getContextualSignatureForFunctionLikeDeclaration(node: FunctionLikeDeclaration): Signature | undefined { + function getContextualSignatureForFunctionLikeDeclaration( + node: FunctionLikeDeclaration, + ): Signature | undefined { // Only function expressions, arrow functions, and object literal methods are contextually typed. return isFunctionExpressionOrArrowFunction(node) || isObjectLiteralMethod(node) ? getContextualSignature(node as FunctionExpression) @@ -28401,7 +37149,9 @@ namespace ts { // If the contextual type is a union type, get the signature from each type possible and if they are // all identical ignoring their return type, the result is same signature but with return type as // union type of return types from these signatures - function getContextualSignature(node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature | undefined { + function getContextualSignature( + node: FunctionExpression | ArrowFunction | MethodDeclaration, + ): Signature | undefined { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); const typeTagSignature = getSignatureOfTypeTag(node); if (typeTagSignature) { @@ -28423,7 +37173,16 @@ namespace ts { // This signature will contribute to contextual union signature signatureList = [signature]; } - else if (!compareSignaturesIdentical(signatureList[0], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true, compareTypesIdentical)) { + else if ( + !compareSignaturesIdentical( + signatureList[0], + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ true, + /*ignoreReturnTypes*/ true, + compareTypesIdentical, + ) + ) { // Signatures aren't identical, do not use return undefined; } @@ -28435,17 +37194,27 @@ namespace ts { } // Result is union of signatures collected (return type is union of return types of this signature set) if (signatureList) { - return signatureList.length === 1 ? signatureList[0] : createUnionSignature(signatureList[0], signatureList); + return signatureList.length === 1 ? signatureList[0] + : createUnionSignature(signatureList[0], signatureList); } } function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type { if (languageVersion < ScriptTarget.ES2015) { - checkExternalEmitHelpers(node, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray); + checkExternalEmitHelpers( + node, + compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes + : ExternalEmitHelpers.SpreadArray, + ); } const arrayOrIterableType = checkExpression(node.expression, checkMode); - return checkIteratedTypeOrElementType(IterationUse.Spread, arrayOrIterableType, undefinedType, node.expression); + return checkIteratedTypeOrElementType( + IterationUse.Spread, + arrayOrIterableType, + undefinedType, + node.expression, + ); } function checkSyntheticExpression(node: SyntheticExpression): Type { @@ -28453,11 +37222,16 @@ namespace ts { } function hasDefaultValue(node: BindingElement | Expression): boolean { - return (node.kind === SyntaxKind.BindingElement && !!(node as BindingElement).initializer) || - (node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken); + return (node.kind === SyntaxKind.BindingElement && !!(node as BindingElement).initializer) + || (node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken); } - function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined, forceTuple: boolean | undefined): Type { + function checkArrayLiteral( + node: ArrayLiteralExpression, + checkMode: CheckMode | undefined, + forceTuple: boolean | undefined, + ): Type { const elements = node.elements; const elementCount = elements.length; const elementTypes: Type[] = []; @@ -28470,7 +37244,11 @@ namespace ts { const e = elements[i]; if (e.kind === SyntaxKind.SpreadElement) { if (languageVersion < ScriptTarget.ES2015) { - checkExternalEmitHelpers(e, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray); + checkExternalEmitHelpers( + e, + compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes + : ExternalEmitHelpers.SpreadArray, + ); } const spreadType = checkExpression((e as SpreadElement).expression, checkMode, forceTuple); if (isArrayLikeType(spreadType)) { @@ -28490,14 +37268,27 @@ namespace ts { // get the contextual element type from it. So we do something similar to // getContextualTypeForElementExpression, which will crucially not error // if there is no index type / iterated type. - const restElementType = getIndexTypeOfType(spreadType, numberType) || - getIteratedTypeOrElementType(IterationUse.Destructuring, spreadType, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false) || - unknownType; + const restElementType = getIndexTypeOfType(spreadType, numberType) + || getIteratedTypeOrElementType( + IterationUse.Destructuring, + spreadType, + undefinedType, + /*errorNode*/ undefined, + /*checkAssignability*/ false, + ) + || unknownType; elementTypes.push(restElementType); elementFlags.push(ElementFlags.Rest); } else { - elementTypes.push(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, (e as SpreadElement).expression)); + elementTypes.push( + checkIteratedTypeOrElementType( + IterationUse.Spread, + spreadType, + undefinedType, + (e as SpreadElement).expression, + ), + ); elementFlags.push(ElementFlags.Rest); } } @@ -28507,11 +37298,18 @@ namespace ts { elementFlags.push(ElementFlags.Optional); } else { - const elementContextualType = getContextualTypeForElementExpression(contextualType, elementTypes.length); + const elementContextualType = getContextualTypeForElementExpression( + contextualType, + elementTypes.length, + ); const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType, forceTuple); elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression)); elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required); - if (contextualType && someType(contextualType, isTupleLikeType) && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) { + if ( + contextualType && someType(contextualType, isTupleLikeType) && checkMode + && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) + && isContextSensitive(e) + ) { const inferenceContext = getInferenceContext(node); Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context addIntraExpressionInferenceSite(inferenceContext, e, type); @@ -28525,9 +37323,14 @@ namespace ts { return createArrayLiteralType(createTupleType(elementTypes, elementFlags, /*readonly*/ inConstContext)); } return createArrayLiteralType(createArrayType( - elementTypes.length ? - getUnionType(sameMap(elementTypes, (t, i) => elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessTypeOrUndefined(t, numberType) || anyType : t), UnionReduction.Subtype) : - strictNullChecks ? implicitNeverType : undefinedWideningType, + elementTypes.length + ? getUnionType( + sameMap(elementTypes, (t, i) => + elementFlags[i] & ElementFlags.Variadic + ? getIndexedAccessTypeOrUndefined(t, numberType) || anyType : t), + UnionReduction.Subtype, + ) + : strictNullChecks ? implicitNeverType : undefinedWideningType, inConstContext, )); } @@ -28568,8 +37371,10 @@ namespace ts { const links = getNodeLinks(node.expression); if (!links.resolvedType) { if ( - (isTypeLiteralNode(node.parent.parent) || isClassLike(node.parent.parent) || isInterfaceDeclaration(node.parent.parent)) - && isBinaryExpression(node.expression) && node.expression.operatorToken.kind === SyntaxKind.InKeyword + (isTypeLiteralNode(node.parent.parent) || isClassLike(node.parent.parent) + || isInterfaceDeclaration(node.parent.parent)) + && isBinaryExpression(node.expression) + && node.expression.operatorToken.kind === SyntaxKind.InKeyword && node.parent.kind !== SyntaxKind.GetAccessor && node.parent.kind !== SyntaxKind.SetAccessor ) { return links.resolvedType = errorType; @@ -28577,12 +37382,16 @@ namespace ts { links.resolvedType = checkExpression(node.expression); // The computed property name of a non-static class field within a loop must be stored in a block-scoped binding. // (It needs to be bound at class evaluation time.) - if (isPropertyDeclaration(node.parent) && !hasStaticModifier(node.parent) && isClassExpression(node.parent.parent)) { + if ( + isPropertyDeclaration(node.parent) && !hasStaticModifier(node.parent) + && isClassExpression(node.parent.parent) + ) { const container = getEnclosingBlockScopeContainer(node.parent.parent); const enclosingIterationStatement = getEnclosingIterationStatement(container); if (enclosingIterationStatement) { // The computed field name will use a block scoped binding which can be unique for each iteration of the loop. - getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; + getNodeLinks(enclosingIterationStatement).flags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding; // The generated variable which stores the computed field name must be block-scoped. getNodeLinks(node).flags |= NodeCheckFlags.BlockScopedBindingInLoop; // The generated variable which stores the class must be block-scoped. @@ -28592,9 +37401,12 @@ namespace ts { // This will allow types number, string, symbol or any. It will also allow enums, the unknown // type, and any union of these types (like string | number). if ( - links.resolvedType.flags & TypeFlags.Nullable || - !isTypeAssignableToKind(links.resolvedType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) && - !isTypeAssignableTo(links.resolvedType, stringNumberSymbolType) + links.resolvedType.flags & TypeFlags.Nullable + || !isTypeAssignableToKind( + links.resolvedType, + TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike, + ) + && !isTypeAssignableTo(links.resolvedType, stringNumberSymbolType) ) { error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any); } @@ -28605,23 +37417,30 @@ namespace ts { function isSymbolWithNumericName(symbol: Symbol) { const firstDecl = symbol.declarations?.[0]; - return isNumericLiteralName(symbol.escapedName) || (firstDecl && isNamedDeclaration(firstDecl) && isNumericName(firstDecl.name)); + return isNumericLiteralName(symbol.escapedName) + || (firstDecl && isNamedDeclaration(firstDecl) && isNumericName(firstDecl.name)); } function isSymbolWithSymbolName(symbol: Symbol) { const firstDecl = symbol.declarations?.[0]; - return isKnownSymbol(symbol) || (firstDecl && isNamedDeclaration(firstDecl) && isComputedPropertyName(firstDecl.name) && - isTypeAssignableToKind(checkComputedPropertyName(firstDecl.name), TypeFlags.ESSymbol)); + return isKnownSymbol(symbol) + || (firstDecl && isNamedDeclaration(firstDecl) && isComputedPropertyName(firstDecl.name) + && isTypeAssignableToKind(checkComputedPropertyName(firstDecl.name), TypeFlags.ESSymbol)); } - function getObjectLiteralIndexInfo(node: ObjectLiteralExpression, offset: number, properties: Symbol[], keyType: Type): IndexInfo { + function getObjectLiteralIndexInfo( + node: ObjectLiteralExpression, + offset: number, + properties: Symbol[], + keyType: Type, + ): IndexInfo { const propTypes: Type[] = []; for (let i = offset; i < properties.length; i++) { const prop = properties[i]; if ( - keyType === stringType && !isSymbolWithSymbolName(prop) || - keyType === numberType && isSymbolWithNumericName(prop) || - keyType === esSymbolType && isSymbolWithSymbolName(prop) + keyType === stringType && !isSymbolWithSymbolName(prop) + || keyType === numberType && isSymbolWithNumericName(prop) + || keyType === esSymbolType && isSymbolWithSymbolName(prop) ) { propTypes.push(getTypeOfSymbol(properties[i])); } @@ -28653,8 +37472,9 @@ namespace ts { let spread: Type = emptyObjectType; const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); - const contextualTypeHasPattern = contextualType && contextualType.pattern && - (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); + const contextualTypeHasPattern = contextualType && contextualType.pattern + && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern + || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); const inConstContext = isConstContext(node); const checkFlags = inConstContext ? CheckFlags.Readonly : 0; const isInJavascript = isInJSFile(node) && !isInJsonFile(node); @@ -28678,19 +37498,25 @@ namespace ts { let offset = 0; for (const memberDecl of node.properties) { let member = getSymbolOfNode(memberDecl); - const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName ? - checkComputedPropertyName(memberDecl.name) : undefined; + const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName + ? checkComputedPropertyName(memberDecl.name) : undefined; if ( - memberDecl.kind === SyntaxKind.PropertyAssignment || - memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment || - isObjectLiteralMethod(memberDecl) + memberDecl.kind === SyntaxKind.PropertyAssignment + || memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment + || isObjectLiteralMethod(memberDecl) ) { - let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, checkMode) : + let type = memberDecl.kind === SyntaxKind.PropertyAssignment + ? checkPropertyAssignment(memberDecl, checkMode) // avoid resolving the left side of the ShorthandPropertyAssignment outside of the destructuring // for error recovery purposes. For example, if a user wrote `{ a = 100 }` instead of `{ a: 100 }`. // we don't want to say "could not find 'a'". - memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(!inDestructuringPattern && memberDecl.objectAssignmentInitializer ? memberDecl.objectAssignmentInitializer : memberDecl.name, checkMode) : - checkObjectLiteralMethod(memberDecl, checkMode); + : memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment + ? checkExpressionForMutableLocation( + !inDestructuringPattern && memberDecl.objectAssignmentInitializer + ? memberDecl.objectAssignmentInitializer : memberDecl.name, + checkMode, + ) + : checkObjectLiteralMethod(memberDecl, checkMode); if (isInJavascript) { const jsDocType = getTypeForDeclarationFromJSDocComment(memberDecl); if (jsDocType) { @@ -28702,10 +37528,15 @@ namespace ts { } } objectFlags |= getObjectFlags(type) & ObjectFlags.PropagatingFlags; - const nameType = computedNameType && isTypeUsableAsPropertyName(computedNameType) ? computedNameType : undefined; - const prop = nameType ? - createSymbol(SymbolFlags.Property | member.flags, getPropertyNameFromType(nameType), checkFlags | CheckFlags.Late) : - createSymbol(SymbolFlags.Property | member.flags, member.escapedName, checkFlags); + const nameType = computedNameType && isTypeUsableAsPropertyName(computedNameType) ? computedNameType + : undefined; + const prop = nameType + ? createSymbol( + SymbolFlags.Property | member.flags, + getPropertyNameFromType(nameType), + checkFlags | CheckFlags.Late, + ) + : createSymbol(SymbolFlags.Property | member.flags, member.escapedName, checkFlags); if (nameType) { prop.nameType = nameType; } @@ -28713,21 +37544,35 @@ namespace ts { if (inDestructuringPattern) { // If object literal is an assignment pattern and if the assignment pattern specifies a default value // for the property, make the property optional. - const isOptional = (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue(memberDecl.initializer)) || - (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment && memberDecl.objectAssignmentInitializer); + const isOptional = (memberDecl.kind === SyntaxKind.PropertyAssignment + && hasDefaultValue(memberDecl.initializer)) + || (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment + && memberDecl.objectAssignmentInitializer); if (isOptional) { prop.flags |= SymbolFlags.Optional; } } - else if (contextualTypeHasPattern && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) { + else if ( + contextualTypeHasPattern + && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) + ) { // If object literal is contextually typed by the implied type of a binding pattern, and if the // binding pattern specifies a default value for the property, make the property optional. const impliedProp = getPropertyOfType(contextualType, member.escapedName); if (impliedProp) { prop.flags |= impliedProp.flags & SymbolFlags.Optional; } - else if (!compilerOptions.suppressExcessPropertyErrors && !getIndexInfoOfType(contextualType, stringType)) { - error(memberDecl.name, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, symbolToString(member), typeToString(contextualType)); + else if ( + !compilerOptions.suppressExcessPropertyErrors + && !getIndexInfoOfType(contextualType, stringType) + ) { + error( + memberDecl.name, + Diagnostics + .Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, + symbolToString(member), + typeToString(contextualType), + ); } } @@ -28743,12 +37588,16 @@ namespace ts { allPropertiesTable?.set(prop.escapedName, prop); if ( - contextualType && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && - (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl) + contextualType && checkMode && checkMode & CheckMode.Inferential + && !(checkMode & CheckMode.SkipContextSensitive) + && (memberDecl.kind === SyntaxKind.PropertyAssignment + || memberDecl.kind === SyntaxKind.MethodDeclaration) + && isContextSensitive(memberDecl) ) { const inferenceContext = getInferenceContext(node); Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context - const inferenceNode = memberDecl.kind === SyntaxKind.PropertyAssignment ? memberDecl.initializer : memberDecl; + const inferenceNode = memberDecl.kind === SyntaxKind.PropertyAssignment ? memberDecl.initializer + : memberDecl; addIntraExpressionInferenceSite(inferenceContext, inferenceNode, type); } } @@ -28757,7 +37606,13 @@ namespace ts { checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); } if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, objectFlags, inConstContext); + spread = getSpreadType( + spread, + createObjectLiteralType(), + node.symbol, + objectFlags, + inConstContext, + ); propertiesArray = []; propertiesTable = createSymbolTable(); hasComputedStringProperty = false; @@ -28788,7 +37643,9 @@ namespace ts { // an ordinary function declaration(section 6.1) with no parameters. // A set accessor declaration is processed in the same manner // as an ordinary function declaration with a single parameter and a Void return type. - Debug.assert(memberDecl.kind === SyntaxKind.GetAccessor || memberDecl.kind === SyntaxKind.SetAccessor); + Debug.assert( + memberDecl.kind === SyntaxKind.GetAccessor || memberDecl.kind === SyntaxKind.SetAccessor, + ); checkNodeDeferred(memberDecl); } @@ -28822,19 +37679,25 @@ namespace ts { // It's not possible to check if the immediate parent node is a spread assignment // since the type flows in non-obvious ways through conditional expressions, IIFEs and more. if (contextualTypeHasPattern) { - const rootPatternParent = findAncestor(contextualType.pattern!.parent, n => - n.kind === SyntaxKind.VariableDeclaration || - n.kind === SyntaxKind.BinaryExpression || - n.kind === SyntaxKind.Parameter); + const rootPatternParent = findAncestor( + contextualType.pattern!.parent, + n => n.kind === SyntaxKind.VariableDeclaration + || n.kind === SyntaxKind.BinaryExpression + || n.kind === SyntaxKind.Parameter, + ); const spreadOrOutsideRootObject = findAncestor(node, n => - n === rootPatternParent || - n.kind === SyntaxKind.SpreadAssignment)!; + n === rootPatternParent + || n.kind === SyntaxKind.SpreadAssignment)!; if (spreadOrOutsideRootObject.kind !== SyntaxKind.SpreadAssignment) { for (const prop of getPropertiesOfType(contextualType)) { if (!propertiesTable.get(prop.escapedName) && !getPropertyOfType(spread, prop.escapedName)) { if (!(prop.flags & SymbolFlags.Optional)) { - error(prop.valueDeclaration || (prop as TransientSymbol).bindingElement, Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value); + error( + prop.valueDeclaration || (prop as TransientSymbol).bindingElement, + Diagnostics + .Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value, + ); } propertiesTable.set(prop.escapedName, prop); propertiesArray.push(prop); @@ -28863,11 +37726,18 @@ namespace ts { function createObjectLiteralType() { const indexInfos = []; - if (hasComputedStringProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, stringType)); - if (hasComputedNumberProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, numberType)); - if (hasComputedSymbolProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, esSymbolType)); + if (hasComputedStringProperty) { + indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, stringType)); + } + if (hasComputedNumberProperty) { + indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, numberType)); + } + if (hasComputedSymbolProperty) { + indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, esSymbolType)); + } const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, indexInfos); - result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; + result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral + | ObjectFlags.ContainsObjectOrArrayLiteral; if (isJSObjectLiteral) { result.objectFlags |= ObjectFlags.JSLiteral; } @@ -28883,8 +37753,10 @@ namespace ts { function isValidSpreadType(type: Type): boolean { const t = removeDefinitelyFalsyTypes(mapType(type, getBaseConstraintOrType)); - return !!(t.flags & (TypeFlags.Any | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) || - t.flags & TypeFlags.UnionOrIntersection && every((t as UnionOrIntersectionType).types, isValidSpreadType)); + return !!(t.flags + & (TypeFlags.Any | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) + || t.flags & TypeFlags.UnionOrIntersection + && every((t as UnionOrIntersectionType).types, isValidSpreadType)); } function checkJsxSelfClosingElementDeferred(node: JsxSelfClosingElement) { @@ -28924,13 +37796,15 @@ namespace ts { // if jsxFactory compiler option is provided, ensure jsxFragmentFactory compiler option or @jsxFrag pragma is provided too const nodeSourceFile = getSourceFileOfNode(node); if ( - getJSXTransformEnabled(compilerOptions) && (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx")) + getJSXTransformEnabled(compilerOptions) + && (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx")) && !compilerOptions.jsxFragmentFactory && !nodeSourceFile.pragmas.has("jsxfrag") ) { error( node, compilerOptions.jsxFactory - ? Diagnostics.The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option + ? Diagnostics + .The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option : Diagnostics.An_jsxFrag_pragma_is_required_when_using_an_jsx_pragma_with_JSX_fragments, ); } @@ -28965,7 +37839,10 @@ namespace ts { * @remarks Because this function calls getSpreadType, it needs to use the same checks as checkObjectLiteral, * which also calls getSpreadType. */ - function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode | undefined) { + function createJsxAttributesTypeFromAttributesProperty( + openingLikeElement: JsxOpeningLikeElement, + checkMode: CheckMode | undefined, + ) { const attributes = openingLikeElement.attributes; const attributesType = getContextualType(attributes, ContextFlags.None); const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined; @@ -28999,14 +37876,24 @@ namespace ts { if (attributesType) { const prop = getPropertyOfType(attributesType, member.escapedName); if (prop && prop.declarations && isDeprecatedSymbol(prop)) { - addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string); + addDeprecatedSuggestion( + attributeDecl.name, + prop.declarations, + attributeDecl.name.escapedText as string, + ); } } } else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); + spread = getSpreadType( + spread, + createJsxAttributesType(), + attributes.symbol, + objectFlags, + /*readonly*/ false, + ); attributesTable = createSymbolTable(); } const exprType = getReducedType(checkExpressionCached(attributeDecl.expression, checkMode)); @@ -29028,12 +37915,19 @@ namespace ts { if (!hasSpreadAnyType) { if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); + spread = getSpreadType( + spread, + createJsxAttributesType(), + attributes.symbol, + objectFlags, + /*readonly*/ false, + ); } } // Handle children attribute - const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ? openingLikeElement.parent as JsxElement : undefined; + const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement + ? openingLikeElement.parent as JsxElement : undefined; // We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement if (parent && parent.openingElement === openingLikeElement && parent.children.length > 0) { const childrenTypes: Type[] = checkJsxChildren(parent, checkMode); @@ -29043,23 +37937,43 @@ namespace ts { // This is because children element will overwrite the value from attributes. // Note: we will not warn "children" attribute overwritten if "children" attribute is specified in object spread. if (explicitlySpecifyChildrenAttribute) { - error(attributes, Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, unescapeLeadingUnderscores(jsxChildrenPropertyName)); + error( + attributes, + Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, + unescapeLeadingUnderscores(jsxChildrenPropertyName), + ); } - const contextualType = getApparentTypeOfContextualType(openingLikeElement.attributes, /*contextFlags*/ undefined); - const childrenContextualType = contextualType && getTypeOfPropertyOfContextualType(contextualType, jsxChildrenPropertyName); + const contextualType = getApparentTypeOfContextualType( + openingLikeElement.attributes, + /*contextFlags*/ undefined, + ); + const childrenContextualType = contextualType + && getTypeOfPropertyOfContextualType(contextualType, jsxChildrenPropertyName); // If there are children in the body of JSX element, create dummy attribute "children" with the union of children types so that it will pass the attribute checking process const childrenPropSymbol = createSymbol(SymbolFlags.Property, jsxChildrenPropertyName); - childrenPropSymbol.type = childrenTypes.length === 1 ? childrenTypes[0] : - childrenContextualType && someType(childrenContextualType, isTupleLikeType) ? createTupleType(childrenTypes) : - createArrayType(getUnionType(childrenTypes)); + childrenPropSymbol.type = childrenTypes.length === 1 ? childrenTypes[0] + : childrenContextualType && someType(childrenContextualType, isTupleLikeType) + ? createTupleType(childrenTypes) + : createArrayType(getUnionType(childrenTypes)); // Fake up a property declaration for the children - childrenPropSymbol.valueDeclaration = factory.createPropertySignature(/*modifiers*/ undefined, unescapeLeadingUnderscores(jsxChildrenPropertyName), /*questionToken*/ undefined, /*type*/ undefined); + childrenPropSymbol.valueDeclaration = factory.createPropertySignature( + /*modifiers*/ undefined, + unescapeLeadingUnderscores(jsxChildrenPropertyName), + /*questionToken*/ undefined, + /*type*/ undefined, + ); setParent(childrenPropSymbol.valueDeclaration, attributes); childrenPropSymbol.valueDeclaration.symbol = childrenPropSymbol; const childPropMap = createSymbolTable(); childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); - spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, emptyArray), attributes.symbol, objectFlags, /*readonly*/ false); + spread = getSpreadType( + spread, + createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, emptyArray), + attributes.symbol, + objectFlags, + /*readonly*/ false, + ); } } @@ -29078,8 +37992,15 @@ namespace ts { */ function createJsxAttributesType() { objectFlags |= freshObjectLiteralFlag; - const result = createAnonymousType(attributes.symbol, attributesTable, emptyArray, emptyArray, emptyArray); - result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; + const result = createAnonymousType( + attributes.symbol, + attributesTable, + emptyArray, + emptyArray, + emptyArray, + ); + result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral + | ObjectFlags.ContainsObjectOrArrayLiteral; return result; } } @@ -29104,13 +38025,24 @@ namespace ts { return childrenTypes; } - function checkSpreadPropOverrides(type: Type, props: SymbolTable, spread: SpreadAssignment | JsxSpreadAttribute) { + function checkSpreadPropOverrides( + type: Type, + props: SymbolTable, + spread: SpreadAssignment | JsxSpreadAttribute, + ) { for (const right of getPropertiesOfType(type)) { if (!(right.flags & SymbolFlags.Optional)) { const left = props.get(right.escapedName); if (left) { - const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName)); - addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property)); + const diagnostic = error( + left.valueDeclaration, + Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, + unescapeLeadingUnderscores(left.escapedName), + ); + addRelatedInfo( + diagnostic, + createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property), + ); } } } @@ -29159,12 +38091,21 @@ namespace ts { } // Wasn't found - error(node, Diagnostics.Property_0_does_not_exist_on_type_1, idText(node.tagName), "JSX." + JsxNames.IntrinsicElements); + error( + node, + Diagnostics.Property_0_does_not_exist_on_type_1, + idText(node.tagName), + "JSX." + JsxNames.IntrinsicElements, + ); return links.resolvedSymbol = unknownSymbol; } else { if (noImplicitAny) { - error(node, Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, unescapeLeadingUnderscores(JsxNames.IntrinsicElements)); + error( + node, + Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, + unescapeLeadingUnderscores(JsxNames.IntrinsicElements), + ); } return links.resolvedSymbol = unknownSymbol; } @@ -29181,13 +38122,17 @@ namespace ts { if (links && links.jsxImplicitImportContainer) { return links.jsxImplicitImportContainer; } - const runtimeImportSpecifier = getJSXRuntimeImport(getJSXImplicitImportBase(compilerOptions, file), compilerOptions); + const runtimeImportSpecifier = getJSXRuntimeImport( + getJSXImplicitImportBase(compilerOptions, file), + compilerOptions, + ); if (!runtimeImportSpecifier) { return undefined; } const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic; const errorMessage = isClassic - ? Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option + ? Diagnostics + .Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option : Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations; const mod = resolveExternalModule(location!, runtimeImportSpecifier, errorMessage, location!); const result = mod && mod !== unknownSymbol ? getMergedSymbol(resolveSymbol(mod)) : undefined; @@ -29207,11 +38152,24 @@ namespace ts { if (!resolvedNamespace || resolvedNamespace === unknownSymbol) { const namespaceName = getJsxNamespace(location); - resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false); + resolvedNamespace = resolveName( + location, + namespaceName, + SymbolFlags.Namespace, + /*diagnosticMessage*/ undefined, + namespaceName, + /*isUse*/ false, + ); } if (resolvedNamespace) { - const candidate = resolveSymbol(getSymbol(getExportsOfSymbol(resolveSymbol(resolvedNamespace)), JsxNames.JSX, SymbolFlags.Namespace)); + const candidate = resolveSymbol( + getSymbol( + getExportsOfSymbol(resolveSymbol(resolvedNamespace)), + JsxNames.JSX, + SymbolFlags.Namespace, + ), + ); if (candidate && candidate !== unknownSymbol) { if (links) { links.jsxNamespace = candidate; @@ -29224,7 +38182,9 @@ namespace ts { } } // JSX global fallback - const s = resolveSymbol(getGlobalSymbol(JsxNames.JSX, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined)); + const s = resolveSymbol( + getGlobalSymbol(JsxNames.JSX, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined), + ); if (s === unknownSymbol) { return undefined!; // TODO: GH#18217 } @@ -29238,13 +38198,19 @@ namespace ts { * @param nameOfAttribPropContainer a string of value JsxNames.ElementAttributesPropertyNameContainer or JsxNames.ElementChildrenAttributeNameContainer * if other string is given or the container doesn't exist, return undefined. */ - function getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer: __String, jsxNamespace: Symbol): __String | undefined { + function getNameFromJsxElementAttributesContainer( + nameOfAttribPropContainer: __String, + jsxNamespace: Symbol, + ): __String | undefined { // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [symbol] - const jsxElementAttribPropInterfaceSym = jsxNamespace && getSymbol(jsxNamespace.exports!, nameOfAttribPropContainer, SymbolFlags.Type); + const jsxElementAttribPropInterfaceSym = jsxNamespace + && getSymbol(jsxNamespace.exports!, nameOfAttribPropContainer, SymbolFlags.Type); // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [type] - const jsxElementAttribPropInterfaceType = jsxElementAttribPropInterfaceSym && getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym); + const jsxElementAttribPropInterfaceType = jsxElementAttribPropInterfaceSym + && getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym); // The properties of JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute - const propertiesOfJsxElementAttribPropInterface = jsxElementAttribPropInterfaceType && getPropertiesOfType(jsxElementAttribPropInterfaceType); + const propertiesOfJsxElementAttribPropInterface = jsxElementAttribPropInterfaceType + && getPropertiesOfType(jsxElementAttribPropInterfaceType); if (propertiesOfJsxElementAttribPropInterface) { // Element Attributes has zero properties, so the element attributes type will be the class instance type if (propertiesOfJsxElementAttribPropInterface.length === 0) { @@ -29255,9 +38221,16 @@ namespace ts { else if (propertiesOfJsxElementAttribPropInterface.length === 1) { return propertiesOfJsxElementAttribPropInterface[0].escapedName; } - else if (propertiesOfJsxElementAttribPropInterface.length > 1 && jsxElementAttribPropInterfaceSym.declarations) { + else if ( + propertiesOfJsxElementAttribPropInterface.length > 1 + && jsxElementAttribPropInterfaceSym.declarations + ) { // More than one property on ElementAttributesProperty is an error - error(jsxElementAttribPropInterfaceSym.declarations[0], Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, unescapeLeadingUnderscores(nameOfAttribPropContainer)); + error( + jsxElementAttribPropInterfaceSym.declarations[0], + Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, + unescapeLeadingUnderscores(nameOfAttribPropContainer), + ); } } return undefined; @@ -29265,7 +38238,8 @@ namespace ts { function getJsxLibraryManagedAttributes(jsxNamespace: Symbol) { // JSX.LibraryManagedAttributes [symbol] - return jsxNamespace && getSymbol(jsxNamespace.exports!, JsxNames.LibraryManagedAttributes, SymbolFlags.Type); + return jsxNamespace + && getSymbol(jsxNamespace.exports!, JsxNames.LibraryManagedAttributes, SymbolFlags.Type); } /// e.g. "props" for React.d.ts, @@ -29274,21 +38248,38 @@ namespace ts { /// or '' if it has 0 properties (which means every /// non-intrinsic elements' attributes type is the element instance type) function getJsxElementPropertiesName(jsxNamespace: Symbol) { - return getNameFromJsxElementAttributesContainer(JsxNames.ElementAttributesPropertyNameContainer, jsxNamespace); + return getNameFromJsxElementAttributesContainer( + JsxNames.ElementAttributesPropertyNameContainer, + jsxNamespace, + ); } function getJsxElementChildrenPropertyName(jsxNamespace: Symbol): __String | undefined { - return getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer, jsxNamespace); + return getNameFromJsxElementAttributesContainer( + JsxNames.ElementChildrenAttributeNameContainer, + jsxNamespace, + ); } - function getUninstantiatedJsxSignaturesOfType(elementType: Type, caller: JsxOpeningLikeElement): readonly Signature[] { + function getUninstantiatedJsxSignaturesOfType( + elementType: Type, + caller: JsxOpeningLikeElement, + ): readonly Signature[] { if (elementType.flags & TypeFlags.String) { return [anySignature]; } else if (elementType.flags & TypeFlags.StringLiteral) { - const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType(elementType as StringLiteralType, caller); + const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType( + elementType as StringLiteralType, + caller, + ); if (!intrinsicType) { - error(caller, Diagnostics.Property_0_does_not_exist_on_type_1, (elementType as StringLiteralType).value, "JSX." + JsxNames.IntrinsicElements); + error( + caller, + Diagnostics.Property_0_does_not_exist_on_type_1, + (elementType as StringLiteralType).value, + "JSX." + JsxNames.IntrinsicElements, + ); return emptyArray; } else { @@ -29305,12 +38296,17 @@ namespace ts { } if (signatures.length === 0 && apparentElemType.flags & TypeFlags.Union) { // If each member has some combination of new/call signatures; make a union signature list for those - signatures = getUnionSignatures(map((apparentElemType as UnionType).types, t => getUninstantiatedJsxSignaturesOfType(t, caller))); + signatures = getUnionSignatures( + map((apparentElemType as UnionType).types, t => getUninstantiatedJsxSignaturesOfType(t, caller)), + ); } return signatures; } - function getIntrinsicAttributesTypeFromStringLiteralType(type: StringLiteralType, location: Node): Type | undefined { + function getIntrinsicAttributesTypeFromStringLiteralType( + type: StringLiteralType, + location: Node, + ): Type | undefined { // If the elemType is a stringLiteral type, we can then provide a check to make sure that the string literal type is one of the Jsx intrinsic element type // For example: // var CustomTag: "h1" = "h1"; @@ -29318,7 +38314,10 @@ namespace ts { const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, location); if (!isErrorType(intrinsicElementsType)) { const stringLiteralTypeName = type.value; - const intrinsicProp = getPropertyOfType(intrinsicElementsType, escapeLeadingUnderscores(stringLiteralTypeName)); + const intrinsicProp = getPropertyOfType( + intrinsicElementsType, + escapeLeadingUnderscores(stringLiteralTypeName), + ); if (intrinsicProp) { return getTypeOfSymbol(intrinsicProp); } @@ -29332,18 +38331,36 @@ namespace ts { return anyType; } - function checkJsxReturnAssignableToAppropriateBound(refKind: JsxReferenceKind, elemInstanceType: Type, openingLikeElement: JsxOpeningLikeElement) { + function checkJsxReturnAssignableToAppropriateBound( + refKind: JsxReferenceKind, + elemInstanceType: Type, + openingLikeElement: JsxOpeningLikeElement, + ) { if (refKind === JsxReferenceKind.Function) { const sfcReturnConstraint = getJsxStatelessElementTypeAt(openingLikeElement); if (sfcReturnConstraint) { - checkTypeRelatedTo(elemInstanceType, sfcReturnConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_return_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); + checkTypeRelatedTo( + elemInstanceType, + sfcReturnConstraint, + assignableRelation, + openingLikeElement.tagName, + Diagnostics.Its_return_type_0_is_not_a_valid_JSX_element, + generateInitialErrorChain, + ); } } else if (refKind === JsxReferenceKind.Component) { const classConstraint = getJsxElementClassTypeAt(openingLikeElement); if (classConstraint) { // Issue an error if this return type isn't assignable to JSX.ElementClass, failing that - checkTypeRelatedTo(elemInstanceType, classConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); + checkTypeRelatedTo( + elemInstanceType, + classConstraint, + assignableRelation, + openingLikeElement.tagName, + Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, + generateInitialErrorChain, + ); } } else { // Mixed @@ -29353,12 +38370,23 @@ namespace ts { return; } const combined = getUnionType([sfcReturnConstraint, classConstraint]); - checkTypeRelatedTo(elemInstanceType, combined, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_element_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); + checkTypeRelatedTo( + elemInstanceType, + combined, + assignableRelation, + openingLikeElement.tagName, + Diagnostics.Its_element_type_0_is_not_a_valid_JSX_element, + generateInitialErrorChain, + ); } function generateInitialErrorChain(): DiagnosticMessageChain { const componentName = getTextOfNode(openingLikeElement.tagName); - return chainDiagnosticMessages(/* details */ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); + return chainDiagnosticMessages( + /* details */ undefined, + Diagnostics._0_cannot_be_used_as_a_JSX_component, + componentName, + ); } } @@ -29376,7 +38404,8 @@ namespace ts { return links.resolvedJsxElementAttributesType = getTypeOfSymbol(symbol) || errorType; } else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) { - return links.resolvedJsxElementAttributesType = getIndexTypeOfType(getJsxType(JsxNames.IntrinsicElements, node), stringType) || errorType; + return links.resolvedJsxElementAttributesType = + getIndexTypeOfType(getJsxType(JsxNames.IntrinsicElements, node), stringType) || errorType; } else { return links.resolvedJsxElementAttributesType = errorType; @@ -29418,7 +38447,11 @@ namespace ts { if (getJsxElementTypeAt(errorNode) === undefined) { if (noImplicitAny) { - error(errorNode, Diagnostics.JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist); + error( + errorNode, + Diagnostics + .JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist, + ); } } } @@ -29435,14 +38468,22 @@ namespace ts { if (!getJsxNamespaceContainerForImplicitImport(node)) { // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. - const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; + const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React + ? Diagnostics.Cannot_find_name_0 : undefined; const jsxFactoryNamespace = getJsxNamespace(node); const jsxFactoryLocation = isNodeOpeningLikeElement ? node.tagName : node; // allow null as jsxFragmentFactory let jsxFactorySym: Symbol | undefined; if (!(isJsxOpeningFragment(node) && jsxFactoryNamespace === "null")) { - jsxFactorySym = resolveName(jsxFactoryLocation, jsxFactoryNamespace, SymbolFlags.Value, jsxFactoryRefErr, jsxFactoryNamespace, /*isUse*/ true); + jsxFactorySym = resolveName( + jsxFactoryLocation, + jsxFactoryNamespace, + SymbolFlags.Value, + jsxFactoryRefErr, + jsxFactoryNamespace, + /*isUse*/ true, + ); } if (jsxFactorySym) { @@ -29461,7 +38502,14 @@ namespace ts { const file = getSourceFileOfNode(node); const localJsxNamespace = getLocalJsxNamespace(file); if (localJsxNamespace) { - resolveName(jsxFactoryLocation, localJsxNamespace, SymbolFlags.Value, jsxFactoryRefErr, localJsxNamespace, /*isUse*/ true); + resolveName( + jsxFactoryLocation, + localJsxNamespace, + SymbolFlags.Value, + jsxFactoryRefErr, + localJsxNamespace, + /*isUse*/ true, + ); } } } @@ -29470,7 +38518,11 @@ namespace ts { const jsxOpeningLikeNode = node; const sig = getResolvedSignature(jsxOpeningLikeNode); checkDeprecatedSignature(sig, node); - checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(jsxOpeningLikeNode), getReturnTypeOfSignature(sig), jsxOpeningLikeNode); + checkJsxReturnAssignableToAppropriateBound( + getJsxReferenceKind(jsxOpeningLikeNode), + getReturnTypeOfSignature(sig), + jsxOpeningLikeNode, + ); } } @@ -29493,10 +38545,10 @@ namespace ts { // is incorrect and inconsistent with element access expressions, where it is an error, so eventually // we should remove this exception. if ( - getPropertyOfObjectType(targetType, name) || - getApplicableIndexInfoForName(targetType, name) || - isLateBoundName(name) && getIndexInfoOfType(targetType, stringType) || - isComparingJsxAttributes && isHyphenatedJsxName(name) + getPropertyOfObjectType(targetType, name) + || getApplicableIndexInfoForName(targetType, name) + || isLateBoundName(name) && getIndexInfoOfType(targetType, stringType) + || isComparingJsxAttributes && isHyphenatedJsxName(name) ) { // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known. return true; @@ -29513,10 +38565,12 @@ namespace ts { } function isExcessPropertyCheckTarget(type: Type): boolean { - return !!(type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) || - type.flags & TypeFlags.NonPrimitive || - type.flags & TypeFlags.Union && some((type as UnionType).types, isExcessPropertyCheckTarget) || - type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isExcessPropertyCheckTarget)); + return !!(type.flags & TypeFlags.Object + && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) + || type.flags & TypeFlags.NonPrimitive + || type.flags & TypeFlags.Union && some((type as UnionType).types, isExcessPropertyCheckTarget) + || type.flags & TypeFlags.Intersection + && every((type as IntersectionType).types, isExcessPropertyCheckTarget)); } function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) { @@ -29547,8 +38601,8 @@ namespace ts { } if (isInJSFile(symbol.valueDeclaration)) { const parent = symbol.valueDeclaration!.parent; - return parent && isBinaryExpression(parent) && - getAssignmentDeclarationKind(parent) === AssignmentDeclarationKind.PrototypeProperty; + return parent && isBinaryExpression(parent) + && getAssignmentDeclarationKind(parent) === AssignmentDeclarationKind.PrototypeProperty; } } @@ -29561,17 +38615,26 @@ namespace ts { * @param prop The symbol for the property being accessed. */ function checkPropertyAccessibility( - node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement, + node: + | PropertyAccessExpression + | QualifiedName + | PropertyAccessExpression + | VariableDeclaration + | ParameterDeclaration + | ImportTypeNode + | PropertyAssignment + | ShorthandPropertyAssignment + | BindingElement, isSuper: boolean, writing: boolean, type: Type, prop: Symbol, reportError = true, ): boolean { - const errorNode = !reportError ? undefined : - node.kind === SyntaxKind.QualifiedName ? node.right : - node.kind === SyntaxKind.ImportType ? node : - node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name; + const errorNode = !reportError ? undefined + : node.kind === SyntaxKind.QualifiedName ? node.right + : node.kind === SyntaxKind.ImportType ? node + : node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name; return checkPropertyAccessibilityAtLocation(node, isSuper, writing, type, prop, errorNode); } @@ -29586,7 +38649,14 @@ namespace ts { * @param prop The symbol for the property being accessed. * @param errorNode The node where we should report an invalid property access error, or undefined if we should not report errors. */ - function checkPropertyAccessibilityAtLocation(location: Node, isSuper: boolean, writing: boolean, containingType: Type, prop: Symbol, errorNode?: Node): boolean { + function checkPropertyAccessibilityAtLocation( + location: Node, + isSuper: boolean, + writing: boolean, + containingType: Type, + prop: Symbol, + errorNode?: Node, + ): boolean { const flags = getDeclarationModifierFlagsFromSymbol(prop, writing); if (isSuper) { @@ -29600,7 +38670,11 @@ namespace ts { if (languageVersion < ScriptTarget.ES2015) { if (symbolHasNonMethodDeclaration(prop)) { if (errorNode) { - error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); + error( + errorNode, + Diagnostics + .Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword, + ); } return false; } @@ -29611,7 +38685,12 @@ namespace ts { // cannot simultaneously be private and abstract, so this will trigger an // additional error elsewhere. if (errorNode) { - error(errorNode, Diagnostics.Abstract_method_0_in_class_1_cannot_be_accessed_via_super_expression, symbolToString(prop), typeToString(getDeclaringClass(prop)!)); + error( + errorNode, + Diagnostics.Abstract_method_0_in_class_1_cannot_be_accessed_via_super_expression, + symbolToString(prop), + typeToString(getDeclaringClass(prop)!), + ); } return false; } @@ -29619,13 +38698,19 @@ namespace ts { // Referencing abstract properties within their own constructors is not allowed if ( - (flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop) && - (isThisProperty(location) || isThisInitializedObjectBindingExpression(location) || isObjectBindingPattern(location.parent) && isThisInitializedDeclaration(location.parent.parent)) + (flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop) + && (isThisProperty(location) || isThisInitializedObjectBindingExpression(location) + || isObjectBindingPattern(location.parent) && isThisInitializedDeclaration(location.parent.parent)) ) { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!); if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(location)) { if (errorNode) { - error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); + error( + errorNode, + Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, + symbolToString(prop), + getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!), + ); } return false; } @@ -29643,7 +38728,12 @@ namespace ts { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!)!; if (!isNodeWithinClass(location, declaringClassDeclaration)) { if (errorNode) { - error(errorNode, Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, symbolToString(prop), typeToString(getDeclaringClass(prop)!)); + error( + errorNode, + Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, + symbolToString(prop), + typeToString(getDeclaringClass(prop)!), + ); } return false; } @@ -29671,7 +38761,12 @@ namespace ts { enclosingClass = enclosingClass && isClassDerivedFromDeclaringClasses(enclosingClass, prop, writing); if (flags & ModifierFlags.Static || !enclosingClass) { if (errorNode) { - error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(getDeclaringClass(prop) || containingType)); + error( + errorNode, + Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, + symbolToString(prop), + typeToString(getDeclaringClass(prop) || containingType), + ); } return false; } @@ -29682,11 +38777,20 @@ namespace ts { } if (containingType.flags & TypeFlags.TypeParameter) { // get the original type -- represented as the type constraint of the 'this' type - containingType = (containingType as TypeParameter).isThisType ? getConstraintOfTypeParameter(containingType as TypeParameter)! : getBaseConstraintOfType(containingType as TypeParameter)!; // TODO: GH#18217 Use a different variable that's allowed to be undefined + containingType = (containingType as TypeParameter).isThisType + ? getConstraintOfTypeParameter(containingType as TypeParameter)! + : getBaseConstraintOfType(containingType as TypeParameter)!; // TODO: GH#18217 Use a different variable that's allowed to be undefined } if (!containingType || !hasBaseType(containingType, enclosingClass)) { if (errorNode) { - error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1_This_is_an_instance_of_class_2, symbolToString(prop), typeToString(enclosingClass), typeToString(containingType)); + error( + errorNode, + Diagnostics + .Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1_This_is_an_instance_of_class_2, + symbolToString(prop), + typeToString(enclosingClass), + typeToString(containingType), + ); } return false; } @@ -29739,20 +38843,20 @@ namespace ts { } error( node, - facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? - Diagnostics._0_is_possibly_null_or_undefined : - Diagnostics._0_is_possibly_undefined : - Diagnostics._0_is_possibly_null, + facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull + ? Diagnostics._0_is_possibly_null_or_undefined + : Diagnostics._0_is_possibly_undefined + : Diagnostics._0_is_possibly_null, nodeText, ); } else { error( node, - facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? - Diagnostics.Object_is_possibly_null_or_undefined : - Diagnostics.Object_is_possibly_undefined : - Diagnostics.Object_is_possibly_null, + facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull + ? Diagnostics.Object_is_possibly_null_or_undefined + : Diagnostics.Object_is_possibly_undefined + : Diagnostics.Object_is_possibly_null, ); } } @@ -29760,10 +38864,10 @@ namespace ts { function reportCannotInvokePossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { error( node, - facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? - Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined : - Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined : - Diagnostics.Cannot_invoke_an_object_which_is_possibly_null, + facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull + ? Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined + : Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined + : Diagnostics.Cannot_invoke_an_object_which_is_possibly_null, ); } @@ -29816,18 +38920,36 @@ namespace ts { } function checkPropertyAccessExpression(node: PropertyAccessExpression, checkMode: CheckMode | undefined) { - return node.flags & NodeFlags.OptionalChain ? checkPropertyAccessChain(node as PropertyAccessChain, checkMode) : - checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullExpression(node.expression), node.name, checkMode); + return node.flags & NodeFlags.OptionalChain + ? checkPropertyAccessChain(node as PropertyAccessChain, checkMode) + : checkPropertyAccessExpressionOrQualifiedName( + node, + node.expression, + checkNonNullExpression(node.expression), + node.name, + checkMode, + ); } function checkPropertyAccessChain(node: PropertyAccessChain, checkMode: CheckMode | undefined) { const leftType = checkExpression(node.expression); const nonOptionalType = getOptionalExpressionType(leftType, node.expression); - return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name, checkMode), node, nonOptionalType !== leftType); + return propagateOptionalTypeMarker( + checkPropertyAccessExpressionOrQualifiedName( + node, + node.expression, + checkNonNullType(nonOptionalType, node.expression), + node.name, + checkMode, + ), + node, + nonOptionalType !== leftType, + ); } function checkQualifiedName(node: QualifiedName, checkMode: CheckMode | undefined) { - const leftType = isPartOfTypeQuery(node) && isThisIdentifier(node.left) ? checkNonNullType(checkThisExpression(node.left), node.left) : checkNonNullExpression(node.left); + const leftType = isPartOfTypeQuery(node) && isThisIdentifier(node.left) + ? checkNonNullType(checkThisExpression(node.left), node.left) : checkNonNullExpression(node.left); return checkPropertyAccessExpressionOrQualifiedName(node, node.left, leftType, node.right, checkMode); } @@ -29840,10 +38962,15 @@ namespace ts { // Lookup the private identifier lexically. function lookupSymbolForPrivateIdentifierDeclaration(propName: __String, location: Node): Symbol | undefined { - for (let containingClass = getContainingClass(location); !!containingClass; containingClass = getContainingClass(containingClass)) { + for ( + let containingClass = getContainingClass(location); + !!containingClass; + containingClass = getContainingClass(containingClass) + ) { const { symbol } = containingClass; const name = getSymbolNameForPrivateIdentifier(symbol, propName); - const prop = (symbol.members && symbol.members.get(name)) || (symbol.exports && symbol.exports.get(name)); + const prop = (symbol.members && symbol.members.get(name)) + || (symbol.exports && symbol.exports.get(name)); if (prop) { return prop; } @@ -29857,10 +38984,15 @@ namespace ts { if (!isForInStatement(privId.parent)) { if (!isExpressionNode(privId)) { - return grammarErrorOnNode(privId, Diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression); + return grammarErrorOnNode( + privId, + Diagnostics + .Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression, + ); } - const isInOperation = isBinaryExpression(privId.parent) && privId.parent.operatorToken.kind === SyntaxKind.InKeyword; + const isInOperation = isBinaryExpression(privId.parent) + && privId.parent.operatorToken.kind === SyntaxKind.InKeyword; if (!getSymbolForPrivateIdentifierExpression(privId) && !isInOperation) { return grammarErrorOnNode(privId, Diagnostics.Cannot_find_name_0, idText(privId)); } @@ -29890,11 +39022,18 @@ namespace ts { return links.resolvedSymbol; } - function getPrivateIdentifierPropertyOfType(leftType: Type, lexicallyScopedIdentifier: Symbol): Symbol | undefined { + function getPrivateIdentifierPropertyOfType( + leftType: Type, + lexicallyScopedIdentifier: Symbol, + ): Symbol | undefined { return getPropertyOfType(leftType, lexicallyScopedIdentifier.escapedName); } - function checkPrivateIdentifierPropertyAccess(leftType: Type, right: PrivateIdentifier, lexicallyScopedIdentifier: Symbol | undefined): boolean { + function checkPrivateIdentifierPropertyAccess( + leftType: Type, + right: PrivateIdentifier, + lexicallyScopedIdentifier: Symbol | undefined, + ): boolean { // Either the identifier could not be looked up in the lexical scope OR the lexically scoped identifier did not exist on the type. // Find a private identifier with the same description on the type. let propertyOnType: Symbol | undefined; @@ -29902,7 +39041,10 @@ namespace ts { if (properties) { forEach(properties, (symbol: Symbol) => { const decl = symbol.valueDeclaration; - if (decl && isNamedDeclaration(decl) && isPrivateIdentifier(decl.name) && decl.name.escapedText === right.escapedText) { + if ( + decl && isNamedDeclaration(decl) && isPrivateIdentifier(decl.name) + && decl.name.escapedText === right.escapedText + ) { propertyOnType = symbol; return true; } @@ -29923,7 +39065,8 @@ namespace ts { if (findAncestor(lexicalClass, n => typeClass === n)) { const diagnostic = error( right, - Diagnostics.The_property_0_cannot_be_accessed_on_type_1_within_this_class_because_it_is_shadowed_by_another_private_identifier_with_the_same_spelling, + Diagnostics + .The_property_0_cannot_be_accessed_on_type_1_within_this_class_because_it_is_shadowed_by_another_private_identifier_with_the_same_spelling, diagName, typeToString(leftType), ); @@ -29955,15 +39098,27 @@ namespace ts { return false; } - function isThisPropertyAccessInConstructor(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol) { + function isThisPropertyAccessInConstructor( + node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, + prop: Symbol, + ) { return (isConstructorDeclaredProperty(prop) || isThisProperty(node) && isAutoTypedProperty(prop)) && getThisContainer(node, /*includeArrowFunctions*/ true) === getDeclaringConstructor(prop); } - function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, leftType: Type, right: Identifier | PrivateIdentifier, checkMode: CheckMode | undefined) { + function checkPropertyAccessExpressionOrQualifiedName( + node: PropertyAccessExpression | QualifiedName, + left: Expression | QualifiedName, + leftType: Type, + right: Identifier | PrivateIdentifier, + checkMode: CheckMode | undefined, + ) { const parentSymbol = getNodeLinks(left).resolvedSymbol; const assignmentKind = getAssignmentTargetKind(node); - const apparentType = getApparentType(assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) : leftType); + const apparentType = getApparentType( + assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) + : leftType, + ); const isAnyLike = isTypeAny(apparentType) || apparentType === silentNeverType; let prop: Symbol | undefined; if (isPrivateIdentifier(right)) { @@ -29977,8 +39132,15 @@ namespace ts { } const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(right.escapedText, right); - if (assignmentKind && lexicallyScopedSymbol && lexicallyScopedSymbol.valueDeclaration && isMethodDeclaration(lexicallyScopedSymbol.valueDeclaration)) { - grammarErrorOnNode(right, Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, idText(right)); + if ( + assignmentKind && lexicallyScopedSymbol && lexicallyScopedSymbol.valueDeclaration + && isMethodDeclaration(lexicallyScopedSymbol.valueDeclaration) + ) { + grammarErrorOnNode( + right, + Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, + idText(right), + ); } if (isAnyLike) { @@ -29990,13 +39152,15 @@ namespace ts { return anyType; } } - prop = lexicallyScopedSymbol ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedSymbol) : undefined; + prop = lexicallyScopedSymbol ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedSymbol) + : undefined; // Check for private-identifier-specific shadowing and lexical-scoping errors. if (!prop && checkPrivateIdentifierPropertyAccess(leftType, right, lexicallyScopedSymbol)) { return errorType; } else { - const isSetonlyAccessor = prop && prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); + const isSetonlyAccessor = prop && prop.flags & SymbolFlags.SetAccessor + && !(prop.flags & SymbolFlags.GetAccessor); if (isSetonlyAccessor && assignmentKind !== AssignmentKind.Definite) { error(node, Diagnostics.Private_accessor_was_defined_without_a_getter); } @@ -30009,7 +39173,12 @@ namespace ts { } return isErrorType(apparentType) ? errorType : apparentType; } - prop = getPropertyOfType(apparentType, right.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ node.kind === SyntaxKind.QualifiedName); + prop = getPropertyOfType( + apparentType, + right.escapedText, + /*skipObjectFunctionPropertyAugment*/ false, + /*includeTypeOnlyMembers*/ node.kind === SyntaxKind.QualifiedName, + ); } // In `Foo.Bar.Baz`, 'Foo' is not referenced if 'Bar' is a const enum or a module containing only const enums. // `Foo` is also not referenced in `enum FooCopy { Bar = Foo.Bar }`, because the enum member value gets inlined @@ -30020,9 +39189,11 @@ namespace ts { // 2. if 'preserveConstEnums' is enabled and the expression is itself an export, e.g. `export = Foo.Bar.Baz`. if ( isIdentifier(left) && parentSymbol && ( - compilerOptions.isolatedModules || - !(prop && (isConstEnumOrConstEnumOnlyModule(prop) || prop.flags & SymbolFlags.EnumMember && node.parent.kind === SyntaxKind.EnumMember)) || - shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(node) + compilerOptions.isolatedModules + || !(prop + && (isConstEnumOrConstEnumOnlyModule(prop) + || prop.flags & SymbolFlags.EnumMember && node.parent.kind === SyntaxKind.EnumMember)) + || shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(node) ) ) { markAliasReferenced(parentSymbol, node); @@ -30030,24 +39201,42 @@ namespace ts { let propType: Type; if (!prop) { - const indexInfo = !isPrivateIdentifier(right) && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType)) ? - getApplicableIndexInfoForName(apparentType, right.escapedText) : undefined; + const indexInfo = !isPrivateIdentifier(right) + && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) + || isThisTypeParameter(leftType)) + ? getApplicableIndexInfoForName(apparentType, right.escapedText) : undefined; if (!(indexInfo && indexInfo.type)) { const isUncheckedJS = isUncheckedJSSuggestion(node, leftType.symbol, /*excludeClasses*/ true); if (!isUncheckedJS && isJSLiteralType(leftType)) { return anyType; } if (leftType.symbol === globalThisSymbol) { - if (globalThisSymbol.exports!.has(right.escapedText) && (globalThisSymbol.exports!.get(right.escapedText)!.flags & SymbolFlags.BlockScoped)) { - error(right, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(right.escapedText), typeToString(leftType)); + if ( + globalThisSymbol.exports!.has(right.escapedText) + && (globalThisSymbol.exports!.get(right.escapedText)!.flags & SymbolFlags.BlockScoped) + ) { + error( + right, + Diagnostics.Property_0_does_not_exist_on_type_1, + unescapeLeadingUnderscores(right.escapedText), + typeToString(leftType), + ); } else if (noImplicitAny) { - error(right, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(leftType)); + error( + right, + Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, + typeToString(leftType), + ); } return anyType; } if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) { - reportNonexistentProperty(right, isThisTypeParameter(leftType) ? apparentType : leftType, isUncheckedJS); + reportNonexistentProperty( + right, + isThisTypeParameter(leftType) ? apparentType : leftType, + isUncheckedJS, + ); } return errorType; } @@ -30055,9 +39244,14 @@ namespace ts { error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType)); } - propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type; + propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) + ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type; if (compilerOptions.noPropertyAccessFromIndexSignature && isPropertyAccessExpression(node)) { - error(right, Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, unescapeLeadingUnderscores(right.escapedText)); + error( + right, + Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, + unescapeLeadingUnderscores(right.escapedText), + ); } if (indexInfo.declaration && getCombinedNodeFlags(indexInfo.declaration) & NodeFlags.Deprecated) { addDeprecatedSuggestion(right, [indexInfo.declaration], right.escapedText as string); @@ -30077,7 +39271,8 @@ namespace ts { return errorType; } - propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : writing ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); + propType = isThisPropertyAccessInConstructor(node, prop) ? autoType + : writing ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); } return getFlowTypeOfAccessExpression(node, prop, propType, right, checkMode); @@ -30090,20 +39285,34 @@ namespace ts { * - Is from a global file that is different from the reference file, or * - (optionally) Is a class, or is a this.x property access expression */ - function isUncheckedJSSuggestion(node: Node | undefined, suggestion: Symbol | undefined, excludeClasses: boolean): boolean { + function isUncheckedJSSuggestion( + node: Node | undefined, + suggestion: Symbol | undefined, + excludeClasses: boolean, + ): boolean { const file = getSourceFileOfNode(node); if (file) { - if (compilerOptions.checkJs === undefined && file.checkJsDirective === undefined && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX)) { + if ( + compilerOptions.checkJs === undefined && file.checkJsDirective === undefined + && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX) + ) { const declarationFile = forEach(suggestion?.declarations, getSourceFileOfNode); return !(file !== declarationFile && !!declarationFile && isGlobalSourceFile(declarationFile)) && !(excludeClasses && suggestion && suggestion.flags & SymbolFlags.Class) - && !(!!node && excludeClasses && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword); + && !(!!node && excludeClasses && isPropertyAccessExpression(node) + && node.expression.kind === SyntaxKind.ThisKeyword); } } return false; } - function getFlowTypeOfAccessExpression(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol | undefined, propType: Type, errorNode: Node, checkMode: CheckMode | undefined) { + function getFlowTypeOfAccessExpression( + node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, + prop: Symbol | undefined, + propType: Type, + errorNode: Node, + checkMode: CheckMode | undefined, + ) { // Only compute control flow type if this is a property access expression that isn't an // assignment target, and the referenced property was declared as a variable, property, // accessor, or optional method. @@ -30112,8 +39321,8 @@ namespace ts { return removeMissingType(propType, !!(prop && prop.flags & SymbolFlags.Optional)); } if ( - prop && - !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) + prop + && !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) && !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union) && !isDuplicatedCommonJSExport(prop.declarations) ) { @@ -30128,26 +39337,36 @@ namespace ts { // and if we are in a constructor of the same class as the property declaration, assume that // the property is uninitialized at the top of the control flow. let assumeUninitialized = false; - if (strictNullChecks && strictPropertyInitialization && isAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword) { + if ( + strictNullChecks && strictPropertyInitialization && isAccessExpression(node) + && node.expression.kind === SyntaxKind.ThisKeyword + ) { const declaration = prop && prop.valueDeclaration; if (declaration && isPropertyWithoutInitializer(declaration)) { if (!isStatic(declaration)) { const flowContainer = getControlFlowContainer(node); - if (flowContainer.kind === SyntaxKind.Constructor && flowContainer.parent === declaration.parent && !(declaration.flags & NodeFlags.Ambient)) { + if ( + flowContainer.kind === SyntaxKind.Constructor && flowContainer.parent === declaration.parent + && !(declaration.flags & NodeFlags.Ambient) + ) { assumeUninitialized = true; } } } } else if ( - strictNullChecks && prop && prop.valueDeclaration && - isPropertyAccessExpression(prop.valueDeclaration) && - getAssignmentDeclarationPropertyAccessKind(prop.valueDeclaration) && - getControlFlowContainer(node) === getControlFlowContainer(prop.valueDeclaration) + strictNullChecks && prop && prop.valueDeclaration + && isPropertyAccessExpression(prop.valueDeclaration) + && getAssignmentDeclarationPropertyAccessKind(prop.valueDeclaration) + && getControlFlowContainer(node) === getControlFlowContainer(prop.valueDeclaration) ) { assumeUninitialized = true; } - const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType); + const flowType = getFlowTypeOfReference( + node, + propType, + assumeUninitialized ? getOptionalType(propType) : propType, + ); if (assumeUninitialized && !containsUndefinedType(propType) && containsUndefinedType(flowType)) { error(errorNode, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217 // Return the declared type to reduce follow-on errors @@ -30156,7 +39375,11 @@ namespace ts { return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; } - function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | QualifiedName, right: Identifier | PrivateIdentifier): void { + function checkPropertyNotUsedBeforeDeclaration( + prop: Symbol, + node: PropertyAccessExpression | QualifiedName, + right: Identifier | PrivateIdentifier, + ): void { const { valueDeclaration } = prop; if (!valueDeclaration || getSourceFileOfNode(node).isDeclarationFile) { return; @@ -30169,22 +39392,30 @@ namespace ts { && !isOptionalPropertyDeclaration(valueDeclaration) && !(isAccessExpression(node) && isAccessExpression(node.expression)) && !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) - && !(isMethodDeclaration(valueDeclaration) && getCombinedModifierFlags(valueDeclaration) & ModifierFlags.Static) + && !(isMethodDeclaration(valueDeclaration) + && getCombinedModifierFlags(valueDeclaration) & ModifierFlags.Static) && (compilerOptions.useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop)) ) { - diagnosticMessage = error(right, Diagnostics.Property_0_is_used_before_its_initialization, declarationName); + diagnosticMessage = error( + right, + Diagnostics.Property_0_is_used_before_its_initialization, + declarationName, + ); } else if ( - valueDeclaration.kind === SyntaxKind.ClassDeclaration && - node.parent.kind !== SyntaxKind.TypeReference && - !(valueDeclaration.flags & NodeFlags.Ambient) && - !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) + valueDeclaration.kind === SyntaxKind.ClassDeclaration + && node.parent.kind !== SyntaxKind.TypeReference + && !(valueDeclaration.flags & NodeFlags.Ambient) + && !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) ) { diagnosticMessage = error(right, Diagnostics.Class_0_used_before_its_declaration, declarationName); } if (diagnosticMessage) { - addRelatedInfo(diagnosticMessage, createDiagnosticForNode(valueDeclaration, Diagnostics._0_is_declared_here, declarationName)); + addRelatedInfo( + diagnosticMessage, + createDiagnosticForNode(valueDeclaration, Diagnostics._0_is_declared_here, declarationName), + ); } } @@ -30210,7 +39441,8 @@ namespace ts { return false; case SyntaxKind.ArrowFunction: case SyntaxKind.ExpressionStatement: - return isBlock(node.parent) && isClassStaticBlockDeclaration(node.parent.parent) ? true : "quit"; + return isBlock(node.parent) && isClassStaticBlockDeclaration(node.parent.parent) ? true + : "quit"; default: return isExpressionNode(node) ? false : "quit"; } @@ -30246,13 +39478,28 @@ namespace ts { return getIntersectionType(x); } - function reportNonexistentProperty(propNode: Identifier | PrivateIdentifier, containingType: Type, isUncheckedJS: boolean) { + function reportNonexistentProperty( + propNode: Identifier | PrivateIdentifier, + containingType: Type, + isUncheckedJS: boolean, + ) { let errorInfo: DiagnosticMessageChain | undefined; let relatedInfo: Diagnostic | undefined; - if (!isPrivateIdentifier(propNode) && containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) { + if ( + !isPrivateIdentifier(propNode) && containingType.flags & TypeFlags.Union + && !(containingType.flags & TypeFlags.Primitive) + ) { for (const subtype of (containingType as UnionType).types) { - if (!getPropertyOfType(subtype, propNode.escapedText) && !getApplicableIndexInfoForName(subtype, propNode.escapedText)) { - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(subtype)); + if ( + !getPropertyOfType(subtype, propNode.escapedText) + && !getApplicableIndexInfoForName(subtype, propNode.escapedText) + ) { + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Property_0_does_not_exist_on_type_1, + declarationNameToString(propNode), + typeToString(subtype), + ); break; } } @@ -30260,12 +39507,23 @@ namespace ts { if (typeHasStaticProperty(propNode.escapedText, containingType)) { const propName = declarationNameToString(propNode); const typeName = typeToString(containingType); - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName, typeName, typeName + "." + propName); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, + propName, + typeName, + typeName + "." + propName, + ); } else { const promisedType = getPromisedTypeOfPromise(containingType); if (promisedType && getPropertyOfType(promisedType, propNode.escapedText)) { - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType)); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Property_0_does_not_exist_on_type_1, + declarationNameToString(propNode), + typeToString(containingType), + ); relatedInfo = createDiagnosticForNode(propNode, Diagnostics.Did_you_forget_to_use_await); } else { @@ -30273,21 +39531,47 @@ namespace ts { const container = typeToString(containingType); const libSuggestion = getSuggestedLibForNonExistentProperty(missingProperty, containingType); if (libSuggestion !== undefined) { - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_2_or_later, missingProperty, container, libSuggestion); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics + .Property_0_does_not_exist_on_type_1_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_2_or_later, + missingProperty, + container, + libSuggestion, + ); } else { const suggestion = getSuggestedSymbolForNonexistentProperty(propNode, containingType); if (suggestion !== undefined) { const suggestedName = symbolName(suggestion); - const message = isUncheckedJS ? Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2 : Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2; - errorInfo = chainDiagnosticMessages(errorInfo, message, missingProperty, container, suggestedName); - relatedInfo = suggestion.valueDeclaration && createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestedName); + const message = isUncheckedJS + ? Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2 + : Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2; + errorInfo = chainDiagnosticMessages( + errorInfo, + message, + missingProperty, + container, + suggestedName, + ); + relatedInfo = suggestion.valueDeclaration + && createDiagnosticForNode( + suggestion.valueDeclaration, + Diagnostics._0_is_declared_here, + suggestedName, + ); } else { const diagnostic = containerSeemsToBeEmptyDomElement(containingType) - ? Diagnostics.Property_0_does_not_exist_on_type_1_Try_changing_the_lib_compiler_option_to_include_dom + ? Diagnostics + .Property_0_does_not_exist_on_type_1_Try_changing_the_lib_compiler_option_to_include_dom : Diagnostics.Property_0_does_not_exist_on_type_1; - errorInfo = chainDiagnosticMessages(elaborateNeverIntersection(errorInfo, containingType), diagnostic, missingProperty, container); + errorInfo = chainDiagnosticMessages( + elaborateNeverIntersection(errorInfo, containingType), + diagnostic, + missingProperty, + container, + ); } } } @@ -30296,13 +39580,23 @@ namespace ts { if (relatedInfo) { addRelatedInfo(resultDiagnostic, relatedInfo); } - addErrorOrSuggestion(!isUncheckedJS || errorInfo.code !== Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2.code, resultDiagnostic); + addErrorOrSuggestion( + !isUncheckedJS || errorInfo.code !== Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2.code, + resultDiagnostic, + ); } function containerSeemsToBeEmptyDomElement(containingType: Type) { - return (compilerOptions.lib && !compilerOptions.lib.includes("dom")) && - everyContainedType(containingType, type => type.symbol && /^(EventTarget|Node|((HTML[a-zA-Z]*)?Element))$/.test(unescapeLeadingUnderscores(type.symbol.escapedName))) && - isEmptyObjectType(containingType); + return (compilerOptions.lib && !compilerOptions.lib.includes("dom")) + && everyContainedType( + containingType, + type => + type.symbol + && /^(EventTarget|Node|((HTML[a-zA-Z]*)?Element))$/.test( + unescapeLeadingUnderscores(type.symbol.escapedName), + ), + ) + && isEmptyObjectType(containingType); } function typeHasStaticProperty(propName: __String, containingType: Type): boolean { @@ -30342,7 +39636,10 @@ namespace ts { return getSpellingSuggestionForName(name, getPropertiesOfType(baseType), SymbolFlags.ClassMember); } - function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { + function getSuggestedSymbolForNonexistentProperty( + name: Identifier | PrivateIdentifier | string, + containingType: Type, + ): Symbol | undefined { let props = getPropertiesOfType(containingType); if (typeof name !== "string") { const parent = name.parent; @@ -30354,7 +39651,10 @@ namespace ts { return getSpellingSuggestionForName(name, props, SymbolFlags.Value); } - function getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { + function getSuggestedSymbolForNonexistentJSXAttribute( + name: Identifier | PrivateIdentifier | string, + containingType: Type, + ): Symbol | undefined { const strName = isString(name) ? name : idText(name); const properties = getPropertiesOfType(containingType); const jsxSpecific = strName === "for" ? find(properties, x => symbolName(x) === "htmlFor") @@ -30363,45 +39663,71 @@ namespace ts { return jsxSpecific ?? getSpellingSuggestionForName(strName, properties, SymbolFlags.Value); } - function getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined { + function getSuggestionForNonexistentProperty( + name: Identifier | PrivateIdentifier | string, + containingType: Type, + ): string | undefined { const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType); return suggestion && symbolName(suggestion); } - function getSuggestedSymbolForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): Symbol | undefined { + function getSuggestedSymbolForNonexistentSymbol( + location: Node | undefined, + outerName: __String, + meaning: SymbolFlags, + ): Symbol | undefined { Debug.assert(outerName !== undefined, "outername should always be defined"); - const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, /*excludeGlobals*/ false, /*getSpellingSuggestions*/ true, (symbols, name, meaning) => { - Debug.assertEqual(outerName, name, "name should equal outerName"); - const symbol = getSymbol(symbols, name, meaning); - // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function - // So the table *contains* `x` but `x` isn't actually in scope. - // However, resolveNameHelper will continue and call this callback again, so we'll eventually get a correct suggestion. - if (symbol) return symbol; - let candidates: Symbol[]; - if (symbols === globals) { - const primitives = mapDefined( - ["string", "number", "boolean", "object", "bigint", "symbol"], - s => symbols.has((s.charAt(0).toUpperCase() + s.slice(1)) as __String) - ? createSymbol(SymbolFlags.TypeAlias, s as __String) as Symbol - : undefined, - ); - candidates = primitives.concat(arrayFrom(symbols.values())); - } - else { - candidates = arrayFrom(symbols.values()); - } - return getSpellingSuggestionForName(unescapeLeadingUnderscores(name), candidates, meaning); - }); + const result = resolveNameHelper( + location, + outerName, + meaning, + /*nameNotFoundMessage*/ undefined, + outerName, + /*isUse*/ false, + /*excludeGlobals*/ false, + /*getSpellingSuggestions*/ true, + (symbols, name, meaning) => { + Debug.assertEqual(outerName, name, "name should equal outerName"); + const symbol = getSymbol(symbols, name, meaning); + // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function + // So the table *contains* `x` but `x` isn't actually in scope. + // However, resolveNameHelper will continue and call this callback again, so we'll eventually get a correct suggestion. + if (symbol) return symbol; + let candidates: Symbol[]; + if (symbols === globals) { + const primitives = mapDefined( + ["string", "number", "boolean", "object", "bigint", "symbol"], + s => symbols.has((s.charAt(0).toUpperCase() + s.slice(1)) as __String) + ? createSymbol(SymbolFlags.TypeAlias, s as __String) as Symbol + : undefined, + ); + candidates = primitives.concat(arrayFrom(symbols.values())); + } + else { + candidates = arrayFrom(symbols.values()); + } + return getSpellingSuggestionForName(unescapeLeadingUnderscores(name), candidates, meaning); + }, + ); return result; } - function getSuggestionForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): string | undefined { + function getSuggestionForNonexistentSymbol( + location: Node | undefined, + outerName: __String, + meaning: SymbolFlags, + ): string | undefined { const symbolResult = getSuggestedSymbolForNonexistentSymbol(location, outerName, meaning); return symbolResult && symbolName(symbolResult); } function getSuggestedSymbolForNonexistentModule(name: Identifier, targetModule: Symbol): Symbol | undefined { - return targetModule.exports && getSpellingSuggestionForName(idText(name), getExportsOfModuleAsArray(targetModule), SymbolFlags.ModuleMember); + return targetModule.exports + && getSpellingSuggestionForName( + idText(name), + getExportsOfModuleAsArray(targetModule), + SymbolFlags.ModuleMember, + ); } function getSuggestionForNonexistentExport(name: Identifier, targetModule: Symbol): string | undefined { @@ -30409,7 +39735,11 @@ namespace ts { return suggestion && symbolName(suggestion); } - function getSuggestionForNonexistentIndexSignature(objectType: Type, expr: ElementAccessExpression, keyedType: Type): string | undefined { + function getSuggestionForNonexistentIndexSignature( + objectType: Type, + expr: ElementAccessExpression, + keyedType: Type, + ): string | undefined { // check if object type has setter or getter function hasProp(name: "set" | "get") { const prop = getPropertyOfObjectType(objectType, name as __String); @@ -30436,8 +39766,13 @@ namespace ts { return suggestion; } - function getSuggestedTypeForNonexistentStringLiteralType(source: StringLiteralType, target: UnionType): StringLiteralType | undefined { - const candidates = target.types.filter((type): type is StringLiteralType => !!(type.flags & TypeFlags.StringLiteral)); + function getSuggestedTypeForNonexistentStringLiteralType( + source: StringLiteralType, + target: UnionType, + ): StringLiteralType | undefined { + const candidates = target.types.filter((type): type is StringLiteralType => + !!(type.flags & TypeFlags.StringLiteral) + ); return getSpellingSuggestion(source.value, candidates, type => type.value); } @@ -30456,7 +39791,11 @@ namespace ts { * (0.4 allows 1 substitution/transposition for every 5 characters, * and 1 insertion/deletion at 3 characters) */ - function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined { + function getSpellingSuggestionForName( + name: string, + symbols: Symbol[], + meaning: SymbolFlags, + ): Symbol | undefined { return getSpellingSuggestion(name, symbols, getCandidateName); function getCandidateName(candidate: Symbol) { @@ -30480,17 +39819,25 @@ namespace ts { } } - function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isSelfTypeAccess: boolean) { + function markPropertyAsReferenced( + prop: Symbol, + nodeForCheckWriteOnly: Node | undefined, + isSelfTypeAccess: boolean, + ) { const valueDeclaration = prop && (prop.flags & SymbolFlags.ClassMember) && prop.valueDeclaration; if (!valueDeclaration) { return; } const hasPrivateModifier = hasEffectiveModifier(valueDeclaration, ModifierFlags.Private); - const hasPrivateIdentifier = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) && isPrivateIdentifier(prop.valueDeclaration.name); + const hasPrivateIdentifier = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) + && isPrivateIdentifier(prop.valueDeclaration.name); if (!hasPrivateModifier && !hasPrivateIdentifier) { return; } - if (nodeForCheckWriteOnly && isWriteOnlyAccess(nodeForCheckWriteOnly) && !(prop.flags & SymbolFlags.SetAccessor)) { + if ( + nodeForCheckWriteOnly && isWriteOnlyAccess(nodeForCheckWriteOnly) + && !(prop.flags & SymbolFlags.SetAccessor) + ) { return; } if (isSelfTypeAccess) { @@ -30501,7 +39848,8 @@ namespace ts { } } - (getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop)!.isReferenced = SymbolFlags.All; + (getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop)!.isReferenced = + SymbolFlags.All; } function isSelfTypeAccess(name: Expression | QualifiedName, parent: Symbol | undefined) { @@ -30509,14 +39857,32 @@ namespace ts { || !!parent && isEntityNameExpression(name) && parent === getResolvedSymbol(getFirstIdentifier(name)); } - function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: __String): boolean { + function isValidPropertyAccess( + node: PropertyAccessExpression | QualifiedName | ImportTypeNode, + propertyName: __String, + ): boolean { switch (node.kind) { case SyntaxKind.PropertyAccessExpression: - return isValidPropertyAccessWithType(node, node.expression.kind === SyntaxKind.SuperKeyword, propertyName, getWidenedType(checkExpression(node.expression))); + return isValidPropertyAccessWithType( + node, + node.expression.kind === SyntaxKind.SuperKeyword, + propertyName, + getWidenedType(checkExpression(node.expression)), + ); case SyntaxKind.QualifiedName: - return isValidPropertyAccessWithType(node, /*isSuper*/ false, propertyName, getWidenedType(checkExpression(node.left))); + return isValidPropertyAccessWithType( + node, + /*isSuper*/ false, + propertyName, + getWidenedType(checkExpression(node.left)), + ); case SyntaxKind.ImportType: - return isValidPropertyAccessWithType(node, /*isSuper*/ false, propertyName, getTypeFromTypeNode(node)); + return isValidPropertyAccessWithType( + node, + /*isSuper*/ false, + propertyName, + getTypeFromTypeNode(node), + ); } } @@ -30530,8 +39896,18 @@ namespace ts { * @param type the type whose property we are checking. * @param property the accessed property's symbol. */ - function isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode | QualifiedName, type: Type, property: Symbol): boolean { - return isPropertyAccessible(node, node.kind === SyntaxKind.PropertyAccessExpression && node.expression.kind === SyntaxKind.SuperKeyword, /* isWrite */ false, type, property); + function isValidPropertyAccessForCompletions( + node: PropertyAccessExpression | ImportTypeNode | QualifiedName, + type: Type, + property: Symbol, + ): boolean { + return isPropertyAccessible( + node, + node.kind === SyntaxKind.PropertyAccessExpression && node.expression.kind === SyntaxKind.SuperKeyword, + /* isWrite */ false, + type, + property, + ); // Previously we validated the 'this' type of methods but this adversely affected performance. See #31377 for more context. } @@ -30619,10 +39995,10 @@ namespace ts { let node = expr.parent; while (node) { if ( - node.kind === SyntaxKind.ForInStatement && - child === (node as ForInStatement).statement && - getForInVariableSymbol(node as ForInStatement) === symbol && - hasNumericPropertyNames(getTypeOfExpression((node as ForInStatement).expression)) + node.kind === SyntaxKind.ForInStatement + && child === (node as ForInStatement).statement + && getForInVariableSymbol(node as ForInStatement) === symbol + && hasNumericPropertyNames(getTypeOfExpression((node as ForInStatement).expression)) ) { return true; } @@ -30635,18 +40011,27 @@ namespace ts { } function checkIndexedAccess(node: ElementAccessExpression, checkMode: CheckMode | undefined): Type { - return node.flags & NodeFlags.OptionalChain ? checkElementAccessChain(node as ElementAccessChain, checkMode) : - checkElementAccessExpression(node, checkNonNullExpression(node.expression), checkMode); + return node.flags & NodeFlags.OptionalChain ? checkElementAccessChain(node as ElementAccessChain, checkMode) + : checkElementAccessExpression(node, checkNonNullExpression(node.expression), checkMode); } function checkElementAccessChain(node: ElementAccessChain, checkMode: CheckMode | undefined) { const exprType = checkExpression(node.expression); const nonOptionalType = getOptionalExpressionType(exprType, node.expression); - return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression), checkMode), node, nonOptionalType !== exprType); + return propagateOptionalTypeMarker( + checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression), checkMode), + node, + nonOptionalType !== exprType, + ); } - function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type, checkMode: CheckMode | undefined): Type { - const objectType = getAssignmentTargetKind(node) !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(exprType) : exprType; + function checkElementAccessExpression( + node: ElementAccessExpression, + exprType: Type, + checkMode: CheckMode | undefined, + ): Type { + const objectType = getAssignmentTargetKind(node) !== AssignmentKind.None || isMethodAccessForCall(node) + ? getWidenedType(exprType) : exprType; const indexExpression = node.argumentExpression; const indexType = checkExpression(indexExpression); @@ -30660,14 +40045,28 @@ namespace ts { } const effectiveIndexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType; - const accessFlags = isAssignmentTarget(node) ? - AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0) : - AccessFlags.ExpressionPosition; - const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, accessFlags, node) || errorType; - return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, getNodeLinks(node).resolvedSymbol, indexedAccessType, indexExpression, checkMode), node); + const accessFlags = isAssignmentTarget(node) + ? AccessFlags.Writing + | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) + ? AccessFlags.NoIndexSignatures : 0) + : AccessFlags.ExpressionPosition; + const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, accessFlags, node) + || errorType; + return checkIndexedAccessIndexType( + getFlowTypeOfAccessExpression( + node, + getNodeLinks(node).resolvedSymbol, + indexedAccessType, + indexExpression, + checkMode, + ), + node, + ); } - function callLikeExpressionMayHaveTypeArguments(node: CallLikeExpression): node is CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement { + function callLikeExpressionMayHaveTypeArguments( + node: CallLikeExpression, + ): node is CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement { return isCallOrNewExpression(node) || isTaggedTemplateExpression(node) || isJsxOpeningLikeElement(node); } @@ -30705,7 +40104,11 @@ namespace ts { // interface B extends A { (x: 'foo'): string } // const b: B; // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void] - function reorderCandidates(signatures: readonly Signature[], result: Signature[], callChainFlags: SignatureFlags): void { + function reorderCandidates( + signatures: readonly Signature[], + result: Signature[], + callChainFlags: SignatureFlags, + ): void { let lastParent: Node | undefined; let lastSymbol: Symbol | undefined; let cutoffIndex = 0; @@ -30747,12 +40150,18 @@ namespace ts { spliceIndex = index; } - result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags) : signature); + result.splice( + spliceIndex, + 0, + callChainFlags ? getOptionalCallSignature(signature, callChainFlags) : signature, + ); } } function isSpreadArgument(arg: Expression | undefined): arg is Expression { - return !!arg && (arg.kind === SyntaxKind.SpreadElement || arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).isSpread); + return !!arg + && (arg.kind === SyntaxKind.SpreadElement + || arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).isSpread); } function getSpreadArgumentIndex(args: readonly Expression[]): number { @@ -30767,7 +40176,12 @@ namespace ts { return !!(t.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Unknown | TypeFlags.Any)); } - function hasCorrectArity(node: CallLikeExpression, args: readonly Expression[], signature: Signature, signatureHelpTrailingComma = false) { + function hasCorrectArity( + node: CallLikeExpression, + args: readonly Expression[], + signature: Signature, + signatureHelpTrailingComma = false, + ) { let argCount: number; let callIsIncomplete = false; // In incomplete call we want to be lenient when we have too few arguments let effectiveParameterCount = getParameterCount(signature); @@ -30816,7 +40230,8 @@ namespace ts { // If a spread argument is present, check that it corresponds to a rest parameter or at least that it's in the valid range. const spreadArgIndex = getSpreadArgumentIndex(args); if (spreadArgIndex >= 0) { - return spreadArgIndex >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || spreadArgIndex < getParameterCount(signature)); + return spreadArgIndex >= getMinArgumentCount(signature) + && (hasEffectiveRestParameter(signature) || spreadArgIndex < getParameterCount(signature)); } } @@ -30832,7 +40247,12 @@ namespace ts { } for (let i = argCount; i < effectiveMinimumArguments; i++) { const type = getTypeAtPosition(signature, i); - if (filterType(type, isInJSFile(node) && !strictNullChecks ? acceptsVoidUndefinedUnknownOrAny : acceptsVoid).flags & TypeFlags.Never) { + if ( + filterType( + type, + isInJSFile(node) && !strictNullChecks ? acceptsVoidUndefinedUnknownOrAny : acceptsVoid, + ).flags & TypeFlags.Never + ) { return false; } } @@ -30844,8 +40264,8 @@ namespace ts { // the declared number of type parameters, the call has an incorrect arity. const numTypeParameters = length(signature.typeParameters); const minTypeArgumentCount = getMinTypeArgumentCount(signature.typeParameters); - return !some(typeArguments) || - (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters); + return !some(typeArguments) + || (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters); } // If type has a single call signature and no other members, return that signature. Otherwise, return undefined. @@ -30854,18 +40274,24 @@ namespace ts { } function getSingleCallOrConstructSignature(type: Type): Signature | undefined { - return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false) || - getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ false); + return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false) + || getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ false); } function getSingleSignature(type: Type, kind: SignatureKind, allowMembers: boolean): Signature | undefined { if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); if (allowMembers || resolved.properties.length === 0 && resolved.indexInfos.length === 0) { - if (kind === SignatureKind.Call && resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0) { + if ( + kind === SignatureKind.Call && resolved.callSignatures.length === 1 + && resolved.constructSignatures.length === 0 + ) { return resolved.callSignatures[0]; } - if (kind === SignatureKind.Construct && resolved.constructSignatures.length === 1 && resolved.callSignatures.length === 0) { + if ( + kind === SignatureKind.Construct && resolved.constructSignatures.length === 1 + && resolved.callSignatures.length === 0 + ) { return resolved.constructSignatures[0]; } } @@ -30874,13 +40300,25 @@ namespace ts { } // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) - function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, inferenceContext?: InferenceContext, compareTypes?: TypeComparer): Signature { - const context = createInferenceContext(signature.typeParameters!, signature, InferenceFlags.None, compareTypes); + function instantiateSignatureInContextOf( + signature: Signature, + contextualSignature: Signature, + inferenceContext?: InferenceContext, + compareTypes?: TypeComparer, + ): Signature { + const context = createInferenceContext( + signature.typeParameters!, + signature, + InferenceFlags.None, + compareTypes, + ); // We clone the inferenceContext to avoid fixing. For example, when the source signature is (x: T) => T[] and // the contextual signature is (...args: A) => B, we want to infer the element type of A's constraint (say 'any') // for T but leave it possible to later infer '[any]' back to A. const restType = getEffectiveRestType(contextualSignature); - const mapper = inferenceContext && (restType && restType.flags & TypeFlags.TypeParameter ? inferenceContext.nonFixingMapper : inferenceContext.mapper); + const mapper = inferenceContext + && (restType && restType.flags & TypeFlags.TypeParameter ? inferenceContext.nonFixingMapper + : inferenceContext.mapper); const sourceSignature = mapper ? instantiateSignature(contextualSignature, mapper) : contextualSignature; applyToParameterTypes(sourceSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type @@ -30891,10 +40329,19 @@ namespace ts { inferTypes(context.inferences, source, target, InferencePriority.ReturnType); }); } - return getSignatureInstantiation(signature, getInferredTypes(context), isInJSFile(contextualSignature.declaration)); + return getSignatureInstantiation( + signature, + getInferredTypes(context), + isInJSFile(contextualSignature.declaration), + ); } - function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, checkMode: CheckMode, context: InferenceContext): Type[] { + function inferJsxTypeArguments( + node: JsxOpeningLikeElement, + signature: Signature, + checkMode: CheckMode, + context: InferenceContext, + ): Type[] { const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, context, checkMode); inferTypes(context.inferences, checkAttrType, paramType); @@ -30906,12 +40353,18 @@ namespace ts { return voidType; } const thisArgumentType = checkExpression(thisArgumentNode); - return isOptionalChainRoot(thisArgumentNode.parent) ? getNonNullableType(thisArgumentType) : - isOptionalChain(thisArgumentNode.parent) ? removeOptionalTypeMarker(thisArgumentType) : - thisArgumentType; + return isOptionalChainRoot(thisArgumentNode.parent) ? getNonNullableType(thisArgumentType) + : isOptionalChain(thisArgumentNode.parent) ? removeOptionalTypeMarker(thisArgumentType) + : thisArgumentType; } - function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: readonly Expression[], checkMode: CheckMode, context: InferenceContext): Type[] { + function inferTypeArguments( + node: CallLikeExpression, + signature: Signature, + args: readonly Expression[], + checkMode: CheckMode, + context: InferenceContext, + ): Type[] { if (isJsxOpeningLikeElement(node)) { return inferJsxTypeArguments(node, signature, checkMode, context); } @@ -30922,12 +40375,16 @@ namespace ts { // return type of 'wrap'. if (node.kind !== SyntaxKind.Decorator) { const skipBindingPatterns = every(signature.typeParameters, p => !!getDefaultFromTypeParameter(p)); - const contextualType = getContextualType(node, skipBindingPatterns ? ContextFlags.SkipBindingPatterns : ContextFlags.None); + const contextualType = getContextualType( + node, + skipBindingPatterns ? ContextFlags.SkipBindingPatterns : ContextFlags.None, + ); if (contextualType) { const inferenceTargetType = getReturnTypeOfSignature(signature); if (couldContainTypeVariables(inferenceTargetType)) { const outerContext = getInferenceContext(node); - const isFromBindingPattern = !skipBindingPatterns && getContextualType(node, ContextFlags.SkipBindingPatterns) !== contextualType; + const isFromBindingPattern = !skipBindingPatterns + && getContextualType(node, ContextFlags.SkipBindingPatterns) !== contextualType; // A return type inference from a binding pattern can be used in instantiating the contextual // type of an argument later in inference, but cannot stand on its own as the final return type. // It is incorporated into `context.returnMapper` which is used in `instantiateContextualType`, @@ -30942,7 +40399,9 @@ namespace ts { // We clone the inference context to avoid disturbing a resolution in progress for an // outer call expression. Effectively we just want a snapshot of whatever has been // inferred for any outer call expression so far. - const outerMapper = getMapperFromContext(cloneInferenceContext(outerContext, InferenceFlags.NoDefault)); + const outerMapper = getMapperFromContext( + cloneInferenceContext(outerContext, InferenceFlags.NoDefault), + ); const instantiatedType = instantiateType(contextualType, outerMapper); // If the contextual type is a generic function type with a single call signature, we // instantiate the type with its own type parameters and type arguments. This ensures that @@ -30952,20 +40411,38 @@ namespace ts { // const boxElements: (a: A[]) => { value: A }[] = arrayMap(value => ({ value })); // Above, the type of the 'value' parameter is inferred to be 'A'. const contextualSignature = getSingleCallSignature(instantiatedType); - const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ? - getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters)) : - instantiatedType; + const inferenceSourceType = contextualSignature && contextualSignature.typeParameters + ? getOrCreateTypeFromSignature( + getSignatureInstantiationWithoutFillingInTypeArguments( + contextualSignature, + contextualSignature.typeParameters, + ), + ) + : instantiatedType; // Inferences made from return types have lower priority than all other inferences. - inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); + inferTypes( + context.inferences, + inferenceSourceType, + inferenceTargetType, + InferencePriority.ReturnType, + ); } // Create a type mapper for instantiating generic contextual types using the inferences made // from the return type. We need a separate inference pass here because (a) instantiation of // the source type uses the outer context's return mapper (which excludes inferences made from // outer arguments), and (b) we don't want any further inferences going into this context. - const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); - const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper); + const returnContext = createInferenceContext( + signature.typeParameters!, + signature, + context.flags, + ); + const returnSourceType = instantiateType( + contextualType, + outerContext && outerContext.returnMapper, + ); inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); - context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; + context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) + ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; } } } @@ -30975,7 +40452,8 @@ namespace ts { if (restType && restType.flags & TypeFlags.TypeParameter) { const info = find(context.inferences, info => info.typeParameter === restType); if (info) { - info.impliedArity = findIndex(args, isSpreadArgument, argCount) < 0 ? args.length - argCount : undefined; + info.impliedArity = findIndex(args, isSpreadArgument, argCount) < 0 ? args.length - argCount + : undefined; } } @@ -30987,7 +40465,10 @@ namespace ts { for (let i = 0; i < argCount; i++) { const arg = args[i]; - if (arg.kind !== SyntaxKind.OmittedExpression && !(checkMode & CheckMode.IsForStringLiteralArgumentCompletions && hasSkipDirectInferenceFlag(arg))) { + if ( + arg.kind !== SyntaxKind.OmittedExpression + && !(checkMode & CheckMode.IsForStringLiteralArgumentCompletions && hasSkipDirectInferenceFlag(arg)) + ) { const paramType = getTypeAtPosition(signature, i); if (couldContainTypeVariables(paramType)) { const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode); @@ -31005,21 +40486,39 @@ namespace ts { } function getMutableArrayOrTupleType(type: Type) { - return type.flags & TypeFlags.Union ? mapType(type, getMutableArrayOrTupleType) : - type.flags & TypeFlags.Any || isMutableArrayOrTuple(getBaseConstraintOfType(type) || type) ? type : - isTupleType(type) ? createTupleType(getTypeArguments(type), type.target.elementFlags, /*readonly*/ false, type.target.labeledElementDeclarations) : - createTupleType([type], [ElementFlags.Variadic]); + return type.flags & TypeFlags.Union ? mapType(type, getMutableArrayOrTupleType) + : type.flags & TypeFlags.Any || isMutableArrayOrTuple(getBaseConstraintOfType(type) || type) ? type + : isTupleType(type) + ? createTupleType( + getTypeArguments(type), + type.target.elementFlags, + /*readonly*/ false, + type.target.labeledElementDeclarations, + ) + : createTupleType([type], [ElementFlags.Variadic]); } - function getSpreadArgumentType(args: readonly Expression[], index: number, argCount: number, restType: Type, context: InferenceContext | undefined, checkMode: CheckMode) { + function getSpreadArgumentType( + args: readonly Expression[], + index: number, + argCount: number, + restType: Type, + context: InferenceContext | undefined, + checkMode: CheckMode, + ) { if (index >= argCount - 1) { const arg = args[argCount - 1]; if (isSpreadArgument(arg)) { // We are inferring from a spread expression in the last argument position, i.e. both the parameter // and the argument are ...x forms. return getMutableArrayOrTupleType( - arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type : - checkExpressionWithContextualType((arg as SpreadElement).expression, restType, context, checkMode), + arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type + : checkExpressionWithContextualType( + (arg as SpreadElement).expression, + restType, + context, + checkMode, + ), ); } } @@ -31029,40 +40528,80 @@ namespace ts { for (let i = index; i < argCount; i++) { const arg = args[i]; if (isSpreadArgument(arg)) { - const spreadType = arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type : checkExpression((arg as SpreadElement).expression); + const spreadType = arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type + : checkExpression((arg as SpreadElement).expression); if (isArrayLikeType(spreadType)) { types.push(spreadType); flags.push(ElementFlags.Variadic); } else { - types.push(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, arg.kind === SyntaxKind.SpreadElement ? (arg as SpreadElement).expression : arg)); + types.push( + checkIteratedTypeOrElementType( + IterationUse.Spread, + spreadType, + undefinedType, + arg.kind === SyntaxKind.SpreadElement ? (arg as SpreadElement).expression : arg, + ), + ); flags.push(ElementFlags.Rest); } } else { - const contextualType = getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual); + const contextualType = getIndexedAccessType( + restType, + getNumberLiteralType(i - index), + AccessFlags.Contextual, + ); const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode); - const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); - types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType)); + const hasPrimitiveContextualType = maybeTypeOfKind( + contextualType, + TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping, + ); + types.push( + hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) + : getWidenedLiteralType(argType), + ); flags.push(ElementFlags.Required); } if (arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).tupleNameSource) { names.push((arg as SyntheticExpression).tupleNameSource!); } } - return createTupleType(types, flags, /*readonly*/ false, length(names) === length(types) ? names : undefined); + return createTupleType( + types, + flags, + /*readonly*/ false, + length(names) === length(types) ? names : undefined, + ); } - function checkTypeArguments(signature: Signature, typeArgumentNodes: readonly TypeNode[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined { + function checkTypeArguments( + signature: Signature, + typeArgumentNodes: readonly TypeNode[], + reportErrors: boolean, + headMessage?: DiagnosticMessage, + ): Type[] | undefined { const isJavascript = isInJSFile(signature.declaration); const typeParameters = signature.typeParameters!; - const typeArgumentTypes = fillMissingTypeArguments(map(typeArgumentNodes, getTypeFromTypeNode), typeParameters, getMinTypeArgumentCount(typeParameters), isJavascript); + const typeArgumentTypes = fillMissingTypeArguments( + map(typeArgumentNodes, getTypeFromTypeNode), + typeParameters, + getMinTypeArgumentCount(typeParameters), + isJavascript, + ); let mapper: TypeMapper | undefined; for (let i = 0; i < typeArgumentNodes.length; i++) { - Debug.assert(typeParameters[i] !== undefined, "Should not call checkTypeArguments with too many type arguments"); + Debug.assert( + typeParameters[i] !== undefined, + "Should not call checkTypeArguments with too many type arguments", + ); const constraint = getConstraintOfTypeParameter(typeParameters[i]); if (constraint) { - const errorInfo = reportErrors && headMessage ? (() => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Type_0_does_not_satisfy_the_constraint_1)) : undefined; + const errorInfo = reportErrors && headMessage ? (() => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Type_0_does_not_satisfy_the_constraint_1, + )) : undefined; const typeArgumentHeadMessage = headMessage || Diagnostics.Type_0_does_not_satisfy_the_constraint_1; if (!mapper) { mapper = createTypeMapper(typeParameters, typeArgumentTypes); @@ -31117,7 +40656,12 @@ namespace ts { // However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props, // can be specified by users through attributes property. const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); - const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode); + const attributesType = checkExpressionWithContextualType( + node.attributes, + paramType, + /*inferenceContext*/ undefined, + checkMode, + ); return checkTagNameDoesNotExpectTooManyArguments() && checkTypeRelatedToAndOptionallyElaborate( attributesType, paramType, @@ -31133,7 +40677,9 @@ namespace ts { if (getJsxNamespaceContainerForImplicitImport(node)) { return true; // factory is implicitly jsx/jsxdev - assume it fits the bill, since we don't strongly look for the jsx/jsxs/jsxDEV factory APIs anywhere else (at least not yet) } - const tagType = isJsxOpeningElement(node) || isJsxSelfClosingElement(node) && !isJsxIntrinsicIdentifier(node.tagName) ? checkExpression(node.tagName) : undefined; + const tagType = isJsxOpeningElement(node) + || isJsxSelfClosingElement(node) && !isJsxIntrinsicIdentifier(node.tagName) + ? checkExpression(node.tagName) : undefined; if (!tagType) { return true; } @@ -31145,7 +40691,13 @@ namespace ts { if (!factory) { return true; } - const factorySymbol = resolveEntityName(factory, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, node); + const factorySymbol = resolveEntityName( + factory, + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ false, + node, + ); if (!factorySymbol) { return true; } @@ -31191,10 +40743,24 @@ namespace ts { } if (reportErrors) { - const diag = createDiagnosticForNode(node.tagName, Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, entityNameToString(node.tagName), absoluteMinArgCount, entityNameToString(factory), maxParamCount); + const diag = createDiagnosticForNode( + node.tagName, + Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, + entityNameToString(node.tagName), + absoluteMinArgCount, + entityNameToString(factory), + maxParamCount, + ); const tagNameDeclaration = getSymbolAtLocation(node.tagName)?.valueDeclaration; if (tagNameDeclaration) { - addRelatedInfo(diag, createDiagnosticForNode(tagNameDeclaration, Diagnostics._0_is_declared_here, entityNameToString(node.tagName))); + addRelatedInfo( + diag, + createDiagnosticForNode( + tagNameDeclaration, + Diagnostics._0_is_declared_here, + entityNameToString(node.tagName), + ), + ); } if (errorOutputContainer && errorOutputContainer.skipLogging) { (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); @@ -31216,10 +40782,26 @@ namespace ts { reportErrors: boolean, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, ): readonly Diagnostic[] | undefined { - const errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } = { errors: undefined, skipLogging: true }; + const errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } = { + errors: undefined, + skipLogging: true, + }; if (isJsxOpeningLikeElement(node)) { - if (!checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "jsx should have errors when reporting errors"); + if ( + !checkApplicableSignatureForJsxOpeningLikeElement( + node, + signature, + relation, + checkMode, + reportErrors, + containingMessageChain, + errorOutputContainer, + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "jsx should have errors when reporting errors", + ); return errorOutputContainer.errors || emptyArray; } return undefined; @@ -31233,8 +40815,21 @@ namespace ts { const thisArgumentType = getThisArgumentType(thisArgumentNode); const errorNode = reportErrors ? (thisArgumentNode || node) : undefined; const headMessage = Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1; - if (!checkTypeRelatedTo(thisArgumentType, thisType, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "this parameter should have errors when reporting errors"); + if ( + !checkTypeRelatedTo( + thisArgumentType, + thisType, + relation, + errorNode, + headMessage, + containingMessageChain, + errorOutputContainer, + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "this parameter should have errors when reporting errors", + ); return errorOutputContainer.errors || emptyArray; } } @@ -31245,27 +40840,71 @@ namespace ts { const arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { const paramType = getTypeAtPosition(signature, i); - const argType = checkExpressionWithContextualType(arg, paramType, /*inferenceContext*/ undefined, checkMode); + const argType = checkExpressionWithContextualType( + arg, + paramType, + /*inferenceContext*/ undefined, + checkMode, + ); // If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive), // we obtain the regular type of any object literal arguments because we may not have inferred complete // parameter types yet and therefore excess property checks may yield false positives (see #17041). - const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType; - if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage, containingMessageChain, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors"); + const checkArgType = checkMode & CheckMode.SkipContextSensitive + ? getRegularTypeOfObjectLiteral(argType) : argType; + if ( + !checkTypeRelatedToAndOptionallyElaborate( + checkArgType, + paramType, + relation, + reportErrors ? arg : undefined, + arg, + headMessage, + containingMessageChain, + errorOutputContainer, + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "parameter should have errors when reporting errors", + ); maybeAddMissingAwaitInfo(arg, checkArgType, paramType); return errorOutputContainer.errors || emptyArray; } } } if (restType) { - const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, /*context*/ undefined, checkMode); + const spreadType = getSpreadArgumentType( + args, + argCount, + args.length, + restType, + /*context*/ undefined, + checkMode, + ); const restArgCount = args.length - argCount; - const errorNode = !reportErrors ? undefined : - restArgCount === 0 ? node : - restArgCount === 1 ? args[argCount] : - setTextRangePosEnd(createSyntheticExpression(node, spreadType), args[argCount].pos, args[args.length - 1].end); - if (!checkTypeRelatedTo(spreadType, restType, relation, errorNode, headMessage, /*containingMessageChain*/ undefined, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "rest parameter should have errors when reporting errors"); + const errorNode = !reportErrors ? undefined + : restArgCount === 0 ? node + : restArgCount === 1 ? args[argCount] + : setTextRangePosEnd( + createSyntheticExpression(node, spreadType), + args[argCount].pos, + args[args.length - 1].end, + ); + if ( + !checkTypeRelatedTo( + spreadType, + restType, + relation, + errorNode, + headMessage, + /*containingMessageChain*/ undefined, + errorOutputContainer, + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "rest parameter should have errors when reporting errors", + ); maybeAddMissingAwaitInfo(errorNode, spreadType, restType); return errorOutputContainer.errors || emptyArray; } @@ -31280,7 +40919,10 @@ namespace ts { } const awaitedTypeOfSource = getAwaitedTypeOfPromise(source); if (awaitedTypeOfSource && isTypeRelatedTo(awaitedTypeOfSource, target, relation)) { - addRelatedInfo(errorOutputContainer.errors[0], createDiagnosticForNode(errorNode, Diagnostics.Did_you_forget_to_use_await)); + addRelatedInfo( + errorOutputContainer.errors[0], + createDiagnosticForNode(errorNode, Diagnostics.Did_you_forget_to_use_await), + ); } } } @@ -31290,8 +40932,8 @@ namespace ts { * Returns the this argument in calls like x.f(...) and x[f](...). Undefined otherwise. */ function getThisArgumentOfCall(node: CallLikeExpression): LeftHandSideExpression | undefined { - const expression = node.kind === SyntaxKind.CallExpression ? node.expression : - node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag : undefined; + const expression = node.kind === SyntaxKind.CallExpression ? node.expression + : node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag : undefined; if (expression) { const callee = skipOuterExpressions(expression); if (isAccessExpression(callee)) { @@ -31300,7 +40942,12 @@ namespace ts { } } - function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember) { + function createSyntheticExpression( + parent: Node, + type: Type, + isSpread?: boolean, + tupleNameSource?: ParameterDeclaration | NamedTupleMember, + ) { const result = parseNodeFactory.createSyntheticExpression(type, isSpread, tupleNameSource); setTextRange(result, parent); setParent(result, parent); @@ -31325,7 +40972,9 @@ namespace ts { return getEffectiveDecoratorArguments(node); } if (isJsxOpeningLikeElement(node)) { - return node.attributes.properties.length > 0 || (isJsxOpeningElement(node) && node.parent.children.length > 0) ? [node.attributes] : emptyArray; + return node.attributes.properties.length > 0 + || (isJsxOpeningElement(node) && node.parent.children.length > 0) ? [node.attributes] + : emptyArray; } const args = node.arguments || emptyArray; const spreadIndex = getSpreadArgumentIndex(args); @@ -31335,11 +40984,18 @@ namespace ts { for (let i = spreadIndex; i < args.length; i++) { const arg = args[i]; // We can call checkExpressionCached because spread expressions never have a contextual type. - const spreadType = arg.kind === SyntaxKind.SpreadElement && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) : checkExpressionCached((arg as SpreadElement).expression)); + const spreadType = arg.kind === SyntaxKind.SpreadElement + && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) + : checkExpressionCached((arg as SpreadElement).expression)); if (spreadType && isTupleType(spreadType)) { forEach(getTypeArguments(spreadType), (t, i) => { const flags = spreadType.target.elementFlags[i]; - const syntheticArg = createSyntheticExpression(arg, flags & ElementFlags.Rest ? createArrayType(t) : t, !!(flags & ElementFlags.Variable), spreadType.target.labeledElementDeclarations?.[i]); + const syntheticArg = createSyntheticExpression( + arg, + flags & ElementFlags.Rest ? createArrayType(t) : t, + !!(flags & ElementFlags.Variable), + spreadType.target.labeledElementDeclarations?.[i], + ); effectiveArgs.push(syntheticArg); }); } @@ -31371,7 +41027,11 @@ namespace ts { // `ParameterDecorator` in core.d.ts). const func = parent.parent as FunctionLikeDeclaration; return [ - createSyntheticExpression(expr, parent.parent.kind === SyntaxKind.Constructor ? getTypeOfSymbol(getSymbolOfNode(func)) : errorType), + createSyntheticExpression( + expr, + parent.parent.kind === SyntaxKind.Constructor ? getTypeOfSymbol(getSymbolOfNode(func)) + : errorType, + ), createSyntheticExpression(expr, anyType), createSyntheticExpression(expr, numberType), ]; @@ -31382,11 +41042,15 @@ namespace ts { // A method or accessor declaration decorator will have two or three arguments (see // `PropertyDecorator` and `MethodDecorator` in core.d.ts). If we are emitting decorators // for ES3, we will only pass two arguments. - const hasPropDesc = languageVersion !== ScriptTarget.ES3 && (!isPropertyDeclaration(parent) || hasAccessorModifier(parent)); + const hasPropDesc = languageVersion !== ScriptTarget.ES3 + && (!isPropertyDeclaration(parent) || hasAccessorModifier(parent)); return [ createSyntheticExpression(expr, getParentTypeOfClassElement(parent as ClassElement)), createSyntheticExpression(expr, getClassElementPropertyKeyType(parent as ClassElement)), - createSyntheticExpression(expr, hasPropDesc ? createTypedPropertyDescriptorType(getTypeOfNode(parent)) : anyType), + createSyntheticExpression( + expr, + hasPropDesc ? createTypedPropertyDescriptorType(getTypeOfNode(parent)) : anyType, + ), ]; } return Debug.fail(); @@ -31430,7 +41094,14 @@ namespace ts { } return { start, length, sourceFile }; } - function getDiagnosticForCallNode(node: CallLikeExpression, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { + function getDiagnosticForCallNode( + node: CallLikeExpression, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): DiagnosticWithLocation { if (isCallExpression(node)) { const { sourceFile, start, length } = getDiagnosticSpanForCallNode(node); return createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2, arg3); @@ -31443,9 +41114,19 @@ namespace ts { function isPromiseResolveArityError(node: CallLikeExpression) { if (!isCallExpression(node) || !isIdentifier(node.expression)) return false; - const symbol = resolveName(node.expression, node.expression.escapedText, SymbolFlags.Value, undefined, undefined, false); + const symbol = resolveName( + node.expression, + node.expression.escapedText, + SymbolFlags.Value, + undefined, + undefined, + false, + ); const decl = symbol?.valueDeclaration; - if (!decl || !isParameter(decl) || !isFunctionExpressionOrArrowFunction(decl.parent) || !isNewExpression(decl.parent.parent) || !isIdentifier(decl.parent.parent.expression)) { + if ( + !decl || !isParameter(decl) || !isFunctionExpressionOrArrowFunction(decl.parent) + || !isNewExpression(decl.parent.parent) || !isIdentifier(decl.parent.parent.expression) + ) { return false; } @@ -31456,10 +41137,17 @@ namespace ts { return constructorSymbol === globalPromiseSymbol; } - function getArgumentArityError(node: CallLikeExpression, signatures: readonly Signature[], args: readonly Expression[]) { + function getArgumentArityError( + node: CallLikeExpression, + signatures: readonly Signature[], + args: readonly Expression[], + ) { const spreadIndex = getSpreadArgumentIndex(args); if (spreadIndex > -1) { - return createDiagnosticForNode(args[spreadIndex], Diagnostics.A_spread_argument_must_either_have_a_tuple_type_or_be_passed_to_a_rest_parameter); + return createDiagnosticForNode( + args[spreadIndex], + Diagnostics.A_spread_argument_must_either_have_a_tuple_type_or_be_passed_to_a_rest_parameter, + ); } let min = Number.POSITIVE_INFINITY; // smallest parameter count let max = Number.NEGATIVE_INFINITY; // largest parameter count @@ -31484,30 +41172,48 @@ namespace ts { const parameterRange = hasRestParameter ? min : min < max ? min + "-" + max : min; - const isVoidPromiseError = !hasRestParameter && parameterRange === 1 && args.length === 0 && isPromiseResolveArityError(node); + const isVoidPromiseError = !hasRestParameter && parameterRange === 1 && args.length === 0 + && isPromiseResolveArityError(node); if (isVoidPromiseError && isInJSFile(node)) { - return getDiagnosticForCallNode(node, Diagnostics.Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments); + return getDiagnosticForCallNode( + node, + Diagnostics + .Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments, + ); } const error = hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 : isVoidPromiseError - ? Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise + ? Diagnostics + .Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise : Diagnostics.Expected_0_arguments_but_got_1; if (min < args.length && args.length < max) { // between min and max, but with no matching overload - return getDiagnosticForCallNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); + return getDiagnosticForCallNode( + node, + Diagnostics + .No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, + args.length, + maxBelow, + minAbove, + ); } else if (args.length < min) { // too short: put the error span on the call expression, not any of the args const diagnostic = getDiagnosticForCallNode(node, error, parameterRange, args.length); - const parameter = closestSignature?.declaration?.parameters[closestSignature.thisParameter ? args.length + 1 : args.length]; + const parameter = closestSignature?.declaration + ?.parameters[closestSignature.thisParameter ? args.length + 1 : args.length]; if (parameter) { const parameterError = createDiagnosticForNode( parameter, - isBindingPattern(parameter.name) ? Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided - : isRestParameter(parameter) ? Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided + isBindingPattern(parameter.name) + ? Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided + : isRestParameter(parameter) + ? Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided : Diagnostics.An_argument_for_0_was_not_provided, - !parameter.name ? args.length : !isBindingPattern(parameter.name) ? idText(getFirstIdentifier(parameter.name)) : undefined, + !parameter.name ? args.length + : !isBindingPattern(parameter.name) ? idText(getFirstIdentifier(parameter.name)) + : undefined, ); return addRelatedInfo(diagnostic, parameterError); } @@ -31522,18 +41228,34 @@ namespace ts { end++; } setTextRangePosEnd(errorSpan, pos, end); - return createDiagnosticForNodeArray(getSourceFileOfNode(node), errorSpan, error, parameterRange, args.length); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + errorSpan, + error, + parameterRange, + args.length, + ); } } - function getTypeArgumentArityError(node: Node, signatures: readonly Signature[], typeArguments: NodeArray) { + function getTypeArgumentArityError( + node: Node, + signatures: readonly Signature[], + typeArguments: NodeArray, + ) { const argCount = typeArguments.length; // No overloads exist if (signatures.length === 1) { const sig = signatures[0]; const min = getMinTypeArgumentCount(sig.typeParameters); const max = length(sig.typeParameters); - return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, min < max ? min + "-" + max : min, argCount); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics.Expected_0_type_arguments_but_got_1, + min < max ? min + "-" + max : min, + argCount, + ); } // Overloads exist let belowArgCount = -Infinity; @@ -31549,12 +41271,33 @@ namespace ts { } } if (belowArgCount !== -Infinity && aboveArgCount !== Infinity) { - return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, argCount, belowArgCount, aboveArgCount); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics + .No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, + argCount, + belowArgCount, + aboveArgCount, + ); } - return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics.Expected_0_type_arguments_but_got_1, + belowArgCount === -Infinity ? aboveArgCount : belowArgCount, + argCount, + ); } - function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags, fallbackError?: DiagnosticMessage): Signature { + function resolveCall( + node: CallLikeExpression, + signatures: readonly Signature[], + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + callChainFlags: SignatureFlags, + fallbackError?: DiagnosticMessage, + ): Signature { const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; const isDecorator = node.kind === SyntaxKind.Decorator; const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node); @@ -31566,7 +41309,10 @@ namespace ts { typeArguments = (node as CallExpression).typeArguments; // We already perform checking on the type arguments on the class declaration itself. - if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || (node as CallExpression).expression.kind !== SyntaxKind.SuperKeyword) { + if ( + isTaggedTemplate || isJsxOpeningOrSelfClosingElement + || (node as CallExpression).expression.kind !== SyntaxKind.SuperKeyword + ) { forEach(typeArguments, checkSourceElement); } } @@ -31576,7 +41322,9 @@ namespace ts { reorderCandidates(signatures, candidates, callChainFlags); if (!candidates.length) { if (reportErrors) { - diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures)); + diagnostics.add( + getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures), + ); } return resolveErrorCall(node); } @@ -31596,7 +41344,8 @@ namespace ts { // For a decorator, no arguments are susceptible to contextual typing due to the fact // decorators are applied to a declaration by the emitter, and not to an expression. const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters; - let argCheckMode = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive) ? CheckMode.SkipContextSensitive : CheckMode.Normal; + let argCheckMode = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive) + ? CheckMode.SkipContextSensitive : CheckMode.Normal; argCheckMode |= checkMode & CheckMode.IsForStringLiteralArgumentCompletions; // The following variables are captured and modified by calls to chooseOverload. @@ -31627,7 +41376,8 @@ namespace ts { // If we are in signature help, a trailing comma indicates that we intend to provide another argument, // so we will only accept overloads with arity at least 1 higher than the current number of provided arguments. - const signatureHelpTrailingComma = !!(checkMode & CheckMode.IsForSignatureHelp) && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma; + const signatureHelpTrailingComma = !!(checkMode & CheckMode.IsForSignatureHelp) + && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma; // Section 4.12.1: // if the candidate list contains one or more signatures for which the type of each argument @@ -31640,10 +41390,20 @@ namespace ts { // is just important for choosing the best signature. So in the case where there is only one // signature, the subtype pass is useless. So skipping it is an optimization. if (candidates.length > 1) { - result = chooseOverload(candidates, subtypeRelation, isSingleNonGenericCandidate, signatureHelpTrailingComma); + result = chooseOverload( + candidates, + subtypeRelation, + isSingleNonGenericCandidate, + signatureHelpTrailingComma, + ); } if (!result) { - result = chooseOverload(candidates, assignableRelation, isSingleNonGenericCandidate, signatureHelpTrailingComma); + result = chooseOverload( + candidates, + assignableRelation, + isSingleNonGenericCandidate, + signatureHelpTrailingComma, + ); } if (result) { return result; @@ -31669,14 +41429,31 @@ namespace ts { const last = candidatesForArgumentError[candidatesForArgumentError.length - 1]; let chain: DiagnosticMessageChain | undefined; if (candidatesForArgumentError.length > 3) { - chain = chainDiagnosticMessages(chain, Diagnostics.The_last_overload_gave_the_following_error); + chain = chainDiagnosticMessages( + chain, + Diagnostics.The_last_overload_gave_the_following_error, + ); chain = chainDiagnosticMessages(chain, Diagnostics.No_overload_matches_this_call); } - const diags = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain); + const diags = getSignatureApplicabilityError( + node, + args, + last, + assignableRelation, + CheckMode.Normal, + /*reportErrors*/ true, + () => chain, + ); if (diags) { for (const d of diags) { if (last.declaration && candidatesForArgumentError.length > 3) { - addRelatedInfo(d, createDiagnosticForNode(last.declaration, Diagnostics.The_last_overload_is_declared_here)); + addRelatedInfo( + d, + createDiagnosticForNode( + last.declaration, + Diagnostics.The_last_overload_is_declared_here, + ), + ); } addImplementationSuccessElaboration(last, d); diagnostics.add(d); @@ -31693,8 +41470,23 @@ namespace ts { let minIndex = 0; let i = 0; for (const c of candidatesForArgumentError) { - const chain = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Overload_0_of_1_2_gave_the_following_error, i + 1, candidates.length, signatureToString(c)); - const diags = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, chain); + const chain = () => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Overload_0_of_1_2_gave_the_following_error, + i + 1, + candidates.length, + signatureToString(c), + ); + const diags = getSignatureApplicabilityError( + node, + args, + c, + assignableRelation, + CheckMode.Normal, + /*reportErrors*/ true, + chain, + ); if (diags) { if (diags.length <= min) { min = diags.length; @@ -31717,11 +41509,30 @@ namespace ts { ); // The below is a spread to guarantee we get a new (mutable) array - our `flatMap` helper tries to do "smart" optimizations where it reuses input // arrays and the emptyArray singleton where possible, which is decidedly not what we want while we're still constructing this diagnostic - const related = [...flatMap(diags, d => (d as Diagnostic).relatedInformation) as DiagnosticRelatedInformation[]]; + const related = [ + ...flatMap( + diags, + d => (d as Diagnostic).relatedInformation, + ) as DiagnosticRelatedInformation[], + ]; let diag: Diagnostic; - if (every(diags, d => d.start === diags[0].start && d.length === diags[0].length && d.file === diags[0].file)) { + if ( + every( + diags, + d => d.start === diags[0].start && d.length === diags[0].length + && d.file === diags[0].file, + ) + ) { const { file, start, length } = diags[0]; - diag = { file, start, length, code: chain.code, category: chain.category, messageText: chain, relatedInformation: related }; + diag = { + file, + start, + length, + code: chain.code, + category: chain.category, + messageText: chain, + relatedInformation: related, + }; } else { diag = createDiagnosticForNodeFromMessageChain(node, chain, related); @@ -31734,10 +41545,18 @@ namespace ts { diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args)); } else if (candidateForTypeArgumentError) { - checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, fallbackError); + checkTypeArguments( + candidateForTypeArgumentError, + (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, + /*reportErrors*/ true, + fallbackError, + ); } else { - const signaturesWithCorrectTypeArgumentArity = filter(signatures, s => hasCorrectTypeArgumentArity(s, typeArguments)); + const signaturesWithCorrectTypeArgumentArity = filter( + signatures, + s => hasCorrectTypeArgumentArity(s, typeArguments), + ); if (signaturesWithCorrectTypeArgumentArity.length === 0) { diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments!)); } @@ -31759,12 +41578,21 @@ namespace ts { const failedSignatureDeclarations = failed.declaration?.symbol?.declarations || emptyArray; const isOverload = failedSignatureDeclarations.length > 1; - const implDecl = isOverload ? find(failedSignatureDeclarations, d => isFunctionLikeDeclaration(d) && nodeIsPresent(d.body)) : undefined; + const implDecl = isOverload + ? find(failedSignatureDeclarations, d => isFunctionLikeDeclaration(d) && nodeIsPresent(d.body)) + : undefined; if (implDecl) { const candidate = getSignatureFromDeclaration(implDecl as FunctionLikeDeclaration); const isSingleNonGenericCandidate = !candidate.typeParameters; if (chooseOverload([candidate], assignableRelation, isSingleNonGenericCandidate)) { - addRelatedInfo(diagnostic, createDiagnosticForNode(implDecl, Diagnostics.The_call_would_have_succeeded_against_this_implementation_but_implementation_signatures_of_overloads_are_not_externally_visible)); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + implDecl, + Diagnostics + .The_call_would_have_succeeded_against_this_implementation_but_implementation_signatures_of_overloads_are_not_externally_visible, + ), + ); } } @@ -31773,7 +41601,12 @@ namespace ts { candidateForTypeArgumentError = oldCandidateForTypeArgumentError; } - function chooseOverload(candidates: Signature[], relation: ESMap, isSingleNonGenericCandidate: boolean, signatureHelpTrailingComma = false) { + function chooseOverload( + candidates: Signature[], + relation: ESMap, + isSingleNonGenericCandidate: boolean, + signatureHelpTrailingComma = false, + ) { candidatesForArgumentError = undefined; candidateForArgumentArityError = undefined; candidateForTypeArgumentError = undefined; @@ -31783,7 +41616,17 @@ namespace ts { if (some(typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { return undefined; } - if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if ( + getSignatureApplicabilityError( + node, + args, + candidate, + relation, + CheckMode.Normal, + /*reportErrors*/ false, + /*containingMessageChain*/ undefined, + ) + ) { candidatesForArgumentError = [candidate]; return undefined; } @@ -31792,7 +41635,10 @@ namespace ts { for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) { const candidate = candidates[candidateIndex]; - if (!hasCorrectTypeArgumentArity(candidate, typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { + if ( + !hasCorrectTypeArgumentArity(candidate, typeArguments) + || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma) + ) { continue; } @@ -31809,14 +41655,33 @@ namespace ts { } } else { - inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); - typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext); - argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal; - } - checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); + inferenceContext = createInferenceContext( + candidate.typeParameters, + candidate, + /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None, + ); + typeArgumentTypes = inferTypeArguments( + node, + candidate, + args, + argCheckMode | CheckMode.SkipGenericFunctions, + inferenceContext, + ); + argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction + ? CheckMode.SkipGenericFunctions : CheckMode.Normal; + } + checkCandidate = getSignatureInstantiation( + candidate, + typeArgumentTypes, + isInJSFile(candidate.declaration), + inferenceContext && inferenceContext.inferredTypeParameters, + ); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. - if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + if ( + getNonArrayRestType(candidate) + && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma) + ) { candidateForArgumentArityError = checkCandidate; continue; } @@ -31824,7 +41689,17 @@ namespace ts { else { checkCandidate = candidate; } - if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if ( + getSignatureApplicabilityError( + node, + args, + checkCandidate, + relation, + argCheckMode, + /*reportErrors*/ false, + /*containingMessageChain*/ undefined, + ) + ) { // Give preference to error candidates that have no rest parameters (as they are more specific) (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); continue; @@ -31835,16 +41710,40 @@ namespace ts { // round of type inference and applicability checking for this particular candidate. argCheckMode = checkMode & CheckMode.IsForStringLiteralArgumentCompletions; if (inferenceContext) { - const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext); - checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters); + const typeArgumentTypes = inferTypeArguments( + node, + candidate, + args, + argCheckMode, + inferenceContext, + ); + checkCandidate = getSignatureInstantiation( + candidate, + typeArgumentTypes, + isInJSFile(candidate.declaration), + inferenceContext.inferredTypeParameters, + ); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. - if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + if ( + getNonArrayRestType(candidate) + && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma) + ) { candidateForArgumentArityError = checkCandidate; continue; } } - if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if ( + getSignatureApplicabilityError( + node, + args, + checkCandidate, + relation, + argCheckMode, + /*reportErrors*/ false, + /*containingMessageChain*/ undefined, + ) + ) { // Give preference to error candidates that have no rest parameters (as they are more specific) (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); continue; @@ -31886,16 +41785,26 @@ namespace ts { const parameters: Symbol[] = []; for (let i = 0; i < maxNonRestParam; i++) { const symbols = mapDefined(candidates, s => - signatureHasRestParameter(s) ? - i < s.parameters.length - 1 ? s.parameters[i] : last(s.parameters) : - i < s.parameters.length ? s.parameters[i] : undefined); + signatureHasRestParameter(s) + ? i < s.parameters.length - 1 ? s.parameters[i] : last(s.parameters) + : i < s.parameters.length ? s.parameters[i] : undefined); Debug.assert(symbols.length !== 0); - parameters.push(createCombinedSymbolFromTypes(symbols, mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i)))); + parameters.push( + createCombinedSymbolFromTypes( + symbols, + mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i)), + ), + ); } - const restParameterSymbols = mapDefined(candidates, c => signatureHasRestParameter(c) ? last(c.parameters) : undefined); + const restParameterSymbols = mapDefined( + candidates, + c => signatureHasRestParameter(c) ? last(c.parameters) : undefined, + ); let flags = SignatureFlags.None; if (restParameterSymbols.length !== 0) { - const type = createArrayType(getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), UnionReduction.Subtype)); + const type = createArrayType( + getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), UnionReduction.Subtype), + ); parameters.push(createCombinedSymbolForOverloadFailure(restParameterSymbols, type)); flags |= SignatureFlags.HasRestParameter; } @@ -31928,42 +41837,78 @@ namespace ts { return createSymbolWithType(first(sources), type); } - function pickLongestCandidateSignature(node: CallLikeExpression, candidates: Signature[], args: readonly Expression[], checkMode: CheckMode): Signature { + function pickLongestCandidateSignature( + node: CallLikeExpression, + candidates: Signature[], + args: readonly Expression[], + checkMode: CheckMode, + ): Signature { // Pick the longest signature. This way we can get a contextual type for cases like: // declare function f(a: { xa: number; xb: number; }, b: number); // f({ | // Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like: // declare function f(k: keyof T); // f(" - const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount); + const bestIndex = getLongestCandidateIndex( + candidates, + apparentArgumentCount === undefined ? args.length : apparentArgumentCount, + ); const candidate = candidates[bestIndex]; const { typeParameters } = candidate; if (!typeParameters) { return candidate; } - const typeArgumentNodes: readonly TypeNode[] | undefined = callLikeExpressionMayHaveTypeArguments(node) ? node.typeArguments : undefined; + const typeArgumentNodes: readonly TypeNode[] | undefined = callLikeExpressionMayHaveTypeArguments(node) + ? node.typeArguments : undefined; const instantiated = typeArgumentNodes - ? createSignatureInstantiation(candidate, getTypeArgumentsFromNodes(typeArgumentNodes, typeParameters, isInJSFile(node))) + ? createSignatureInstantiation( + candidate, + getTypeArgumentsFromNodes(typeArgumentNodes, typeParameters, isInJSFile(node)), + ) : inferSignatureInstantiationForOverloadFailure(node, typeParameters, candidate, args, checkMode); candidates[bestIndex] = instantiated; return instantiated; } - function getTypeArgumentsFromNodes(typeArgumentNodes: readonly TypeNode[], typeParameters: readonly TypeParameter[], isJs: boolean): readonly Type[] { + function getTypeArgumentsFromNodes( + typeArgumentNodes: readonly TypeNode[], + typeParameters: readonly TypeParameter[], + isJs: boolean, + ): readonly Type[] { const typeArguments = typeArgumentNodes.map(getTypeOfNode); while (typeArguments.length > typeParameters.length) { typeArguments.pop(); } while (typeArguments.length < typeParameters.length) { - typeArguments.push(getDefaultFromTypeParameter(typeParameters[typeArguments.length]) || getConstraintOfTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isJs)); + typeArguments.push( + getDefaultFromTypeParameter(typeParameters[typeArguments.length]) + || getConstraintOfTypeParameter(typeParameters[typeArguments.length]) + || getDefaultTypeArgumentType(isJs), + ); } return typeArguments; } - function inferSignatureInstantiationForOverloadFailure(node: CallLikeExpression, typeParameters: readonly TypeParameter[], candidate: Signature, args: readonly Expression[], checkMode: CheckMode): Signature { - const inferenceContext = createInferenceContext(typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); - const typeArgumentTypes = inferTypeArguments(node, candidate, args, checkMode | CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, inferenceContext); + function inferSignatureInstantiationForOverloadFailure( + node: CallLikeExpression, + typeParameters: readonly TypeParameter[], + candidate: Signature, + args: readonly Expression[], + checkMode: CheckMode, + ): Signature { + const inferenceContext = createInferenceContext( + typeParameters, + candidate, + /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None, + ); + const typeArgumentTypes = inferTypeArguments( + node, + candidate, + args, + checkMode | CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, + inferenceContext, + ); return createSignatureInstantiation(candidate, typeArgumentTypes); } @@ -31986,7 +41931,11 @@ namespace ts { return maxParamsIndex; } - function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveCallExpression( + node: CallExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { if (node.expression.kind === SyntaxKind.SuperKeyword) { const superType = checkSuperExpression(node.expression); if (isTypeAny(superType)) { @@ -32000,7 +41949,11 @@ namespace ts { // with the type arguments specified in the extends clause. const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!); if (baseTypeNode) { - const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode); + const baseConstructors = getInstantiatedConstructorsForTypeArguments( + superType, + baseTypeNode.typeArguments, + baseTypeNode, + ); return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, SignatureFlags.None); } } @@ -32011,9 +41964,9 @@ namespace ts { let funcType = checkExpression(node.expression); if (isCallChain(node)) { const nonOptionalType = getOptionalExpressionType(funcType, node.expression); - callChainFlags = nonOptionalType === funcType ? SignatureFlags.None : - isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain : - SignatureFlags.IsInnerCallChain; + callChainFlags = nonOptionalType === funcType ? SignatureFlags.None + : isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain + : SignatureFlags.IsInnerCallChain; funcType = nonOptionalType; } else { @@ -32059,14 +42012,27 @@ namespace ts { // with multiple call signatures. if (!callSignatures.length) { if (numConstructSignatures) { - error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); + error( + node, + Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, + typeToString(funcType), + ); } else { let relatedInformation: DiagnosticRelatedInformation | undefined; if (node.arguments.length === 1) { const text = getSourceFileOfNode(node).text; - if (isLineBreak(text.charCodeAt(skipTrivia(text, node.expression.end, /* stopAfterLineBreak */ true) - 1))) { - relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.Are_you_missing_a_semicolon); + if ( + isLineBreak( + text.charCodeAt( + skipTrivia(text, node.expression.end, /* stopAfterLineBreak */ true) - 1, + ), + ) + ) { + relatedInformation = createDiagnosticForNode( + node.expression, + Diagnostics.Are_you_missing_a_semicolon, + ); } } invocationError(node.expression, apparentType, SignatureKind.Call, relatedInformation); @@ -32085,13 +42051,20 @@ namespace ts { // use the resolvingSignature singleton to indicate that we deferred processing. This result will be // propagated out and eventually turned into silentNeverType (a type that is assignable to anything and // from which we never make inferences). - if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunction)) { + if ( + checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments + && callSignatures.some(isGenericFunctionReturningFunction) + ) { skippedGenericFunction(node, checkMode); return resolvingSignature; } // If the function is explicitly marked with `@class`, then it must be constructed. if (callSignatures.some(sig => isInJSFile(sig.declaration) && !!getJSDocClassTag(sig.declaration!))) { - error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); + error( + node, + Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, + typeToString(funcType), + ); return resolveErrorCall(node); } @@ -32107,17 +42080,32 @@ namespace ts { * If FuncExpr is of type Any, or of an object type that has no call or construct signatures * but is a subtype of the Function interface, the call is an untyped function call. */ - function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number): boolean { + function isUntypedFunctionCall( + funcType: Type, + apparentFuncType: Type, + numCallSignatures: number, + numConstructSignatures: number, + ): boolean { // We exclude union types because we may have a union of function types that happen to have no common signatures. - return isTypeAny(funcType) || isTypeAny(apparentFuncType) && !!(funcType.flags & TypeFlags.TypeParameter) || - !numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & TypeFlags.Union) && !(getReducedType(apparentFuncType).flags & TypeFlags.Never) && isTypeAssignableTo(funcType, globalFunctionType); + return isTypeAny(funcType) || isTypeAny(apparentFuncType) && !!(funcType.flags & TypeFlags.TypeParameter) + || !numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & TypeFlags.Union) + && !(getReducedType(apparentFuncType).flags & TypeFlags.Never) + && isTypeAssignableTo(funcType, globalFunctionType); } - function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveNewExpression( + node: NewExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { if (node.arguments && languageVersion < ScriptTarget.ES5) { const spreadIndex = getSpreadArgumentIndex(node.arguments); if (spreadIndex >= 0) { - error(node.arguments[spreadIndex], Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_5_and_higher); + error( + node.arguments[spreadIndex], + Diagnostics + .Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_5_and_higher, + ); } } @@ -32181,11 +42169,18 @@ namespace ts { if (callSignatures.length) { const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None); if (!noImplicitAny) { - if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) { + if ( + signature.declaration && !isJSConstructor(signature.declaration) + && getReturnTypeOfSignature(signature) !== voidType + ) { error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); } if (getThisTypeOfSignature(signature) === voidType) { - error(node, Diagnostics.A_function_that_is_called_with_the_new_keyword_cannot_have_a_this_type_that_is_void); + error( + node, + Diagnostics + .A_function_that_is_called_with_the_new_keyword_cannot_have_a_this_type_that_is_void, + ); } } return signature; @@ -32199,7 +42194,8 @@ namespace ts { if (isArray(signatures)) { return some(signatures, signature => someSignature(signature, f)); } - return signatures.compositeKind === TypeFlags.Union ? some(signatures.compositeSignatures, f) : f(signatures); + return signatures.compositeKind === TypeFlags.Union ? some(signatures.compositeSignatures, f) + : f(signatures); } function typeHasProtectedAccessibleBase(target: Symbol, type: InterfaceType): boolean { @@ -32240,7 +42236,10 @@ namespace ts { } const declaration = signature.declaration; - const modifiers = getSelectedEffectiveModifierFlags(declaration, ModifierFlags.NonPublicAccessibilityModifier); + const modifiers = getSelectedEffectiveModifierFlags( + declaration, + ModifierFlags.NonPublicAccessibilityModifier, + ); // (1) Public constructors and (2) constructor functions are always accessible. if (!modifiers || declaration.kind !== SyntaxKind.Constructor) { @@ -32260,10 +42259,19 @@ namespace ts { } } if (modifiers & ModifierFlags.Private) { - error(node, Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); + error( + node, + Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, + typeToString(declaringClass), + ); } if (modifiers & ModifierFlags.Protected) { - error(node, Diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); + error( + node, + Diagnostics + .Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, + typeToString(declaringClass), + ); } return false; } @@ -32271,7 +42279,11 @@ namespace ts { return true; } - function invocationErrorDetails(errorTarget: Node, apparentType: Type, kind: SignatureKind): { messageChain: DiagnosticMessageChain; relatedMessage: DiagnosticMessage | undefined; } { + function invocationErrorDetails( + errorTarget: Node, + apparentType: Type, + kind: SignatureKind, + ): { messageChain: DiagnosticMessageChain; relatedMessage: DiagnosticMessage | undefined; } { let errorInfo: DiagnosticMessageChain | undefined; const isCall = kind === SignatureKind.Call; const awaitedType = getAwaitedType(apparentType); @@ -32293,16 +42305,16 @@ namespace ts { if (!errorInfo) { errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Type_0_has_no_call_signatures : - Diagnostics.Type_0_has_no_construct_signatures, + isCall + ? Diagnostics.Type_0_has_no_call_signatures + : Diagnostics.Type_0_has_no_construct_signatures, typeToString(constituent), ); errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Not_all_constituents_of_type_0_are_callable : - Diagnostics.Not_all_constituents_of_type_0_are_constructable, + isCall + ? Diagnostics.Not_all_constituents_of_type_0_are_callable + : Diagnostics.Not_all_constituents_of_type_0_are_constructable, typeToString(apparentType), ); } @@ -32315,18 +42327,20 @@ namespace ts { if (!hasSignatures) { errorInfo = chainDiagnosticMessages( /* detials */ undefined, - isCall ? - Diagnostics.No_constituent_of_type_0_is_callable : - Diagnostics.No_constituent_of_type_0_is_constructable, + isCall + ? Diagnostics.No_constituent_of_type_0_is_callable + : Diagnostics.No_constituent_of_type_0_is_constructable, typeToString(apparentType), ); } if (!errorInfo) { errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other : - Diagnostics.Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other, + isCall + ? Diagnostics + .Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other + : Diagnostics + .Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other, typeToString(apparentType), ); } @@ -32334,20 +42348,22 @@ namespace ts { else { errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Type_0_has_no_call_signatures : - Diagnostics.Type_0_has_no_construct_signatures, + isCall + ? Diagnostics.Type_0_has_no_call_signatures + : Diagnostics.Type_0_has_no_construct_signatures, typeToString(apparentType), ); } - let headMessage = isCall ? Diagnostics.This_expression_is_not_callable : Diagnostics.This_expression_is_not_constructable; + let headMessage = isCall ? Diagnostics.This_expression_is_not_callable + : Diagnostics.This_expression_is_not_constructable; // Diagnose get accessors incorrectly called as functions if (isCallExpression(errorTarget.parent) && errorTarget.parent.arguments.length === 0) { const { resolvedSymbol } = getNodeLinks(errorTarget); if (resolvedSymbol && resolvedSymbol.flags & SymbolFlags.GetAccessor) { - headMessage = Diagnostics.This_expression_is_not_callable_because_it_is_a_get_accessor_Did_you_mean_to_use_it_without; + headMessage = Diagnostics + .This_expression_is_not_callable_because_it_is_a_get_accessor_Did_you_mean_to_use_it_without; } } @@ -32356,19 +42372,35 @@ namespace ts { relatedMessage: maybeMissingAwait ? Diagnostics.Did_you_forget_to_use_await : undefined, }; } - function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) { - const { messageChain, relatedMessage: relatedInfo } = invocationErrorDetails(errorTarget, apparentType, kind); + function invocationError( + errorTarget: Node, + apparentType: Type, + kind: SignatureKind, + relatedInformation?: DiagnosticRelatedInformation, + ) { + const { messageChain, relatedMessage: relatedInfo } = invocationErrorDetails( + errorTarget, + apparentType, + kind, + ); const diagnostic = createDiagnosticForNodeFromMessageChain(errorTarget, messageChain); if (relatedInfo) { addRelatedInfo(diagnostic, createDiagnosticForNode(errorTarget, relatedInfo)); } if (isCallExpression(errorTarget.parent)) { - const { start, length } = getDiagnosticSpanForCallNode(errorTarget.parent, /* doNotIncludeArguments */ true); + const { start, length } = getDiagnosticSpanForCallNode( + errorTarget.parent, + /* doNotIncludeArguments */ true, + ); diagnostic.start = start; diagnostic.length = length; } diagnostics.add(diagnostic); - invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic); + invocationErrorRecovery( + apparentType, + kind, + relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic, + ); } function invocationErrorRecovery(apparentType: Type, kind: SignatureKind, diagnostic: Diagnostic) { @@ -32382,11 +42414,22 @@ namespace ts { const sigs = getSignaturesOfType(getTypeOfSymbol(getSymbolLinks(apparentType.symbol).target!), kind); if (!sigs || !sigs.length) return; - addRelatedInfo(diagnostic, createDiagnosticForNode(importNode, Diagnostics.Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead)); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + importNode, + Diagnostics + .Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead, + ), + ); } } - function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveTaggedTemplateExpression( + node: TaggedTemplateExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { const tagType = checkExpression(node.tag); const apparentType = getApparentType(tagType); @@ -32404,7 +42447,11 @@ namespace ts { if (!callSignatures.length) { if (isArrayLiteralExpression(node.parent)) { - const diagnostic = createDiagnosticForNode(node.tag, Diagnostics.It_is_likely_that_you_are_missing_a_comma_to_separate_these_two_template_expressions_They_form_a_tagged_template_expression_which_cannot_be_invoked); + const diagnostic = createDiagnosticForNode( + node.tag, + Diagnostics + .It_is_likely_that_you_are_missing_a_comma_to_separate_these_two_template_expressions_They_form_a_tagged_template_expression_which_cannot_be_invoked, + ); diagnostics.add(diagnostic); return resolveErrorCall(node); } @@ -32444,7 +42491,11 @@ namespace ts { /** * Resolves a decorator as if it were a call expression. */ - function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveDecorator( + node: Decorator, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { const funcType = checkExpression(node.expression); const apparentType = getApparentType(funcType); if (isErrorType(apparentType)) { @@ -32459,7 +42510,12 @@ namespace ts { if (isPotentiallyUncalledDecorator(node, callSignatures)) { const nodeStr = getTextOfNode(node.expression, /*includeTrivia*/ false); - error(node, Diagnostics._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0, nodeStr); + error( + node, + Diagnostics + ._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0, + nodeStr, + ); return resolveErrorCall(node); } @@ -32486,7 +42542,18 @@ namespace ts { // file would probably be preferable. const typeSymbol = exports && getSymbol(exports, JsxNames.Element, SymbolFlags.Type); const returnNode = typeSymbol && nodeBuilder.symbolToEntityName(typeSymbol, SymbolFlags.Type, node); - const declaration = factory.createFunctionTypeNode(/*typeParameters*/ undefined, [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotdotdot*/ undefined, "props", /*questionMark*/ undefined, nodeBuilder.typeToTypeNode(result, node))], returnNode ? factory.createTypeReferenceNode(returnNode, /*typeArguments*/ undefined) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)); + const declaration = factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotdotdot*/ undefined, + "props", + /*questionMark*/ undefined, + nodeBuilder.typeToTypeNode(result, node), + )], + returnNode ? factory.createTypeReferenceNode(returnNode, /*typeArguments*/ undefined) + : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + ); const parameterSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "props" as __String); parameterSymbol.type = result; return createSignature( @@ -32501,14 +42568,36 @@ namespace ts { ); } - function resolveJsxOpeningLikeElement(node: JsxOpeningLikeElement, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveJsxOpeningLikeElement( + node: JsxOpeningLikeElement, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { if (isJsxIntrinsicIdentifier(node.tagName)) { const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node); const fakeSignature = createSignatureForJSXIntrinsic(node, result); - checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes); + checkTypeAssignableToAndOptionallyElaborate( + checkExpressionWithContextualType( + node.attributes, + getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), + /*mapper*/ undefined, + CheckMode.Normal, + ), + result, + node.tagName, + node.attributes, + ); if (length(node.typeArguments)) { forEach(node.typeArguments, checkSourceElement); - diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), node.typeArguments!, Diagnostics.Expected_0_type_arguments_but_got_1, 0, length(node.typeArguments))); + diagnostics.add( + createDiagnosticForNodeArray( + getSourceFileOfNode(node), + node.typeArguments!, + Diagnostics.Expected_0_type_arguments_but_got_1, + 0, + length(node.typeArguments), + ), + ); } return fakeSignature; } @@ -32525,7 +42614,11 @@ namespace ts { if (signatures.length === 0) { // We found no signatures at all, which is an error - error(node.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node.tagName)); + error( + node.tagName, + Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, + getTextOfNode(node.tagName), + ); return resolveErrorCall(node); } @@ -32539,12 +42632,16 @@ namespace ts { */ function isPotentiallyUncalledDecorator(decorator: Decorator, signatures: readonly Signature[]) { return signatures.length && every(signatures, signature => - signature.minArgumentCount === 0 && - !signatureHasRestParameter(signature) && - signature.parameters.length < getDecoratorArgumentCount(decorator, signature)); + signature.minArgumentCount === 0 + && !signatureHasRestParameter(signature) + && signature.parameters.length < getDecoratorArgumentCount(decorator, signature)); } - function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveSignature( + node: CallLikeExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { switch (node.kind) { case SyntaxKind.CallExpression: return resolveCallExpression(node, candidatesOutArray, checkMode); @@ -32568,7 +42665,11 @@ namespace ts { * the function will fill it up with appropriate candidate signatures * @return a signature of the call-like expression or undefined if one can't be found */ - function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, checkMode?: CheckMode): Signature { + function getResolvedSignature( + node: CallLikeExpression, + candidatesOutArray?: Signature[] | undefined, + checkMode?: CheckMode, + ): Signature { const links = getNodeLinks(node); // If getResolvedSignature has already been called, we will have cached the resolvedSignature. // However, it is possible that either candidatesOutArray was not passed in the first time, @@ -32599,9 +42700,10 @@ namespace ts { if (!node || !isInJSFile(node)) { return false; } - const func = isFunctionDeclaration(node) || isFunctionExpression(node) ? node : - (isVariableDeclaration(node) || isPropertyAssignment(node)) && node.initializer && isFunctionExpression(node.initializer) ? node.initializer : - undefined; + const func = isFunctionDeclaration(node) || isFunctionExpression(node) ? node + : (isVariableDeclaration(node) || isPropertyAssignment(node)) && node.initializer + && isFunctionExpression(node.initializer) ? node.initializer + : undefined; if (func) { // If the node has a @class or @constructor tag, treat it like a constructor. if (getJSDocClassTag(node)) return true; @@ -32630,7 +42732,10 @@ namespace ts { if (source.members?.size) { mergeSymbolTable(inferred.members, source.members); } - (links.inferredClassSymbol || (links.inferredClassSymbol = new Map())).set(getSymbolId(inferred), inferred); + (links.inferredClassSymbol || (links.inferredClassSymbol = new Map())).set( + getSymbolId(inferred), + inferred, + ); return inferred; } return links.inferredClassSymbol.get(getSymbolId(target)); @@ -32664,12 +42769,19 @@ namespace ts { name = parentNode.left; decl = name; } - else if (parentNodeOperator === SyntaxKind.BarBarToken || parentNodeOperator === SyntaxKind.QuestionQuestionToken) { + else if ( + parentNodeOperator === SyntaxKind.BarBarToken + || parentNodeOperator === SyntaxKind.QuestionQuestionToken + ) { if (isVariableDeclaration(parentNode.parent) && parentNode.parent.initializer === parentNode) { name = parentNode.parent.name; decl = parentNode.parent; } - else if (isBinaryExpression(parentNode.parent) && parentNode.parent.operatorToken.kind === SyntaxKind.EqualsToken && (allowDeclaration || parentNode.parent.right === parentNode)) { + else if ( + isBinaryExpression(parentNode.parent) + && parentNode.parent.operatorToken.kind === SyntaxKind.EqualsToken + && (allowDeclaration || parentNode.parent.right === parentNode) + ) { name = parentNode.parent.left; decl = name; } @@ -32698,7 +42810,10 @@ namespace ts { while (parent && parent.kind === SyntaxKind.PropertyAccessExpression) { parent = parent.parent; } - if (parent && isBinaryExpression(parent) && isPrototypeAccess(parent.left) && parent.operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + parent && isBinaryExpression(parent) && isPrototypeAccess(parent.left) + && parent.operatorToken.kind === SyntaxKind.EqualsToken + ) { const right = getInitializerOfBinaryExpression(parent); return isObjectLiteralExpression(right) && right; } @@ -32729,16 +42844,20 @@ namespace ts { const declaration = signature.declaration; if ( - declaration && - declaration.kind !== SyntaxKind.Constructor && - declaration.kind !== SyntaxKind.ConstructSignature && - declaration.kind !== SyntaxKind.ConstructorType && - !isJSDocConstructSignature(declaration) && - !isJSConstructor(declaration) + declaration + && declaration.kind !== SyntaxKind.Constructor + && declaration.kind !== SyntaxKind.ConstructSignature + && declaration.kind !== SyntaxKind.ConstructorType + && !isJSDocConstructSignature(declaration) + && !isJSConstructor(declaration) ) { // When resolved signature is a call signature (and not a construct signature) the result type is any if (noImplicitAny) { - error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); + error( + node, + Diagnostics + .new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type, + ); } return anyType; } @@ -32756,14 +42875,22 @@ namespace ts { return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent)); } if ( - node.kind === SyntaxKind.CallExpression && !node.questionDotToken && node.parent.kind === SyntaxKind.ExpressionStatement && - returnType.flags & TypeFlags.Void && getTypePredicateOfSignature(signature) + node.kind === SyntaxKind.CallExpression && !node.questionDotToken + && node.parent.kind === SyntaxKind.ExpressionStatement + && returnType.flags & TypeFlags.Void && getTypePredicateOfSignature(signature) ) { if (!isDottedName(node.expression)) { - error(node.expression, Diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name); + error( + node.expression, + Diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name, + ); } else if (!getEffectsSignature(node)) { - const diagnostic = error(node.expression, Diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation); + const diagnostic = error( + node.expression, + Diagnostics + .Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation, + ); getTypeOfDottedName(node.expression, diagnostic); } } @@ -32771,7 +42898,13 @@ namespace ts { if (isInJSFile(node)) { const jsSymbol = getSymbolOfExpando(node, /*allowDeclaration*/ false); if (jsSymbol?.exports?.size) { - const jsAssignmentType = createAnonymousType(jsSymbol, jsSymbol.exports, emptyArray, emptyArray, emptyArray); + const jsAssignmentType = createAnonymousType( + jsSymbol, + jsSymbol.exports, + emptyArray, + emptyArray, + emptyArray, + ); jsAssignmentType.objectFlags |= ObjectFlags.JSLiteral; return getIntersectionType([returnType, jsAssignmentType]); } @@ -32784,7 +42917,12 @@ namespace ts { if (signature.declaration && signature.declaration.flags & NodeFlags.Deprecated) { const suggestionNode = getDeprecatedSuggestionNode(node); const name = tryGetPropertyAccessOrIdentifierToString(getInvokedExpression(node)); - addDeprecatedSuggestionWithSignature(suggestionNode, signature.declaration, name, signatureToString(signature)); + addDeprecatedSuggestionWithSignature( + suggestionNode, + signature.declaration, + name, + signatureToString(signature), + ); } } @@ -32828,7 +42966,15 @@ namespace ts { return false; } - return globalESSymbol === resolveName(left, "Symbol" as __String, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); + return globalESSymbol + === resolveName( + left, + "Symbol" as __String, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ); } function checkImportCallExpression(node: ImportCall): Type { @@ -32847,33 +42993,63 @@ namespace ts { checkExpressionCached(node.arguments[i]); } - if (specifierType.flags & TypeFlags.Undefined || specifierType.flags & TypeFlags.Null || !isTypeAssignableTo(specifierType, stringType)) { - error(specifier, Diagnostics.Dynamic_import_s_specifier_must_be_of_type_string_but_here_has_type_0, typeToString(specifierType)); + if ( + specifierType.flags & TypeFlags.Undefined || specifierType.flags & TypeFlags.Null + || !isTypeAssignableTo(specifierType, stringType) + ) { + error( + specifier, + Diagnostics.Dynamic_import_s_specifier_must_be_of_type_string_but_here_has_type_0, + typeToString(specifierType), + ); } if (optionsType) { const importCallOptionsType = getGlobalImportCallOptionsType(/*reportErrors*/ true); if (importCallOptionsType !== emptyObjectType) { - checkTypeAssignableTo(optionsType, getNullableType(importCallOptionsType, TypeFlags.Undefined), node.arguments[1]); + checkTypeAssignableTo( + optionsType, + getNullableType(importCallOptionsType, TypeFlags.Undefined), + node.arguments[1], + ); } } // resolveExternalModuleName will return undefined if the moduleReferenceExpression is not a string literal const moduleSymbol = resolveExternalModuleName(node, specifier); if (moduleSymbol) { - const esModuleSymbol = resolveESModuleSymbol(moduleSymbol, specifier, /*dontRecursivelyResolve*/ true, /*suppressUsageError*/ false); + const esModuleSymbol = resolveESModuleSymbol( + moduleSymbol, + specifier, + /*dontRecursivelyResolve*/ true, + /*suppressUsageError*/ false, + ); if (esModuleSymbol) { return createPromiseReturnType( node, - getTypeWithSyntheticDefaultOnly(getTypeOfSymbol(esModuleSymbol), esModuleSymbol, moduleSymbol, specifier) || - getTypeWithSyntheticDefaultImportType(getTypeOfSymbol(esModuleSymbol), esModuleSymbol, moduleSymbol, specifier), + getTypeWithSyntheticDefaultOnly( + getTypeOfSymbol(esModuleSymbol), + esModuleSymbol, + moduleSymbol, + specifier, + ) + || getTypeWithSyntheticDefaultImportType( + getTypeOfSymbol(esModuleSymbol), + esModuleSymbol, + moduleSymbol, + specifier, + ), ); } } return createPromiseReturnType(node, anyType); } - function createDefaultPropertyWrapperForModule(symbol: Symbol, originalSymbol: Symbol, anonymousSymbol?: Symbol | undefined) { + function createDefaultPropertyWrapperForModule( + symbol: Symbol, + originalSymbol: Symbol, + anonymousSymbol?: Symbol | undefined, + ) { const memberTable = createSymbolTable(); const newSymbol = createSymbol(SymbolFlags.Alias, InternalSymbolName.Default); newSymbol.parent = originalSymbol; @@ -32883,7 +43059,12 @@ namespace ts { return createAnonymousType(anonymousSymbol, memberTable, emptyArray, emptyArray, emptyArray); } - function getTypeWithSyntheticDefaultOnly(type: Type, symbol: Symbol, originalSymbol: Symbol, moduleSpecifier: Expression) { + function getTypeWithSyntheticDefaultOnly( + type: Type, + symbol: Symbol, + originalSymbol: Symbol, + moduleSpecifier: Expression, + ) { const hasDefaultOnly = isOnlyImportedAsDefault(moduleSpecifier); if (hasDefaultOnly && type && !isErrorType(type)) { const synthType = type as SyntheticDefaultModuleType; @@ -32896,17 +43077,38 @@ namespace ts { return undefined; } - function getTypeWithSyntheticDefaultImportType(type: Type, symbol: Symbol, originalSymbol: Symbol, moduleSpecifier: Expression): Type { + function getTypeWithSyntheticDefaultImportType( + type: Type, + symbol: Symbol, + originalSymbol: Symbol, + moduleSpecifier: Expression, + ): Type { if (allowSyntheticDefaultImports && type && !isErrorType(type)) { const synthType = type as SyntheticDefaultModuleType; if (!synthType.syntheticType) { const file = originalSymbol.declarations?.find(isSourceFile); - const hasSyntheticDefault = canHaveSyntheticDefault(file, originalSymbol, /*dontResolveAlias*/ false, moduleSpecifier); + const hasSyntheticDefault = canHaveSyntheticDefault( + file, + originalSymbol, + /*dontResolveAlias*/ false, + moduleSpecifier, + ); if (hasSyntheticDefault) { const anonymousSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type); - const defaultContainingObject = createDefaultPropertyWrapperForModule(symbol, originalSymbol, anonymousSymbol); + const defaultContainingObject = createDefaultPropertyWrapperForModule( + symbol, + originalSymbol, + anonymousSymbol, + ); anonymousSymbol.type = defaultContainingObject; - synthType.syntheticType = isValidSpreadType(type) ? getSpreadType(type, defaultContainingObject, anonymousSymbol, /*objectFlags*/ 0, /*readonly*/ false) : defaultContainingObject; + synthType.syntheticType = isValidSpreadType(type) + ? getSpreadType( + type, + defaultContainingObject, + anonymousSymbol, + /*objectFlags*/ 0, + /*readonly*/ false, + ) : defaultContainingObject; } else { synthType.syntheticType = type; @@ -32924,7 +43126,14 @@ namespace ts { // Make sure require is not a local function if (!isIdentifier(node.expression)) return Debug.fail(); - const resolvedRequire = resolveName(node.expression, node.expression.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true)!; // TODO: GH#18217 + const resolvedRequire = resolveName( + node.expression, + node.expression.escapedText, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + )!; // TODO: GH#18217 if (resolvedRequire === requireSymbol) { return true; } @@ -32960,7 +43169,11 @@ namespace ts { if (node.kind === SyntaxKind.TypeAssertionExpression) { const file = getSourceFileOfNode(node); if (file && fileExtensionIsOneOf(file.fileName, [Extension.Cts, Extension.Mts])) { - grammarErrorOnNode(node, Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Use_an_as_expression_instead); + grammarErrorOnNode( + node, + Diagnostics + .This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Use_an_as_expression_instead, + ); } } return checkAssertionWorker(node, node.type, node.expression); @@ -32983,8 +43196,9 @@ namespace ts { case SyntaxKind.PrefixUnaryExpression: const op = (node as PrefixUnaryExpression).operator; const arg = (node as PrefixUnaryExpression).operand; - return op === SyntaxKind.MinusToken && (arg.kind === SyntaxKind.NumericLiteral || arg.kind === SyntaxKind.BigIntLiteral) || - op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral; + return op === SyntaxKind.MinusToken + && (arg.kind === SyntaxKind.NumericLiteral || arg.kind === SyntaxKind.BigIntLiteral) + || op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: const expr = (node as PropertyAccessExpression | ElementAccessExpression).expression; @@ -32992,16 +43206,26 @@ namespace ts { if (symbol && symbol.flags & SymbolFlags.Alias) { symbol = resolveAlias(symbol); } - return !!(symbol && (getAllSymbolFlags(symbol) & SymbolFlags.Enum) && getEnumKind(symbol) === EnumKind.Literal); + return !!(symbol && (getAllSymbolFlags(symbol) & SymbolFlags.Enum) + && getEnumKind(symbol) === EnumKind.Literal); } return false; } - function checkAssertionWorker(errNode: Node, type: TypeNode, expression: UnaryExpression | Expression, checkMode?: CheckMode) { + function checkAssertionWorker( + errNode: Node, + type: TypeNode, + expression: UnaryExpression | Expression, + checkMode?: CheckMode, + ) { let exprType = checkExpression(expression, checkMode); if (isConstTypeReference(type)) { if (!isValidConstAssertionArgument(expression)) { - error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); + error( + expression, + Diagnostics + .A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals, + ); } return getRegularTypeOfLiteralType(exprType); } @@ -33012,7 +43236,13 @@ namespace ts { addLazyDiagnostic(() => { const widenedType = getWidenedType(exprType); if (!isTypeComparableTo(targetType, widenedType)) { - checkTypeComparableTo(exprType, targetType, errNode, Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first); + checkTypeComparableTo( + exprType, + targetType, + errNode, + Diagnostics + .Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first, + ); } }); } @@ -33026,15 +43256,15 @@ namespace ts { } function checkNonNullAssertion(node: NonNullExpression) { - return node.flags & NodeFlags.OptionalChain ? checkNonNullChain(node as NonNullChain) : - getNonNullableType(checkExpression(node.expression)); + return node.flags & NodeFlags.OptionalChain ? checkNonNullChain(node as NonNullChain) + : getNonNullableType(checkExpression(node.expression)); } function checkExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode) { checkGrammarExpressionWithTypeArguments(node); - const exprType = node.kind === SyntaxKind.ExpressionWithTypeArguments ? checkExpression(node.expression) : - isThisIdentifier(node.exprName) ? checkThisExpression(node.exprName) : - checkExpression(node.exprName); + const exprType = node.kind === SyntaxKind.ExpressionWithTypeArguments ? checkExpression(node.expression) + : isThisIdentifier(node.exprName) ? checkThisExpression(node.exprName) + : checkExpression(node.exprName); const typeArguments = node.typeArguments; if (exprType === silentNeverType || isErrorType(exprType) || !some(typeArguments)) { return exprType; @@ -33044,7 +43274,14 @@ namespace ts { const result = getInstantiatedType(exprType); const errorType = hasSomeApplicableSignature ? nonApplicableType : exprType; if (errorType) { - diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Type_0_has_no_signatures_for_which_the_type_argument_list_is_applicable, typeToString(errorType))); + diagnostics.add( + createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics.Type_0_has_no_signatures_for_which_the_type_argument_list_is_applicable, + typeToString(errorType), + ), + ); } return result; @@ -33063,10 +43300,20 @@ namespace ts { const resolved = resolveStructuredTypeMembers(type as ObjectType); const callSignatures = getInstantiatedSignatures(resolved.callSignatures); const constructSignatures = getInstantiatedSignatures(resolved.constructSignatures); - hasSignatures ||= resolved.callSignatures.length !== 0 || resolved.constructSignatures.length !== 0; + hasSignatures ||= resolved.callSignatures.length !== 0 + || resolved.constructSignatures.length !== 0; hasApplicableSignature ||= callSignatures.length !== 0 || constructSignatures.length !== 0; - if (callSignatures !== resolved.callSignatures || constructSignatures !== resolved.constructSignatures) { - const result = createAnonymousType(undefined, resolved.members, callSignatures, constructSignatures, resolved.indexInfos) as ResolvedType & InstantiationExpressionType; + if ( + callSignatures !== resolved.callSignatures + || constructSignatures !== resolved.constructSignatures + ) { + const result = createAnonymousType( + undefined, + resolved.members, + callSignatures, + constructSignatures, + resolved.indexInfos, + ) as ResolvedType & InstantiationExpressionType; result.objectFlags |= ObjectFlags.InstantiationExpressionType; result.node = node; return result; @@ -33092,10 +43339,14 @@ namespace ts { } function getInstantiatedSignatures(signatures: readonly Signature[]) { - const applicableSignatures = filter(signatures, sig => !!sig.typeParameters && hasCorrectTypeArgumentArity(sig, typeArguments)); + const applicableSignatures = filter( + signatures, + sig => !!sig.typeParameters && hasCorrectTypeArgumentArity(sig, typeArguments), + ); return sameMap(applicableSignatures, sig => { const typeArgumentTypes = checkTypeArguments(sig, typeArguments!, /*reportErrors*/ true); - return typeArgumentTypes ? getSignatureInstantiation(sig, typeArgumentTypes, isInJSFile(sig.declaration)) : sig; + return typeArgumentTypes + ? getSignatureInstantiation(sig, typeArgumentTypes, isInJSFile(sig.declaration)) : sig; }); } } @@ -33109,7 +43360,13 @@ namespace ts { } const exprType = checkExpression(node.expression); - checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, node.type, node.expression, Diagnostics.Type_0_does_not_satisfy_the_expected_type_1); + checkTypeAssignableToAndOptionallyElaborate( + exprType, + targetType, + node.type, + node.expression, + Diagnostics.Type_0_does_not_satisfy_the_expected_type_1, + ); return exprType; } @@ -33143,7 +43400,12 @@ namespace ts { function checkNewTargetMetaProperty(node: MetaProperty) { const container = getNewTargetContainer(node); if (!container) { - error(node, Diagnostics.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, "new.target"); + error( + node, + Diagnostics + .Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, + "new.target", + ); return errorType; } else if (container.kind === SyntaxKind.Constructor) { @@ -33159,14 +43421,25 @@ namespace ts { function checkImportMetaProperty(node: MetaProperty) { if (moduleKind === ModuleKind.Node16 || moduleKind === ModuleKind.NodeNext) { if (getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.ESNext) { - error(node, Diagnostics.The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output); + error( + node, + Diagnostics + .The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output, + ); } } else if (moduleKind < ModuleKind.ES2020 && moduleKind !== ModuleKind.System) { - error(node, Diagnostics.The_import_meta_meta_property_is_only_allowed_when_the_module_option_is_es2020_es2022_esnext_system_node16_or_nodenext); + error( + node, + Diagnostics + .The_import_meta_meta_property_is_only_allowed_when_the_module_option_is_es2020_es2022_esnext_system_node16_or_nodenext, + ); } const file = getSourceFileOfNode(node); - Debug.assert(!!(file.flags & NodeFlags.PossiblyContainsImportMeta), "Containing file is missing import meta node flag."); + Debug.assert( + !!(file.flags & NodeFlags.PossiblyContainsImportMeta), + "Containing file is missing import meta node flag.", + ); return node.name.escapedText === "meta" ? getGlobalImportMetaType() : errorType; } @@ -33196,12 +43469,16 @@ namespace ts { if (isTupleType(restType)) { const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; const index = pos - paramCount; - return associatedNames && getTupleElementLabel(associatedNames[index]) || restParameter.escapedName + "_" + index as __String; + return associatedNames && getTupleElementLabel(associatedNames[index]) + || restParameter.escapedName + "_" + index as __String; } return restParameter.escapedName; } - function getParameterIdentifierNameAtPosition(signature: Signature, pos: number): [parameterName: __String, isRestParameter: boolean] | undefined { + function getParameterIdentifierNameAtPosition( + signature: Signature, + pos: number, + ): [parameterName: __String, isRestParameter: boolean] | undefined { if (signature.declaration?.kind === SyntaxKind.JSDocFunctionType) { return undefined; } @@ -33235,9 +43512,12 @@ namespace ts { } function isParameterDeclarationWithIdentifierName(symbol: Symbol) { - return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) && isIdentifier(symbol.valueDeclaration.name); + return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) + && isIdentifier(symbol.valueDeclaration.name); } - function isValidDeclarationForTupleLabel(d: Declaration): d is NamedTupleMember | (ParameterDeclaration & { name: Identifier; }) { + function isValidDeclarationForTupleLabel( + d: Declaration, + ): d is NamedTupleMember | (ParameterDeclaration & { name: Identifier; }) { return d.kind === SyntaxKind.NamedTupleMember || (isParameter(d) && d.name && isIdentifier(d.name)); } @@ -33254,7 +43534,8 @@ namespace ts { const index = pos - paramCount; return associatedNames && associatedNames[index]; } - return restParameter.valueDeclaration && isValidDeclarationForTupleLabel(restParameter.valueDeclaration) ? restParameter.valueDeclaration : undefined; + return restParameter.valueDeclaration && isValidDeclarationForTupleLabel(restParameter.valueDeclaration) + ? restParameter.valueDeclaration : undefined; } function getTypeAtPosition(signature: Signature, pos: number): Type { @@ -33284,7 +43565,8 @@ namespace ts { const minArgumentCount = getMinArgumentCount(source); const restType = getEffectiveRestType(source); if (restType && pos >= parameterCount - 1) { - return pos === parameterCount - 1 ? restType : createArrayType(getIndexedAccessType(restType, numberType)); + return pos === parameterCount - 1 ? restType + : createArrayType(getIndexedAccessType(restType, numberType)); } const types = []; const flags = []; @@ -33303,7 +43585,12 @@ namespace ts { names.push(name); } } - return createTupleType(types, flags, /*readonly*/ false, length(names) === length(types) ? names : undefined); + return createTupleType( + types, + flags, + /*readonly*/ false, + length(names) === length(types) ? names : undefined, + ); } // Return the number of parameters in a signature. The rest parameter, if present, counts as one @@ -33329,7 +43616,10 @@ namespace ts { if (signatureHasRestParameter(signature)) { const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); if (isTupleType(restType)) { - const firstOptionalIndex = findIndex(restType.target.elementFlags, f => !(f & ElementFlags.Required)); + const firstOptionalIndex = findIndex( + restType.target.elementFlags, + f => !(f & ElementFlags.Required), + ); const requiredCount = firstOptionalIndex < 0 ? restType.target.fixedLength : firstOptionalIndex; if (requiredCount > 0) { minArgumentCount = signature.parameters.length - 1 + requiredCount; @@ -33380,7 +43670,8 @@ namespace ts { function getNonArrayRestType(signature: Signature) { const restType = getEffectiveRestType(signature); - return restType && !isArrayType(restType) && !isTypeAny(restType) && (getReducedType(restType).flags & TypeFlags.Never) === 0 ? restType : undefined; + return restType && !isArrayType(restType) && !isTypeAny(restType) + && (getReducedType(restType).flags & TypeFlags.Never) === 0 ? restType : undefined; } function getTypeOfFirstParameterOfSignature(signature: Signature) { @@ -33391,14 +43682,22 @@ namespace ts { return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : fallbackType; } - function inferFromAnnotatedParameters(signature: Signature, context: Signature, inferenceContext: InferenceContext) { + function inferFromAnnotatedParameters( + signature: Signature, + context: Signature, + inferenceContext: InferenceContext, + ) { const len = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); for (let i = 0; i < len; i++) { const declaration = signature.parameters[i].valueDeclaration as ParameterDeclaration; if (declaration.type) { const typeNode = getEffectiveTypeAnnotationNode(declaration); if (typeNode) { - inferTypes(inferenceContext.inferences, getTypeFromTypeNode(typeNode), getTypeAtPosition(context, i)); + inferTypes( + inferenceContext.inferences, + getTypeFromTypeNode(typeNode), + getTypeAtPosition(context, i), + ); } } } @@ -33415,7 +43714,10 @@ namespace ts { } if (context.thisParameter) { const parameter = signature.thisParameter; - if (!parameter || parameter.valueDeclaration && !(parameter.valueDeclaration as ParameterDeclaration).type) { + if ( + !parameter + || parameter.valueDeclaration && !(parameter.valueDeclaration as ParameterDeclaration).type + ) { if (!parameter) { signature.thisParameter = createSymbolWithType(context.thisParameter, /*type*/ undefined); } @@ -33459,7 +43761,9 @@ namespace ts { const links = getSymbolLinks(parameter); if (!links.type) { const declaration = parameter.valueDeclaration as ParameterDeclaration | undefined; - links.type = type || (declaration ? getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true) : getTypeOfSymbol(parameter)); + links.type = type + || (declaration ? getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true) + : getTypeOfSymbol(parameter)); if (declaration && declaration.name.kind !== SyntaxKind.Identifier) { // if inference didn't come up with anything but unknown, fall back to the binding pattern if present. if (links.type === unknownType) { @@ -33469,7 +43773,11 @@ namespace ts { } } else if (type) { - Debug.assertEqual(links.type, type, "Parameter symbol already has a cached type which differs from newly assigned type"); + Debug.assertEqual( + links.type, + type, + "Parameter symbol already has a cached type which differs from newly assigned type", + ); } } @@ -33520,18 +43828,22 @@ namespace ts { if (promiseType === unknownType) { error( func, - isImportCall(func) ? - Diagnostics.A_dynamic_import_call_returns_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option : - Diagnostics.An_async_function_or_method_must_return_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option, + isImportCall(func) + ? Diagnostics + .A_dynamic_import_call_returns_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option + : Diagnostics + .An_async_function_or_method_must_return_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option, ); return errorType; } else if (!getGlobalPromiseConstructorSymbol(/*reportErrors*/ true)) { error( func, - isImportCall(func) ? - Diagnostics.A_dynamic_import_call_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option : - Diagnostics.An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option, + isImportCall(func) + ? Diagnostics + .A_dynamic_import_call_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option + : Diagnostics + .An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option, ); } @@ -33571,7 +43883,15 @@ namespace ts { // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body should be unwrapped to its awaited type, which we will wrap in // the native Promise type later in this function. - returnType = unwrapAwaitedType(checkAwaitedType(returnType, /*withAlias*/ false, /*errorNode*/ func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)); + returnType = unwrapAwaitedType( + checkAwaitedType( + returnType, + /*withAlias*/ false, + /*errorNode*/ func, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ), + ); } } else if (isGenerator) { // Generator or AsyncGenerator function @@ -33610,21 +43930,45 @@ namespace ts { if (returnType) reportErrorsFromWidening(func, returnType, WideningKind.FunctionReturn); if (nextType) reportErrorsFromWidening(func, nextType, WideningKind.GeneratorNext); if ( - returnType && isUnitType(returnType) || - yieldType && isUnitType(yieldType) || - nextType && isUnitType(nextType) + returnType && isUnitType(returnType) + || yieldType && isUnitType(yieldType) + || nextType && isUnitType(nextType) ) { const contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func); - const contextualType = !contextualSignature ? undefined : - contextualSignature === getSignatureFromDeclaration(func) ? isGenerator ? undefined : returnType : - instantiateContextualType(getReturnTypeOfSignature(contextualSignature), func, /*contextFlags*/ undefined); + const contextualType = !contextualSignature ? undefined + : contextualSignature === getSignatureFromDeclaration(func) + ? isGenerator ? undefined : returnType + : instantiateContextualType( + getReturnTypeOfSignature(contextualSignature), + func, + /*contextFlags*/ undefined, + ); if (isGenerator) { - yieldType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(yieldType, contextualType, IterationTypeKind.Yield, isAsync); - returnType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(returnType, contextualType, IterationTypeKind.Return, isAsync); - nextType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(nextType, contextualType, IterationTypeKind.Next, isAsync); + yieldType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + yieldType, + contextualType, + IterationTypeKind.Yield, + isAsync, + ); + returnType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + returnType, + contextualType, + IterationTypeKind.Return, + isAsync, + ); + nextType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + nextType, + contextualType, + IterationTypeKind.Next, + isAsync, + ); } else { - returnType = getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded(returnType, contextualType, isAsync); + returnType = getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded( + returnType, + contextualType, + isAsync, + ); } } @@ -33651,7 +43995,12 @@ namespace ts { } } - function createGeneratorReturnType(yieldType: Type, returnType: Type, nextType: Type, isAsyncGenerator: boolean) { + function createGeneratorReturnType( + yieldType: Type, + returnType: Type, + nextType: Type, + isAsyncGenerator: boolean, + ) { const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver; const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false); yieldType = resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || unknownType; @@ -33662,12 +44011,13 @@ namespace ts { // type of IterableIterator, and the expected next iteration type of IterableIterator is assignable to // nextType. const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false); - const iterationTypes = globalType !== emptyGenericType ? getIterationTypesOfGlobalIterableType(globalType, resolver) : undefined; + const iterationTypes = globalType !== emptyGenericType + ? getIterationTypesOfGlobalIterableType(globalType, resolver) : undefined; const iterableIteratorReturnType = iterationTypes ? iterationTypes.returnType : anyType; const iterableIteratorNextType = iterationTypes ? iterationTypes.nextType : undefinedType; if ( - isTypeAssignableTo(returnType, iterableIteratorReturnType) && - isTypeAssignableTo(iterableIteratorNextType, nextType) + isTypeAssignableTo(returnType, iterableIteratorReturnType) + && isTypeAssignableTo(iterableIteratorNextType, nextType) ) { if (globalType !== emptyGenericType) { return createTypeFromGenericGlobalType(globalType, [yieldType]); @@ -33691,8 +44041,12 @@ namespace ts { const nextTypes: Type[] = []; const isAsync = (getFunctionFlags(func) & FunctionFlags.Async) !== 0; forEachYieldExpression(func.body as Block, yieldExpression => { - const yieldExpressionType = yieldExpression.expression ? checkExpression(yieldExpression.expression, checkMode) : undefinedWideningType; - pushIfUnique(yieldTypes, getYieldedTypeOfYieldExpression(yieldExpression, yieldExpressionType, anyType, isAsync)); + const yieldExpressionType = yieldExpression.expression + ? checkExpression(yieldExpression.expression, checkMode) : undefinedWideningType; + pushIfUnique( + yieldTypes, + getYieldedTypeOfYieldExpression(yieldExpression, yieldExpressionType, anyType, isAsync), + ); let nextType: Type | undefined; if (yieldExpression.asteriskToken) { const iterationTypes = getIterationTypesOfIterable( @@ -33710,21 +44064,38 @@ namespace ts { return { yieldTypes, nextTypes }; } - function getYieldedTypeOfYieldExpression(node: YieldExpression, expressionType: Type, sentType: Type, isAsync: boolean): Type | undefined { + function getYieldedTypeOfYieldExpression( + node: YieldExpression, + expressionType: Type, + sentType: Type, + isAsync: boolean, + ): Type | undefined { const errorNode = node.expression || node; // A `yield*` expression effectively yields everything that its operand yields - const yieldedType = node.asteriskToken ? checkIteratedTypeOrElementType(isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar, expressionType, sentType, errorNode) : expressionType; + const yieldedType = node.asteriskToken + ? checkIteratedTypeOrElementType( + isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar, + expressionType, + sentType, + errorNode, + ) : expressionType; return !isAsync ? yieldedType : getAwaitedType( yieldedType, errorNode, node.asteriskToken - ? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member - : Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ? Diagnostics + .Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member + : Diagnostics + .Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, ); } // Return the combined not-equal type facts for all cases except those between the start and end indices. - function getNotEqualFactsFromTypeofSwitch(start: number, end: number, witnesses: (string | undefined)[]): TypeFacts { + function getNotEqualFactsFromTypeofSwitch( + start: number, + end: number, + witnesses: (string | undefined)[], + ): TypeFacts { let facts: TypeFacts = TypeFacts.None; for (let i = 0; i < witnesses.length; i++) { const witness = i < start || i >= end ? witnesses[i] : undefined; @@ -33754,7 +44125,9 @@ namespace ts { if (!witnesses) { return false; } - const operandConstraint = getBaseConstraintOrType(checkExpressionCached((node.expression as TypeOfExpression).expression)); + const operandConstraint = getBaseConstraintOrType( + checkExpressionCached((node.expression as TypeOfExpression).expression), + ); // Get the not-equal flags for all handled cases. const notEqualFacts = getNotEqualFactsFromTypeofSwitch(0, 0, witnesses); if (operandConstraint.flags & TypeFlags.AnyOrUnknown) { @@ -33780,7 +44153,10 @@ namespace ts { } /** NOTE: Return value of `[]` means a different thing than `undefined`. `[]` means func returns `void`, `undefined` means it returns `never`. */ - function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, checkMode: CheckMode | undefined): Type[] | undefined { + function checkAndAggregateReturnExpressionTypes( + func: FunctionLikeDeclaration, + checkMode: CheckMode | undefined, + ): Type[] | undefined { const functionFlags = getFunctionFlags(func); const aggregatedTypes: Type[] = []; let hasReturnWithNoExpression = functionHasImplicitReturn(func); @@ -33794,7 +44170,15 @@ namespace ts { // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body should be unwrapped to its awaited type, which should be wrapped in // the native Promise type by the caller. - type = unwrapAwaitedType(checkAwaitedType(type, /*withAlias*/ false, func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)); + type = unwrapAwaitedType( + checkAwaitedType( + type, + /*withAlias*/ false, + func, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ), + ); } if (type.flags & TypeFlags.Never) { hasReturnOfTypeNever = true; @@ -33805,12 +44189,15 @@ namespace ts { hasReturnWithNoExpression = true; } }); - if (aggregatedTypes.length === 0 && !hasReturnWithNoExpression && (hasReturnOfTypeNever || mayReturnNever(func))) { + if ( + aggregatedTypes.length === 0 && !hasReturnWithNoExpression + && (hasReturnOfTypeNever || mayReturnNever(func)) + ) { return undefined; } if ( - strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression && - !(isJSConstructor(func) && aggregatedTypes.some(t => t.symbol === func.symbol)) + strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression + && !(isJSConstructor(func) && aggregatedTypes.some(t => t.symbol === func.symbol)) ) { // Javascript "callable constructors", containing eg `if (!(this instanceof A)) return new A()` should not add undefined pushIfUnique(aggregatedTypes, undefinedType); @@ -33838,7 +44225,10 @@ namespace ts { * * @param returnType - return type of the function, can be undefined if return type is not explicitly specified */ - function checkAllCodePathsInNonVoidFunctionReturnOrThrow(func: FunctionLikeDeclaration | MethodSignature, returnType: Type | undefined) { + function checkAllCodePathsInNonVoidFunctionReturnOrThrow( + func: FunctionLikeDeclaration | MethodSignature, + returnType: Type | undefined, + ) { addLazyDiagnostic(checkAllCodePathsInNonVoidFunctionReturnOrThrowDiagnostics); return; @@ -33853,7 +44243,10 @@ namespace ts { // If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check. // also if HasImplicitReturn flag is not set this means that all codepaths in function body end with return or throw - if (func.kind === SyntaxKind.MethodSignature || nodeIsMissing(func.body) || func.body!.kind !== SyntaxKind.Block || !functionHasImplicitReturn(func)) { + if ( + func.kind === SyntaxKind.MethodSignature || nodeIsMissing(func.body) + || func.body!.kind !== SyntaxKind.Block || !functionHasImplicitReturn(func) + ) { return; } @@ -33866,10 +44259,16 @@ namespace ts { else if (type && !hasExplicitReturn) { // minimal check: function has syntactic return type annotation and no explicit return statements in the body // this function does not conform to the specification. - error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value); + error( + errorNode, + Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value, + ); } else if (type && strictNullChecks && !isTypeAssignableTo(undefinedType, type)) { - error(errorNode, Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined); + error( + errorNode, + Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined, + ); } else if (compilerOptions.noImplicitReturns) { if (!type) { @@ -33889,7 +44288,10 @@ namespace ts { } } - function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode): Type { + function checkFunctionExpressionOrObjectLiteralMethod( + node: FunctionExpression | ArrowFunction | MethodDeclaration, + checkMode?: CheckMode, + ): Type { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); checkNodeDeferred(node); @@ -33903,14 +44305,31 @@ namespace ts { if (!getEffectiveReturnTypeNode(node) && !hasContextSensitiveParameters(node)) { // Return plain anyFunctionType if there is no possibility we'll make inferences from the return type const contextualSignature = getContextualSignature(node); - if (contextualSignature && couldContainTypeVariables(getReturnTypeOfSignature(contextualSignature))) { + if ( + contextualSignature && couldContainTypeVariables(getReturnTypeOfSignature(contextualSignature)) + ) { const links = getNodeLinks(node); if (links.contextFreeType) { return links.contextFreeType; } const returnType = getReturnTypeFromBody(node, checkMode); - const returnOnlySignature = createSignature(undefined, undefined, undefined, emptyArray, returnType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - const returnOnlyType = createAnonymousType(node.symbol, emptySymbols, [returnOnlySignature], emptyArray, emptyArray); + const returnOnlySignature = createSignature( + undefined, + undefined, + undefined, + emptyArray, + returnType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None, + ); + const returnOnlyType = createAnonymousType( + node.symbol, + emptySymbols, + [returnOnlySignature], + emptyArray, + emptyArray, + ); returnOnlyType.objectFlags |= ObjectFlags.NonInferrableType; return links.contextFreeType = returnOnlyType; } @@ -33929,7 +44348,10 @@ namespace ts { return getTypeOfSymbol(getSymbolOfNode(node)); } - function contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode) { + function contextuallyCheckFunctionExpressionOrObjectLiteralMethod( + node: FunctionExpression | ArrowFunction | MethodDeclaration, + checkMode?: CheckMode, + ) { const links = getNodeLinks(node); // Check if function expression is contextually typed and assign parameter types if so. if (!(links.flags & NodeCheckFlags.ContextChecked)) { @@ -33939,7 +44361,9 @@ namespace ts { // already assigned contextual types. if (!(links.flags & NodeCheckFlags.ContextChecked)) { links.flags |= NodeCheckFlags.ContextChecked; - const signature = firstOrUndefined(getSignaturesOfType(getTypeOfSymbol(getSymbolOfNode(node)), SignatureKind.Call)); + const signature = firstOrUndefined( + getSignaturesOfType(getTypeOfSymbol(getSymbolOfNode(node)), SignatureKind.Call), + ); if (!signature) { return; } @@ -33951,11 +44375,15 @@ namespace ts { inferFromAnnotatedParameters(signature, contextualSignature, inferenceContext!); const restType = getEffectiveRestType(contextualSignature); if (restType && restType.flags & TypeFlags.TypeParameter) { - instantiatedContextualSignature = instantiateSignature(contextualSignature, inferenceContext!.nonFixingMapper); + instantiatedContextualSignature = instantiateSignature( + contextualSignature, + inferenceContext!.nonFixingMapper, + ); } } - instantiatedContextualSignature ||= inferenceContext ? - instantiateSignature(contextualSignature, inferenceContext.mapper) : contextualSignature; + instantiatedContextualSignature ||= inferenceContext + ? instantiateSignature(contextualSignature, inferenceContext.mapper) + : contextualSignature; assignContextualParameterTypes(signature, instantiatedContextualSignature); } else { @@ -33974,7 +44402,9 @@ namespace ts { } } - function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) { + function checkFunctionExpressionOrObjectLiteralMethodDeferred( + node: ArrowFunction | FunctionExpression | MethodDeclaration, + ) { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); const functionFlags = getFunctionFlags(node); @@ -34004,18 +44434,39 @@ namespace ts { const returnOrPromisedType = returnType && unwrapReturnType(returnType, functionFlags); if (returnOrPromisedType) { if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { // Async function - const awaitedType = checkAwaitedType(exprType, /*withAlias*/ false, node.body, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); - checkTypeAssignableToAndOptionallyElaborate(awaitedType, returnOrPromisedType, node.body, node.body); + const awaitedType = checkAwaitedType( + exprType, + /*withAlias*/ false, + node.body, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ); + checkTypeAssignableToAndOptionallyElaborate( + awaitedType, + returnOrPromisedType, + node.body, + node.body, + ); } else { // Normal function - checkTypeAssignableToAndOptionallyElaborate(exprType, returnOrPromisedType, node.body, node.body); + checkTypeAssignableToAndOptionallyElaborate( + exprType, + returnOrPromisedType, + node.body, + node.body, + ); } } } } } - function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage, isAwaitValid = false): boolean { + function checkArithmeticOperandType( + operand: Node, + type: Type, + diagnostic: DiagnosticMessage, + isAwaitValid = false, + ): boolean { if (!isTypeAssignableTo(type, numberOrBigIntType)) { const awaitedType = isAwaitValid && getAwaitedTypeOfPromise(type); errorAndMaybeSuggestAwait( @@ -34046,7 +44497,9 @@ namespace ts { // We include this definition whereupon we walk back and check the type at the declaration because // The usual definition of `Object.defineProperty` will _not_ cause literal types to be preserved in the // argument types, should the type be contextualized by the call itself. - if (writableProp && writableProp.valueDeclaration && isPropertyAssignment(writableProp.valueDeclaration)) { + if ( + writableProp && writableProp.valueDeclaration && isPropertyAssignment(writableProp.valueDeclaration) + ) { const initializer = writableProp.valueDeclaration.initializer; const rawOriginalType = checkExpression(initializer); if (rawOriginalType === falseType || rawOriginalType === regularFalseType) { @@ -34067,12 +44520,13 @@ namespace ts { // Enum members // Object.defineProperty assignments with writable false or no setter // Unions and intersections of the above (unions and intersections eagerly set isReadonly on creation) - return !!(getCheckFlags(symbol) & CheckFlags.Readonly || - symbol.flags & SymbolFlags.Property && getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.Readonly || - symbol.flags & SymbolFlags.Variable && getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const || - symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor) || - symbol.flags & SymbolFlags.EnumMember || - some(symbol.declarations, isReadonlyAssignmentDeclaration)); + return !!(getCheckFlags(symbol) & CheckFlags.Readonly + || symbol.flags & SymbolFlags.Property + && getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.Readonly + || symbol.flags & SymbolFlags.Variable && getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const + || symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor) + || symbol.flags & SymbolFlags.EnumMember + || some(symbol.declarations, isReadonlyAssignmentDeclaration)); } function isAssignmentToReadonlyEntity(expr: Expression, symbol: Symbol, assignmentKind: AssignmentKind) { @@ -34083,9 +44537,9 @@ namespace ts { if (isReadonlySymbol(symbol)) { // Allow assignments to readonly properties within constructors of the same class declaration. if ( - symbol.flags & SymbolFlags.Property && - isAccessExpression(expr) && - expr.expression.kind === SyntaxKind.ThisKeyword + symbol.flags & SymbolFlags.Property + && isAccessExpression(expr) + && expr.expression.kind === SyntaxKind.ThisKeyword ) { // Look for if this is the constructor for the class that `symbol` is a property of. const ctor = getContainingFunction(expr); @@ -34096,8 +44550,10 @@ namespace ts { const isAssignmentDeclaration = isBinaryExpression(symbol.valueDeclaration); const isLocalPropertyDeclaration = ctor.parent === symbol.valueDeclaration.parent; const isLocalParameterProperty = ctor === symbol.valueDeclaration.parent; - const isLocalThisPropertyAssignment = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor.parent; - const isLocalThisPropertyAssignmentConstructorFunction = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor; + const isLocalThisPropertyAssignment = isAssignmentDeclaration + && symbol.parent?.valueDeclaration === ctor.parent; + const isLocalThisPropertyAssignmentConstructorFunction = isAssignmentDeclaration + && symbol.parent?.valueDeclaration === ctor; const isWriteableSymbol = isLocalPropertyDeclaration || isLocalParameterProperty || isLocalThisPropertyAssignment @@ -34121,7 +44577,11 @@ namespace ts { return false; } - function checkReferenceExpression(expr: Expression, invalidReferenceMessage: DiagnosticMessage, invalidOptionalChainMessage: DiagnosticMessage): boolean { + function checkReferenceExpression( + expr: Expression, + invalidReferenceMessage: DiagnosticMessage, + invalidOptionalChainMessage: DiagnosticMessage, + ): boolean { // References are combinations of identifiers, parentheses, and property accesses. const node = skipOuterExpressions(expr, OuterExpressionKinds.Assertions | OuterExpressionKinds.Parentheses); if (node.kind !== SyntaxKind.Identifier && !isAccessExpression(node)) { @@ -34159,9 +44619,10 @@ namespace ts { function checkDeleteExpressionMustBeOptional(expr: AccessExpression, symbol: Symbol) { const type = getTypeOfSymbol(symbol); if ( - strictNullChecks && - !(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) && - !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : getTypeFacts(type) & TypeFacts.IsUndefined) + strictNullChecks + && !(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) + && !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional + : getTypeFacts(type) & TypeFacts.IsUndefined) ) { error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional); } @@ -34190,7 +44651,13 @@ namespace ts { let span: TextSpan | undefined; if (!isEffectiveExternalModule(sourceFile, compilerOptions)) { span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); - const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module); + const diagnostic = createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics + .await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module, + ); diagnostics.add(diagnostic); } switch (moduleKind) { @@ -34199,7 +44666,13 @@ namespace ts { if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) { span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); diagnostics.add( - createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level), + createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics + .The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level, + ), ); break; } @@ -34214,7 +44687,13 @@ namespace ts { default: span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); diagnostics.add( - createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher), + createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics + .Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher, + ), ); break; } @@ -34225,9 +44704,21 @@ namespace ts { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); - const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules); - if (container && container.kind !== SyntaxKind.Constructor && (getFunctionFlags(container) & FunctionFlags.Async) === 0) { - const relatedInfo = createDiagnosticForNode(container, Diagnostics.Did_you_mean_to_mark_this_function_as_async); + const diagnostic = createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics + .await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules, + ); + if ( + container && container.kind !== SyntaxKind.Constructor + && (getFunctionFlags(container) & FunctionFlags.Async) === 0 + ) { + const relatedInfo = createDiagnosticForNode( + container, + Diagnostics.Did_you_mean_to_mark_this_function_as_async, + ); addRelatedInfo(diagnostic, relatedInfo); } diagnostics.add(diagnostic); @@ -34244,9 +44735,21 @@ namespace ts { addLazyDiagnostic(() => checkAwaitExpressionGrammar(node)); const operandType = checkExpression(node.expression); - const awaitedType = checkAwaitedType(operandType, /*withAlias*/ true, node, Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); - if (awaitedType === operandType && !isErrorType(awaitedType) && !(operandType.flags & TypeFlags.AnyOrUnknown)) { - addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(node, Diagnostics.await_has_no_effect_on_the_type_of_this_expression)); + const awaitedType = checkAwaitedType( + operandType, + /*withAlias*/ true, + node, + Diagnostics + .Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ); + if ( + awaitedType === operandType && !isErrorType(awaitedType) + && !(operandType.flags & TypeFlags.AnyOrUnknown) + ) { + addErrorOrSuggestion( + /*isError*/ false, + createDiagnosticForNode(node, Diagnostics.await_has_no_effect_on_the_type_of_this_expression), + ); } return awaitedType; } @@ -34260,9 +44763,13 @@ namespace ts { case SyntaxKind.NumericLiteral: switch (node.operator) { case SyntaxKind.MinusToken: - return getFreshTypeOfLiteralType(getNumberLiteralType(-(node.operand as NumericLiteral).text)); + return getFreshTypeOfLiteralType( + getNumberLiteralType(-(node.operand as NumericLiteral).text), + ); case SyntaxKind.PlusToken: - return getFreshTypeOfLiteralType(getNumberLiteralType(+(node.operand as NumericLiteral).text)); + return getFreshTypeOfLiteralType( + getNumberLiteralType(+(node.operand as NumericLiteral).text), + ); } break; case SyntaxKind.BigIntLiteral: @@ -34279,11 +44786,20 @@ namespace ts { case SyntaxKind.TildeToken: checkNonNullType(operandType, node.operand); if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.ESSymbolLike)) { - error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator)); + error( + node.operand, + Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, + tokenToString(node.operator), + ); } if (node.operator === SyntaxKind.PlusToken) { if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.BigIntLike)) { - error(node.operand, Diagnostics.Operator_0_cannot_be_applied_to_type_1, tokenToString(node.operator), typeToString(getBaseTypeOfLiteralType(operandType))); + error( + node.operand, + Diagnostics.Operator_0_cannot_be_applied_to_type_1, + tokenToString(node.operator), + typeToString(getBaseTypeOfLiteralType(operandType)), + ); } return numberType; } @@ -34291,18 +44807,24 @@ namespace ts { case SyntaxKind.ExclamationToken: checkTruthinessExpression(node.operand); const facts = getTypeFacts(operandType) & (TypeFacts.Truthy | TypeFacts.Falsy); - return facts === TypeFacts.Truthy ? falseType : - facts === TypeFacts.Falsy ? trueType : - booleanType; + return facts === TypeFacts.Truthy ? falseType + : facts === TypeFacts.Falsy ? trueType + : booleanType; case SyntaxKind.PlusPlusToken: case SyntaxKind.MinusMinusToken: - const ok = checkArithmeticOperandType(node.operand, checkNonNullType(operandType, node.operand), Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type); + const ok = checkArithmeticOperandType( + node.operand, + checkNonNullType(operandType, node.operand), + Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type, + ); if (ok) { // run check only if former checks succeeded to avoid reporting cascading errors checkReferenceExpression( node.operand, - Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, - Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, + Diagnostics + .The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, + Diagnostics + .The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, ); } return getUnaryResultType(operandType); @@ -34324,8 +44846,10 @@ namespace ts { // run check only if former checks succeeded to avoid reporting cascading errors checkReferenceExpression( node.operand, - Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, - Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, + Diagnostics + .The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, + Diagnostics + .The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, ); } return getUnaryResultType(operandType); @@ -34333,7 +44857,8 @@ namespace ts { function getUnaryResultType(operandType: Type): Type { if (maybeTypeOfKind(operandType, TypeFlags.BigIntLike)) { - return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) || maybeTypeOfKind(operandType, TypeFlags.NumberLike) + return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) + || maybeTypeOfKind(operandType, TypeFlags.NumberLike) ? numberOrBigIntType : bigintType; } @@ -34371,25 +44896,28 @@ namespace ts { if (source.flags & kind) { return true; } - if (strict && source.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null)) { + if ( + strict + && source.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null) + ) { return false; } - return !!(kind & TypeFlags.NumberLike) && isTypeAssignableTo(source, numberType) || - !!(kind & TypeFlags.BigIntLike) && isTypeAssignableTo(source, bigintType) || - !!(kind & TypeFlags.StringLike) && isTypeAssignableTo(source, stringType) || - !!(kind & TypeFlags.BooleanLike) && isTypeAssignableTo(source, booleanType) || - !!(kind & TypeFlags.Void) && isTypeAssignableTo(source, voidType) || - !!(kind & TypeFlags.Never) && isTypeAssignableTo(source, neverType) || - !!(kind & TypeFlags.Null) && isTypeAssignableTo(source, nullType) || - !!(kind & TypeFlags.Undefined) && isTypeAssignableTo(source, undefinedType) || - !!(kind & TypeFlags.ESSymbol) && isTypeAssignableTo(source, esSymbolType) || - !!(kind & TypeFlags.NonPrimitive) && isTypeAssignableTo(source, nonPrimitiveType); + return !!(kind & TypeFlags.NumberLike) && isTypeAssignableTo(source, numberType) + || !!(kind & TypeFlags.BigIntLike) && isTypeAssignableTo(source, bigintType) + || !!(kind & TypeFlags.StringLike) && isTypeAssignableTo(source, stringType) + || !!(kind & TypeFlags.BooleanLike) && isTypeAssignableTo(source, booleanType) + || !!(kind & TypeFlags.Void) && isTypeAssignableTo(source, voidType) + || !!(kind & TypeFlags.Never) && isTypeAssignableTo(source, neverType) + || !!(kind & TypeFlags.Null) && isTypeAssignableTo(source, nullType) + || !!(kind & TypeFlags.Undefined) && isTypeAssignableTo(source, undefinedType) + || !!(kind & TypeFlags.ESSymbol) && isTypeAssignableTo(source, esSymbolType) + || !!(kind & TypeFlags.NonPrimitive) && isTypeAssignableTo(source, nonPrimitiveType); } function allTypesAssignableToKind(source: Type, kind: TypeFlags, strict?: boolean): boolean { - return source.flags & TypeFlags.Union ? - every((source as UnionType).types, subType => allTypesAssignableToKind(subType, kind, strict)) : - isTypeAssignableToKind(source, kind, strict); + return source.flags & TypeFlags.Union + ? every((source as UnionType).types, subType => allTypesAssignableToKind(subType, kind, strict)) + : isTypeAssignableToKind(source, kind, strict); } function isConstEnumObjectType(type: Type): boolean { @@ -34410,20 +44938,36 @@ namespace ts { // The result is always of the Boolean primitive type. // NOTE: do not raise error if leftType is unknown as related error was already reported if ( - !isTypeAny(leftType) && - allTypesAssignableToKind(leftType, TypeFlags.Primitive) + !isTypeAny(leftType) + && allTypesAssignableToKind(leftType, TypeFlags.Primitive) ) { - error(left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); + error( + left, + Diagnostics + .The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter, + ); } // NOTE: do not raise error if right is unknown as related error was already reported - if (!(isTypeAny(rightType) || typeHasCallOrConstructSignatures(rightType) || isTypeSubtypeOf(rightType, globalFunctionType))) { - error(right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type); + if ( + !(isTypeAny(rightType) || typeHasCallOrConstructSignatures(rightType) + || isTypeSubtypeOf(rightType, globalFunctionType)) + ) { + error( + right, + Diagnostics + .The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type, + ); } return booleanType; } function hasEmptyObjectIntersection(type: Type): boolean { - return someType(type, t => t === unknownEmptyObjectType || !!(t.flags & TypeFlags.Intersection) && some((t as IntersectionType).types, isEmptyAnonymousObjectType)); + return someType( + type, + t => t === unknownEmptyObjectType + || !!(t.flags & TypeFlags.Intersection) + && some((t as IntersectionType).types, isEmptyAnonymousObjectType), + ); } function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type { @@ -34452,14 +44996,23 @@ namespace ts { // that include {} (we know that the other types in such intersections are assignable to object // since we already checked for that). if (hasEmptyObjectIntersection(rightType)) { - error(right, Diagnostics.Type_0_may_represent_a_primitive_value_which_is_not_permitted_as_the_right_operand_of_the_in_operator, typeToString(rightType)); + error( + right, + Diagnostics + .Type_0_may_represent_a_primitive_value_which_is_not_permitted_as_the_right_operand_of_the_in_operator, + typeToString(rightType), + ); } } // The result is always of the Boolean primitive type. return booleanType; } - function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, rightIsThis?: boolean): Type { + function checkObjectLiteralAssignment( + node: ObjectLiteralExpression, + sourceType: Type, + rightIsThis?: boolean, + ): Type { const properties = node.properties; if (strictNullChecks && properties.length === 0) { return checkNonNullType(sourceType, node); @@ -34471,10 +45024,19 @@ namespace ts { } /** Note: If property cannot be a SpreadAssignment, then allProperties does not need to be provided */ - function checkObjectLiteralDestructuringPropertyAssignment(node: ObjectLiteralExpression, objectLiteralType: Type, propertyIndex: number, allProperties?: NodeArray, rightIsThis = false) { + function checkObjectLiteralDestructuringPropertyAssignment( + node: ObjectLiteralExpression, + objectLiteralType: Type, + propertyIndex: number, + allProperties?: NodeArray, + rightIsThis = false, + ) { const properties = node.properties; const property = properties[propertyIndex]; - if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) { + if ( + property.kind === SyntaxKind.PropertyAssignment + || property.kind === SyntaxKind.ShorthandPropertyAssignment + ) { const name = property.name; const exprType = getLiteralTypeFromPropertyName(name); if (isTypeUsableAsPropertyName(exprType)) { @@ -34482,12 +45044,26 @@ namespace ts { const prop = getPropertyOfType(objectLiteralType, text); if (prop) { markPropertyAsReferenced(prop, property, rightIsThis); - checkPropertyAccessibility(property, /*isSuper*/ false, /*writing*/ true, objectLiteralType, prop); + checkPropertyAccessibility( + property, + /*isSuper*/ false, + /*writing*/ true, + objectLiteralType, + prop, + ); } } - const elementType = getIndexedAccessType(objectLiteralType, exprType, AccessFlags.ExpressionPosition, name); + const elementType = getIndexedAccessType( + objectLiteralType, + exprType, + AccessFlags.ExpressionPosition, + name, + ); const type = getFlowTypeOfDestructuring(property, elementType); - return checkDestructuringAssignment(property.kind === SyntaxKind.ShorthandPropertyAssignment ? property : property.initializer, type); + return checkDestructuringAssignment( + property.kind === SyntaxKind.ShorthandPropertyAssignment ? property : property.initializer, + type, + ); } else if (property.kind === SyntaxKind.SpreadAssignment) { if (propertyIndex < properties.length - 1) { @@ -34506,7 +45082,10 @@ namespace ts { } } const type = getRestType(objectLiteralType, nonRestNames, objectLiteralType.symbol); - checkGrammarForDisallowedTrailingComma(allProperties, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + allProperties, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, + ); return checkDestructuringAssignment(property.expression, type); } } @@ -34515,7 +45094,11 @@ namespace ts { } } - function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, checkMode?: CheckMode): Type { + function checkArrayLiteralAssignment( + node: ArrayLiteralExpression, + sourceType: Type, + checkMode?: CheckMode, + ): Type { const elements = node.elements; if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Read); @@ -34523,19 +45106,33 @@ namespace ts { // This elementType will be used if the specific property corresponding to this index is not // present (aka the tuple element property). This call also checks that the parentType is in // fact an iterable or array (depending on target language). - const possiblyOutOfBoundsType = checkIteratedTypeOrElementType(IterationUse.Destructuring | IterationUse.PossiblyOutOfBounds, sourceType, undefinedType, node) || errorType; - let inBoundsType: Type | undefined = compilerOptions.noUncheckedIndexedAccess ? undefined : possiblyOutOfBoundsType; + const possiblyOutOfBoundsType = checkIteratedTypeOrElementType( + IterationUse.Destructuring | IterationUse.PossiblyOutOfBounds, + sourceType, + undefinedType, + node, + ) || errorType; + let inBoundsType: Type | undefined = compilerOptions.noUncheckedIndexedAccess ? undefined + : possiblyOutOfBoundsType; for (let i = 0; i < elements.length; i++) { let type = possiblyOutOfBoundsType; if (node.elements[i].kind === SyntaxKind.SpreadElement) { - type = inBoundsType = inBoundsType ?? (checkIteratedTypeOrElementType(IterationUse.Destructuring, sourceType, undefinedType, node) || errorType); + type = inBoundsType = inBoundsType + ?? (checkIteratedTypeOrElementType(IterationUse.Destructuring, sourceType, undefinedType, node) + || errorType); } checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, type, checkMode); } return sourceType; } - function checkArrayLiteralDestructuringElementAssignment(node: ArrayLiteralExpression, sourceType: Type, elementIndex: number, elementType: Type, checkMode?: CheckMode) { + function checkArrayLiteralDestructuringElementAssignment( + node: ArrayLiteralExpression, + sourceType: Type, + elementIndex: number, + elementType: Type, + checkMode?: CheckMode, + ) { const elements = node.elements; const element = elements[elementIndex]; if (element.kind !== SyntaxKind.OmittedExpression) { @@ -34544,9 +45141,16 @@ namespace ts { if (isArrayLikeType(sourceType)) { // We create a synthetic expression so that getIndexedAccessType doesn't get confused // when the element is a SyntaxKind.ElementAccessExpression. - const accessFlags = AccessFlags.ExpressionPosition | (hasDefaultValue(element) ? AccessFlags.NoTupleBoundsCheck : 0); - const elementType = getIndexedAccessTypeOrUndefined(sourceType, indexType, accessFlags, createSyntheticExpression(element, indexType)) || errorType; - const assignedType = hasDefaultValue(element) ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) : elementType; + const accessFlags = AccessFlags.ExpressionPosition + | (hasDefaultValue(element) ? AccessFlags.NoTupleBoundsCheck : 0); + const elementType = getIndexedAccessTypeOrUndefined( + sourceType, + indexType, + accessFlags, + createSyntheticExpression(element, indexType), + ) || errorType; + const assignedType = hasDefaultValue(element) + ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) : elementType; const type = getFlowTypeOfDestructuring(element, assignedType); return checkDestructuringAssignment(element, type, checkMode); } @@ -34557,14 +45161,23 @@ namespace ts { } else { const restExpression = (element as SpreadElement).expression; - if (restExpression.kind === SyntaxKind.BinaryExpression && (restExpression as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { - error((restExpression as BinaryExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer); + if ( + restExpression.kind === SyntaxKind.BinaryExpression + && (restExpression as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { + error( + (restExpression as BinaryExpression).operatorToken, + Diagnostics.A_rest_element_cannot_have_an_initializer, + ); } else { - checkGrammarForDisallowedTrailingComma(node.elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); - const type = everyType(sourceType, isTupleType) ? - mapType(sourceType, t => sliceTupleType(t as TupleTypeReference, elementIndex)) : - createArrayType(elementType); + checkGrammarForDisallowedTrailingComma( + node.elements, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, + ); + const type = everyType(sourceType, isTupleType) + ? mapType(sourceType, t => sliceTupleType(t as TupleTypeReference, elementIndex)) + : createArrayType(elementType); return checkDestructuringAssignment(restExpression, type, checkMode); } } @@ -34572,7 +45185,12 @@ namespace ts { return undefined; } - function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, checkMode?: CheckMode, rightIsThis?: boolean): Type { + function checkDestructuringAssignment( + exprOrAssignment: Expression | ShorthandPropertyAssignment, + sourceType: Type, + checkMode?: CheckMode, + rightIsThis?: boolean, + ): Type { let target: Expression; if (exprOrAssignment.kind === SyntaxKind.ShorthandPropertyAssignment) { const prop = exprOrAssignment as ShorthandPropertyAssignment; @@ -34580,12 +45198,17 @@ namespace ts { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. if ( - strictNullChecks && - !(getTypeFacts(checkExpression(prop.objectAssignmentInitializer)) & TypeFacts.IsUndefined) + strictNullChecks + && !(getTypeFacts(checkExpression(prop.objectAssignmentInitializer)) & TypeFacts.IsUndefined) ) { sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); } - checkBinaryLikeExpression(prop.name, prop.equalsToken!, prop.objectAssignmentInitializer, checkMode); + checkBinaryLikeExpression( + prop.name, + prop.equalsToken!, + prop.objectAssignmentInitializer, + checkMode, + ); } target = (exprOrAssignment as ShorthandPropertyAssignment).name; } @@ -34593,7 +45216,10 @@ namespace ts { target = exprOrAssignment; } - if (target.kind === SyntaxKind.BinaryExpression && (target as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + target.kind === SyntaxKind.BinaryExpression + && (target as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { checkBinaryExpression(target as BinaryExpression, checkMode); target = (target as BinaryExpression).left; // A default value is specified, so remove undefined from the final type. @@ -34612,12 +45238,12 @@ namespace ts { function checkReferenceAssignment(target: Expression, sourceType: Type, checkMode?: CheckMode): Type { const targetType = checkExpression(target, checkMode); - const error = target.parent.kind === SyntaxKind.SpreadAssignment ? - Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access : - Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access; - const optionalError = target.parent.kind === SyntaxKind.SpreadAssignment ? - Diagnostics.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access : - Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access; + const error = target.parent.kind === SyntaxKind.SpreadAssignment + ? Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access + : Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access; + const optionalError = target.parent.kind === SyntaxKind.SpreadAssignment + ? Diagnostics.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access + : Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access; if (checkReferenceExpression(target, error, optionalError)) { checkTypeAssignableToAndOptionallyElaborate(sourceType, targetType, target, target); } @@ -34662,15 +45288,15 @@ namespace ts { return true; case SyntaxKind.ConditionalExpression: - return isSideEffectFree((node as ConditionalExpression).whenTrue) && - isSideEffectFree((node as ConditionalExpression).whenFalse); + return isSideEffectFree((node as ConditionalExpression).whenTrue) + && isSideEffectFree((node as ConditionalExpression).whenFalse); case SyntaxKind.BinaryExpression: if (isAssignmentOperator((node as BinaryExpression).operatorToken.kind)) { return false; } - return isSideEffectFree((node as BinaryExpression).left) && - isSideEffectFree((node as BinaryExpression).right); + return isSideEffectFree((node as BinaryExpression).left) + && isSideEffectFree((node as BinaryExpression).right); case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: @@ -34711,7 +45337,14 @@ namespace ts { typeStack: (Type | undefined)[]; } - const trampoline = createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, foldState); + const trampoline = createBinaryExpressionTrampoline( + onEnter, + onLeft, + onOperator, + onRight, + onExit, + foldState, + ); return (node: BinaryExpression, checkMode: CheckMode | undefined) => { const result = trampoline(node, checkMode); @@ -34744,9 +45377,21 @@ namespace ts { checkGrammarNullishCoalesceWithLogicalExpression(node); const operator = node.operatorToken.kind; - if (operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { + if ( + operator === SyntaxKind.EqualsToken + && (node.left.kind === SyntaxKind.ObjectLiteralExpression + || node.left.kind === SyntaxKind.ArrayLiteralExpression) + ) { state.skip = true; - setLastResult(state, checkDestructuringAssignment(node.left, checkExpression(node.right, checkMode), checkMode, node.right.kind === SyntaxKind.ThisKeyword)); + setLastResult( + state, + checkDestructuringAssignment( + node.left, + checkExpression(node.right, checkMode), + checkMode, + node.right.kind === SyntaxKind.ThisKeyword, + ), + ); return state; } @@ -34766,16 +45411,25 @@ namespace ts { setLeftType(state, leftType); setLastResult(state, /*type*/ undefined); const operator = operatorToken.kind; - if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) { + if ( + operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken + || operator === SyntaxKind.QuestionQuestionToken + ) { if (operator === SyntaxKind.AmpersandAmpersandToken) { let parent = node.parent; while ( parent.kind === SyntaxKind.ParenthesizedExpression - || isBinaryExpression(parent) && (parent.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || parent.operatorToken.kind === SyntaxKind.BarBarToken) + || isBinaryExpression(parent) + && (parent.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken + || parent.operatorToken.kind === SyntaxKind.BarBarToken) ) { parent = parent.parent; } - checkTestingKnownTruthyCallableOrAwaitableType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined); + checkTestingKnownTruthyCallableOrAwaitableType( + node.left, + leftType, + isIfStatement(parent) ? parent.thenStatement : undefined, + ); } checkTruthinessOfType(leftType, node.left); } @@ -34800,7 +45454,14 @@ namespace ts { const rightType = getLastResult(state); Debug.assertIsDefined(rightType); - result = checkBinaryLikeExpressionWorker(node.left, node.operatorToken, node.right, leftType, rightType, node); + result = checkBinaryLikeExpressionWorker( + node.left, + node.operatorToken, + node.right, + leftType, + rightType, + node, + ); } state.skip = false; @@ -34846,24 +45507,59 @@ namespace ts { function checkGrammarNullishCoalesceWithLogicalExpression(node: BinaryExpression) { const { left, operatorToken, right } = node; if (operatorToken.kind === SyntaxKind.QuestionQuestionToken) { - if (isBinaryExpression(left) && (left.operatorToken.kind === SyntaxKind.BarBarToken || left.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) { - grammarErrorOnNode(left, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(left.operatorToken.kind), tokenToString(operatorToken.kind)); + if ( + isBinaryExpression(left) + && (left.operatorToken.kind === SyntaxKind.BarBarToken + || left.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) + ) { + grammarErrorOnNode( + left, + Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, + tokenToString(left.operatorToken.kind), + tokenToString(operatorToken.kind), + ); } - if (isBinaryExpression(right) && (right.operatorToken.kind === SyntaxKind.BarBarToken || right.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) { - grammarErrorOnNode(right, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(right.operatorToken.kind), tokenToString(operatorToken.kind)); + if ( + isBinaryExpression(right) + && (right.operatorToken.kind === SyntaxKind.BarBarToken + || right.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) + ) { + grammarErrorOnNode( + right, + Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, + tokenToString(right.operatorToken.kind), + tokenToString(operatorToken.kind), + ); } } } // Note that this and `checkBinaryExpression` above should behave mostly the same, except this elides some // expression-wide checks and does not use a work stack to fold nested binary expressions into the same callstack frame - function checkBinaryLikeExpression(left: Expression, operatorToken: Node, right: Expression, checkMode?: CheckMode, errorNode?: Node): Type { + function checkBinaryLikeExpression( + left: Expression, + operatorToken: Node, + right: Expression, + checkMode?: CheckMode, + errorNode?: Node, + ): Type { const operator = operatorToken.kind; - if (operator === SyntaxKind.EqualsToken && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression)) { - return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode, right.kind === SyntaxKind.ThisKeyword); + if ( + operator === SyntaxKind.EqualsToken + && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression) + ) { + return checkDestructuringAssignment( + left, + checkExpression(right, checkMode), + checkMode, + right.kind === SyntaxKind.ThisKeyword, + ); } let leftType: Type; - if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) { + if ( + operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken + || operator === SyntaxKind.QuestionQuestionToken + ) { leftType = checkTruthinessExpression(left, checkMode); } else { @@ -34917,23 +45613,42 @@ namespace ts { // if a user tries to apply a bitwise operator to 2 boolean operands // try and return them a helpful suggestion if ( - (leftType.flags & TypeFlags.BooleanLike) && - (rightType.flags & TypeFlags.BooleanLike) && - (suggestedOperator = getSuggestedBooleanOperator(operatorToken.kind)) !== undefined + (leftType.flags & TypeFlags.BooleanLike) + && (rightType.flags & TypeFlags.BooleanLike) + && (suggestedOperator = getSuggestedBooleanOperator(operatorToken.kind)) !== undefined ) { - error(errorNode || operatorToken, Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, tokenToString(operatorToken.kind), tokenToString(suggestedOperator)); + error( + errorNode || operatorToken, + Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, + tokenToString(operatorToken.kind), + tokenToString(suggestedOperator), + ); return numberType; } else { // otherwise just check each operand separately and report errors as normal - const leftOk = checkArithmeticOperandType(left, leftType, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true); - const rightOk = checkArithmeticOperandType(right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true); + const leftOk = checkArithmeticOperandType( + left, + leftType, + Diagnostics + .The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, + /*isAwaitValid*/ true, + ); + const rightOk = checkArithmeticOperandType( + right, + rightType, + Diagnostics + .The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, + /*isAwaitValid*/ true, + ); let resultType: Type; // If both are any or unknown, allow operation; assume it will resolve to number if ( - (isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) || + (isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) + && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) // Or, if neither could be bigint, implicit coercion results in a number result - !(maybeTypeOfKind(leftType, TypeFlags.BigIntLike) || maybeTypeOfKind(rightType, TypeFlags.BigIntLike)) + || !(maybeTypeOfKind(leftType, TypeFlags.BigIntLike) + || maybeTypeOfKind(rightType, TypeFlags.BigIntLike)) ) { resultType = numberType; } @@ -34947,7 +45662,11 @@ namespace ts { case SyntaxKind.AsteriskAsteriskToken: case SyntaxKind.AsteriskAsteriskEqualsToken: if (languageVersion < ScriptTarget.ES2016) { - error(errorNode, Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later); + error( + errorNode, + Diagnostics + .Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later, + ); } } resultType = bigintType; @@ -34968,22 +45687,34 @@ namespace ts { return silentNeverType; } - if (!isTypeAssignableToKind(leftType, TypeFlags.StringLike) && !isTypeAssignableToKind(rightType, TypeFlags.StringLike)) { + if ( + !isTypeAssignableToKind(leftType, TypeFlags.StringLike) + && !isTypeAssignableToKind(rightType, TypeFlags.StringLike) + ) { leftType = checkNonNullType(leftType, left); rightType = checkNonNullType(rightType, right); } let resultType: Type | undefined; - if (isTypeAssignableToKind(leftType, TypeFlags.NumberLike, /*strict*/ true) && isTypeAssignableToKind(rightType, TypeFlags.NumberLike, /*strict*/ true)) { + if ( + isTypeAssignableToKind(leftType, TypeFlags.NumberLike, /*strict*/ true) + && isTypeAssignableToKind(rightType, TypeFlags.NumberLike, /*strict*/ true) + ) { // Operands of an enum type are treated as having the primitive type Number. // If both operands are of the Number primitive type, the result is of the Number primitive type. resultType = numberType; } - else if (isTypeAssignableToKind(leftType, TypeFlags.BigIntLike, /*strict*/ true) && isTypeAssignableToKind(rightType, TypeFlags.BigIntLike, /*strict*/ true)) { + else if ( + isTypeAssignableToKind(leftType, TypeFlags.BigIntLike, /*strict*/ true) + && isTypeAssignableToKind(rightType, TypeFlags.BigIntLike, /*strict*/ true) + ) { // If both operands are of the BigInt primitive type, the result is of the BigInt primitive type. resultType = bigintType; } - else if (isTypeAssignableToKind(leftType, TypeFlags.StringLike, /*strict*/ true) || isTypeAssignableToKind(rightType, TypeFlags.StringLike, /*strict*/ true)) { + else if ( + isTypeAssignableToKind(leftType, TypeFlags.StringLike, /*strict*/ true) + || isTypeAssignableToKind(rightType, TypeFlags.StringLike, /*strict*/ true) + ) { // If one or both operands are of the String primitive type, the result is of the String primitive type. resultType = stringType; } @@ -35003,10 +45734,11 @@ namespace ts { // If both types have an awaited type of one of these, we'll assume the user // might be missing an await without doing an exhaustive check that inserting // await(s) will actually be a completely valid binary expression. - const closeEnoughKind = TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.AnyOrUnknown; + const closeEnoughKind = TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike + | TypeFlags.AnyOrUnknown; reportOperatorError((left, right) => - isTypeAssignableToKind(left, closeEnoughKind) && - isTypeAssignableToKind(right, closeEnoughKind) + isTypeAssignableToKind(left, closeEnoughKind) + && isTypeAssignableToKind(right, closeEnoughKind) ); return anyType; } @@ -35024,7 +45756,8 @@ namespace ts { rightType = getBaseTypeOfLiteralType(checkNonNullType(rightType, right)); reportOperatorErrorUnless((left, right) => isTypeComparableTo(left, right) || isTypeComparableTo(right, left) || ( - isTypeAssignableTo(left, numberOrBigIntType) && isTypeAssignableTo(right, numberOrBigIntType) + isTypeAssignableTo(left, numberOrBigIntType) + && isTypeAssignableTo(right, numberOrBigIntType) ) ); } @@ -35034,11 +45767,19 @@ namespace ts { case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: if (isLiteralExpressionOfObject(left) || isLiteralExpressionOfObject(right)) { - const eqType = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; - error(errorNode, Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value, eqType ? "false" : "true"); + const eqType = operator === SyntaxKind.EqualsEqualsToken + || operator === SyntaxKind.EqualsEqualsEqualsToken; + error( + errorNode, + Diagnostics + .This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value, + eqType ? "false" : "true", + ); } checkNaNEquality(errorNode, operator, left, right); - reportOperatorErrorUnless((left, right) => isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left)); + reportOperatorErrorUnless((left, right) => + isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left) + ); return booleanType; case SyntaxKind.InstanceOfKeyword: @@ -35047,9 +45788,14 @@ namespace ts { return checkInExpression(left, right, leftType, rightType); case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.AmpersandAmpersandEqualsToken: { - const resultType = getTypeFacts(leftType) & TypeFacts.Truthy ? - getUnionType([extractDefinitelyFalsyTypes(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType)), rightType]) : - leftType; + const resultType = getTypeFacts(leftType) & TypeFacts.Truthy + ? getUnionType([ + extractDefinitelyFalsyTypes( + strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType), + ), + rightType, + ]) + : leftType; if (operator === SyntaxKind.AmpersandAmpersandEqualsToken) { checkAssignmentOperator(rightType); } @@ -35057,9 +45803,12 @@ namespace ts { } case SyntaxKind.BarBarToken: case SyntaxKind.BarBarEqualsToken: { - const resultType = getTypeFacts(leftType) & TypeFacts.Falsy ? - getUnionType([getNonNullableType(removeDefinitelyFalsyTypes(leftType)), rightType], UnionReduction.Subtype) : - leftType; + const resultType = getTypeFacts(leftType) & TypeFacts.Falsy + ? getUnionType( + [getNonNullableType(removeDefinitelyFalsyTypes(leftType)), rightType], + UnionReduction.Subtype, + ) + : leftType; if (operator === SyntaxKind.BarBarEqualsToken) { checkAssignmentOperator(rightType); } @@ -35067,25 +45816,26 @@ namespace ts { } case SyntaxKind.QuestionQuestionToken: case SyntaxKind.QuestionQuestionEqualsToken: { - const resultType = getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ? - getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) : - leftType; + const resultType = getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull + ? getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) + : leftType; if (operator === SyntaxKind.QuestionQuestionEqualsToken) { checkAssignmentOperator(rightType); } return resultType; } case SyntaxKind.EqualsToken: - const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None; + const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) + : AssignmentDeclarationKind.None; checkAssignmentDeclaration(declKind, rightType); if (isAssignmentDeclaration(declKind)) { if ( - !(rightType.flags & TypeFlags.Object) || - declKind !== AssignmentDeclarationKind.ModuleExports && - declKind !== AssignmentDeclarationKind.Prototype && - !isEmptyObjectType(rightType) && - !isFunctionObjectType(rightType as ObjectType) && - !(getObjectFlags(rightType) & ObjectFlags.Class) + !(rightType.flags & TypeFlags.Object) + || declKind !== AssignmentDeclarationKind.ModuleExports + && declKind !== AssignmentDeclarationKind.Prototype + && !isEmptyObjectType(rightType) + && !isFunctionObjectType(rightType as ObjectType) + && !(getObjectFlags(rightType) & ObjectFlags.Class) ) { // don't check assignability of module.exports=, C.prototype=, or expando types because they will necessarily be incomplete checkAssignmentOperator(rightType); @@ -35102,10 +45852,14 @@ namespace ts { const sourceText = sf.text; const start = skipTrivia(sourceText, left.pos); const isInDiag2657 = sf.parseDiagnostics.some(diag => { - if (diag.code !== Diagnostics.JSX_expressions_must_have_one_parent_element.code) return false; + if (diag.code !== Diagnostics.JSX_expressions_must_have_one_parent_element.code) { + return false; + } return textSpanContainsPosition(diag, start); }); - if (!isInDiag2657) error(left, Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects); + if (!isInDiag2657) { + error(left, Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects); + } } return rightType; @@ -35114,7 +45868,8 @@ namespace ts { } function bothAreBigIntLike(left: Type, right: Type): boolean { - return isTypeAssignableToKind(left, TypeFlags.BigIntLike) && isTypeAssignableToKind(right, TypeFlags.BigIntLike); + return isTypeAssignableToKind(left, TypeFlags.BigIntLike) + && isTypeAssignableToKind(right, TypeFlags.BigIntLike); } function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, rightType: Type) { @@ -35123,10 +45878,27 @@ namespace ts { const propType = getTypeOfSymbol(prop); if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) { const name = prop.escapedName; - const symbol = resolveName(prop.valueDeclaration, name, SymbolFlags.Type, undefined, name, /*isUse*/ false); + const symbol = resolveName( + prop.valueDeclaration, + name, + SymbolFlags.Type, + undefined, + name, + /*isUse*/ false, + ); if (symbol?.declarations && symbol.declarations.some(isJSDocTypedefTag)) { - addDuplicateDeclarationErrorsForSymbols(symbol, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name), prop); - addDuplicateDeclarationErrorsForSymbols(prop, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name), symbol); + addDuplicateDeclarationErrorsForSymbols( + symbol, + Diagnostics.Duplicate_identifier_0, + unescapeLeadingUnderscores(name), + prop, + ); + addDuplicateDeclarationErrorsForSymbols( + prop, + Diagnostics.Duplicate_identifier_0, + unescapeLeadingUnderscores(name), + symbol, + ); } } } @@ -35139,12 +45911,17 @@ namespace ts { // Return true if there was no error, false if there was an error. function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean { - const offendingSymbolOperand = maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.ESSymbolLike) ? left : - maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.ESSymbolLike) ? right : - undefined; + const offendingSymbolOperand = + maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.ESSymbolLike) ? left + : maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.ESSymbolLike) ? right + : undefined; if (offendingSymbolOperand) { - error(offendingSymbolOperand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(operator)); + error( + offendingSymbolOperand, + Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, + tokenToString(operator), + ); return false; } @@ -35181,14 +45958,27 @@ namespace ts { // and the type of the non-compound operation to be assignable to the type of VarExpr. if ( - checkReferenceExpression(left, Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access, Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access) + checkReferenceExpression( + left, + Diagnostics + .The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access, + Diagnostics + .The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access, + ) && (!isIdentifier(left) || unescapeLeadingUnderscores(left.escapedText) !== "exports") ) { let headMessage: DiagnosticMessage | undefined; - if (exactOptionalPropertyTypes && isPropertyAccessExpression(left) && maybeTypeOfKind(valueType, TypeFlags.Undefined)) { - const target = getTypeOfPropertyOfType(getTypeOfExpression(left.expression), left.name.escapedText); + if ( + exactOptionalPropertyTypes && isPropertyAccessExpression(left) + && maybeTypeOfKind(valueType, TypeFlags.Undefined) + ) { + const target = getTypeOfPropertyOfType( + getTypeOfExpression(left.expression), + left.name.escapedText, + ); if (isExactOptionalPropertyMismatch(valueType, target)) { - headMessage = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target; + headMessage = Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target; } } // to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported @@ -35208,8 +45998,8 @@ namespace ts { case AssignmentDeclarationKind.ThisProperty: const symbol = getSymbolOfNode(left); const init = getAssignedExpandoInitializer(right); - return !!init && isObjectLiteralExpression(init) && - !!symbol?.exports?.size; + return !!init && isObjectLiteralExpression(init) + && !!symbol?.exports?.size; default: return false; } @@ -35255,7 +46045,12 @@ namespace ts { } } - function tryGiveBetterPrimaryError(errNode: Node, maybeMissingAwait: boolean, leftStr: string, rightStr: string) { + function tryGiveBetterPrimaryError( + errNode: Node, + maybeMissingAwait: boolean, + leftStr: string, + rightStr: string, + ) { switch (operatorToken.kind) { case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.EqualsEqualsToken: @@ -35264,7 +46059,8 @@ namespace ts { return errorAndMaybeSuggestAwait( errNode, maybeMissingAwait, - Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap, + Diagnostics + .This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap, leftStr, rightStr, ); @@ -35273,16 +46069,39 @@ namespace ts { } } - function checkNaNEquality(errorNode: Node | undefined, operator: SyntaxKind, left: Expression, right: Expression) { + function checkNaNEquality( + errorNode: Node | undefined, + operator: SyntaxKind, + left: Expression, + right: Expression, + ) { const isLeftNaN = isGlobalNaN(skipParentheses(left)); const isRightNaN = isGlobalNaN(skipParentheses(right)); if (isLeftNaN || isRightNaN) { - const err = error(errorNode, Diagnostics.This_condition_will_always_return_0, tokenToString(operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.EqualsEqualsToken ? SyntaxKind.FalseKeyword : SyntaxKind.TrueKeyword)); + const err = error( + errorNode, + Diagnostics.This_condition_will_always_return_0, + tokenToString( + operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.EqualsEqualsToken + ? SyntaxKind.FalseKeyword : SyntaxKind.TrueKeyword, + ), + ); if (isLeftNaN && isRightNaN) return; - const operatorString = operator === SyntaxKind.ExclamationEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken ? tokenToString(SyntaxKind.ExclamationToken) : ""; + const operatorString = operator === SyntaxKind.ExclamationEqualsEqualsToken + || operator === SyntaxKind.ExclamationEqualsToken + ? tokenToString(SyntaxKind.ExclamationToken) : ""; const location = isLeftNaN ? right : left; const expression = skipParentheses(location); - addRelatedInfo(err, createDiagnosticForNode(location, Diagnostics.Did_you_mean_0, `${operatorString}Number.isNaN(${isEntityNameExpression(expression) ? entityNameToString(expression) : "..."})`)); + addRelatedInfo( + err, + createDiagnosticForNode( + location, + Diagnostics.Did_you_mean_0, + `${operatorString}Number.isNaN(${ + isEntityNameExpression(expression) ? entityNameToString(expression) : "..." + })`, + ), + ); } } @@ -35295,7 +46114,11 @@ namespace ts { } } - function getBaseTypesIfUnrelated(leftType: Type, rightType: Type, isRelated: (left: Type, right: Type) => boolean): [Type, Type] { + function getBaseTypesIfUnrelated( + leftType: Type, + rightType: Type, + isRelated: (left: Type, right: Type) => boolean, + ): [Type, Type] { let effectiveLeft = leftType; let effectiveRight = rightType; const leftBase = getBaseTypeOfLiteralType(leftType); @@ -35340,11 +46163,22 @@ namespace ts { const iterationTypes = returnType && getIterationTypesOfGeneratorFunctionReturnType(returnType, isAsync); const signatureYieldType = iterationTypes && iterationTypes.yieldType || anyType; const signatureNextType = iterationTypes && iterationTypes.nextType || anyType; - const resolvedSignatureNextType = isAsync ? getAwaitedType(signatureNextType) || anyType : signatureNextType; + const resolvedSignatureNextType = isAsync ? getAwaitedType(signatureNextType) || anyType + : signatureNextType; const yieldExpressionType = node.expression ? checkExpression(node.expression) : undefinedWideningType; - const yieldedType = getYieldedTypeOfYieldExpression(node, yieldExpressionType, resolvedSignatureNextType, isAsync); + const yieldedType = getYieldedTypeOfYieldExpression( + node, + yieldExpressionType, + resolvedSignatureNextType, + isAsync, + ); if (returnType && yieldedType) { - checkTypeAssignableToAndOptionallyElaborate(yieldedType, signatureYieldType, node.expression || node, node.expression); + checkTypeAssignableToAndOptionallyElaborate( + yieldedType, + signatureYieldType, + node.expression || node, + node.expression, + ); } if (node.asteriskToken) { @@ -35363,7 +46197,11 @@ namespace ts { if (noImplicitAny && !expressionResultIsUnused(node)) { const contextualType = getContextualType(node, /*contextFlags*/ undefined); if (!contextualType || isTypeAny(contextualType)) { - error(node, Diagnostics.yield_expression_implicitly_results_in_an_any_type_because_its_containing_generator_lacks_a_return_type_annotation); + error( + node, + Diagnostics + .yield_expression_implicitly_results_in_an_any_type_because_its_containing_generator_lacks_a_return_type_annotation, + ); } } }); @@ -35391,8 +46229,8 @@ namespace ts { function isTemplateLiteralContext(node: Node): boolean { const parent = node.parent; - return isParenthesizedExpression(parent) && isTemplateLiteralContext(parent) || - isElementAccessExpression(parent) && parent.argumentExpression === node; + return isParenthesizedExpression(parent) && isTemplateLiteralContext(parent) + || isElementAccessExpression(parent) && parent.argumentExpression === node; } function checkTemplateExpression(node: TemplateExpression): Type { @@ -35401,17 +46239,26 @@ namespace ts { for (const span of node.templateSpans) { const type = checkExpression(span.expression); if (maybeTypeOfKindConsideringBaseConstraint(type, TypeFlags.ESSymbolLike)) { - error(span.expression, Diagnostics.Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_in_String); + error( + span.expression, + Diagnostics + .Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_in_String, + ); } texts.push(span.literal.text); types.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType); } - return isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType) ? getTemplateLiteralType(texts, types) : stringType; + return isConstContext(node) || isTemplateLiteralContext(node) + || someType( + getContextualType(node, /*contextFlags*/ undefined) || unknownType, + isTemplateLiteralContextualType, + ) ? getTemplateLiteralType(texts, types) : stringType; } function isTemplateLiteralContextualType(type: Type): boolean { - return !!(type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral) || - type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike)); + return !!(type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral) + || type.flags & TypeFlags.InstantiableNonPrimitive + && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike)); } function getContextNode(node: Expression): Node { @@ -35421,14 +46268,22 @@ namespace ts { return node; } - function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type { + function checkExpressionWithContextualType( + node: Expression, + contextualType: Type, + inferenceContext: InferenceContext | undefined, + checkMode: CheckMode, + ): Type { const context = getContextNode(node); const saveContextualType = context.contextualType; const saveInferenceContext = context.inferenceContext; try { context.contextualType = contextualType; context.inferenceContext = inferenceContext; - const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0)); + const type = checkExpression( + node, + checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0), + ); // In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type // parameters. This information is no longer needed after the call to checkExpression. if (inferenceContext && inferenceContext.intraExpressionInferenceSites) { @@ -35437,8 +46292,12 @@ namespace ts { // We strip literal freshness when an appropriate contextual type is present such that contextually typed // literals always preserve their literal types (otherwise they might widen during type inference). An alternative // here would be to not mark contextually typed literals as fresh in the first place. - const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ? - getRegularTypeOfLiteralType(type) : type; + const result = maybeTypeOfKind(type, TypeFlags.Literal) + && isLiteralOfContextualType( + type, + instantiateContextualType(contextualType, node, /*contextFlags*/ undefined), + ) + ? getRegularTypeOfLiteralType(type) : type; return result; } finally { @@ -35472,9 +46331,9 @@ namespace ts { function isTypeAssertion(node: Expression) { node = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); - return node.kind === SyntaxKind.TypeAssertionExpression || - node.kind === SyntaxKind.AsExpression || - isJSDocTypeAssertion(node); + return node.kind === SyntaxKind.TypeAssertionExpression + || node.kind === SyntaxKind.AsExpression + || isJSDocTypeAssertion(node); } function checkDeclarationInitializer( @@ -35483,13 +46342,19 @@ namespace ts { contextualType?: Type | undefined, ) { const initializer = getEffectiveInitializer(declaration)!; - const type = getQuickTypeOfExpression(initializer) || - (contextualType ? - checkExpressionWithContextualType(initializer, contextualType, /*inferenceContext*/ undefined, checkMode || CheckMode.Normal) + const type = getQuickTypeOfExpression(initializer) + || (contextualType + ? checkExpressionWithContextualType( + initializer, + contextualType, + /*inferenceContext*/ undefined, + checkMode || CheckMode.Normal, + ) : checkExpressionCached(initializer, checkMode)); - return isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern && - isTupleType(type) && !type.target.hasRestElement && getTypeReferenceArity(type) < declaration.name.elements.length ? - padTupleType(type, declaration.name) : type; + return isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern + && isTupleType(type) && !type.target.hasRestElement + && getTypeReferenceArity(type) < declaration.name.elements.length + ? padTupleType(type, declaration.name) : type; } function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) { @@ -35499,7 +46364,11 @@ namespace ts { for (let i = getTypeReferenceArity(type); i < patternElements.length; i++) { const e = patternElements[i]; if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && e.dotDotDotToken)) { - elementTypes.push(!isOmittedExpression(e) && hasDefaultValue(e) ? getTypeFromBindingElement(e, /*includePatternInType*/ false, /*reportErrors*/ false) : anyType); + elementTypes.push( + !isOmittedExpression(e) && hasDefaultValue(e) + ? getTypeFromBindingElement(e, /*includePatternInType*/ false, /*reportErrors*/ false) + : anyType, + ); elementFlags.push(ElementFlags.Optional); if (!isOmittedExpression(e) && !hasDefaultValue(e)) { reportImplicitAny(e, anyType); @@ -35510,7 +46379,8 @@ namespace ts { } function widenTypeInferredFromInitializer(declaration: HasExpressionInitializer, type: Type) { - const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const || isDeclarationReadonly(declaration) ? type : getWidenedLiteralType(type); + const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const || isDeclarationReadonly(declaration) + ? type : getWidenedLiteralType(type); if (isInJSFile(declaration)) { if (isEmptyLiteralType(widened)) { reportImplicitAny(declaration, anyType); @@ -35535,36 +46405,61 @@ namespace ts { // this a literal context for literals of that primitive type. For example, given a // type parameter 'T extends string', infer string literal types for T. const constraint = getBaseConstraintOfType(contextualType) || unknownType; - return maybeTypeOfKind(constraint, TypeFlags.String) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || - maybeTypeOfKind(constraint, TypeFlags.Number) && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || - maybeTypeOfKind(constraint, TypeFlags.BigInt) && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || - maybeTypeOfKind(constraint, TypeFlags.ESSymbol) && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) || - isLiteralOfContextualType(candidateType, constraint); + return maybeTypeOfKind(constraint, TypeFlags.String) + && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) + || maybeTypeOfKind(constraint, TypeFlags.Number) + && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) + || maybeTypeOfKind(constraint, TypeFlags.BigInt) + && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) + || maybeTypeOfKind(constraint, TypeFlags.ESSymbol) + && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) + || isLiteralOfContextualType(candidateType, constraint); } // If the contextual type is a literal of a particular primitive type, we consider this a // literal context for all literals of that primitive type. - return !!(contextualType.flags & (TypeFlags.StringLiteral | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || - contextualType.flags & TypeFlags.NumberLiteral && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || - contextualType.flags & TypeFlags.BigIntLiteral && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || - contextualType.flags & TypeFlags.BooleanLiteral && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) || - contextualType.flags & TypeFlags.UniqueESSymbol && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol)); + return !!(contextualType.flags + & (TypeFlags.StringLiteral | TypeFlags.Index | TypeFlags.TemplateLiteral + | TypeFlags.StringMapping) + && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) + || contextualType.flags & TypeFlags.NumberLiteral + && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) + || contextualType.flags & TypeFlags.BigIntLiteral + && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) + || contextualType.flags & TypeFlags.BooleanLiteral + && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) + || contextualType.flags & TypeFlags.UniqueESSymbol + && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol)); } return false; } function isConstContext(node: Expression): boolean { const parent = node.parent; - return isAssertionExpression(parent) && isConstTypeReference(parent.type) || - isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) || - (isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) && isConstContext(parent) || - (isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) && isConstContext(parent.parent); + return isAssertionExpression(parent) && isConstTypeReference(parent.type) + || isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) + || (isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) + && isConstContext(parent) + || (isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) + && isConstContext(parent.parent); } - function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type { + function checkExpressionForMutableLocation( + node: Expression, + checkMode: CheckMode | undefined, + contextualType?: Type, + forceTuple?: boolean, + ): Type { const type = checkExpression(node, checkMode, forceTuple); - return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) : - isTypeAssertion(node) ? type : - getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(arguments.length === 2 ? getContextualType(node, /*contextFlags*/ undefined) : contextualType, node, /*contextFlags*/ undefined)); + return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) + : isTypeAssertion(node) ? type + : getWidenedLiteralLikeTypeForContextualType( + type, + instantiateContextualType( + arguments.length === 2 ? getContextualType(node, /*contextFlags*/ undefined) : contextualType, + node, + /*contextFlags*/ undefined, + ), + ); } function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type { @@ -35593,15 +46488,26 @@ namespace ts { return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode); } - function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration | QualifiedName, type: Type, checkMode?: CheckMode) { + function instantiateTypeWithSingleGenericCallSignature( + node: Expression | MethodDeclaration | QualifiedName, + type: Type, + checkMode?: CheckMode, + ) { if (checkMode && checkMode & (CheckMode.Inferential | CheckMode.SkipGenericFunctions)) { const callSignature = getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ true); const constructSignature = getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ true); const signature = callSignature || constructSignature; if (signature && signature.typeParameters) { - const contextualType = getApparentTypeOfContextualType(node as Expression, ContextFlags.NoConstraints); + const contextualType = getApparentTypeOfContextualType( + node as Expression, + ContextFlags.NoConstraints, + ); if (contextualType) { - const contextualSignature = getSingleSignature(getNonNullableType(contextualType), callSignature ? SignatureKind.Call : SignatureKind.Construct, /*allowMembers*/ false); + const contextualSignature = getSingleSignature( + getNonNullableType(contextualType), + callSignature ? SignatureKind.Call : SignatureKind.Construct, + /*allowMembers*/ false, + ); if (contextualSignature && !contextualSignature.typeParameters) { if (checkMode & CheckMode.SkipGenericFunctions) { skippedGenericFunction(node, checkMode); @@ -35616,14 +46522,23 @@ namespace ts { // potentially add inferred type parameters to the outer function return type. const returnType = context.signature && getReturnTypeOfSignature(context.signature); const returnSignature = returnType && getSingleCallOrConstructSignature(returnType); - if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) { + if ( + returnSignature && !returnSignature.typeParameters + && !every(context.inferences, hasInferenceCandidates) + ) { // Instantiate the signature with its own type parameters as type arguments, possibly // renaming the type parameters to ensure they have unique names. const uniqueTypeParameters = getUniqueTypeParameters(context, signature.typeParameters); - const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, uniqueTypeParameters); + const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments( + signature, + uniqueTypeParameters, + ); // Infer from the parameters of the instantiated signature to the parameters of the // contextual signature starting with an empty set of inference candidates. - const inferences = map(context.inferences, info => createInferenceInfo(info.typeParameter)); + const inferences = map( + context.inferences, + info => createInferenceInfo(info.typeParameter), + ); applyToParameterTypes(instantiatedSignature, contextualSignature, (source, target) => { inferTypes(inferences, source, target, /*priority*/ 0, /*contravariant*/ true); }); @@ -35638,12 +46553,17 @@ namespace ts { // to the set of inferred type parameters for the outer function return type. if (!hasOverlappingInferences(context.inferences, inferences)) { mergeInferences(context.inferences, inferences); - context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters); + context.inferredTypeParameters = concatenate( + context.inferredTypeParameters, + uniqueTypeParameters, + ); return getOrCreateTypeFromSignature(instantiatedSignature); } } } - return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, context)); + return getOrCreateTypeFromSignature( + instantiateSignatureInContextOf(signature, contextualSignature, context), + ); } } } @@ -35685,14 +46605,22 @@ namespace ts { } } - function getUniqueTypeParameters(context: InferenceContext, typeParameters: readonly TypeParameter[]): readonly TypeParameter[] { + function getUniqueTypeParameters( + context: InferenceContext, + typeParameters: readonly TypeParameter[], + ): readonly TypeParameter[] { const result: TypeParameter[] = []; let oldTypeParameters: TypeParameter[] | undefined; let newTypeParameters: TypeParameter[] | undefined; for (const tp of typeParameters) { const name = tp.symbol.escapedName; - if (hasTypeParameterByName(context.inferredTypeParameters, name) || hasTypeParameterByName(result, name)) { - const newName = getUniqueTypeParameterName(concatenate(context.inferredTypeParameters, result), name); + if ( + hasTypeParameterByName(context.inferredTypeParameters, name) || hasTypeParameterByName(result, name) + ) { + const newName = getUniqueTypeParameterName( + concatenate(context.inferredTypeParameters, result), + name, + ); const symbol = createSymbol(SymbolFlags.TypeParameter, newName); const newTypeParameter = createTypeParameter(symbol); newTypeParameter.target = tp; @@ -35719,7 +46647,10 @@ namespace ts { function getUniqueTypeParameterName(typeParameters: readonly TypeParameter[], baseName: __String) { let len = (baseName as string).length; - while (len > 1 && (baseName as string).charCodeAt(len - 1) >= CharacterCodes._0 && (baseName as string).charCodeAt(len - 1) <= CharacterCodes._9) len--; + while ( + len > 1 && (baseName as string).charCodeAt(len - 1) >= CharacterCodes._0 + && (baseName as string).charCodeAt(len - 1) <= CharacterCodes._9 + ) len--; const s = (baseName as string).slice(0, len); for (let index = 1; true; index++) { const augmentedName = (s + index as __String); @@ -35782,9 +46713,12 @@ namespace ts { expr = skipParentheses(node); // Optimize for the common case of a call to a function with a single non-generic call // signature where we can just fetch the return type without checking the arguments. - if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) { - const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) : - getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression)); + if ( + isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword + && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr) + ) { + const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) + : getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression)); if (type) { return type; } @@ -35793,8 +46727,8 @@ namespace ts { return getTypeFromTypeNode((expr as TypeAssertion).type); } else if ( - node.kind === SyntaxKind.NumericLiteral || node.kind === SyntaxKind.StringLiteral || - node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword + node.kind === SyntaxKind.NumericLiteral || node.kind === SyntaxKind.StringLiteral + || node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword ) { return checkExpression(node); } @@ -35828,7 +46762,12 @@ namespace ts { } function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type { - tracing?.push(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); + tracing?.push(tracing.Phase.Check, "checkExpression", { + kind: node.kind, + pos: node.pos, + end: node.end, + path: (node as TracingNode).tracingPath, + }); const saveCurrentNode = currentNode; currentNode = node; instantiationCount = 0; @@ -35847,21 +46786,31 @@ namespace ts { // - 'left' in property access // - 'object' in indexed access // - target in rhs of import statement - const ok = (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent as PropertyAccessExpression).expression === node) || - (node.parent.kind === SyntaxKind.ElementAccessExpression && (node.parent as ElementAccessExpression).expression === node) || - ((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(node as Identifier) || - (node.parent.kind === SyntaxKind.TypeQuery && (node.parent as TypeQueryNode).exprName === node)) || - (node.parent.kind === SyntaxKind.ExportSpecifier); // We allow reexporting const enums + const ok = (node.parent.kind === SyntaxKind.PropertyAccessExpression + && (node.parent as PropertyAccessExpression).expression === node) + || (node.parent.kind === SyntaxKind.ElementAccessExpression + && (node.parent as ElementAccessExpression).expression === node) + || ((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) + && isInRightSideOfImportOrExportAssignment(node as Identifier) + || (node.parent.kind === SyntaxKind.TypeQuery && (node.parent as TypeQueryNode).exprName === node)) + || (node.parent.kind === SyntaxKind.ExportSpecifier); // We allow reexporting const enums if (!ok) { - error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query); + error( + node, + Diagnostics + .const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query, + ); } if (compilerOptions.isolatedModules) { Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum)); const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration; if (constEnumDeclaration.flags & NodeFlags.Ambient) { - error(node, Diagnostics.Cannot_access_ambient_const_enums_when_the_isolatedModules_flag_is_provided); + error( + node, + Diagnostics.Cannot_access_ambient_const_enums_when_the_isolatedModules_flag_is_provided, + ); } } } @@ -35874,7 +46823,11 @@ namespace ts { return checkExpression(node.expression, checkMode); } - function checkExpressionWorker(node: Expression | QualifiedName, checkMode: CheckMode | undefined, forceTuple?: boolean): Type { + function checkExpressionWorker( + node: Expression | QualifiedName, + checkMode: CheckMode | undefined, + forceTuple?: boolean, + ): Type { const kind = node.kind; if (cancellationToken) { // Only bother checking on a few construct kinds. We don't want to be excessively @@ -35942,7 +46895,10 @@ namespace ts { return checkClassExpression(node as ClassExpression); case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - return checkFunctionExpressionOrObjectLiteralMethod(node as FunctionExpression | ArrowFunction, checkMode); + return checkFunctionExpressionOrObjectLiteralMethod( + node as FunctionExpression | ArrowFunction, + checkMode, + ); case SyntaxKind.TypeOfExpression: return checkTypeOfExpression(node as TypeOfExpression); case SyntaxKind.TypeAssertionExpression: @@ -36014,28 +46970,62 @@ namespace ts { const constraintType = getConstraintOfTypeParameter(typeParameter); const defaultType = getDefaultFromTypeParameter(typeParameter); if (constraintType && defaultType) { - checkTypeAssignableTo(defaultType, getTypeWithThisArgument(instantiateType(constraintType, makeUnaryTypeMapper(typeParameter, defaultType)), defaultType), node.default, Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + checkTypeAssignableTo( + defaultType, + getTypeWithThisArgument( + instantiateType(constraintType, makeUnaryTypeMapper(typeParameter, defaultType)), + defaultType, + ), + node.default, + Diagnostics.Type_0_does_not_satisfy_the_constraint_1, + ); } checkNodeDeferred(node); addLazyDiagnostic(() => checkTypeNameIsReserved(node.name, Diagnostics.Type_parameter_name_cannot_be_0)); } function checkTypeParameterDeferred(node: TypeParameterDeclaration) { - if (isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent)) { + if ( + isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent) + ) { const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node)); const modifiers = getVarianceModifiers(typeParameter); if (modifiers) { const symbol = getSymbolOfNode(node.parent); - if (isTypeAliasDeclaration(node.parent) && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & (ObjectFlags.Anonymous | ObjectFlags.Mapped))) { - error(node, Diagnostics.Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types); + if ( + isTypeAliasDeclaration(node.parent) + && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) + & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) + ) { + error( + node, + Diagnostics + .Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types, + ); } else if (modifiers === ModifierFlags.In || modifiers === ModifierFlags.Out) { - tracing?.push(tracing.Phase.CheckTypes, "checkTypeParameterDeferred", { parent: getTypeId(getDeclaredTypeOfSymbol(symbol)), id: getTypeId(typeParameter) }); - const source = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSubTypeForCheck : markerSuperTypeForCheck); - const target = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSuperTypeForCheck : markerSubTypeForCheck); + tracing?.push(tracing.Phase.CheckTypes, "checkTypeParameterDeferred", { + parent: getTypeId(getDeclaredTypeOfSymbol(symbol)), + id: getTypeId(typeParameter), + }); + const source = createMarkerType( + symbol, + typeParameter, + modifiers === ModifierFlags.Out ? markerSubTypeForCheck : markerSuperTypeForCheck, + ); + const target = createMarkerType( + symbol, + typeParameter, + modifiers === ModifierFlags.Out ? markerSuperTypeForCheck : markerSubTypeForCheck, + ); const saveVarianceTypeParameter = typeParameter; varianceTypeParameter = typeParameter; - checkTypeAssignableTo(source, target, node, Diagnostics.Type_0_is_not_assignable_to_type_1_as_implied_by_variance_annotation); + checkTypeAssignableTo( + source, + target, + node, + Diagnostics.Type_0_is_not_assignable_to_type_1_as_implied_by_variance_annotation, + ); varianceTypeParameter = saveVarianceTypeParameter; tracing?.pop(); } @@ -36056,18 +47046,30 @@ namespace ts { if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); } - if (func.kind === SyntaxKind.Constructor && isIdentifier(node.name) && node.name.escapedText === "constructor") { + if ( + func.kind === SyntaxKind.Constructor && isIdentifier(node.name) + && node.name.escapedText === "constructor" + ) { error(node.name, Diagnostics.constructor_cannot_be_used_as_a_parameter_property_name); } } - if ((node.questionToken || isJSDocOptionalParameter(node)) && isBindingPattern(node.name) && (func as FunctionLikeDeclaration).body) { + if ( + (node.questionToken || isJSDocOptionalParameter(node)) && isBindingPattern(node.name) + && (func as FunctionLikeDeclaration).body + ) { error(node, Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature); } - if (node.name && isIdentifier(node.name) && (node.name.escapedText === "this" || node.name.escapedText === "new")) { + if ( + node.name && isIdentifier(node.name) + && (node.name.escapedText === "this" || node.name.escapedText === "new") + ) { if (func.parameters.indexOf(node) !== 0) { error(node, Diagnostics.A_0_parameter_must_be_the_first_parameter, node.name.escapedText as string); } - if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature || func.kind === SyntaxKind.ConstructorType) { + if ( + func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature + || func.kind === SyntaxKind.ConstructorType + ) { error(node, Diagnostics.A_constructor_cannot_have_a_this_parameter); } if (func.kind === SyntaxKind.ArrowFunction) { @@ -36080,7 +47082,10 @@ namespace ts { // Only check rest parameter type if it's not a binding pattern. Since binding patterns are // not allowed in a rest parameter, we already have an error from checkGrammarParameterList. - if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getReducedType(getTypeOfSymbol(node.symbol)), anyReadonlyArrayType)) { + if ( + node.dotDotDotToken && !isBindingPattern(node.name) + && !isTypeAssignableTo(getReducedType(getTypeOfSymbol(node.symbol)), anyReadonlyArrayType) + ) { error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type); } } @@ -36089,7 +47094,10 @@ namespace ts { const parent = getTypePredicateParent(node); if (!parent) { // The parent must not be valid. - error(node, Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); + error( + node, + Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods, + ); return; } @@ -36107,13 +47115,26 @@ namespace ts { } else { if (typePredicate.parameterIndex >= 0) { - if (signatureHasRestParameter(signature) && typePredicate.parameterIndex === signature.parameters.length - 1) { + if ( + signatureHasRestParameter(signature) + && typePredicate.parameterIndex === signature.parameters.length - 1 + ) { error(parameterName, Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); } else { if (typePredicate.type) { - const leadingError = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.A_type_predicate_s_type_must_be_assignable_to_its_parameter_s_type); - checkTypeAssignableTo(typePredicate.type, getTypeOfSymbol(signature.parameters[typePredicate.parameterIndex]), node.type, /*headMessage*/ undefined, leadingError); + const leadingError = () => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.A_type_predicate_s_type_must_be_assignable_to_its_parameter_s_type, + ); + checkTypeAssignableTo( + typePredicate.type, + getTypeOfSymbol(signature.parameters[typePredicate.parameterIndex]), + node.type, + /*headMessage*/ undefined, + leadingError, + ); } } } @@ -36121,8 +47142,12 @@ namespace ts { let hasReportedError = false; for (const { name } of parent.parameters) { if ( - isBindingPattern(name) && - checkIfTypePredicateVariableIsDeclaredInBindingPattern(name, parameterName, typePredicate.parameterName) + isBindingPattern(name) + && checkIfTypePredicateVariableIsDeclaredInBindingPattern( + name, + parameterName, + typePredicate.parameterName, + ) ) { hasReportedError = true; break; @@ -36163,10 +47188,16 @@ namespace ts { const name = element.name; if (name.kind === SyntaxKind.Identifier && name.escapedText === predicateVariableName) { - error(predicateVariableNode, Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, predicateVariableName); + error( + predicateVariableNode, + Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, + predicateVariableName, + ); return true; } - else if (name.kind === SyntaxKind.ArrayBindingPattern || name.kind === SyntaxKind.ObjectBindingPattern) { + else if ( + name.kind === SyntaxKind.ArrayBindingPattern || name.kind === SyntaxKind.ObjectBindingPattern + ) { if ( checkIfTypePredicateVariableIsDeclaredInBindingPattern( name, @@ -36187,9 +47218,10 @@ namespace ts { } // TODO (yuisu): Remove this check in else-if when SyntaxKind.Construct is moved and ambient context is handled else if ( - node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.ConstructorType || - node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.Constructor || - node.kind === SyntaxKind.ConstructSignature + node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration + || node.kind === SyntaxKind.ConstructorType + || node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.Constructor + || node.kind === SyntaxKind.ConstructSignature ) { checkGrammarFunctionLikeDeclaration(node as FunctionLikeDeclaration); } @@ -36197,18 +47229,27 @@ namespace ts { const functionFlags = getFunctionFlags(node as FunctionLikeDeclaration); if (!(functionFlags & FunctionFlags.Invalid)) { // Async generators prior to ESNext require the __await and __asyncGenerator helpers - if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator && languageVersion < ScriptTarget.ESNext) { + if ( + (functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator + && languageVersion < ScriptTarget.ESNext + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncGeneratorIncludes); } // Async functions prior to ES2017 require the __awaiter helper - if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async && languageVersion < ScriptTarget.ES2017) { + if ( + (functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async + && languageVersion < ScriptTarget.ES2017 + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Awaiter); } // Generator functions, Async functions, and Async Generator functions prior to // ES2015 require the __generator helper - if ((functionFlags & FunctionFlags.AsyncGenerator) !== FunctionFlags.Normal && languageVersion < ScriptTarget.ES2015) { + if ( + (functionFlags & FunctionFlags.AsyncGenerator) !== FunctionFlags.Normal + && languageVersion < ScriptTarget.ES2015 + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Generator); } } @@ -36231,17 +47272,27 @@ namespace ts { if (noImplicitAny && !returnTypeNode) { switch (node.kind) { case SyntaxKind.ConstructSignature: - error(node, Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + error( + node, + Diagnostics + .Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type, + ); break; case SyntaxKind.CallSignature: - error(node, Diagnostics.Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + error( + node, + Diagnostics + .Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type, + ); break; } } if (returnTypeNode) { const functionFlags = getFunctionFlags(node as FunctionDeclaration); - if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Generator)) === FunctionFlags.Generator) { + if ( + (functionFlags & (FunctionFlags.Invalid | FunctionFlags.Generator)) === FunctionFlags.Generator + ) { const returnType = getTypeFromTypeNode(returnTypeNode); if (returnType === voidType) { error(returnTypeNode, Diagnostics.A_generator_cannot_have_a_void_type_annotation); @@ -36253,10 +47304,27 @@ namespace ts { // interface BadGenerator extends Iterable, Iterator { } // function* g(): BadGenerator { } // Iterable and Iterator have different types! // - const generatorYieldType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, returnType, (functionFlags & FunctionFlags.Async) !== 0) || anyType; - const generatorReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, (functionFlags & FunctionFlags.Async) !== 0) || generatorYieldType; - const generatorNextType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, (functionFlags & FunctionFlags.Async) !== 0) || unknownType; - const generatorInstantiation = createGeneratorReturnType(generatorYieldType, generatorReturnType, generatorNextType, !!(functionFlags & FunctionFlags.Async)); + const generatorYieldType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Yield, + returnType, + (functionFlags & FunctionFlags.Async) !== 0, + ) || anyType; + const generatorReturnType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + returnType, + (functionFlags & FunctionFlags.Async) !== 0, + ) || generatorYieldType; + const generatorNextType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Next, + returnType, + (functionFlags & FunctionFlags.Async) !== 0, + ) || unknownType; + const generatorInstantiation = createGeneratorReturnType( + generatorYieldType, + generatorReturnType, + generatorNextType, + !!(functionFlags & FunctionFlags.Async), + ); checkTypeAssignableTo(generatorInstantiation, returnType, returnTypeNode); } } @@ -36279,7 +47347,12 @@ namespace ts { if (member.kind === SyntaxKind.Constructor) { for (const param of (member as ConstructorDeclaration).parameters) { if (isParameterPropertyDeclaration(param, member) && !isBindingPattern(param.name)) { - addName(instanceNames, param.name, param.name.escapedText, DeclarationMeaning.GetOrSetAccessor); + addName( + instanceNames, + param.name, + param.name.escapedText, + DeclarationMeaning.GetOrSetAccessor, + ); } } } @@ -36291,9 +47364,9 @@ namespace ts { } const isPrivate = isPrivateIdentifier(name); const privateStaticFlags = isPrivate && isStaticMember ? DeclarationMeaning.PrivateStatic : 0; - const names = isPrivate ? privateIdentifiers : - isStaticMember ? staticNames : - instanceNames; + const names = isPrivate ? privateIdentifiers + : isStaticMember ? staticNames + : instanceNames; const memberName = name && getPropertyNameForPropertyNameNode(name); if (memberName) { @@ -36307,7 +47380,12 @@ namespace ts { break; case SyntaxKind.PropertyDeclaration: - addName(names, name, memberName, DeclarationMeaning.GetOrSetAccessor | privateStaticFlags); + addName( + names, + name, + memberName, + DeclarationMeaning.GetOrSetAccessor | privateStaticFlags, + ); break; case SyntaxKind.MethodDeclaration: @@ -36318,12 +47396,22 @@ namespace ts { } } - function addName(names: UnderscoreEscapedMap, location: Node, name: __String, meaning: DeclarationMeaning) { + function addName( + names: UnderscoreEscapedMap, + location: Node, + name: __String, + meaning: DeclarationMeaning, + ) { const prev = names.get(name); if (prev) { // For private identifiers, do not allow mixing of static and instance members with the same name if ((prev & DeclarationMeaning.PrivateStatic) !== (meaning & DeclarationMeaning.PrivateStatic)) { - error(location, Diagnostics.Duplicate_identifier_0_Static_and_instance_elements_cannot_share_the_same_private_name, getTextOfNode(location)); + error( + location, + Diagnostics + .Duplicate_identifier_0_Static_and_instance_elements_cannot_share_the_same_private_name, + getTextOfNode(location), + ); } else { const prevIsMethod = !!(prev & DeclarationMeaning.Method); @@ -36371,7 +47459,8 @@ namespace ts { case "caller": case "arguments": case "prototype": - const message = Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1; + const message = Diagnostics + .Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1; const className = getNameOfSymbolAsWritten(getSymbolOfNode(node)); error(memberNameNode, message, memberName, className); break; @@ -36399,7 +47488,11 @@ namespace ts { } if (names.get(memberName)) { - error(getNameOfDeclaration(member.symbol.valueDeclaration), Diagnostics.Duplicate_identifier_0, memberName); + error( + getNameOfDeclaration(member.symbol.valueDeclaration), + Diagnostics.Duplicate_identifier_0, + memberName, + ); error(member.name, Diagnostics.Duplicate_identifier_0, memberName); } else { @@ -36414,7 +47507,9 @@ namespace ts { const nodeSymbol = getSymbolOfNode(node as InterfaceDeclaration); // in case of merging interface declaration it is possible that we'll enter this check procedure several times for every declaration // to prevent this run check only for the first declaration of a given kind - if (nodeSymbol.declarations && nodeSymbol.declarations.length > 0 && nodeSymbol.declarations[0] !== node) { + if ( + nodeSymbol.declarations && nodeSymbol.declarations.length > 0 && nodeSymbol.declarations[0] !== node + ) { return; } } @@ -36441,7 +47536,11 @@ namespace ts { indexSignatureMap.forEach(entry => { if (entry.declarations.length > 1) { for (const declaration of entry.declarations) { - error(declaration, Diagnostics.Duplicate_index_signature_for_type_0, typeToString(entry.type)); + error( + declaration, + Diagnostics.Duplicate_index_signature_for_type_0, + typeToString(entry.type), + ); } } }); @@ -36450,14 +47549,23 @@ namespace ts { function checkPropertyDeclaration(node: PropertyDeclaration | PropertySignature) { // Grammar checking - if (!checkGrammarDecoratorsAndModifiers(node) && !checkGrammarProperty(node)) checkGrammarComputedPropertyName(node.name); + if (!checkGrammarDecoratorsAndModifiers(node) && !checkGrammarProperty(node)) { + checkGrammarComputedPropertyName(node.name); + } checkVariableLikeDeclaration(node); setNodeLinksForPrivateIdentifierScope(node); // property signatures already report "initializer not allowed in ambient context" elsewhere - if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.PropertyDeclaration && node.initializer) { - error(node, Diagnostics.Property_0_cannot_have_an_initializer_because_it_is_marked_abstract, declarationNameToString(node.name)); + if ( + hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.PropertyDeclaration + && node.initializer + ) { + error( + node, + Diagnostics.Property_0_cannot_have_an_initializer_because_it_is_marked_abstract, + declarationNameToString(node.name), + ); } } @@ -36472,7 +47580,10 @@ namespace ts { // Grammar checking if (!checkGrammarMethod(node)) checkGrammarComputedPropertyName(node.name); - if (isMethodDeclaration(node) && node.asteriskToken && isIdentifier(node.name) && idText(node.name) === "constructor") { + if ( + isMethodDeclaration(node) && node.asteriskToken && isIdentifier(node.name) + && idText(node.name) === "constructor" + ) { error(node.name, Diagnostics.Class_constructor_may_not_be_a_generator); } @@ -36480,8 +47591,15 @@ namespace ts { checkFunctionOrMethodDeclaration(node); // method signatures already report "implementation not allowed in ambient context" elsewhere - if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body) { - error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name)); + if ( + hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration + && node.body + ) { + error( + node, + Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, + declarationNameToString(node.name), + ); } // Private named methods are only allowed in class declarations @@ -36492,9 +47610,15 @@ namespace ts { setNodeLinksForPrivateIdentifierScope(node); } - function setNodeLinksForPrivateIdentifierScope(node: PropertyDeclaration | PropertySignature | MethodDeclaration | MethodSignature | AccessorDeclaration) { + function setNodeLinksForPrivateIdentifierScope( + node: PropertyDeclaration | PropertySignature | MethodDeclaration | MethodSignature | AccessorDeclaration, + ) { if (isPrivateIdentifier(node.name) && languageVersion < ScriptTarget.ESNext) { - for (let lexicalScope = getEnclosingBlockScopeContainer(node); !!lexicalScope; lexicalScope = getEnclosingBlockScopeContainer(lexicalScope)) { + for ( + let lexicalScope = getEnclosingBlockScopeContainer(node); + !!lexicalScope; + lexicalScope = getEnclosingBlockScopeContainer(lexicalScope) + ) { getNodeLinks(lexicalScope).flags |= NodeCheckFlags.ContainsClassWithPrivateIdentifiers; } @@ -36505,7 +47629,8 @@ namespace ts { const enclosingIterationStatement = getEnclosingIterationStatement(node.parent); if (enclosingIterationStatement) { getNodeLinks(node.name).flags |= NodeCheckFlags.BlockScopedBindingInLoop; - getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; + getNodeLinks(enclosingIterationStatement).flags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding; } } } @@ -36546,9 +47671,9 @@ namespace ts { if (isPrivateIdentifierClassElementDeclaration(n)) { return true; } - return n.kind === SyntaxKind.PropertyDeclaration && - !isStatic(n) && - !!(n as PropertyDeclaration).initializer; + return n.kind === SyntaxKind.PropertyDeclaration + && !isStatic(n) + && !!(n as PropertyDeclaration).initializer; } function checkConstructorDeclarationDiagnostics() { @@ -36562,7 +47687,10 @@ namespace ts { const superCall = findFirstSuperCall(node.body!); if (superCall) { if (classExtendsNull) { - error(superCall, Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null); + error( + superCall, + Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null, + ); } // A super call must be root-level in a constructor if both of the following are true: @@ -36570,22 +47698,36 @@ namespace ts { // - The constructor declares parameter properties // or the containing class declares instance member variables with initializers. - const superCallShouldBeRootLevel = (getEmitScriptTarget(compilerOptions) !== ScriptTarget.ESNext || !useDefineForClassFields) && - (some((node.parent as ClassDeclaration).members, isInstancePropertyWithInitializerOrPrivateIdentifierProperty) || - some(node.parameters, p => hasSyntacticModifier(p, ModifierFlags.ParameterPropertyModifier))); + const superCallShouldBeRootLevel = + (getEmitScriptTarget(compilerOptions) !== ScriptTarget.ESNext || !useDefineForClassFields) + && (some( + (node.parent as ClassDeclaration).members, + isInstancePropertyWithInitializerOrPrivateIdentifierProperty, + ) + || some( + node.parameters, + p => hasSyntacticModifier(p, ModifierFlags.ParameterPropertyModifier), + )); if (superCallShouldBeRootLevel) { // Until we have better flow analysis, it is an error to place the super call within any kind of block or conditional // See GH #8277 if (!superCallIsRootLevelInConstructor(superCall, node.body!)) { - error(superCall, Diagnostics.A_super_call_must_be_a_root_level_statement_within_a_constructor_of_a_derived_class_that_contains_initialized_properties_parameter_properties_or_private_identifiers); + error( + superCall, + Diagnostics + .A_super_call_must_be_a_root_level_statement_within_a_constructor_of_a_derived_class_that_contains_initialized_properties_parameter_properties_or_private_identifiers, + ); } // Skip past any prologue directives to check statements for referring to 'super' or 'this' before a super call else { let superCallStatement: ExpressionStatement | undefined; for (const statement of node.body!.statements) { - if (isExpressionStatement(statement) && isSuperCall(skipOuterExpressions(statement.expression))) { + if ( + isExpressionStatement(statement) + && isSuperCall(skipOuterExpressions(statement.expression)) + ) { superCallStatement = statement; break; } @@ -36597,7 +47739,11 @@ namespace ts { // Until we have better flow analysis, it is an error to place the super call within any kind of block or conditional // See GH #8277 if (superCallStatement === undefined) { - error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_to_refer_to_super_or_this_when_a_derived_class_contains_initialized_properties_parameter_properties_or_private_identifiers); + error( + node, + Diagnostics + .A_super_call_must_be_the_first_statement_in_the_constructor_to_refer_to_super_or_this_when_a_derived_class_contains_initialized_properties_parameter_properties_or_private_identifiers, + ); } } } @@ -36636,12 +47782,17 @@ namespace ts { function checkAccessorDeclarationDiagnostics() { // Grammar checking accessors - if (!checkGrammarFunctionLikeDeclaration(node) && !checkGrammarAccessor(node)) checkGrammarComputedPropertyName(node.name); + if (!checkGrammarFunctionLikeDeclaration(node) && !checkGrammarAccessor(node)) { + checkGrammarComputedPropertyName(node.name); + } checkDecorators(node); checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { - if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { + if ( + !(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) + && (node.flags & NodeFlags.HasImplicitReturn) + ) { if (!(node.flags & NodeFlags.HasExplicitReturn)) { error(node.name, Diagnostics.A_get_accessor_must_return_a_value); } @@ -36669,8 +47820,9 @@ namespace ts { error(setter.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract); } if ( - ((getterFlags & ModifierFlags.Protected) && !(setterFlags & (ModifierFlags.Protected | ModifierFlags.Private))) || - ((getterFlags & ModifierFlags.Private) && !(setterFlags & ModifierFlags.Private)) + ((getterFlags & ModifierFlags.Protected) + && !(setterFlags & (ModifierFlags.Protected | ModifierFlags.Private))) + || ((getterFlags & ModifierFlags.Private) && !(setterFlags & ModifierFlags.Private)) ) { error(getter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter); error(setter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter); @@ -36679,7 +47831,13 @@ namespace ts { const getterType = getAnnotatedAccessorType(getter); const setterType = getAnnotatedAccessorType(setter); if (getterType && setterType) { - checkTypeAssignableTo(getterType, setterType, getter, Diagnostics.The_return_type_of_a_get_accessor_must_be_assignable_to_its_set_accessor_type); + checkTypeAssignableTo( + getterType, + setterType, + getter, + Diagnostics + .The_return_type_of_a_get_accessor_must_be_assignable_to_its_set_accessor_type, + ); } } } @@ -36694,18 +47852,33 @@ namespace ts { checkDecorators(node); } - function getEffectiveTypeArgumentAtIndex(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[], index: number): Type { + function getEffectiveTypeArgumentAtIndex( + node: TypeReferenceNode | ExpressionWithTypeArguments, + typeParameters: readonly TypeParameter[], + index: number, + ): Type { if (node.typeArguments && index < node.typeArguments.length) { return getTypeFromTypeNode(node.typeArguments[index]); } return getEffectiveTypeArguments(node, typeParameters)[index]; } - function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[]): Type[] { - return fillMissingTypeArguments(map(node.typeArguments!, getTypeFromTypeNode), typeParameters, getMinTypeArgumentCount(typeParameters), isInJSFile(node)); + function getEffectiveTypeArguments( + node: TypeReferenceNode | ExpressionWithTypeArguments, + typeParameters: readonly TypeParameter[], + ): Type[] { + return fillMissingTypeArguments( + map(node.typeArguments!, getTypeFromTypeNode), + typeParameters, + getMinTypeArgumentCount(typeParameters), + isInJSFile(node), + ); } - function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[]): boolean { + function checkTypeArgumentConstraints( + node: TypeReferenceNode | ExpressionWithTypeArguments, + typeParameters: readonly TypeParameter[], + ): boolean { let typeArguments: Type[] | undefined; let mapper: TypeMapper | undefined; let result = true; @@ -36732,8 +47905,9 @@ namespace ts { if (!isErrorType(type)) { const symbol = getNodeLinks(node).resolvedSymbol; if (symbol) { - return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters || - (getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target.localTypeParameters : undefined); + return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters + || (getObjectFlags(type) & ObjectFlags.Reference + ? (type as TypeReference).target.localTypeParameters : undefined); } } return undefined; @@ -36741,8 +47915,16 @@ namespace ts { function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) { checkGrammarTypeArguments(node, node.typeArguments); - if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJSFile(node) && !isInJSDoc(node)) { - grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); + if ( + node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJSFile(node) + && !isInJSDoc(node) + ) { + grammarErrorAtPos( + node, + node.typeName.jsdocDotPos, + 1, + Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments, + ); } forEach(node.typeArguments, checkSourceElement); const type = getTypeFromTypeReference(node); @@ -36765,7 +47947,11 @@ namespace ts { ); } if (type.flags & TypeFlags.Enum && symbol.flags & SymbolFlags.EnumMember) { - error(node, Diagnostics.Enum_type_0_has_members_with_initializers_that_are_not_literals, typeToString(type)); + error( + node, + Diagnostics.Enum_type_0_has_members_with_initializers_that_are_not_literals, + typeToString(type), + ); } } } @@ -36776,8 +47962,14 @@ namespace ts { if (!typeReferenceNode) return undefined; const typeParameters = getTypeParametersForTypeReference(typeReferenceNode); if (!typeParameters) return undefined; - const constraint = getConstraintOfTypeParameter(typeParameters[typeReferenceNode.typeArguments!.indexOf(node)]); - return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters))); + const constraint = getConstraintOfTypeParameter( + typeParameters[typeReferenceNode.typeArguments!.indexOf(node)], + ); + return constraint + && instantiateType( + constraint, + createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)), + ); } function checkTypeQuery(node: TypeQueryNode) { @@ -36858,30 +48050,51 @@ namespace ts { const indexType = (type as IndexedAccessType).indexType; if (isTypeAssignableTo(indexType, getIndexType(objectType, /*stringsOnly*/ false))) { if ( - accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && - getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly + accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) + && getObjectFlags(objectType) & ObjectFlags.Mapped + && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly ) { - error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); + error( + accessNode, + Diagnostics.Index_signature_in_type_0_only_permits_reading, + typeToString(objectType), + ); } return type; } // Check if we're indexing with a numeric type and if either object or index types // is a generic type with a constraint that has a numeric index signature. const apparentObjectType = getApparentType(objectType); - if (getIndexInfoOfType(apparentObjectType, numberType) && isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) { + if ( + getIndexInfoOfType(apparentObjectType, numberType) + && isTypeAssignableToKind(indexType, TypeFlags.NumberLike) + ) { return type; } if (isGenericObjectType(objectType)) { const propertyName = getPropertyNameFromIndex(indexType, accessNode); if (propertyName) { const propertySymbol = forEachType(apparentObjectType, t => getPropertyOfType(t, propertyName)); - if (propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.NonPublicAccessibilityModifier) { - error(accessNode, Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, unescapeLeadingUnderscores(propertyName)); + if ( + propertySymbol + && getDeclarationModifierFlagsFromSymbol(propertySymbol) + & ModifierFlags.NonPublicAccessibilityModifier + ) { + error( + accessNode, + Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, + unescapeLeadingUnderscores(propertyName), + ); return errorType; } } } - error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType)); + error( + accessNode, + Diagnostics.Type_0_cannot_be_used_to_index_type_1, + typeToString(indexType), + typeToString(objectType), + ); return errorType; } @@ -36908,13 +48121,20 @@ namespace ts { } else { const constraintType = getConstraintTypeFromMappedType(type); - checkTypeAssignableTo(constraintType, keyofConstraintType, getEffectiveConstraintOfTypeParameter(node.typeParameter)); + checkTypeAssignableTo( + constraintType, + keyofConstraintType, + getEffectiveConstraintOfTypeParameter(node.typeParameter), + ); } } function checkGrammarMappedType(node: MappedTypeNode) { if (node.members?.length) { - return grammarErrorOnNode(node.members[0], Diagnostics.A_mapped_type_may_not_declare_properties_or_methods); + return grammarErrorOnNode( + node.members[0], + Diagnostics.A_mapped_type_may_not_declare_properties_or_methods, + ); } } @@ -36932,8 +48152,15 @@ namespace ts { } function checkInferType(node: InferTypeNode) { - if (!findAncestor(node, n => n.parent && n.parent.kind === SyntaxKind.ConditionalType && (n.parent as ConditionalTypeNode).extendsType === n)) { - grammarErrorOnNode(node, Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type); + if ( + !findAncestor(node, n => + n.parent && n.parent.kind === SyntaxKind.ConditionalType + && (n.parent as ConditionalTypeNode).extendsType === n) + ) { + grammarErrorOnNode( + node, + Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type, + ); } checkSourceElement(node.typeParameter); const symbol = getSymbolOfNode(node.typeParameter); @@ -36942,12 +48169,19 @@ namespace ts { if (!links.typeParametersChecked) { links.typeParametersChecked = true; const typeParameter = getDeclaredTypeOfTypeParameter(symbol); - const declarations: TypeParameterDeclaration[] = getDeclarationsOfKind(symbol, SyntaxKind.TypeParameter); + const declarations: TypeParameterDeclaration[] = getDeclarationsOfKind( + symbol, + SyntaxKind.TypeParameter, + ); if (!areTypeParametersIdentical(declarations, [typeParameter], decl => [decl])) { // Report an error on every conflicting declaration. const name = symbolToString(symbol); for (const declaration of declarations) { - error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_constraints, name); + error( + declaration.name, + Diagnostics.All_declarations_of_0_must_have_identical_constraints, + name, + ); } } } @@ -36971,10 +48205,21 @@ namespace ts { const override = getResolutionModeOverrideForClause(node.assertions.assertClause, grammarErrorOnNode); if (override) { if (!isNightly()) { - grammarErrorOnNode(node.assertions.assertClause, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next); + grammarErrorOnNode( + node.assertions.assertClause, + Diagnostics + .resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next, + ); } - if (getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) { - grammarErrorOnNode(node.assertions.assertClause, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext); + if ( + getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 + && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext + ) { + grammarErrorOnNode( + node.assertions.assertClause, + Diagnostics + .resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext, + ); } } } @@ -36987,17 +48232,26 @@ namespace ts { grammarErrorOnNode(node, Diagnostics.A_tuple_member_cannot_be_both_optional_and_rest); } if (node.type.kind === SyntaxKind.OptionalType) { - grammarErrorOnNode(node.type, Diagnostics.A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type); + grammarErrorOnNode( + node.type, + Diagnostics + .A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type, + ); } if (node.type.kind === SyntaxKind.RestType) { - grammarErrorOnNode(node.type, Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type); + grammarErrorOnNode( + node.type, + Diagnostics + .A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type, + ); } checkSourceElement(node.type); getTypeFromTypeNode(node); } function isPrivateWithinAmbient(node: Node): boolean { - return (hasEffectiveModifier(node, ModifierFlags.Private) || isPrivateIdentifierClassElementDeclaration(node)) && !!(node.flags & NodeFlags.Ambient); + return (hasEffectiveModifier(node, ModifierFlags.Private) + || isPrivateIdentifierClassElementDeclaration(node)) && !!(node.flags & NodeFlags.Ambient); } function getEffectiveDeclarationFlags(n: Declaration, flagsToCheck: ModifierFlags): ModifierFlags { @@ -37006,12 +48260,16 @@ namespace ts { // children of classes (even ambient classes) should not be marked as ambient or export // because those flags have no useful semantics there. if ( - n.parent.kind !== SyntaxKind.InterfaceDeclaration && - n.parent.kind !== SyntaxKind.ClassDeclaration && - n.parent.kind !== SyntaxKind.ClassExpression && - n.flags & NodeFlags.Ambient + n.parent.kind !== SyntaxKind.InterfaceDeclaration + && n.parent.kind !== SyntaxKind.ClassDeclaration + && n.parent.kind !== SyntaxKind.ClassExpression + && n.flags & NodeFlags.Ambient ) { - if (!(flags & ModifierFlags.Ambient) && !(isModuleBlock(n.parent) && isModuleDeclaration(n.parent.parent) && isGlobalScopeAugmentation(n.parent.parent))) { + if ( + !(flags & ModifierFlags.Ambient) + && !(isModuleBlock(n.parent) && isModuleDeclaration(n.parent.parent) + && isGlobalScopeAugmentation(n.parent.parent)) + ) { // It is nested in an ambient context, which means it is automatically exported flags |= ModifierFlags.Export; } @@ -37026,53 +48284,87 @@ namespace ts { } function checkFunctionOrConstructorSymbolWorker(symbol: Symbol): void { - function getCanonicalOverload(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined): Declaration { + function getCanonicalOverload( + overloads: Declaration[], + implementation: FunctionLikeDeclaration | undefined, + ): Declaration { // Consider the canonical set of flags to be the flags of the bodyDeclaration or the first declaration // Error on all deviations from this canonical set of flags // The caveat is that if some overloads are defined in lib.d.ts, we don't want to // report the errors on those. To achieve this, we will say that the implementation is // the canonical signature only if it is in the same container as the first overload - const implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent; + const implementationSharesContainerWithFirstOverload = implementation !== undefined + && implementation.parent === overloads[0].parent; return implementationSharesContainerWithFirstOverload ? implementation : overloads[0]; } - function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, flagsToCheck: ModifierFlags, someOverloadFlags: ModifierFlags, allOverloadFlags: ModifierFlags): void { + function checkFlagAgreementBetweenOverloads( + overloads: Declaration[], + implementation: FunctionLikeDeclaration | undefined, + flagsToCheck: ModifierFlags, + someOverloadFlags: ModifierFlags, + allOverloadFlags: ModifierFlags, + ): void { // Error if some overloads have a flag that is not shared by all overloads. To find the // deviations, we XOR someOverloadFlags with allOverloadFlags const someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags; if (someButNotAllOverloadFlags !== 0) { - const canonicalFlags = getEffectiveDeclarationFlags(getCanonicalOverload(overloads, implementation), flagsToCheck); + const canonicalFlags = getEffectiveDeclarationFlags( + getCanonicalOverload(overloads, implementation), + flagsToCheck, + ); forEach(overloads, o => { const deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags; if (deviation & ModifierFlags.Export) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_exported_or_non_exported); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_exported_or_non_exported, + ); } else if (deviation & ModifierFlags.Ambient) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient, + ); } else if (deviation & (ModifierFlags.Private | ModifierFlags.Protected)) { - error(getNameOfDeclaration(o) || o, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected); + error( + getNameOfDeclaration(o) || o, + Diagnostics.Overload_signatures_must_all_be_public_private_or_protected, + ); } else if (deviation & ModifierFlags.Abstract) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract, + ); } }); } } - function checkQuestionTokenAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, someHaveQuestionToken: boolean, allHaveQuestionToken: boolean): void { + function checkQuestionTokenAgreementBetweenOverloads( + overloads: Declaration[], + implementation: FunctionLikeDeclaration | undefined, + someHaveQuestionToken: boolean, + allHaveQuestionToken: boolean, + ): void { if (someHaveQuestionToken !== allHaveQuestionToken) { const canonicalHasQuestionToken = hasQuestionToken(getCanonicalOverload(overloads, implementation)); forEach(overloads, o => { const deviation = hasQuestionToken(o) !== canonicalHasQuestionToken; if (deviation) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_optional_or_required); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_optional_or_required, + ); } }); } } - const flagsToCheck: ModifierFlags = ModifierFlags.Export | ModifierFlags.Ambient | ModifierFlags.Private | ModifierFlags.Protected | ModifierFlags.Abstract; + const flagsToCheck: ModifierFlags = ModifierFlags.Export | ModifierFlags.Ambient | ModifierFlags.Private + | ModifierFlags.Protected | ModifierFlags.Abstract; let someNodeFlags: ModifierFlags = ModifierFlags.None; let allNodeFlags = flagsToCheck; let someHaveQuestionToken = false; @@ -37108,29 +48400,37 @@ namespace ts { if ( node.name && subsequentName && ( // both are private identifiers - isPrivateIdentifier(node.name) && isPrivateIdentifier(subsequentName) && node.name.escapedText === subsequentName.escapedText || + isPrivateIdentifier(node.name) && isPrivateIdentifier(subsequentName) + && node.name.escapedText === subsequentName.escapedText // Both are computed property names // TODO: GH#17345: These are methods, so handle computed name case. (`Always allowing computed property names is *not* the correct behavior!) - isComputedPropertyName(node.name) && isComputedPropertyName(subsequentName) || + || isComputedPropertyName(node.name) && isComputedPropertyName(subsequentName) // Both are literal property names that are the same. - isPropertyNameLiteral(node.name) && isPropertyNameLiteral(subsequentName) && - getEscapedTextOfIdentifierOrLiteral(node.name) === getEscapedTextOfIdentifierOrLiteral(subsequentName) + || isPropertyNameLiteral(node.name) && isPropertyNameLiteral(subsequentName) + && getEscapedTextOfIdentifierOrLiteral(node.name) + === getEscapedTextOfIdentifierOrLiteral(subsequentName) ) ) { - const reportError = (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && - isStatic(node) !== isStatic(subsequentNode); + const reportError = + (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) + && isStatic(node) !== isStatic(subsequentNode); // we can get here in two cases // 1. mixed static and instance class members // 2. something with the same name was defined before the set of overloads that prevents them from merging // here we'll report error only for the first case since for second we should already report error in binder if (reportError) { - const diagnostic = isStatic(node) ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; + const diagnostic = isStatic(node) ? Diagnostics.Function_overload_must_be_static + : Diagnostics.Function_overload_must_not_be_static; error(errorNode, diagnostic); } return; } if (nodeIsPresent((subsequentNode as FunctionLikeDeclaration).body)) { - error(errorNode, Diagnostics.Function_implementation_name_must_be_0, declarationNameToString(node.name)); + error( + errorNode, + Diagnostics.Function_implementation_name_must_be_0, + declarationNameToString(node.name), + ); return; } } @@ -37146,7 +48446,10 @@ namespace ts { error(errorNode, Diagnostics.All_declarations_of_an_abstract_method_must_be_consecutive); } else { - error(errorNode, Diagnostics.Function_implementation_is_missing_or_not_immediately_following_the_declaration); + error( + errorNode, + Diagnostics.Function_implementation_is_missing_or_not_immediately_following_the_declaration, + ); } } } @@ -37159,7 +48462,9 @@ namespace ts { for (const current of declarations) { const node = current as SignatureDeclaration | ClassDeclaration | ClassExpression; const inAmbientContext = node.flags & NodeFlags.Ambient; - const inAmbientContextOrInterface = node.parent && (node.parent.kind === SyntaxKind.InterfaceDeclaration || node.parent.kind === SyntaxKind.TypeLiteral) || inAmbientContext; + const inAmbientContextOrInterface = node.parent + && (node.parent.kind === SyntaxKind.InterfaceDeclaration + || node.parent.kind === SyntaxKind.TypeLiteral) || inAmbientContext; if (inAmbientContextOrInterface) { // check if declarations are consecutive only if they are non-ambient // 1. ambient declarations can be interleaved @@ -37171,11 +48476,17 @@ namespace ts { previousDeclaration = undefined; } - if ((node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && !inAmbientContext) { + if ( + (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) + && !inAmbientContext + ) { hasNonAmbientClass = true; } - if (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature || node.kind === SyntaxKind.Constructor) { + if ( + node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration + || node.kind === SyntaxKind.MethodSignature || node.kind === SyntaxKind.Constructor + ) { functionDeclarations.push(node); const currentNodeFlags = getEffectiveDeclarationFlags(node, flagsToCheck); someNodeFlags |= currentNodeFlags; @@ -37222,7 +48533,10 @@ namespace ts { if (duplicateFunctionDeclaration) { forEach(functionDeclarations, declaration => { - error(getNameOfDeclaration(declaration) || declaration, Diagnostics.Duplicate_function_implementation); + error( + getNameOfDeclaration(declaration) || declaration, + Diagnostics.Duplicate_function_implementation, + ); }); } @@ -37247,16 +48561,28 @@ namespace ts { // Abstract methods can't have an implementation -- in particular, they don't need one. if ( - lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body && - !hasSyntacticModifier(lastSeenNonAmbientDeclaration, ModifierFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken + lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body + && !hasSyntacticModifier(lastSeenNonAmbientDeclaration, ModifierFlags.Abstract) + && !lastSeenNonAmbientDeclaration.questionToken ) { reportImplementationExpectedError(lastSeenNonAmbientDeclaration); } if (hasOverloads) { if (declarations) { - checkFlagAgreementBetweenOverloads(declarations, bodyDeclaration, flagsToCheck, someNodeFlags, allNodeFlags); - checkQuestionTokenAgreementBetweenOverloads(declarations, bodyDeclaration, someHaveQuestionToken, allHaveQuestionToken); + checkFlagAgreementBetweenOverloads( + declarations, + bodyDeclaration, + flagsToCheck, + someNodeFlags, + allNodeFlags, + ); + checkQuestionTokenAgreementBetweenOverloads( + declarations, + bodyDeclaration, + someHaveQuestionToken, + allHaveQuestionToken, + ); } if (bodyDeclaration) { @@ -37265,8 +48591,15 @@ namespace ts { for (const signature of signatures) { if (!isImplementationCompatibleWithOverload(bodySignature, signature)) { addRelatedInfo( - error(signature.declaration, Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature), - createDiagnosticForNode(bodyDeclaration, Diagnostics.The_implementation_signature_is_declared_here), + error( + signature.declaration, + Diagnostics + .This_overload_signature_is_not_compatible_with_its_implementation_signature, + ), + createDiagnosticForNode( + bodyDeclaration, + Diagnostics.The_implementation_signature_is_declared_here, + ), ); break; } @@ -37302,7 +48635,10 @@ namespace ts { let defaultExportedDeclarationSpaces = DeclarationSpaces.None; for (const d of symbol.declarations!) { const declarationSpaces = getDeclarationSpaces(d); - const effectiveDeclarationFlags = getEffectiveDeclarationFlags(d, ModifierFlags.Export | ModifierFlags.Default); + const effectiveDeclarationFlags = getEffectiveDeclarationFlags( + d, + ModifierFlags.Export | ModifierFlags.Default, + ); if (effectiveDeclarationFlags & ModifierFlags.Export) { if (effectiveDeclarationFlags & ModifierFlags.Default) { @@ -37321,7 +48657,8 @@ namespace ts { const nonDefaultExportedDeclarationSpaces = exportedDeclarationSpaces | nonExportedDeclarationSpaces; const commonDeclarationSpacesForExportsAndLocals = exportedDeclarationSpaces & nonExportedDeclarationSpaces; - const commonDeclarationSpacesForDefaultAndNonDefault = defaultExportedDeclarationSpaces & nonDefaultExportedDeclarationSpaces; + const commonDeclarationSpacesForDefaultAndNonDefault = defaultExportedDeclarationSpaces + & nonDefaultExportedDeclarationSpaces; if (commonDeclarationSpacesForExportsAndLocals || commonDeclarationSpacesForDefaultAndNonDefault) { // declaration spaces for exported and non-exported declarations intersect @@ -37331,10 +48668,20 @@ namespace ts { const name = getNameOfDeclaration(d); // Only error on the declarations that contributed to the intersecting spaces. if (declarationSpaces & commonDeclarationSpacesForDefaultAndNonDefault) { - error(name, Diagnostics.Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead, declarationNameToString(name)); + error( + name, + Diagnostics + .Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead, + declarationNameToString(name), + ); } else if (declarationSpaces & commonDeclarationSpacesForExportsAndLocals) { - error(name, Diagnostics.Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, declarationNameToString(name)); + error( + name, + Diagnostics + .Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, + declarationNameToString(name), + ); } } } @@ -37352,7 +48699,9 @@ namespace ts { case SyntaxKind.JSDocEnumTag: return DeclarationSpaces.ExportType; case SyntaxKind.ModuleDeclaration: - return isAmbientModule(d as ModuleDeclaration) || getModuleInstanceState(d as ModuleDeclaration) !== ModuleInstanceState.NonInstantiated + return isAmbientModule(d as ModuleDeclaration) + || getModuleInstanceState(d as ModuleDeclaration) + !== ModuleInstanceState.NonInstantiated ? DeclarationSpaces.ExportNamespace | DeclarationSpaces.ExportValue : DeclarationSpaces.ExportNamespace; case SyntaxKind.ClassDeclaration: @@ -37360,7 +48709,8 @@ namespace ts { case SyntaxKind.EnumMember: return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue; case SyntaxKind.SourceFile: - return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue | DeclarationSpaces.ExportNamespace; + return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue + | DeclarationSpaces.ExportNamespace; case SyntaxKind.ExportAssignment: case SyntaxKind.BinaryExpression: const node = d as ExportAssignment | BinaryExpression; @@ -37400,7 +48750,12 @@ namespace ts { } } - function getAwaitedTypeOfPromise(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { + function getAwaitedTypeOfPromise( + type: Type, + errorNode?: Node, + diagnosticMessage?: DiagnosticMessage, + arg0?: string | number, + ): Type | undefined { const promisedType = getPromisedTypeOfPromise(type, errorNode); return promisedType && getAwaitedType(promisedType, errorNode, diagnosticMessage, arg0); } @@ -37410,7 +48765,11 @@ namespace ts { * @param type The type of the promise. * @remarks The "promised type" of a type is the type of the "value" parameter of the "onfulfilled" callback. */ - function getPromisedTypeOfPromise(type: Type, errorNode?: Node, thisTypeForErrorOut?: { value?: Type; }): Type | undefined { + function getPromisedTypeOfPromise( + type: Type, + errorNode?: Node, + thisTypeForErrorOut?: { value?: Type; }, + ): Type | undefined { // // { // type // then( // thenFunction @@ -37470,12 +48829,20 @@ namespace ts { thisTypeForErrorOut.value = thisTypeForError; } if (errorNode) { - error(errorNode, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, typeToString(type), typeToString(thisTypeForError)); + error( + errorNode, + Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, + typeToString(type), + typeToString(thisTypeForError), + ); } return undefined; } - const onfulfilledParameterType = getTypeWithFacts(getUnionType(map(candidates, getTypeOfFirstParameterOfSignature)), TypeFacts.NEUndefinedOrNull); + const onfulfilledParameterType = getTypeWithFacts( + getUnionType(map(candidates, getTypeOfFirstParameterOfSignature)), + TypeFacts.NEUndefinedOrNull, + ); if (isTypeAny(onfulfilledParameterType)) { return undefined; } @@ -37483,12 +48850,18 @@ namespace ts { const onfulfilledParameterSignatures = getSignaturesOfType(onfulfilledParameterType, SignatureKind.Call); if (onfulfilledParameterSignatures.length === 0) { if (errorNode) { - error(errorNode, Diagnostics.The_first_parameter_of_the_then_method_of_a_promise_must_be_a_callback); + error( + errorNode, + Diagnostics.The_first_parameter_of_the_then_method_of_a_promise_must_be_a_callback, + ); } return undefined; } - return typeAsPromise.promisedTypeOfPromise = getUnionType(map(onfulfilledParameterSignatures, getTypeOfFirstParameterOfSignature), UnionReduction.Subtype); + return typeAsPromise.promisedTypeOfPromise = getUnionType( + map(onfulfilledParameterSignatures, getTypeOfFirstParameterOfSignature), + UnionReduction.Subtype, + ); } /** @@ -37499,10 +48872,16 @@ namespace ts { * Promise-like type; otherwise, it is the type of the expression. This is used to reflect * The runtime behavior of the `await` keyword. */ - function checkAwaitedType(type: Type, withAlias: boolean, errorNode: Node, diagnosticMessage: DiagnosticMessage, arg0?: string | number): Type { - const awaitedType = withAlias ? - getAwaitedType(type, errorNode, diagnosticMessage, arg0) : - getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, arg0); + function checkAwaitedType( + type: Type, + withAlias: boolean, + errorNode: Node, + diagnosticMessage: DiagnosticMessage, + arg0?: string | number, + ): Type { + const awaitedType = withAlias + ? getAwaitedType(type, errorNode, diagnosticMessage, arg0) + : getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, arg0); return awaitedType || errorType; } @@ -37516,7 +48895,9 @@ namespace ts { } const thenFunction = getTypeOfPropertyOfType(type, "then" as __String); - return !!thenFunction && getSignaturesOfType(getTypeWithFacts(thenFunction, TypeFacts.NEUndefinedOrNull), SignatureKind.Call).length > 0; + return !!thenFunction + && getSignaturesOfType(getTypeWithFacts(thenFunction, TypeFacts.NEUndefinedOrNull), SignatureKind.Call) + .length > 0; } interface AwaitedTypeInstantiation extends Type { @@ -37537,9 +48918,9 @@ namespace ts { * For a generic `Awaited`, gets `T`. */ function unwrapAwaitedType(type: Type) { - return type.flags & TypeFlags.Union ? mapType(type, unwrapAwaitedType) : - isAwaitedTypeInstantiation(type) ? type.aliasTypeArguments[0] : - type; + return type.flags & TypeFlags.Union ? mapType(type, unwrapAwaitedType) + : isAwaitedTypeInstantiation(type) ? type.aliasTypeArguments[0] + : type; } function isAwaitedTypeNeeded(type: Type) { @@ -37554,9 +48935,10 @@ namespace ts { // We only need `Awaited` if `T` is a type variable that has no base constraint, or the base constraint of `T` is `any`, `unknown`, `{}`, `object`, // or is promise-like. if ( - baseConstraint ? - baseConstraint.flags & TypeFlags.AnyOrUnknown || isEmptyObjectType(baseConstraint) || isThenableType(baseConstraint) : - maybeTypeOfKind(type, TypeFlags.TypeVariable) + baseConstraint + ? baseConstraint.flags & TypeFlags.AnyOrUnknown || isEmptyObjectType(baseConstraint) + || isThenableType(baseConstraint) + : maybeTypeOfKind(type, TypeFlags.TypeVariable) ) { return true; } @@ -37593,7 +48975,10 @@ namespace ts { } } - Debug.assert(getPromisedTypeOfPromise(type) === undefined, "type provided should not be a non-generic 'promise'-like."); + Debug.assert( + getPromisedTypeOfPromise(type) === undefined, + "type provided should not be a non-generic 'promise'-like.", + ); return type; } @@ -37607,7 +48992,12 @@ namespace ts { * * This is used to reflect the runtime behavior of the `await` keyword. */ - function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { + function getAwaitedType( + type: Type, + errorNode?: Node, + diagnosticMessage?: DiagnosticMessage, + arg0?: string | number, + ): Type | undefined { const awaitedType = getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, arg0); return awaitedType && createAwaitedTypeIfNeeded(awaitedType); } @@ -37617,7 +49007,12 @@ namespace ts { * * @see {@link getAwaitedType} */ - function getAwaitedTypeNoAlias(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { + function getAwaitedTypeNoAlias( + type: Type, + errorNode?: Node, + diagnosticMessage?: DiagnosticMessage, + arg0?: string | number, + ): Type | undefined { if (isTypeAny(type)) { return type; } @@ -37637,12 +49032,17 @@ namespace ts { if (type.flags & TypeFlags.Union) { if (awaitedTypeStack.lastIndexOf(type.id) >= 0) { if (errorNode) { - error(errorNode, Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method); + error( + errorNode, + Diagnostics + .Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method, + ); } return undefined; } - const mapper = errorNode ? (constituentType: Type) => getAwaitedTypeNoAlias(constituentType, errorNode, diagnosticMessage, arg0) : getAwaitedTypeNoAlias; + const mapper = errorNode ? (constituentType: Type) => + getAwaitedTypeNoAlias(constituentType, errorNode, diagnosticMessage, arg0) : getAwaitedTypeNoAlias; awaitedTypeStack.push(type.id); const mapped = mapType(type, mapper); @@ -37694,7 +49094,11 @@ namespace ts { // } // if (errorNode) { - error(errorNode, Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method); + error( + errorNode, + Diagnostics + .Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method, + ); } return undefined; } @@ -37732,7 +49136,12 @@ namespace ts { Debug.assertIsDefined(diagnosticMessage); let chain: DiagnosticMessageChain | undefined; if (thisTypeForErrorOut.value) { - chain = chainDiagnosticMessages(chain, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, typeToString(type), typeToString(thisTypeForErrorOut.value)); + chain = chainDiagnosticMessages( + chain, + Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, + typeToString(type), + typeToString(thisTypeForErrorOut.value), + ); } chain = chainDiagnosticMessages(chain, diagnosticMessage, arg0); diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, chain)); @@ -37755,7 +49164,10 @@ namespace ts { * * @param node The signature to check */ - function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration | MethodSignature, returnTypeNode: TypeNode) { + function checkAsyncFunctionReturnType( + node: FunctionLikeDeclaration | MethodSignature, + returnTypeNode: TypeNode, + ) { // As part of our emit for an async function, we will need to emit the entity name of // the return type annotation as an expression. To meet the necessary runtime semantics // for __awaiter, we must also check that the type of the declaration (e.g. the static @@ -37790,7 +49202,12 @@ namespace ts { if (globalPromiseType !== emptyGenericType && !isReferenceToType(returnType, globalPromiseType)) { // The promise type was not a valid type reference to the global promise type, so we // report an error and return the unknown type. - error(returnTypeNode, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, typeToString(getAwaitedTypeNoAlias(returnType) || voidType)); + error( + returnTypeNode, + Diagnostics + .The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, + typeToString(getAwaitedTypeNoAlias(returnType) || voidType), + ); return; } } @@ -37804,18 +49221,41 @@ namespace ts { const promiseConstructorName = getEntityNameFromTypeNode(returnTypeNode); if (promiseConstructorName === undefined) { - error(returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, typeToString(returnType)); + error( + returnTypeNode, + Diagnostics + .Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + typeToString(returnType), + ); return; } - const promiseConstructorSymbol = resolveEntityName(promiseConstructorName, SymbolFlags.Value, /*ignoreErrors*/ true); - const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) : errorType; + const promiseConstructorSymbol = resolveEntityName( + promiseConstructorName, + SymbolFlags.Value, + /*ignoreErrors*/ true, + ); + const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) + : errorType; if (isErrorType(promiseConstructorType)) { - if (promiseConstructorName.kind === SyntaxKind.Identifier && promiseConstructorName.escapedText === "Promise" && getTargetType(returnType) === getGlobalPromiseType(/*reportErrors*/ false)) { - error(returnTypeNode, Diagnostics.An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option); + if ( + promiseConstructorName.kind === SyntaxKind.Identifier + && promiseConstructorName.escapedText === "Promise" + && getTargetType(returnType) === getGlobalPromiseType(/*reportErrors*/ false) + ) { + error( + returnTypeNode, + Diagnostics + .An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option, + ); } else { - error(returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName)); + error( + returnTypeNode, + Diagnostics + .Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + entityNameToString(promiseConstructorName), + ); } return; } @@ -37824,11 +49264,24 @@ namespace ts { if (globalPromiseConstructorLikeType === emptyObjectType) { // If we couldn't resolve the global PromiseConstructorLike type we cannot verify // compatibility with __awaiter. - error(returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName)); + error( + returnTypeNode, + Diagnostics + .Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + entityNameToString(promiseConstructorName), + ); return; } - if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, returnTypeNode, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value)) { + if ( + !checkTypeAssignableTo( + promiseConstructorType, + globalPromiseConstructorLikeType, + returnTypeNode, + Diagnostics + .Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + ) + ) { return; } @@ -37836,11 +49289,22 @@ namespace ts { const rootName = promiseConstructorName && getFirstIdentifier(promiseConstructorName); const collidingSymbol = getSymbol(node.locals!, rootName.escapedText, SymbolFlags.Value); if (collidingSymbol) { - error(collidingSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions, idText(rootName), entityNameToString(promiseConstructorName)); + error( + collidingSymbol.valueDeclaration, + Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions, + idText(rootName), + entityNameToString(promiseConstructorName), + ); return; } } - checkAwaitedType(returnType, /*withAlias*/ false, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); + checkAwaitedType( + returnType, + /*withAlias*/ false, + node, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ); } /** Check a decorator */ @@ -37894,15 +49358,29 @@ namespace ts { * marked as referenced to prevent import elision. */ function markTypeNodeAsReferenced(node: TypeNode) { - markEntityNameOrEntityExpressionAsReference(node && getEntityNameFromTypeNode(node), /*forDecoratorMetadata*/ false); + markEntityNameOrEntityExpressionAsReference( + node && getEntityNameFromTypeNode(node), + /*forDecoratorMetadata*/ false, + ); } - function markEntityNameOrEntityExpressionAsReference(typeName: EntityNameOrEntityNameExpression | undefined, forDecoratorMetadata: boolean) { + function markEntityNameOrEntityExpressionAsReference( + typeName: EntityNameOrEntityNameExpression | undefined, + forDecoratorMetadata: boolean, + ) { if (!typeName) return; const rootName = getFirstIdentifier(typeName); - const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) | SymbolFlags.Alias; - const rootSymbol = resolveName(rootName, rootName.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isReference*/ true); + const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) + | SymbolFlags.Alias; + const rootSymbol = resolveName( + rootName, + rootName.escapedText, + meaning, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isReference*/ true, + ); if (rootSymbol && rootSymbol.flags & SymbolFlags.Alias) { if ( symbolIsValue(rootSymbol) @@ -37918,10 +49396,21 @@ namespace ts { && !symbolIsValue(rootSymbol) && !some(rootSymbol.declarations, isTypeOnlyImportOrExportDeclaration) ) { - const diag = error(typeName, Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled); + const diag = error( + typeName, + Diagnostics + .A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled, + ); const aliasDeclaration = find(rootSymbol.declarations || emptyArray, isAliasSymbolDeclaration); if (aliasDeclaration) { - addRelatedInfo(diag, createDiagnosticForNode(aliasDeclaration, Diagnostics._0_was_imported_here, idText(rootName))); + addRelatedInfo( + diag, + createDiagnosticForNode( + aliasDeclaration, + Diagnostics._0_was_imported_here, + idText(rootName), + ), + ); } } } @@ -37946,10 +49435,15 @@ namespace ts { switch (node.kind) { case SyntaxKind.IntersectionType: case SyntaxKind.UnionType: - return getEntityNameForDecoratorMetadataFromTypeList((node as UnionOrIntersectionTypeNode).types); + return getEntityNameForDecoratorMetadataFromTypeList( + (node as UnionOrIntersectionTypeNode).types, + ); case SyntaxKind.ConditionalType: - return getEntityNameForDecoratorMetadataFromTypeList([(node as ConditionalTypeNode).trueType, (node as ConditionalTypeNode).falseType]); + return getEntityNameForDecoratorMetadataFromTypeList([ + (node as ConditionalTypeNode).trueType, + (node as ConditionalTypeNode).falseType, + ]); case SyntaxKind.ParenthesizedType: case SyntaxKind.NamedTupleMember: @@ -37964,13 +49458,20 @@ namespace ts { function getEntityNameForDecoratorMetadataFromTypeList(types: readonly TypeNode[]): EntityName | undefined { let commonEntityName: EntityName | undefined; for (let typeNode of types) { - while (typeNode.kind === SyntaxKind.ParenthesizedType || typeNode.kind === SyntaxKind.NamedTupleMember) { + while ( + typeNode.kind === SyntaxKind.ParenthesizedType || typeNode.kind === SyntaxKind.NamedTupleMember + ) { typeNode = (typeNode as ParenthesizedTypeNode | NamedTupleMember).type; // Skip parens if need be } if (typeNode.kind === SyntaxKind.NeverKeyword) { continue; // Always elide `never` from the union/intersection if possible } - if (!strictNullChecks && (typeNode.kind === SyntaxKind.LiteralType && (typeNode as LiteralTypeNode).literal.kind === SyntaxKind.NullKeyword || typeNode.kind === SyntaxKind.UndefinedKeyword)) { + if ( + !strictNullChecks + && (typeNode.kind === SyntaxKind.LiteralType + && (typeNode as LiteralTypeNode).literal.kind === SyntaxKind.NullKeyword + || typeNode.kind === SyntaxKind.UndefinedKeyword) + ) { continue; // Elide null and undefined from unions for metadata, just like what we did prior to the implementation of strict null checks } const individualEntityName = getEntityNameForDecoratorMetadata(typeNode); @@ -37987,9 +49488,9 @@ namespace ts { // Verify if they refer to same entity and is identifier // return undefined if they dont match because we would emit object if ( - !isIdentifier(commonEntityName) || - !isIdentifier(individualEntityName) || - commonEntityName.escapedText !== individualEntityName.escapedText + !isIdentifier(commonEntityName) + || !isIdentifier(individualEntityName) + || commonEntityName.escapedText !== individualEntityName.escapedText ) { return undefined; } @@ -38010,12 +49511,19 @@ namespace ts { function checkDecorators(node: Node): void { // skip this check for nodes that cannot have decorators. These should have already had an error reported by // checkGrammarDecorators. - if (!canHaveDecorators(node) || !hasDecorators(node) || !node.modifiers || !nodeCanBeDecorated(node, node.parent, node.parent.parent)) { + if ( + !canHaveDecorators(node) || !hasDecorators(node) || !node.modifiers + || !nodeCanBeDecorated(node, node.parent, node.parent.parent) + ) { return; } if (!compilerOptions.experimentalDecorators) { - error(node, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_in_your_tsconfig_or_jsconfig_to_remove_this_warning); + error( + node, + Diagnostics + .Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_in_your_tsconfig_or_jsconfig_to_remove_this_warning, + ); } const firstDecorator = find(node.modifiers, isDecorator); @@ -38037,20 +49545,31 @@ namespace ts { const constructor = getFirstConstructorWithBody(node); if (constructor) { for (const parameter of constructor.parameters) { - markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); + markDecoratorMedataDataTypeNodeAsReferenced( + getParameterTypeNodeForDecoratorCheck(parameter), + ); } } break; case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; - const otherAccessor = getDeclarationOfKind(getSymbolOfNode(node), otherKind); - markDecoratorMedataDataTypeNodeAsReferenced(getAnnotatedAccessorTypeNode(node) || otherAccessor && getAnnotatedAccessorTypeNode(otherAccessor)); + const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor + : SyntaxKind.GetAccessor; + const otherAccessor = getDeclarationOfKind( + getSymbolOfNode(node), + otherKind, + ); + markDecoratorMedataDataTypeNodeAsReferenced( + getAnnotatedAccessorTypeNode(node) + || otherAccessor && getAnnotatedAccessorTypeNode(otherAccessor), + ); break; case SyntaxKind.MethodDeclaration: for (const parameter of node.parameters) { - markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); + markDecoratorMedataDataTypeNodeAsReferenced( + getParameterTypeNodeForDecoratorCheck(parameter), + ); } markDecoratorMedataDataTypeNodeAsReferenced(getEffectiveReturnTypeNode(node)); @@ -38064,7 +49583,9 @@ namespace ts { markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(node)); const containingSignature = node.parent; for (const parameter of containingSignature.parameters) { - markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); + markDecoratorMedataDataTypeNodeAsReferenced( + getParameterTypeNodeForDecoratorCheck(parameter), + ); } break; } @@ -38090,7 +49611,11 @@ namespace ts { function checkJSDocTypeAliasTag(node: JSDocTypedefTag | JSDocCallbackTag) { if (!node.typeExpression) { // If the node had `@property` tags, `typeExpression` would have been set to the first property tag. - error(node.name, Diagnostics.JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags); + error( + node.name, + Diagnostics + .JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags, + ); } if (node.name) { @@ -38152,7 +49677,10 @@ namespace ts { const augmentsTags = getJSDocTags(classLike).filter(isJSDocAugmentsTag); Debug.assert(augmentsTags.length > 0); if (augmentsTags.length > 1) { - error(augmentsTags[1], Diagnostics.Class_declarations_cannot_have_more_than_one_augments_or_extends_tag); + error( + augmentsTags[1], + Diagnostics.Class_declarations_cannot_have_more_than_one_augments_or_extends_tag, + ); } const name = getIdentifierFromEntityNameExpression(node.class.expression); @@ -38160,7 +49688,13 @@ namespace ts { if (extend) { const className = getIdentifierFromEntityNameExpression(extend.expression); if (className && name.escapedText !== className.escapedText) { - error(name, Diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, idText(node.tagName), idText(name), idText(className)); + error( + name, + Diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, + idText(node.tagName), + idText(name), + idText(className), + ); } } } @@ -38172,7 +49706,9 @@ namespace ts { } } - function getIdentifierFromEntityNameExpression(node: Identifier | PropertyAccessExpression): Identifier | PrivateIdentifier; + function getIdentifierFromEntityNameExpression( + node: Identifier | PropertyAccessExpression, + ): Identifier | PrivateIdentifier; function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined; function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined { switch (node.kind) { @@ -38185,7 +49721,9 @@ namespace ts { } } - function checkFunctionOrMethodDeclaration(node: FunctionDeclaration | MethodDeclaration | MethodSignature): void { + function checkFunctionOrMethodDeclaration( + node: FunctionDeclaration | MethodDeclaration | MethodSignature, + ): void { checkDecorators(node); checkSignatureDeclaration(node); const functionFlags = getFunctionFlags(node); @@ -38234,8 +49772,14 @@ namespace ts { // A js function declaration can have a @type tag instead of a return type node, but that type must have a call signature if (isInJSFile(node)) { const typeTag = getJSDocTypeTag(node); - if (typeTag && typeTag.typeExpression && !getContextualCallSignature(getTypeFromTypeNode(typeTag.typeExpression), node)) { - error(typeTag.typeExpression.type, Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature); + if ( + typeTag && typeTag.typeExpression + && !getContextualCallSignature(getTypeFromTypeNode(typeTag.typeExpression), node) + ) { + error( + typeTag.typeExpression.type, + Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature, + ); } } @@ -38274,9 +49818,24 @@ namespace ts { } } - type PotentiallyUnusedIdentifier = SourceFile | ModuleDeclaration | ClassLikeDeclaration | InterfaceDeclaration | Block | CaseBlock | ForStatement | ForInStatement | ForOfStatement | Exclude | TypeAliasDeclaration | InferTypeNode; - - function checkUnusedIdentifiers(potentiallyUnusedIdentifiers: readonly PotentiallyUnusedIdentifier[], addDiagnostic: AddUnusedDiagnostic) { + type PotentiallyUnusedIdentifier = + | SourceFile + | ModuleDeclaration + | ClassLikeDeclaration + | InterfaceDeclaration + | Block + | CaseBlock + | ForStatement + | ForInStatement + | ForOfStatement + | Exclude + | TypeAliasDeclaration + | InferTypeNode; + + function checkUnusedIdentifiers( + potentiallyUnusedIdentifiers: readonly PotentiallyUnusedIdentifier[], + addDiagnostic: AddUnusedDiagnostic, + ) { for (const node of potentiallyUnusedIdentifiers) { switch (node.kind) { case SyntaxKind.ClassDeclaration: @@ -38325,7 +49884,8 @@ namespace ts { function errorUnusedLocal(declaration: Declaration, name: string, addDiagnostic: AddUnusedDiagnostic) { const node = getNameOfDeclaration(declaration) || declaration; - const message = isTypeDeclaration(declaration) ? Diagnostics._0_is_declared_but_never_used : Diagnostics._0_is_declared_but_its_value_is_never_read; + const message = isTypeDeclaration(declaration) ? Diagnostics._0_is_declared_but_never_used + : Diagnostics._0_is_declared_but_its_value_is_never_read; addDiagnostic(declaration, UnusedKind.Local, createDiagnosticForNode(node, message, name)); } @@ -38333,7 +49893,10 @@ namespace ts { return isIdentifier(node) && idText(node).charCodeAt(0) === CharacterCodes._; } - function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression, addDiagnostic: AddUnusedDiagnostic): void { + function checkUnusedClassMembers( + node: ClassDeclaration | ClassExpression, + addDiagnostic: AddUnusedDiagnostic, + ): void { for (const member of node.members) { switch (member.kind) { case SyntaxKind.MethodDeclaration: @@ -38347,16 +49910,35 @@ namespace ts { const symbol = getSymbolOfNode(member); if ( !symbol.isReferenced - && (hasEffectiveModifier(member, ModifierFlags.Private) || isNamedDeclaration(member) && isPrivateIdentifier(member.name)) + && (hasEffectiveModifier(member, ModifierFlags.Private) + || isNamedDeclaration(member) && isPrivateIdentifier(member.name)) && !(member.flags & NodeFlags.Ambient) ) { - addDiagnostic(member, UnusedKind.Local, createDiagnosticForNode(member.name!, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolToString(symbol))); + addDiagnostic( + member, + UnusedKind.Local, + createDiagnosticForNode( + member.name!, + Diagnostics._0_is_declared_but_its_value_is_never_read, + symbolToString(symbol), + ), + ); } break; case SyntaxKind.Constructor: for (const parameter of (member as ConstructorDeclaration).parameters) { - if (!parameter.symbol.isReferenced && hasSyntacticModifier(parameter, ModifierFlags.Private)) { - addDiagnostic(parameter, UnusedKind.Local, createDiagnosticForNode(parameter.name, Diagnostics.Property_0_is_declared_but_its_value_is_never_read, symbolName(parameter.symbol))); + if ( + !parameter.symbol.isReferenced && hasSyntacticModifier(parameter, ModifierFlags.Private) + ) { + addDiagnostic( + parameter, + UnusedKind.Local, + createDiagnosticForNode( + parameter.name, + Diagnostics.Property_0_is_declared_but_its_value_is_never_read, + symbolName(parameter.symbol), + ), + ); } } break; @@ -38374,11 +49956,22 @@ namespace ts { function checkUnusedInferTypeParameter(node: InferTypeNode, addDiagnostic: AddUnusedDiagnostic): void { const { typeParameter } = node; if (isTypeParameterUnused(typeParameter)) { - addDiagnostic(node, UnusedKind.Parameter, createDiagnosticForNode(node, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(typeParameter.name))); + addDiagnostic( + node, + UnusedKind.Parameter, + createDiagnosticForNode( + node, + Diagnostics._0_is_declared_but_its_value_is_never_read, + idText(typeParameter.name), + ), + ); } } - function checkUnusedTypeParameters(node: ClassLikeDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration, addDiagnostic: AddUnusedDiagnostic): void { + function checkUnusedTypeParameters( + node: ClassLikeDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration, + addDiagnostic: AddUnusedDiagnostic, + ): void { // Only report errors on the last declaration for the type parameter container; // this ensures that all uses have been accounted for. const declarations = getSymbolOfNode(node).declarations; @@ -38402,22 +49995,41 @@ namespace ts { : rangeOfTypeParameters(sourceFile, parent.typeParameters!); const only = parent.typeParameters!.length === 1; // TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag - const message = only ? Diagnostics._0_is_declared_but_its_value_is_never_read : Diagnostics.All_type_parameters_are_unused; + const message = only ? Diagnostics._0_is_declared_but_its_value_is_never_read + : Diagnostics.All_type_parameters_are_unused; const arg0 = only ? name : undefined; - addDiagnostic(typeParameter, UnusedKind.Parameter, createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, message, arg0)); + addDiagnostic( + typeParameter, + UnusedKind.Parameter, + createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, message, arg0), + ); } } else { // TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag - addDiagnostic(typeParameter, UnusedKind.Parameter, createDiagnosticForNode(typeParameter, Diagnostics._0_is_declared_but_its_value_is_never_read, name)); + addDiagnostic( + typeParameter, + UnusedKind.Parameter, + createDiagnosticForNode( + typeParameter, + Diagnostics._0_is_declared_but_its_value_is_never_read, + name, + ), + ); } } } function isTypeParameterUnused(typeParameter: TypeParameterDeclaration): boolean { - return !(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderscore(typeParameter.name); + return !(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) + && !isIdentifierThatStartsWithUnderscore(typeParameter.name); } - function addToGroup(map: ESMap, key: K, value: V, getKey: (key: K) => number | string): void { + function addToGroup( + map: ESMap, + key: K, + value: V, + getKey: (key: K) => number | string, + ): void { const keyString = String(getKey(key)); const group = map.get(keyString); if (group) { @@ -38443,8 +50055,10 @@ namespace ts { } return isIdentifierThatStartsWithUnderscore(declaration.name); } - return isAmbientModule(declaration) || - (isVariableDeclaration(declaration) && isForInOrOfStatement(declaration.parent.parent) || isImportedDeclaration(declaration)) && isIdentifierThatStartsWithUnderscore(declaration.name!); + return isAmbientModule(declaration) + || (isVariableDeclaration(declaration) && isForInOrOfStatement(declaration.parent.parent) + || isImportedDeclaration(declaration)) + && isIdentifierThatStartsWithUnderscore(declaration.name!); } function checkUnusedLocalsAndParameters(nodeWithLocals: Node, addDiagnostic: AddUnusedDiagnostic): void { @@ -38455,7 +50069,11 @@ namespace ts { nodeWithLocals.locals!.forEach(local => { // If it's purely a type parameter, ignore, will be checked in `checkUnusedTypeParameters`. // If it's a type parameter merged with a parameter, check if the parameter-side is used. - if (local.flags & SymbolFlags.TypeParameter ? !(local.flags & SymbolFlags.Variable && !(local.isReferenced! & SymbolFlags.Variable)) : local.isReferenced || local.exportSymbol) { + if ( + local.flags & SymbolFlags.TypeParameter + ? !(local.flags & SymbolFlags.Variable && !(local.isReferenced! & SymbolFlags.Variable)) + : local.isReferenced || local.exportSymbol + ) { return; } @@ -38479,15 +50097,27 @@ namespace ts { addToGroup(unusedVariables, declaration.parent, declaration, getNodeId); } else { - const parameter = local.valueDeclaration && tryGetRootParameterDeclaration(local.valueDeclaration); + const parameter = local.valueDeclaration + && tryGetRootParameterDeclaration(local.valueDeclaration); const name = local.valueDeclaration && getNameOfDeclaration(local.valueDeclaration); if (parameter && name) { - if (!isParameterPropertyDeclaration(parameter, parameter.parent) && !parameterIsThisKeyword(parameter) && !isIdentifierThatStartsWithUnderscore(name)) { + if ( + !isParameterPropertyDeclaration(parameter, parameter.parent) + && !parameterIsThisKeyword(parameter) && !isIdentifierThatStartsWithUnderscore(name) + ) { if (isBindingElement(declaration) && isArrayBindingPattern(declaration.parent)) { addToGroup(unusedDestructures, declaration.parent, declaration, getNodeId); } else { - addDiagnostic(parameter, UnusedKind.Parameter, createDiagnosticForNode(name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(local))); + addDiagnostic( + parameter, + UnusedKind.Parameter, + createDiagnosticForNode( + name, + Diagnostics._0_is_declared_but_its_value_is_never_read, + symbolName(local), + ), + ); } } } @@ -38500,17 +50130,25 @@ namespace ts { }); unusedImports.forEach(([importClause, unuseds]) => { const importDecl = importClause.parent; - const nDeclarations = (importClause.name ? 1 : 0) + - (importClause.namedBindings ? - (importClause.namedBindings.kind === SyntaxKind.NamespaceImport ? 1 : importClause.namedBindings.elements.length) + const nDeclarations = (importClause.name ? 1 : 0) + + (importClause.namedBindings + ? (importClause.namedBindings.kind === SyntaxKind.NamespaceImport ? 1 + : importClause.namedBindings.elements.length) : 0); if (nDeclarations === unuseds.length) { addDiagnostic( importDecl, UnusedKind.Local, unuseds.length === 1 - ? createDiagnosticForNode(importDecl, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(first(unuseds).name!)) - : createDiagnosticForNode(importDecl, Diagnostics.All_imports_in_import_declaration_are_unused), + ? createDiagnosticForNode( + importDecl, + Diagnostics._0_is_declared_but_its_value_is_never_read, + idText(first(unuseds).name!), + ) + : createDiagnosticForNode( + importDecl, + Diagnostics.All_imports_in_import_declaration_are_unused, + ), ); } else { @@ -38518,9 +50156,13 @@ namespace ts { } }); unusedDestructures.forEach(([bindingPattern, bindingElements]) => { - const kind = tryGetRootParameterDeclaration(bindingPattern.parent) ? UnusedKind.Parameter : UnusedKind.Local; + const kind = tryGetRootParameterDeclaration(bindingPattern.parent) ? UnusedKind.Parameter + : UnusedKind.Local; if (bindingPattern.elements.length === bindingElements.length) { - if (bindingElements.length === 1 && bindingPattern.parent.kind === SyntaxKind.VariableDeclaration && bindingPattern.parent.parent.kind === SyntaxKind.VariableDeclarationList) { + if ( + bindingElements.length === 1 && bindingPattern.parent.kind === SyntaxKind.VariableDeclaration + && bindingPattern.parent.parent.kind === SyntaxKind.VariableDeclarationList + ) { addToGroup(unusedVariables, bindingPattern.parent.parent, bindingPattern.parent, getNodeId); } else { @@ -38528,14 +50170,29 @@ namespace ts { bindingPattern, kind, bindingElements.length === 1 - ? createDiagnosticForNode(bindingPattern, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(first(bindingElements).name)) - : createDiagnosticForNode(bindingPattern, Diagnostics.All_destructured_elements_are_unused), + ? createDiagnosticForNode( + bindingPattern, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(first(bindingElements).name), + ) + : createDiagnosticForNode( + bindingPattern, + Diagnostics.All_destructured_elements_are_unused, + ), ); } } else { for (const e of bindingElements) { - addDiagnostic(e, kind, createDiagnosticForNode(e, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(e.name))); + addDiagnostic( + e, + kind, + createDiagnosticForNode( + e, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(e.name), + ), + ); } } }); @@ -38545,13 +50202,29 @@ namespace ts { declarationList, UnusedKind.Local, declarations.length === 1 - ? createDiagnosticForNode(first(declarations).name, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(first(declarations).name)) - : createDiagnosticForNode(declarationList.parent.kind === SyntaxKind.VariableStatement ? declarationList.parent : declarationList, Diagnostics.All_variables_are_unused), + ? createDiagnosticForNode( + first(declarations).name, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(first(declarations).name), + ) + : createDiagnosticForNode( + declarationList.parent.kind === SyntaxKind.VariableStatement ? declarationList.parent + : declarationList, + Diagnostics.All_variables_are_unused, + ), ); } else { for (const decl of declarations) { - addDiagnostic(decl, UnusedKind.Local, createDiagnosticForNode(decl, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(decl.name))); + addDiagnostic( + decl, + UnusedKind.Local, + createDiagnosticForNode( + decl, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(decl.name), + ), + ); } } }); @@ -38561,13 +50234,28 @@ namespace ts { for (const node of potentialUnusedRenamedBindingElementsInTypes) { if (!getSymbolOfNode(node)?.isReferenced) { const wrappingDeclaration = walkUpBindingElementsAndPatterns(node); - Debug.assert(isParameterDeclaration(wrappingDeclaration), "Only parameter declaration should be checked here"); - const diagnostic = createDiagnosticForNode(node.name, Diagnostics._0_is_an_unused_renaming_of_1_Did_you_intend_to_use_it_as_a_type_annotation, declarationNameToString(node.name), declarationNameToString(node.propertyName)); + Debug.assert( + isParameterDeclaration(wrappingDeclaration), + "Only parameter declaration should be checked here", + ); + const diagnostic = createDiagnosticForNode( + node.name, + Diagnostics._0_is_an_unused_renaming_of_1_Did_you_intend_to_use_it_as_a_type_annotation, + declarationNameToString(node.name), + declarationNameToString(node.propertyName), + ); if (!wrappingDeclaration.type) { // entire parameter does not have type annotation, suggest adding an annotation addRelatedInfo( diagnostic, - createFileDiagnostic(getSourceFileOfNode(wrappingDeclaration), wrappingDeclaration.end, 1, Diagnostics.We_can_only_write_a_type_for_0_by_adding_a_type_for_the_entire_parameter_here, declarationNameToString(node.propertyName)), + createFileDiagnostic( + getSourceFileOfNode(wrappingDeclaration), + wrappingDeclaration.end, + 1, + Diagnostics + .We_can_only_write_a_type_for_0_by_adding_a_type_for_the_entire_parameter_here, + declarationNameToString(node.propertyName), + ), ); } diagnostics.add(diagnostic); @@ -38589,10 +50277,12 @@ namespace ts { type ImportedDeclaration = ImportClause | ImportSpecifier | NamespaceImport; function isImportedDeclaration(node: Node): node is ImportedDeclaration { - return node.kind === SyntaxKind.ImportClause || node.kind === SyntaxKind.ImportSpecifier || node.kind === SyntaxKind.NamespaceImport; + return node.kind === SyntaxKind.ImportClause || node.kind === SyntaxKind.ImportSpecifier + || node.kind === SyntaxKind.NamespaceImport; } function importClauseFromImported(decl: ImportedDeclaration): ImportClause { - return decl.kind === SyntaxKind.ImportClause ? decl : decl.kind === SyntaxKind.NamespaceImport ? decl.parent : decl.parent.parent; + return decl.kind === SyntaxKind.ImportClause ? decl + : decl.kind === SyntaxKind.NamespaceImport ? decl.parent : decl.parent.parent; } function checkBlock(node: Block) { @@ -38615,13 +50305,21 @@ namespace ts { function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { // no rest parameters \ declaration context \ overload - no codegen impact - if (languageVersion >= ScriptTarget.ES2015 || !hasRestParameter(node) || node.flags & NodeFlags.Ambient || nodeIsMissing((node as FunctionLikeDeclaration).body)) { + if ( + languageVersion >= ScriptTarget.ES2015 || !hasRestParameter(node) || node.flags & NodeFlags.Ambient + || nodeIsMissing((node as FunctionLikeDeclaration).body) + ) { return; } forEach(node.parameters, p => { if (p.name && !isBindingPattern(p.name) && p.name.escapedText === argumentsSymbol.escapedName) { - errorSkippedOn("noEmit", p, Diagnostics.Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters); + errorSkippedOn( + "noEmit", + p, + Diagnostics + .Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters, + ); } }); } @@ -38631,19 +50329,23 @@ namespace ts { * of {@link name} in an outer scope. This is used to check for collisions for downlevel transformations that * require names like `Object`, `Promise`, `Reflect`, `require`, `exports`, etc. */ - function needCollisionCheckForIdentifier(node: Node, identifier: Identifier | undefined, name: string): boolean { + function needCollisionCheckForIdentifier( + node: Node, + identifier: Identifier | undefined, + name: string, + ): boolean { if (identifier?.escapedText !== name) { return false; } if ( - node.kind === SyntaxKind.PropertyDeclaration || - node.kind === SyntaxKind.PropertySignature || - node.kind === SyntaxKind.MethodDeclaration || - node.kind === SyntaxKind.MethodSignature || - node.kind === SyntaxKind.GetAccessor || - node.kind === SyntaxKind.SetAccessor || - node.kind === SyntaxKind.PropertyAssignment + node.kind === SyntaxKind.PropertyDeclaration + || node.kind === SyntaxKind.PropertySignature + || node.kind === SyntaxKind.MethodDeclaration + || node.kind === SyntaxKind.MethodSignature + || node.kind === SyntaxKind.GetAccessor + || node.kind === SyntaxKind.SetAccessor + || node.kind === SyntaxKind.PropertyAssignment ) { // it is ok to have member named '_super', '_this', `Promise`, etc. - member access is always qualified return false; @@ -38676,10 +50378,18 @@ namespace ts { if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureThis) { const isDeclaration = node.kind !== SyntaxKind.Identifier; if (isDeclaration) { - error(getNameOfDeclaration(node as Declaration), Diagnostics.Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference); + error( + getNameOfDeclaration(node as Declaration), + Diagnostics + .Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference, + ); } else { - error(node, Diagnostics.Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference); + error( + node, + Diagnostics + .Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference, + ); } return true; } @@ -38692,10 +50402,18 @@ namespace ts { if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureNewTarget) { const isDeclaration = node.kind !== SyntaxKind.Identifier; if (isDeclaration) { - error(getNameOfDeclaration(node as Declaration), Diagnostics.Duplicate_identifier_newTarget_Compiler_uses_variable_declaration_newTarget_to_capture_new_target_meta_property_reference); + error( + getNameOfDeclaration(node as Declaration), + Diagnostics + .Duplicate_identifier_newTarget_Compiler_uses_variable_declaration_newTarget_to_capture_new_target_meta_property_reference, + ); } else { - error(node, Diagnostics.Expression_resolves_to_variable_declaration_newTarget_that_compiler_uses_to_capture_new_target_meta_property_reference); + error( + node, + Diagnostics + .Expression_resolves_to_variable_declaration_newTarget_that_compiler_uses_to_capture_new_target_meta_property_reference, + ); } return true; } @@ -38705,11 +50423,19 @@ namespace ts { function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier | undefined) { // No need to check for require or exports for ES6 modules and later - if (moduleKind >= ModuleKind.ES2015 && !(moduleKind >= ModuleKind.Node16 && getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) { + if ( + moduleKind >= ModuleKind.ES2015 + && !(moduleKind >= ModuleKind.Node16 + && getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + ) { return; } - if (!name || !needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) { + if ( + !name + || !needCollisionCheckForIdentifier(node, name, "require") + && !needCollisionCheckForIdentifier(node, name, "exports") + ) { return; } @@ -38722,12 +50448,21 @@ namespace ts { const parent = getDeclarationContainer(node); if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile)) { // If the declaration happens to be in external module, report error that require and exports are reserved keywords - errorSkippedOn("noEmit", name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module, declarationNameToString(name), declarationNameToString(name)); + errorSkippedOn( + "noEmit", + name, + Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module, + declarationNameToString(name), + declarationNameToString(name), + ); } } function checkCollisionWithGlobalPromiseInGeneratedCode(node: Node, name: Identifier | undefined): void { - if (!name || languageVersion >= ScriptTarget.ES2017 || !needCollisionCheckForIdentifier(node, name, "Promise")) { + if ( + !name || languageVersion >= ScriptTarget.ES2017 + || !needCollisionCheckForIdentifier(node, name, "Promise") + ) { return; } @@ -38738,16 +50473,27 @@ namespace ts { // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent const parent = getDeclarationContainer(node); - if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile) && parent.flags & NodeFlags.HasAsyncFunctions) { + if ( + parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile) + && parent.flags & NodeFlags.HasAsyncFunctions + ) { // If the declaration happens to be in external module, report error that Promise is a reserved identifier. - errorSkippedOn("noEmit", name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module_containing_async_functions, declarationNameToString(name), declarationNameToString(name)); + errorSkippedOn( + "noEmit", + name, + Diagnostics + .Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module_containing_async_functions, + declarationNameToString(name), + declarationNameToString(name), + ); } } function recordPotentialCollisionWithWeakMapSetInGeneratedCode(node: Node, name: Identifier): void { if ( languageVersion <= ScriptTarget.ES2021 - && (needCollisionCheckForIdentifier(node, name, "WeakMap") || needCollisionCheckForIdentifier(node, name, "WeakSet")) + && (needCollisionCheckForIdentifier(node, name, "WeakMap") + || needCollisionCheckForIdentifier(node, name, "WeakSet")) ) { potentialWeakMapSetCollisions.push(node); } @@ -38756,8 +50502,16 @@ namespace ts { function checkWeakMapSetCollision(node: Node) { const enclosingBlockScope = getEnclosingBlockScopeContainer(node); if (getNodeCheckFlags(enclosingBlockScope) & NodeCheckFlags.ContainsClassWithPrivateIdentifiers) { - Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name) && typeof node.name.escapedText === "string", "The target of a WeakMap/WeakSet collision check should be an identifier"); - errorSkippedOn("noEmit", node, Diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, node.name.escapedText); + Debug.assert( + isNamedDeclaration(node) && isIdentifier(node.name) && typeof node.name.escapedText === "string", + "The target of a WeakMap/WeakSet collision check should be an identifier", + ); + errorSkippedOn( + "noEmit", + node, + Diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, + node.name.escapedText, + ); } } @@ -38789,13 +50543,25 @@ namespace ts { } else { const container = getEnclosingBlockScopeContainer(node); - if (container && getNodeCheckFlags(container) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer) { + if ( + container && getNodeCheckFlags(container) & NodeCheckFlags.ContainsSuperPropertyInStaticInitializer + ) { hasCollision = true; } } if (hasCollision) { - Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name), "The target of a Reflect collision check should be an identifier"); - errorSkippedOn("noEmit", node, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_when_emitting_super_references_in_static_initializers, declarationNameToString(node.name), "Reflect"); + Debug.assert( + isNamedDeclaration(node) && isIdentifier(node.name), + "The target of a Reflect collision check should be an identifier", + ); + errorSkippedOn( + "noEmit", + node, + Diagnostics + .Duplicate_identifier_0_Compiler_reserves_name_1_when_emitting_super_references_in_static_initializers, + declarationNameToString(node.name), + "Reflect", + ); } } @@ -38857,25 +50623,36 @@ namespace ts { const symbol = getSymbolOfNode(node); if (symbol.flags & SymbolFlags.FunctionScopedVariable) { if (!isIdentifier(node.name)) return Debug.fail(); - const localDeclarationSymbol = resolveName(node, node.name.escapedText, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); + const localDeclarationSymbol = resolveName( + node, + node.name.escapedText, + SymbolFlags.Variable, + /*nodeNotFoundErrorMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ); if ( - localDeclarationSymbol && - localDeclarationSymbol !== symbol && - localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable + localDeclarationSymbol + && localDeclarationSymbol !== symbol + && localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable ) { if (getDeclarationNodeFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) { - const varDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList)!; - const container = varDeclList.parent.kind === SyntaxKind.VariableStatement && varDeclList.parent.parent - ? varDeclList.parent.parent - : undefined; + const varDeclList = getAncestor( + localDeclarationSymbol.valueDeclaration, + SyntaxKind.VariableDeclarationList, + )!; + const container = + varDeclList.parent.kind === SyntaxKind.VariableStatement && varDeclList.parent.parent + ? varDeclList.parent.parent + : undefined; // names of block-scoped and function scoped variables can collide only // if block scoped variable is defined in the function\module\source file scope (because of variable hoisting) - const namesShareScope = container && - (container.kind === SyntaxKind.Block && isFunctionLike(container.parent) || - container.kind === SyntaxKind.ModuleBlock || - container.kind === SyntaxKind.ModuleDeclaration || - container.kind === SyntaxKind.SourceFile); + const namesShareScope = container + && (container.kind === SyntaxKind.Block && isFunctionLike(container.parent) + || container.kind === SyntaxKind.ModuleBlock + || container.kind === SyntaxKind.ModuleDeclaration + || container.kind === SyntaxKind.SourceFile); // here we know that function scoped variable is shadowed by block scoped one // if they are defined in the same scope - binder has already reported redeclaration error @@ -38883,7 +50660,13 @@ namespace ts { // since LHS will be block scoped name instead of function scoped if (!namesShareScope) { const name = symbolToString(localDeclarationSymbol); - error(node, Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name); + error( + node, + Diagnostics + .Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, + name, + name, + ); } } } @@ -38895,7 +50678,9 @@ namespace ts { } // Check variable, parameter, or property declaration - function checkVariableLikeDeclaration(node: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement) { + function checkVariableLikeDeclaration( + node: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement, + ) { checkDecorators(node); if (!isBindingElement(node)) { checkSourceElement(node.type); @@ -38919,10 +50704,10 @@ namespace ts { if (isBindingElement(node)) { if ( - node.propertyName && - isIdentifier(node.name) && - isParameterDeclaration(node) && - nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body) + node.propertyName + && isIdentifier(node.name) + && isParameterDeclaration(node) + && nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body) ) { // type F = ({a: string}) => void; // ^^^^^^ @@ -38932,7 +50717,9 @@ namespace ts { return; } - if (isObjectBindingPattern(node.parent) && node.dotDotDotToken && languageVersion < ScriptTarget.ES2018) { + if ( + isObjectBindingPattern(node.parent) && node.dotDotDotToken && languageVersion < ScriptTarget.ES2018 + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Rest); } // check computed properties inside property names of binding elements @@ -38951,8 +50738,18 @@ namespace ts { const nameText = getPropertyNameFromType(exprType); const property = getPropertyOfType(parentType, nameText); if (property) { - markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isSelfTypeAccess*/ false); // A destructuring is never a write-only reference. - checkPropertyAccessibility(node, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, /*writing*/ false, parentType, property); + markPropertyAsReferenced( + property, + /*nodeForCheckWriteOnly*/ undefined, + /*isSelfTypeAccess*/ false, + ); // A destructuring is never a write-only reference. + checkPropertyAccessibility( + node, + !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, + /*writing*/ false, + parentType, + property, + ); } } } @@ -38960,20 +50757,30 @@ namespace ts { // For a binding pattern, check contained binding elements if (isBindingPattern(node.name)) { - if (node.name.kind === SyntaxKind.ArrayBindingPattern && languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) { + if ( + node.name.kind === SyntaxKind.ArrayBindingPattern && languageVersion < ScriptTarget.ES2015 + && compilerOptions.downlevelIteration + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Read); } forEach(node.name.elements, checkSourceElement); } // For a parameter declaration with an initializer, error and exit if the containing function doesn't have a body - if (isParameter(node) && node.initializer && nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body)) { - error(node, Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation); + if ( + isParameter(node) && node.initializer + && nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body) + ) { + error( + node, + Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation, + ); return; } // For a binding pattern, validate the initializer and exit if (isBindingPattern(node.name)) { - const needCheckInitializer = hasOnlyExpressionInitializer(node) && node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement; + const needCheckInitializer = hasOnlyExpressionInitializer(node) && node.initializer + && node.parent.parent.kind !== SyntaxKind.ForInStatement; const needCheckWidenedType = !some(node.name.elements, not(isOmittedExpression)); if (needCheckInitializer || needCheckWidenedType) { // Don't validate for-in initializer as it is already an error @@ -38984,13 +50791,23 @@ namespace ts { checkNonNullNonVoidType(initializerType, node); } else { - checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer); + checkTypeAssignableToAndOptionallyElaborate( + initializerType, + getWidenedTypeForVariableLikeDeclaration(node), + node, + node.initializer, + ); } } // check the binding pattern with empty elements if (needCheckWidenedType) { if (isArrayBindingPattern(node.name)) { - checkIteratedTypeOrElementType(IterationUse.Destructuring, widenedType, undefinedType, node); + checkIteratedTypeOrElementType( + IterationUse.Destructuring, + widenedType, + undefinedType, + node, + ); } else if (strictNullChecks) { checkNonNullNonVoidType(widenedType, node); @@ -39001,7 +50818,12 @@ namespace ts { } // For a commonjs `const x = require`, validate the alias and exit const symbol = getSymbolOfNode(node); - if (symbol.flags & SymbolFlags.Alias && isVariableDeclarationInitializedToBareOrAccessedRequire(node.kind === SyntaxKind.BindingElement ? node.parent.parent : node)) { + if ( + symbol.flags & SymbolFlags.Alias + && isVariableDeclarationInitializedToBareOrAccessedRequire( + node.kind === SyntaxKind.BindingElement ? node.parent.parent : node, + ) + ) { checkAliasSymbol(node as BindingElement | VariableDeclaration); return; } @@ -39012,17 +50834,32 @@ namespace ts { // Don't validate for-in initializer as it is already an error const initializer = hasOnlyExpressionInitializer(node) && getEffectiveInitializer(node); if (initializer) { - const isJSObjectLiteralInitializer = isInJSFile(node) && - isObjectLiteralExpression(initializer) && - (initializer.properties.length === 0 || isPrototypeAccess(node.name)) && - !!symbol.exports?.size; + const isJSObjectLiteralInitializer = isInJSFile(node) + && isObjectLiteralExpression(initializer) + && (initializer.properties.length === 0 || isPrototypeAccess(node.name)) + && !!symbol.exports?.size; if (!isJSObjectLiteralInitializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) { - checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(initializer), type, node, initializer, /*headMessage*/ undefined); + checkTypeAssignableToAndOptionallyElaborate( + checkExpressionCached(initializer), + type, + node, + initializer, + /*headMessage*/ undefined, + ); } } if (symbol.declarations && symbol.declarations.length > 1) { - if (some(symbol.declarations, d => d !== node && isVariableLike(d) && !areDeclarationFlagsIdentical(d, node))) { - error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); + if ( + some( + symbol.declarations, + d => d !== node && isVariableLike(d) && !areDeclarationFlagsIdentical(d, node), + ) + ) { + error( + node.name, + Diagnostics.All_declarations_of_0_must_have_identical_modifiers, + declarationNameToString(node.name), + ); } } } @@ -39032,17 +50869,32 @@ namespace ts { const declarationType = convertAutoToAny(getWidenedTypeForVariableLikeDeclaration(node)); if ( - !isErrorType(type) && !isErrorType(declarationType) && - !isTypeIdenticalTo(type, declarationType) && - !(symbol.flags & SymbolFlags.Assignment) + !isErrorType(type) && !isErrorType(declarationType) + && !isTypeIdenticalTo(type, declarationType) + && !(symbol.flags & SymbolFlags.Assignment) ) { - errorNextVariableOrPropertyDeclarationMustHaveSameType(symbol.valueDeclaration, type, node, declarationType); + errorNextVariableOrPropertyDeclarationMustHaveSameType( + symbol.valueDeclaration, + type, + node, + declarationType, + ); } if (hasOnlyExpressionInitializer(node) && node.initializer) { - checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(node.initializer), declarationType, node, node.initializer, /*headMessage*/ undefined); + checkTypeAssignableToAndOptionallyElaborate( + checkExpressionCached(node.initializer), + declarationType, + node, + node.initializer, + /*headMessage*/ undefined, + ); } if (symbol.valueDeclaration && !areDeclarationFlagsIdentical(node, symbol.valueDeclaration)) { - error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); + error( + node.name, + Diagnostics.All_declarations_of_0_must_have_identical_modifiers, + declarationNameToString(node.name), + ); } } if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature) { @@ -39055,11 +50907,19 @@ namespace ts { } } - function errorNextVariableOrPropertyDeclarationMustHaveSameType(firstDeclaration: Declaration | undefined, firstType: Type, nextDeclaration: Declaration, nextType: Type): void { + function errorNextVariableOrPropertyDeclarationMustHaveSameType( + firstDeclaration: Declaration | undefined, + firstType: Type, + nextDeclaration: Declaration, + nextType: Type, + ): void { const nextDeclarationName = getNameOfDeclaration(nextDeclaration); - const message = nextDeclaration.kind === SyntaxKind.PropertyDeclaration || nextDeclaration.kind === SyntaxKind.PropertySignature - ? Diagnostics.Subsequent_property_declarations_must_have_the_same_type_Property_0_must_be_of_type_1_but_here_has_type_2 - : Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2; + const message = nextDeclaration.kind === SyntaxKind.PropertyDeclaration + || nextDeclaration.kind === SyntaxKind.PropertySignature + ? Diagnostics + .Subsequent_property_declarations_must_have_the_same_type_Property_0_must_be_of_type_1_but_here_has_type_2 + : Diagnostics + .Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2; const declName = declarationNameToString(nextDeclarationName); const err = error( nextDeclarationName, @@ -39069,14 +50929,17 @@ namespace ts { typeToString(nextType), ); if (firstDeclaration) { - addRelatedInfo(err, createDiagnosticForNode(firstDeclaration, Diagnostics._0_was_also_declared_here, declName)); + addRelatedInfo( + err, + createDiagnosticForNode(firstDeclaration, Diagnostics._0_was_also_declared_here, declName), + ); } } function areDeclarationFlagsIdentical(left: Declaration, right: Declaration) { if ( - (left.kind === SyntaxKind.Parameter && right.kind === SyntaxKind.VariableDeclaration) || - (left.kind === SyntaxKind.VariableDeclaration && right.kind === SyntaxKind.Parameter) + (left.kind === SyntaxKind.Parameter && right.kind === SyntaxKind.VariableDeclaration) + || (left.kind === SyntaxKind.VariableDeclaration && right.kind === SyntaxKind.Parameter) ) { // Differences in optionality between parameters and variables are allowed. return true; @@ -39086,18 +50949,24 @@ namespace ts { return false; } - const interestingFlags = ModifierFlags.Private | - ModifierFlags.Protected | - ModifierFlags.Async | - ModifierFlags.Abstract | - ModifierFlags.Readonly | - ModifierFlags.Static; + const interestingFlags = ModifierFlags.Private + | ModifierFlags.Protected + | ModifierFlags.Async + | ModifierFlags.Abstract + | ModifierFlags.Readonly + | ModifierFlags.Static; - return getSelectedEffectiveModifierFlags(left, interestingFlags) === getSelectedEffectiveModifierFlags(right, interestingFlags); + return getSelectedEffectiveModifierFlags(left, interestingFlags) + === getSelectedEffectiveModifierFlags(right, interestingFlags); } function checkVariableDeclaration(node: VariableDeclaration) { - tracing?.push(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); + tracing?.push(tracing.Phase.Check, "checkVariableDeclaration", { + kind: node.kind, + pos: node.pos, + end: node.end, + path: (node as TracingNode).tracingPath, + }); checkGrammarVariableDeclaration(node); checkVariableLikeDeclaration(node); tracing?.pop(); @@ -39110,7 +50979,9 @@ namespace ts { function checkVariableStatement(node: VariableStatement) { // Grammar checking - if (!checkGrammarDecoratorsAndModifiers(node) && !checkGrammarVariableDeclarationList(node.declarationList)) checkGrammarForDisallowedLetOrConstStatement(node); + if ( + !checkGrammarDecoratorsAndModifiers(node) && !checkGrammarVariableDeclarationList(node.declarationList) + ) checkGrammarForDisallowedLetOrConstStatement(node); forEach(node.declarationList.declarations, checkSourceElement); } @@ -39135,7 +51006,11 @@ namespace ts { checkSourceElement(node.elseStatement); } - function checkTestingKnownTruthyCallableOrAwaitableType(condExpr: Expression, condType: Type, body?: Statement | Expression) { + function checkTestingKnownTruthyCallableOrAwaitableType( + condExpr: Expression, + condType: Type, + body?: Statement | Expression, + ) { if (!strictNullChecks) return; helper(condExpr, body); @@ -39145,13 +51020,15 @@ namespace ts { } function helper(condExpr: Expression, body: Expression | Statement | undefined) { - const location = isBinaryExpression(condExpr) && - (condExpr.operatorToken.kind === SyntaxKind.BarBarToken || condExpr.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) + const location = isBinaryExpression(condExpr) + && (condExpr.operatorToken.kind === SyntaxKind.BarBarToken + || condExpr.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) ? condExpr.right : condExpr; if (isModuleExportsAccessExpression(location)) return; const type = location === condExpr ? condType : checkTruthinessExpression(location); - const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression); + const isPropertyExpressionCast = isPropertyAccessExpression(location) + && isTypeAssertion(location.expression); if (!(getTypeFacts(type) & TypeFacts.Truthy) || isPropertyExpressionCast) return; // While it technically should be invalid for any known-truthy value @@ -39174,7 +51051,8 @@ namespace ts { return; } - const isUsed = testedSymbol && isBinaryExpression(condExpr.parent) && isSymbolUsedInBinaryExpressionChain(condExpr.parent, testedSymbol) + const isUsed = testedSymbol && isBinaryExpression(condExpr.parent) + && isSymbolUsedInBinaryExpressionChain(condExpr.parent, testedSymbol) || testedSymbol && body && isSymbolUsedInConditionBody(condExpr, body, testedNode, testedSymbol); if (!isUsed) { if (isPromise) { @@ -39186,13 +51064,22 @@ namespace ts { ); } else { - error(location, Diagnostics.This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead); + error( + location, + Diagnostics + .This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead, + ); } } } } - function isSymbolUsedInConditionBody(expr: Expression, body: Statement | Expression, testedNode: Node, testedSymbol: Symbol): boolean { + function isSymbolUsedInConditionBody( + expr: Expression, + body: Statement | Expression, + testedNode: Node, + testedSymbol: Symbol, + ): boolean { return !!forEachChild(body, function check(childNode): boolean | undefined { if (isIdentifier(childNode)) { const childSymbol = getSymbolAtLocation(childNode); @@ -39206,13 +51093,20 @@ namespace ts { let childExpression = childNode.parent; while (testedExpression && childExpression) { if ( - isIdentifier(testedExpression) && isIdentifier(childExpression) || - testedExpression.kind === SyntaxKind.ThisKeyword && childExpression.kind === SyntaxKind.ThisKeyword + isIdentifier(testedExpression) && isIdentifier(childExpression) + || testedExpression.kind === SyntaxKind.ThisKeyword + && childExpression.kind === SyntaxKind.ThisKeyword ) { return getSymbolAtLocation(testedExpression) === getSymbolAtLocation(childExpression); } - else if (isPropertyAccessExpression(testedExpression) && isPropertyAccessExpression(childExpression)) { - if (getSymbolAtLocation(testedExpression.name) !== getSymbolAtLocation(childExpression.name)) { + else if ( + isPropertyAccessExpression(testedExpression) + && isPropertyAccessExpression(childExpression) + ) { + if ( + getSymbolAtLocation(testedExpression.name) + !== getSymbolAtLocation(childExpression.name) + ) { return false; } childExpression = childExpression.expression; @@ -39309,11 +51203,17 @@ namespace ts { const container = getContainingFunctionOrClassStaticBlock(node); if (node.awaitModifier) { if (container && isClassStaticBlockDeclaration(container)) { - grammarErrorOnNode(node.awaitModifier, Diagnostics.For_await_loops_cannot_be_used_inside_a_class_static_block); + grammarErrorOnNode( + node.awaitModifier, + Diagnostics.For_await_loops_cannot_be_used_inside_a_class_static_block, + ); } else { const functionFlags = getFunctionFlags(container); - if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Async)) === FunctionFlags.Async && languageVersion < ScriptTarget.ESNext) { + if ( + (functionFlags & (FunctionFlags.Invalid | FunctionFlags.Async)) === FunctionFlags.Async + && languageVersion < ScriptTarget.ESNext + ) { // for..await..of in an async function or async generator function prior to ESNext requires the __asyncValues helper checkExternalEmitHelpers(node, ExternalEmitHelpers.ForAwaitOfIncludes); } @@ -39337,7 +51237,10 @@ namespace ts { const iteratedType = checkRightHandSideOfForOf(node); // There may be a destructuring assignment on the left side - if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { + if ( + varExpr.kind === SyntaxKind.ArrayLiteralExpression + || varExpr.kind === SyntaxKind.ObjectLiteralExpression + ) { // iteratedType may be undefined. In this case, we still want to check the structure of // varExpr, in particular making sure it's a valid LeftHandSideExpression. But we'd like // to short circuit the type relation checking as much as possible, so we pass the unknownType. @@ -39380,7 +51283,10 @@ namespace ts { if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { const variable = (node.initializer as VariableDeclarationList).declarations[0]; if (variable && isBindingPattern(variable.name)) { - error(variable.name, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); + error( + variable.name, + Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern, + ); } checkForInOrForOfVariableDeclaration(node); } @@ -39391,8 +51297,14 @@ namespace ts { // and Expr must be an expression of type Any, an object type, or a type parameter type. const varExpr = node.initializer; const leftType = checkExpression(varExpr); - if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { - error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); + if ( + varExpr.kind === SyntaxKind.ArrayLiteralExpression + || varExpr.kind === SyntaxKind.ObjectLiteralExpression + ) { + error( + varExpr, + Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern, + ); } else if (!isTypeAssignableTo(getIndexTypeOrString(rightType), leftType)) { error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any); @@ -39409,8 +51321,16 @@ namespace ts { // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved // in this case error about missing name is already reported - do not report extra one - if (rightType === neverType || !isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { - error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter_but_here_has_type_0, typeToString(rightType)); + if ( + rightType === neverType + || !isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) + ) { + error( + node.expression, + Diagnostics + .The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter_but_here_has_type_0, + typeToString(rightType), + ); } checkSourceElement(node.statement); @@ -39430,14 +51350,25 @@ namespace ts { function checkRightHandSideOfForOf(statement: ForOfStatement): Type { const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf; - return checkIteratedTypeOrElementType(use, checkNonNullExpression(statement.expression), undefinedType, statement.expression); + return checkIteratedTypeOrElementType( + use, + checkNonNullExpression(statement.expression), + undefinedType, + statement.expression, + ); } - function checkIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined): Type { + function checkIteratedTypeOrElementType( + use: IterationUse, + inputType: Type, + sentType: Type, + errorNode: Node | undefined, + ): Type { if (isTypeAny(inputType)) { return inputType; } - return getIteratedTypeOrElementType(use, inputType, sentType, errorNode, /*checkAssignability*/ true) || anyType; + return getIteratedTypeOrElementType(use, inputType, sentType, errorNode, /*checkAssignability*/ true) + || anyType; } /** @@ -39445,7 +51376,13 @@ namespace ts { * we want to get the iterated type of an iterable for ES2015 or later, or the iterated type * of a iterable (if defined globally) or element type of an array like for ES2015 or earlier. */ - function getIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined, checkAssignability: boolean): Type | undefined { + function getIteratedTypeOrElementType( + use: IterationUse, + inputType: Type, + sentType: Type, + errorNode: Node | undefined, + checkAssignability: boolean, + ): Type | undefined { const allowAsyncIterables = (use & IterationUse.AllowsAsyncIterablesFlag) !== 0; if (inputType === neverType) { reportTypeNotIterableError(errorNode!, inputType, allowAsyncIterables); // TODO: GH#18217 @@ -39454,28 +51391,43 @@ namespace ts { const uplevelIteration = languageVersion >= ScriptTarget.ES2015; const downlevelIteration = !uplevelIteration && compilerOptions.downlevelIteration; - const possibleOutOfBounds = compilerOptions.noUncheckedIndexedAccess && !!(use & IterationUse.PossiblyOutOfBounds); + const possibleOutOfBounds = compilerOptions.noUncheckedIndexedAccess + && !!(use & IterationUse.PossiblyOutOfBounds); // Get the iterated type of an `Iterable` or `IterableIterator` only in ES2015 // or higher, when inside of an async generator or for-await-if, or when // downlevelIteration is requested. if (uplevelIteration || downlevelIteration || allowAsyncIterables) { // We only report errors for an invalid iterable type in ES2015 or higher. - const iterationTypes = getIterationTypesOfIterable(inputType, use, uplevelIteration ? errorNode : undefined); + const iterationTypes = getIterationTypesOfIterable( + inputType, + use, + uplevelIteration ? errorNode : undefined, + ); if (checkAssignability) { if (iterationTypes) { - const diagnostic = use & IterationUse.ForOfFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_for_of_will_always_send_0 : - use & IterationUse.SpreadFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_spread_will_always_send_0 : - use & IterationUse.DestructuringFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_destructuring_will_always_send_0 : - use & IterationUse.YieldStarFlag ? Diagnostics.Cannot_delegate_iteration_to_value_because_the_next_method_of_its_iterator_expects_type_1_but_the_containing_generator_will_always_send_0 : - undefined; + const diagnostic = use & IterationUse.ForOfFlag + ? Diagnostics + .Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_for_of_will_always_send_0 + : use & IterationUse.SpreadFlag + ? Diagnostics + .Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_spread_will_always_send_0 + : use & IterationUse.DestructuringFlag + ? Diagnostics + .Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_destructuring_will_always_send_0 + : use & IterationUse.YieldStarFlag + ? Diagnostics + .Cannot_delegate_iteration_to_value_because_the_next_method_of_its_iterator_expects_type_1_but_the_containing_generator_will_always_send_0 + : undefined; if (diagnostic) { checkTypeAssignableTo(sentType, iterationTypes.nextType, errorNode, diagnostic); } } } if (iterationTypes || uplevelIteration) { - return possibleOutOfBounds ? includeUndefinedInIndexSignature(iterationTypes && iterationTypes.yieldType) : (iterationTypes && iterationTypes.yieldType); + return possibleOutOfBounds + ? includeUndefinedInIndexSignature(iterationTypes && iterationTypes.yieldType) + : (iterationTypes && iterationTypes.yieldType); } } @@ -39504,7 +51456,11 @@ namespace ts { if (hasStringConstituent) { if (languageVersion < ScriptTarget.ES5) { if (errorNode) { - error(errorNode, Diagnostics.Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher); + error( + errorNode, + Diagnostics + .Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher, + ); reportedError = true; } } @@ -39525,7 +51481,10 @@ namespace ts { // number and string input is allowed, we want to say that number is not an // array type or a string type. const allowsStrings = !!(use & IterationUse.AllowsStringInputFlag) && !hasStringConstituent; - const [defaultDiagnostic, maybeMissingAwait] = getIterationDiagnosticDetails(allowsStrings, downlevelIteration); + const [defaultDiagnostic, maybeMissingAwait] = getIterationDiagnosticDetails( + allowsStrings, + downlevelIteration, + ); errorAndMaybeSuggestAwait( errorNode, maybeMissingAwait && !!getAwaitedTypeOfPromise(arrayType), @@ -39533,7 +51492,8 @@ namespace ts { typeToString(arrayType), ); } - return hasStringConstituent ? possibleOutOfBounds ? includeUndefinedInIndexSignature(stringType) : stringType : undefined; + return hasStringConstituent + ? possibleOutOfBounds ? includeUndefinedInIndexSignature(stringType) : stringType : undefined; } const arrayElementType = getIndexTypeOfType(arrayType, numberType); @@ -39543,26 +51503,55 @@ namespace ts { return stringType; } - return getUnionType(possibleOutOfBounds ? [arrayElementType, stringType, undefinedType] : [arrayElementType, stringType], UnionReduction.Subtype); + return getUnionType( + possibleOutOfBounds ? [arrayElementType, stringType, undefinedType] + : [arrayElementType, stringType], + UnionReduction.Subtype, + ); } - return (use & IterationUse.PossiblyOutOfBounds) ? includeUndefinedInIndexSignature(arrayElementType) : arrayElementType; + return (use & IterationUse.PossiblyOutOfBounds) ? includeUndefinedInIndexSignature(arrayElementType) + : arrayElementType; - function getIterationDiagnosticDetails(allowsStrings: boolean, downlevelIteration: boolean | undefined): [error: DiagnosticMessage, maybeMissingAwait: boolean] { + function getIterationDiagnosticDetails( + allowsStrings: boolean, + downlevelIteration: boolean | undefined, + ): [error: DiagnosticMessage, maybeMissingAwait: boolean] { if (downlevelIteration) { return allowsStrings - ? [Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, true] - : [Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, true]; + ? [ + Diagnostics + .Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, + true, + ] + : [ + Diagnostics + .Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, + true, + ]; } - const yieldType = getIterationTypeOfIterable(use, IterationTypeKind.Yield, inputType, /*errorNode*/ undefined); + const yieldType = getIterationTypeOfIterable( + use, + IterationTypeKind.Yield, + inputType, + /*errorNode*/ undefined, + ); if (yieldType) { - return [Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, false]; + return [ + Diagnostics + .Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, + false, + ]; } if (isES2015OrLaterIterable(inputType.symbol?.escapedName)) { - return [Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, true]; + return [ + Diagnostics + .Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, + true, + ]; } return allowsStrings @@ -39591,7 +51580,12 @@ namespace ts { /** * Gets the requested "iteration type" from an `Iterable`-like or `AsyncIterable`-like type. */ - function getIterationTypeOfIterable(use: IterationUse, typeKind: IterationTypeKind, inputType: Type, errorNode: Node | undefined): Type | undefined { + function getIterationTypeOfIterable( + use: IterationUse, + typeKind: IterationTypeKind, + inputType: Type, + errorNode: Node | undefined, + ): Type | undefined { if (isTypeAny(inputType)) { return undefined; } @@ -39600,7 +51594,11 @@ namespace ts { return iterationTypes && iterationTypes[getIterationTypesKeyFromIterationTypeKind(typeKind)]; } - function createIterationTypes(yieldType: Type = neverType, returnType: Type = neverType, nextType: Type = unknownType): IterationTypes { + function createIterationTypes( + yieldType: Type = neverType, + returnType: Type = neverType, + nextType: Type = unknownType, + ): IterationTypes { // `yieldType` and `returnType` are defaulted to `neverType` they each will be combined // via `getUnionType` when merging iteration types. `nextType` is defined as `unknownType` // as it is combined via `getIntersectionType` when merging iteration types. @@ -39610,9 +51608,11 @@ namespace ts { // are also cached on the type they are requested for, so we shouldn't need to maintain // the cache for less-frequently used types. if ( - yieldType.flags & TypeFlags.Intrinsic && - returnType.flags & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) && - nextType.flags & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) + yieldType.flags & TypeFlags.Intrinsic + && returnType.flags + & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) + && nextType.flags + & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) ) { const id = getTypeListId([yieldType, returnType, nextType]); let iterationTypes = iterationTypesCache.get(id); @@ -39657,11 +51657,18 @@ namespace ts { return noIterationTypes; } - function getCachedIterationTypes(type: Type, cacheKey: MatchingKeys) { + function getCachedIterationTypes( + type: Type, + cacheKey: MatchingKeys, + ) { return (type as IterableOrIteratorType)[cacheKey]; } - function setCachedIterationTypes(type: Type, cacheKey: MatchingKeys, cachedTypes: IterationTypes) { + function setCachedIterationTypes( + type: Type, + cacheKey: MatchingKeys, + cachedTypes: IterationTypes, + ) { return (type as IterableOrIteratorType)[cacheKey] = cachedTypes; } @@ -39692,11 +51699,16 @@ namespace ts { } if (!(type.flags & TypeFlags.Union)) { - const errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined = errorNode ? { errors: undefined } : undefined; + const errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined = errorNode + ? { errors: undefined } : undefined; const iterationTypes = getIterationTypesOfIterableWorker(type, use, errorNode, errorOutputContainer); if (iterationTypes === noIterationTypes) { if (errorNode) { - const rootDiag = reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag)); + const rootDiag = reportTypeNotIterableError( + errorNode, + type, + !!(use & IterationUse.AllowsAsyncIterablesFlag), + ); if (errorOutputContainer?.errors) { addRelatedInfo(rootDiag, ...errorOutputContainer.errors); } @@ -39711,17 +51723,28 @@ namespace ts { return iterationTypes; } - const cacheKey = use & IterationUse.AllowsAsyncIterablesFlag ? "iterationTypesOfAsyncIterable" : "iterationTypesOfIterable"; + const cacheKey = use & IterationUse.AllowsAsyncIterablesFlag ? "iterationTypesOfAsyncIterable" + : "iterationTypesOfIterable"; const cachedTypes = getCachedIterationTypes(type, cacheKey); if (cachedTypes) return cachedTypes === noIterationTypes ? undefined : cachedTypes; let allIterationTypes: IterationTypes[] | undefined; for (const constituent of (type as UnionType).types) { - const errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined = errorNode ? { errors: undefined } : undefined; - const iterationTypes = getIterationTypesOfIterableWorker(constituent, use, errorNode, errorOutputContainer); + const errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined = errorNode + ? { errors: undefined } : undefined; + const iterationTypes = getIterationTypesOfIterableWorker( + constituent, + use, + errorNode, + errorOutputContainer, + ); if (iterationTypes === noIterationTypes) { if (errorNode) { - const rootDiag = reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag)); + const rootDiag = reportTypeNotIterableError( + errorNode, + type, + !!(use & IterationUse.AllowsAsyncIterablesFlag), + ); if (errorOutputContainer?.errors) { addRelatedInfo(rootDiag, ...errorOutputContainer.errors); } @@ -39768,7 +51791,12 @@ namespace ts { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterable` instead. */ - function getIterationTypesOfIterableWorker(type: Type, use: IterationUse, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined) { + function getIterationTypesOfIterableWorker( + type: Type, + use: IterationUse, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + ) { if (isTypeAny(type)) { return anyIterationTypes; } @@ -39778,24 +51806,24 @@ namespace ts { let noCache = false; if (use & IterationUse.AllowsAsyncIterablesFlag) { - const iterationTypes = getIterationTypesOfIterableCached(type, asyncIterationTypesResolver) || - getIterationTypesOfIterableFast(type, asyncIterationTypesResolver); + const iterationTypes = getIterationTypesOfIterableCached(type, asyncIterationTypesResolver) + || getIterationTypesOfIterableFast(type, asyncIterationTypesResolver); if (iterationTypes) { if (iterationTypes === noIterationTypes && errorNode) { // ignore the cached value noCache = true; } else { - return use & IterationUse.ForOfFlag ? - getAsyncFromSyncIterationTypes(iterationTypes, errorNode) : - iterationTypes; + return use & IterationUse.ForOfFlag + ? getAsyncFromSyncIterationTypes(iterationTypes, errorNode) + : iterationTypes; } } } if (use & IterationUse.AllowsSyncIterablesFlag) { - let iterationTypes = getIterationTypesOfIterableCached(type, syncIterationTypesResolver) || - getIterationTypesOfIterableFast(type, syncIterationTypesResolver); + let iterationTypes = getIterationTypesOfIterableCached(type, syncIterationTypesResolver) + || getIterationTypesOfIterableFast(type, syncIterationTypesResolver); if (iterationTypes) { if (iterationTypes === noIterationTypes && errorNode) { // ignore the cached value @@ -39806,7 +51834,8 @@ namespace ts { // for a sync iterable in an async context, only use the cached types if they are valid. if (iterationTypes !== noIterationTypes) { iterationTypes = getAsyncFromSyncIterationTypes(iterationTypes, errorNode); - return noCache ? iterationTypes : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); + return noCache ? iterationTypes + : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); } } else { @@ -39817,18 +51846,31 @@ namespace ts { } if (use & IterationUse.AllowsAsyncIterablesFlag) { - const iterationTypes = getIterationTypesOfIterableSlow(type, asyncIterationTypesResolver, errorNode, errorOutputContainer, noCache); + const iterationTypes = getIterationTypesOfIterableSlow( + type, + asyncIterationTypesResolver, + errorNode, + errorOutputContainer, + noCache, + ); if (iterationTypes !== noIterationTypes) { return iterationTypes; } } if (use & IterationUse.AllowsSyncIterablesFlag) { - let iterationTypes = getIterationTypesOfIterableSlow(type, syncIterationTypesResolver, errorNode, errorOutputContainer, noCache); + let iterationTypes = getIterationTypesOfIterableSlow( + type, + syncIterationTypesResolver, + errorNode, + errorOutputContainer, + noCache, + ); if (iterationTypes !== noIterationTypes) { if (use & IterationUse.AllowsAsyncIterablesFlag) { iterationTypes = getAsyncFromSyncIterationTypes(iterationTypes, errorNode); - return noCache ? iterationTypes : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); + return noCache ? iterationTypes + : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); } else { return iterationTypes; @@ -39851,8 +51893,14 @@ namespace ts { } function getIterationTypesOfGlobalIterableType(globalType: Type, resolver: IterationTypesResolver) { - const globalIterationTypes = getIterationTypesOfIterableCached(globalType, resolver) || - getIterationTypesOfIterableSlow(globalType, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined, /*noCache*/ false); + const globalIterationTypes = getIterationTypesOfIterableCached(globalType, resolver) + || getIterationTypesOfIterableSlow( + globalType, + resolver, + /*errorNode*/ undefined, + /*errorOutputContainer*/ undefined, + /*noCache*/ false, + ); return globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes; } @@ -39875,8 +51923,8 @@ namespace ts { // - `IterableIterator` or `AsyncIterableIterator` let globalType: Type; if ( - isReferenceToType(type, globalType = resolver.getGlobalIterableType(/*reportErrors*/ false)) || - isReferenceToType(type, globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false)) + isReferenceToType(type, globalType = resolver.getGlobalIterableType(/*reportErrors*/ false)) + || isReferenceToType(type, globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false)) ) { const [yieldType] = getTypeArguments(type as GenericType); // The "return" and "next" types of `Iterable` and `IterableIterator` are defined by the @@ -39884,7 +51932,15 @@ namespace ts { // While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use // different definitions. const { returnType, nextType } = getIterationTypesOfGlobalIterableType(globalType, resolver); - return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, nextType)); + return setCachedIterationTypes( + type, + resolver.iterableCacheKey, + createIterationTypes( + resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, + resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, + nextType, + ), + ); } // As an optimization, if the type is an instantiation of the following global type, then @@ -39892,14 +51948,24 @@ namespace ts { // - `Generator` or `AsyncGenerator` if (isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) { const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); - return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, nextType)); + return setCachedIterationTypes( + type, + resolver.iterableCacheKey, + createIterationTypes( + resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, + resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, + nextType, + ), + ); } } function getPropertyNameForKnownSymbolName(symbolName: string): __String { const ctorType = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false); - const uniqueType = ctorType && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName)); - return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) : `__@${symbolName}` as __String; + const uniqueType = ctorType + && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName)); + return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) + : `__@${symbolName}` as __String; } /** @@ -39912,20 +51978,30 @@ namespace ts { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterable` instead. */ - function getIterationTypesOfIterableSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, noCache: boolean) { + function getIterationTypesOfIterableSlow( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + noCache: boolean, + ) { const method = getPropertyOfType(type, getPropertyNameForKnownSymbolName(resolver.iteratorSymbolName)); const methodType = method && !(method.flags & SymbolFlags.Optional) ? getTypeOfSymbol(method) : undefined; if (isTypeAny(methodType)) { - return noCache ? anyIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, anyIterationTypes); + return noCache ? anyIterationTypes + : setCachedIterationTypes(type, resolver.iterableCacheKey, anyIterationTypes); } const signatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : undefined; if (!some(signatures)) { - return noCache ? noIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, noIterationTypes); + return noCache ? noIterationTypes + : setCachedIterationTypes(type, resolver.iterableCacheKey, noIterationTypes); } const iteratorType = getIntersectionType(map(signatures, getReturnTypeOfSignature)); - const iterationTypes = getIterationTypesOfIteratorWorker(iteratorType, resolver, errorNode, errorOutputContainer, noCache) ?? noIterationTypes; + const iterationTypes = + getIterationTypesOfIteratorWorker(iteratorType, resolver, errorNode, errorOutputContainer, noCache) + ?? noIterationTypes; return noCache ? iterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, iterationTypes); } @@ -39938,11 +52014,11 @@ namespace ts { !!getAwaitedTypeOfPromise(type) // for (const x of AsyncIterable<...>) || ( - !allowAsyncIterables && - isForOfStatement(errorNode.parent) && - errorNode.parent.expression === errorNode && - getGlobalAsyncIterableType(/** reportErrors */ false) !== emptyGenericType && - isTypeAssignableTo(type, getGlobalAsyncIterableType(/** reportErrors */ false)) + !allowAsyncIterables + && isForOfStatement(errorNode.parent) + && errorNode.parent.expression === errorNode + && getGlobalAsyncIterableType(/** reportErrors */ false) !== emptyGenericType + && isTypeAssignableTo(type, getGlobalAsyncIterableType(/** reportErrors */ false)) ); return errorAndMaybeSuggestAwait(errorNode, suggestAwait, message, typeToString(type)); } @@ -39953,8 +52029,19 @@ namespace ts { * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` * record is returned. Otherwise, `undefined` is returned. */ - function getIterationTypesOfIterator(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined) { - return getIterationTypesOfIteratorWorker(type, resolver, errorNode, errorOutputContainer, /*noCache*/ false); + function getIterationTypesOfIterator( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + ) { + return getIterationTypesOfIteratorWorker( + type, + resolver, + errorNode, + errorOutputContainer, + /*noCache*/ false, + ); } /** @@ -39966,20 +52053,32 @@ namespace ts { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterator` instead. */ - function getIterationTypesOfIteratorWorker(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, noCache: boolean) { + function getIterationTypesOfIteratorWorker( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + noCache: boolean, + ) { if (isTypeAny(type)) { return anyIterationTypes; } - let iterationTypes = getIterationTypesOfIteratorCached(type, resolver) || - getIterationTypesOfIteratorFast(type, resolver); + let iterationTypes = getIterationTypesOfIteratorCached(type, resolver) + || getIterationTypesOfIteratorFast(type, resolver); if (iterationTypes === noIterationTypes && errorNode) { iterationTypes = undefined; noCache = true; } - iterationTypes ??= getIterationTypesOfIteratorSlow(type, resolver, errorNode, errorOutputContainer, noCache); + iterationTypes ??= getIterationTypesOfIteratorSlow( + type, + resolver, + errorNode, + errorOutputContainer, + noCache, + ); return iterationTypes === noIterationTypes ? undefined : iterationTypes; } @@ -40018,17 +52117,32 @@ namespace ts { // The "return" and "next" types of `IterableIterator` and `AsyncIterableIterator` are defined by the // iteration types of their `next`, `return`, and `throw` methods. While we define these as `any` // and `undefined` in our libs by default, a custom lib *could* use different definitions. - const globalIterationTypes = getIterationTypesOfIteratorCached(globalType, resolver) || - getIterationTypesOfIteratorSlow(globalType, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined, /*noCache*/ false); - const { returnType, nextType } = globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes; - return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType)); + const globalIterationTypes = getIterationTypesOfIteratorCached(globalType, resolver) + || getIterationTypesOfIteratorSlow( + globalType, + resolver, + /*errorNode*/ undefined, + /*errorOutputContainer*/ undefined, + /*noCache*/ false, + ); + const { returnType, nextType } = globalIterationTypes === noIterationTypes ? defaultIterationTypes + : globalIterationTypes; + return setCachedIterationTypes( + type, + resolver.iteratorCacheKey, + createIterationTypes(yieldType, returnType, nextType), + ); } if ( - isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) || - isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false)) + isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) + || isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false)) ) { const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); - return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType)); + return setCachedIterationTypes( + type, + resolver.iteratorCacheKey, + createIterationTypes(yieldType, returnType, nextType), + ); } } @@ -40070,19 +52184,29 @@ namespace ts { // or `IteratorReturnResult` types, then just grab its type argument. if (isReferenceToType(type, getGlobalIteratorYieldResultType(/*reportErrors*/ false))) { const yieldType = getTypeArguments(type as GenericType)[0]; - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined)); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined), + ); } if (isReferenceToType(type, getGlobalIteratorReturnResultType(/*reportErrors*/ false))) { const returnType = getTypeArguments(type as GenericType)[0]; - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined)); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined), + ); } // Choose any constituents that can produce the requested iteration type. const yieldIteratorResult = filterType(type, isYieldIteratorResult); - const yieldType = yieldIteratorResult !== neverType ? getTypeOfPropertyOfType(yieldIteratorResult, "value" as __String) : undefined; + const yieldType = yieldIteratorResult !== neverType + ? getTypeOfPropertyOfType(yieldIteratorResult, "value" as __String) : undefined; const returnIteratorResult = filterType(type, isReturnIteratorResult); - const returnType = returnIteratorResult !== neverType ? getTypeOfPropertyOfType(returnIteratorResult, "value" as __String) : undefined; + const returnType = returnIteratorResult !== neverType + ? getTypeOfPropertyOfType(returnIteratorResult, "value" as __String) : undefined; if (!yieldType && !returnType) { return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", noIterationTypes); @@ -40092,7 +52216,11 @@ namespace ts { // > ... If the iterator does not have a return value, `value` is `undefined`. In that case, the // > `value` property may be absent from the conforming object if it does not inherit an explicit // > `value` property. - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, returnType || voidType, /*nextType*/ undefined)); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + createIterationTypes(yieldType, returnType || voidType, /*nextType*/ undefined), + ); } /** @@ -40102,7 +52230,13 @@ namespace ts { * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` * record is returned. Otherwise, we return `undefined`. */ - function getIterationTypesOfMethod(type: Type, resolver: IterationTypesResolver, methodName: "next" | "return" | "throw", errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined): IterationTypes | undefined { + function getIterationTypesOfMethod( + type: Type, + resolver: IterationTypesResolver, + methodName: "next" | "return" | "throw", + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + ): IterationTypes | undefined { const method = getPropertyOfType(type, methodName as __String); // Ignore 'return' or 'throw' if they are missing. @@ -40111,7 +52245,8 @@ namespace ts { } const methodType = method && !(methodName === "next" && (method.flags & SymbolFlags.Optional)) - ? methodName === "next" ? getTypeOfSymbol(method) : getTypeWithFacts(getTypeOfSymbol(method), TypeFacts.NEUndefinedOrNull) + ? methodName === "next" ? getTypeOfSymbol(method) + : getTypeWithFacts(getTypeOfSymbol(method), TypeFacts.NEUndefinedOrNull) : undefined; if (isTypeAny(methodType)) { @@ -40147,8 +52282,10 @@ namespace ts { if (methodType?.symbol && methodSignatures.length === 1) { const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false); const globalIteratorType = resolver.getGlobalIteratorType(/*reportErrors*/ false); - const isGeneratorMethod = globalGeneratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; - const isIteratorMethod = !isGeneratorMethod && globalIteratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; + const isGeneratorMethod = + globalGeneratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; + const isIteratorMethod = !isGeneratorMethod + && globalIteratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; if (isGeneratorMethod || isIteratorMethod) { const globalType = isGeneratorMethod ? globalGeneratorType : globalIteratorType; const { mapper } = methodType as AnonymousType; @@ -40182,7 +52319,8 @@ namespace ts { } else if (methodName === "return") { // The value of `return(value)` *is* awaited by async generators - const resolvedMethodParameterType = resolver.resolveIterationType(methodParameterType, errorNode) || anyType; + const resolvedMethodParameterType = resolver.resolveIterationType(methodParameterType, errorNode) + || anyType; returnTypes = append(returnTypes, resolvedMethodParameterType); } } @@ -40196,7 +52334,9 @@ namespace ts { if (errorNode) { if (errorOutputContainer) { errorOutputContainer.errors ??= []; - errorOutputContainer.errors.push(createDiagnosticForNode(errorNode, resolver.mustHaveAValueDiagnostic, methodName)); + errorOutputContainer.errors.push( + createDiagnosticForNode(errorNode, resolver.mustHaveAValueDiagnostic, methodName), + ); } else { error(errorNode, resolver.mustHaveAValueDiagnostic, methodName); @@ -40223,7 +52363,13 @@ namespace ts { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterator` instead. */ - function getIterationTypesOfIteratorSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, noCache: boolean) { + function getIterationTypesOfIteratorSlow( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + noCache: boolean, + ) { const iterationTypes = combineIterationTypes([ getIterationTypesOfMethod(type, resolver, "next", errorNode, errorOutputContainer), getIterationTypesOfMethod(type, resolver, "return", errorNode, errorOutputContainer), @@ -40237,7 +52383,11 @@ namespace ts { * `IterableIterator`-like, or `Generator`-like (for a non-async generator); or `AsyncIterable`-like, * `AsyncIterator`-like, `AsyncIterableIterator`-like, or `AsyncGenerator`-like (for an async generator). */ - function getIterationTypeOfGeneratorFunctionReturnType(kind: IterationTypeKind, returnType: Type, isAsyncGenerator: boolean): Type | undefined { + function getIterationTypeOfGeneratorFunctionReturnType( + kind: IterationTypeKind, + returnType: Type, + isAsyncGenerator: boolean, + ): Type | undefined { if (isTypeAny(returnType)) { return undefined; } @@ -40253,8 +52403,13 @@ namespace ts { const use = isAsyncGenerator ? IterationUse.AsyncGeneratorReturnType : IterationUse.GeneratorReturnType; const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver; - return getIterationTypesOfIterable(type, use, /*errorNode*/ undefined) || - getIterationTypesOfIterator(type, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined); + return getIterationTypesOfIterable(type, use, /*errorNode*/ undefined) + || getIterationTypesOfIterator( + type, + resolver, + /*errorNode*/ undefined, + /*errorOutputContainer*/ undefined, + ); } function checkBreakOrContinueStatement(node: BreakOrContinueStatement) { @@ -40268,7 +52423,11 @@ namespace ts { const isGenerator = !!(functionFlags & FunctionFlags.Generator); const isAsync = !!(functionFlags & FunctionFlags.Async); if (isGenerator) { - const returnIterationType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, isAsync); + const returnIterationType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + returnType, + isAsync, + ); if (!returnIterationType) { return errorType; } @@ -40279,7 +52438,8 @@ namespace ts { function isUnwrappedReturnTypeVoidOrAny(func: SignatureDeclaration, returnType: Type): boolean { const unwrappedReturnType = unwrapReturnType(returnType, getFunctionFlags(func)); - return !!unwrappedReturnType && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.AnyOrUnknown); + return !!unwrappedReturnType + && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.AnyOrUnknown); } function checkReturnStatement(node: ReturnStatement) { @@ -40290,7 +52450,10 @@ namespace ts { const container = getContainingFunctionOrClassStaticBlock(node); if (container && isClassStaticBlockDeclaration(container)) { - grammarErrorOnFirstToken(node, Diagnostics.A_return_statement_cannot_be_used_inside_a_class_static_block); + grammarErrorOnFirstToken( + node, + Diagnostics.A_return_statement_cannot_be_used_inside_a_class_static_block, + ); return; } @@ -40310,24 +52473,45 @@ namespace ts { } } else if (container.kind === SyntaxKind.Constructor) { - if (node.expression && !checkTypeAssignableToAndOptionallyElaborate(exprType, returnType, node, node.expression)) { - error(node, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); + if ( + node.expression + && !checkTypeAssignableToAndOptionallyElaborate(exprType, returnType, node, node.expression) + ) { + error( + node, + Diagnostics + .Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class, + ); } } else if (getReturnTypeFromAnnotation(container)) { const unwrappedReturnType = unwrapReturnType(returnType, functionFlags) ?? returnType; const unwrappedExprType = functionFlags & FunctionFlags.Async - ? checkAwaitedType(exprType, /*withAlias*/ false, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member) + ? checkAwaitedType( + exprType, + /*withAlias*/ false, + node, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ) : exprType; if (unwrappedReturnType) { // If the function has a return type, but promisedType is // undefined, an error will be reported in checkAsyncFunctionReturnType // so we don't need to report one here. - checkTypeAssignableToAndOptionallyElaborate(unwrappedExprType, unwrappedReturnType, node, node.expression); + checkTypeAssignableToAndOptionallyElaborate( + unwrappedExprType, + unwrappedReturnType, + node, + node.expression, + ); } } } - else if (container.kind !== SyntaxKind.Constructor && compilerOptions.noImplicitReturns && !isUnwrappedReturnTypeVoidOrAny(container, returnType)) { + else if ( + container.kind !== SyntaxKind.Constructor && compilerOptions.noImplicitReturns + && !isUnwrappedReturnTypeVoidOrAny(container, returnType) + ) { // The function has a return type, but the return statement doesn't have an expression. error(node, Diagnostics.Not_all_code_paths_return_a_value); } @@ -40337,7 +52521,10 @@ namespace ts { // Grammar checking for withStatement if (!checkGrammarStatementInAmbientContext(node)) { if (node.flags & NodeFlags.AwaitContext) { - grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_an_async_function_block); + grammarErrorOnFirstToken( + node, + Diagnostics.with_statements_are_not_allowed_in_an_async_function_block, + ); } } @@ -40347,7 +52534,12 @@ namespace ts { if (!hasParseDiagnostics(sourceFile)) { const start = getSpanOfTokenAtPosition(sourceFile, node.pos).start; const end = node.statement.pos; - grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.The_with_statement_is_not_supported_All_symbols_in_a_with_block_will_have_type_any); + grammarErrorAtPos( + sourceFile, + start, + end - start, + Diagnostics.The_with_statement_is_not_supported_All_symbols_in_a_with_block_will_have_type_any, + ); } } @@ -40367,7 +52559,10 @@ namespace ts { firstDefaultClause = clause; } else { - grammarErrorOnNode(clause, Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement); + grammarErrorOnNode( + clause, + Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement, + ); hasDuplicateDefaultClause = true; } } @@ -40376,7 +52571,10 @@ namespace ts { addLazyDiagnostic(createLazyCaseClauseDiagnostics(clause)); } forEach(clause.statements, checkSourceElement); - if (compilerOptions.noFallthroughCasesInSwitch && clause.fallthroughFlowNode && isReachableFlowNode(clause.fallthroughFlowNode)) { + if ( + compilerOptions.noFallthroughCasesInSwitch && clause.fallthroughFlowNode + && isReachableFlowNode(clause.fallthroughFlowNode) + ) { error(clause, Diagnostics.Fallthrough_case_in_switch); } @@ -40394,7 +52592,12 @@ namespace ts { } if (!isTypeEqualityComparableTo(comparedExpressionType, caseType)) { // expressionType is not comparable to caseType, try the reversed check and report errors if it fails - checkTypeComparableTo(caseType, comparedExpressionType, clause.expression, /*headMessage*/ undefined); + checkTypeComparableTo( + caseType, + comparedExpressionType, + clause.expression, + /*headMessage*/ undefined, + ); } }; } @@ -40411,7 +52614,10 @@ namespace ts { if (isFunctionLike(current)) { return "quit"; } - if (current.kind === SyntaxKind.LabeledStatement && (current as LabeledStatement).label.escapedText === node.label.escapedText) { + if ( + current.kind === SyntaxKind.LabeledStatement + && (current as LabeledStatement).label.escapedText === node.label.escapedText + ) { grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNode(node.label)); return true; } @@ -40448,21 +52654,38 @@ namespace ts { const declaration = catchClause.variableDeclaration; const typeNode = getEffectiveTypeAnnotationNode(getRootDeclaration(declaration)); if (typeNode) { - const type = getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ false, CheckMode.Normal); + const type = getTypeForVariableLikeDeclaration( + declaration, + /*includeOptionality*/ false, + CheckMode.Normal, + ); if (type && !(type.flags & TypeFlags.AnyOrUnknown)) { - grammarErrorOnFirstToken(typeNode, Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified); + grammarErrorOnFirstToken( + typeNode, + Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified, + ); } } else if (declaration.initializer) { - grammarErrorOnFirstToken(declaration.initializer, Diagnostics.Catch_clause_variable_cannot_have_an_initializer); + grammarErrorOnFirstToken( + declaration.initializer, + Diagnostics.Catch_clause_variable_cannot_have_an_initializer, + ); } else { const blockLocals = catchClause.block.locals; if (blockLocals) { forEachKey(catchClause.locals!, caughtName => { const blockLocal = blockLocals.get(caughtName); - if (blockLocal?.valueDeclaration && (blockLocal.flags & SymbolFlags.BlockScopedVariable) !== 0) { - grammarErrorOnNode(blockLocal.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, caughtName); + if ( + blockLocal?.valueDeclaration + && (blockLocal.flags & SymbolFlags.BlockScopedVariable) !== 0 + ) { + grammarErrorOnNode( + blockLocal.valueDeclaration, + Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, + caughtName, + ); } }); } @@ -40484,7 +52707,16 @@ namespace ts { } for (const prop of getPropertiesOfObjectType(type)) { if (!(isStaticIndex && prop.flags & SymbolFlags.Prototype)) { - checkIndexConstraintForProperty(type, prop, getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique, /*includeNonPublic*/ true), getNonMissingTypeOfSymbol(prop)); + checkIndexConstraintForProperty( + type, + prop, + getLiteralTypeFromProperty( + prop, + TypeFlags.StringOrNumberLiteralOrUnique, + /*includeNonPublic*/ true, + ), + getNonMissingTypeOfSymbol(prop), + ); } } const typeDeclaration = symbol.valueDeclaration; @@ -40494,7 +52726,12 @@ namespace ts { // and properties with literal names were already checked. if (!isStatic(member) && !hasBindableName(member)) { const symbol = getSymbolOfNode(member); - checkIndexConstraintForProperty(type, symbol, getTypeOfExpression((member as DynamicNamedDeclaration).name.expression), getNonMissingTypeOfSymbol(symbol)); + checkIndexConstraintForProperty( + type, + symbol, + getTypeOfExpression((member as DynamicNamedDeclaration).name.expression), + getNonMissingTypeOfSymbol(symbol), + ); } } } @@ -40512,21 +52749,44 @@ namespace ts { return; } const indexInfos = getApplicableIndexInfos(type, propNameType); - const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; - const propDeclaration = declaration && declaration.kind === SyntaxKind.BinaryExpression || - name && name.kind === SyntaxKind.ComputedPropertyName ? declaration : undefined; + const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface + ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; + const propDeclaration = declaration && declaration.kind === SyntaxKind.BinaryExpression + || name && name.kind === SyntaxKind.ComputedPropertyName ? declaration : undefined; const localPropDeclaration = getParentOfSymbol(prop) === type.symbol ? declaration : undefined; for (const info of indexInfos) { - const localIndexDeclaration = info.declaration && getParentOfSymbol(getSymbolOfNode(info.declaration)) === type.symbol ? info.declaration : undefined; + const localIndexDeclaration = + info.declaration && getParentOfSymbol(getSymbolOfNode(info.declaration)) === type.symbol + ? info.declaration : undefined; // We check only when (a) the property is declared in the containing type, or (b) the applicable index signature is declared // in the containing type, or (c) the containing type is an interface and no base interface contains both the property and // the index signature (i.e. property and index signature are declared in separate inherited interfaces). - const errorNode = localPropDeclaration || localIndexDeclaration || - (interfaceDeclaration && !some(getBaseTypes(type as InterfaceType), base => !!getPropertyOfObjectType(base, prop.escapedName) && !!getIndexTypeOfType(base, info.keyType)) ? interfaceDeclaration : undefined); + const errorNode = localPropDeclaration || localIndexDeclaration + || (interfaceDeclaration + && !some( + getBaseTypes(type as InterfaceType), + base => + !!getPropertyOfObjectType(base, prop.escapedName) + && !!getIndexTypeOfType(base, info.keyType), + ) ? interfaceDeclaration : undefined); if (errorNode && !isTypeAssignableTo(propType, info.type)) { - const diagnostic = createError(errorNode, Diagnostics.Property_0_of_type_1_is_not_assignable_to_2_index_type_3, symbolToString(prop), typeToString(propType), typeToString(info.keyType), typeToString(info.type)); + const diagnostic = createError( + errorNode, + Diagnostics.Property_0_of_type_1_is_not_assignable_to_2_index_type_3, + symbolToString(prop), + typeToString(propType), + typeToString(info.keyType), + typeToString(info.type), + ); if (propDeclaration && errorNode !== propDeclaration) { - addRelatedInfo(diagnostic, createDiagnosticForNode(propDeclaration, Diagnostics._0_is_declared_here, symbolToString(prop))); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + propDeclaration, + Diagnostics._0_is_declared_here, + symbolToString(prop), + ), + ); } diagnostics.add(diagnostic); } @@ -40536,18 +52796,35 @@ namespace ts { function checkIndexConstraintForIndexSignature(type: Type, checkInfo: IndexInfo) { const declaration = checkInfo.declaration; const indexInfos = getApplicableIndexInfos(type, checkInfo.keyType); - const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; - const localCheckDeclaration = declaration && getParentOfSymbol(getSymbolOfNode(declaration)) === type.symbol ? declaration : undefined; + const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface + ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; + const localCheckDeclaration = declaration && getParentOfSymbol(getSymbolOfNode(declaration)) === type.symbol + ? declaration : undefined; for (const info of indexInfos) { if (info === checkInfo) continue; - const localIndexDeclaration = info.declaration && getParentOfSymbol(getSymbolOfNode(info.declaration)) === type.symbol ? info.declaration : undefined; + const localIndexDeclaration = + info.declaration && getParentOfSymbol(getSymbolOfNode(info.declaration)) === type.symbol + ? info.declaration : undefined; // We check only when (a) the check index signature is declared in the containing type, or (b) the applicable index // signature is declared in the containing type, or (c) the containing type is an interface and no base interface contains // both index signatures (i.e. the index signatures are declared in separate inherited interfaces). - const errorNode = localCheckDeclaration || localIndexDeclaration || - (interfaceDeclaration && !some(getBaseTypes(type as InterfaceType), base => !!getIndexInfoOfType(base, checkInfo.keyType) && !!getIndexTypeOfType(base, info.keyType)) ? interfaceDeclaration : undefined); + const errorNode = localCheckDeclaration || localIndexDeclaration + || (interfaceDeclaration + && !some( + getBaseTypes(type as InterfaceType), + base => + !!getIndexInfoOfType(base, checkInfo.keyType) + && !!getIndexTypeOfType(base, info.keyType), + ) ? interfaceDeclaration : undefined); if (errorNode && !isTypeAssignableTo(checkInfo.type, info.type)) { - error(errorNode, Diagnostics._0_index_type_1_is_not_assignable_to_2_index_type_3, typeToString(checkInfo.keyType), typeToString(checkInfo.type), typeToString(info.keyType), typeToString(info.type)); + error( + errorNode, + Diagnostics._0_index_type_1_is_not_assignable_to_2_index_type_3, + typeToString(checkInfo.keyType), + typeToString(checkInfo.type), + typeToString(info.keyType), + typeToString(info.type), + ); } } } @@ -40576,9 +52853,14 @@ namespace ts { function checkClassNameCollisionWithObject(name: Identifier): void { if ( languageVersion >= ScriptTarget.ES5 && name.escapedText === "Object" - && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(name).impliedNodeFormat === ModuleKind.CommonJS) + && (moduleKind < ModuleKind.ES2015 + || getSourceFileOfNode(name).impliedNodeFormat === ModuleKind.CommonJS) ) { - error(name, Diagnostics.Class_name_cannot_be_Object_when_targeting_ES5_with_module_0, ModuleKind[moduleKind]); // https://github.com/Microsoft/TypeScript/issues/17494 + error( + name, + Diagnostics.Class_name_cannot_be_Object_when_targeting_ES5_with_module_0, + ModuleKind[moduleKind], + ); // https://github.com/Microsoft/TypeScript/issues/17494 } } @@ -40602,10 +52884,16 @@ namespace ts { if (containsArguments) { const lastJSDocParam = lastOrUndefined(jsdocParameters); if ( - isJs && lastJSDocParam && isIdentifier(lastJSDocParam.name) && lastJSDocParam.typeExpression && - lastJSDocParam.typeExpression.type && !parameters.has(lastJSDocParam.name.escapedText) && !isArrayType(getTypeFromTypeNode(lastJSDocParam.typeExpression.type)) + isJs && lastJSDocParam && isIdentifier(lastJSDocParam.name) && lastJSDocParam.typeExpression + && lastJSDocParam.typeExpression.type && !parameters.has(lastJSDocParam.name.escapedText) + && !isArrayType(getTypeFromTypeNode(lastJSDocParam.typeExpression.type)) ) { - error(lastJSDocParam.name, Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name_It_would_match_arguments_if_it_had_an_array_type, idText(lastJSDocParam.name)); + error( + lastJSDocParam.name, + Diagnostics + .JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name_It_would_match_arguments_if_it_had_an_array_type, + idText(lastJSDocParam.name), + ); } } else { @@ -40615,12 +52903,22 @@ namespace ts { } if (isQualifiedName(name)) { if (isJs) { - error(name, Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1, entityNameToString(name), entityNameToString(name.left)); + error( + name, + Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1, + entityNameToString(name), + entityNameToString(name.left), + ); } } else { if (!isNameFirst) { - errorOrSuggestion(isJs, name, Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name, idText(name)); + errorOrSuggestion( + isJs, + name, + Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name, + idText(name), + ); } } }); @@ -40660,7 +52958,11 @@ namespace ts { } /** Check that type parameter defaults only reference previously declared type parameters */ - function checkTypeParametersNotReferenced(root: TypeNode, typeParameters: readonly TypeParameterDeclaration[], index: number) { + function checkTypeParametersNotReferenced( + root: TypeNode, + typeParameters: readonly TypeParameterDeclaration[], + index: number, + ) { visit(root); function visit(node: Node) { if (node.kind === SyntaxKind.TypeReference) { @@ -40668,7 +52970,11 @@ namespace ts { if (type.flags & TypeFlags.TypeParameter) { for (let i = index; i < typeParameters.length; i++) { if (type.symbol === getSymbolOfNode(typeParameters[i])) { - error(node, Diagnostics.Type_parameter_defaults_can_only_reference_previously_declared_type_parameters); + error( + node, + Diagnostics + .Type_parameter_defaults_can_only_reference_previously_declared_type_parameters, + ); } } } @@ -40692,17 +52998,31 @@ namespace ts { } const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; - if (!areTypeParametersIdentical(declarations, type.localTypeParameters!, getEffectiveTypeParameterDeclarations)) { + if ( + !areTypeParametersIdentical( + declarations, + type.localTypeParameters!, + getEffectiveTypeParameterDeclarations, + ) + ) { // Report an error on every conflicting declaration. const name = symbolToString(symbol); for (const declaration of declarations) { - error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_type_parameters, name); + error( + declaration.name, + Diagnostics.All_declarations_of_0_must_have_identical_type_parameters, + name, + ); } } } } - function areTypeParametersIdentical(declarations: readonly T[], targetParameters: TypeParameter[], getTypeParameterDeclarations: (node: T) => readonly TypeParameterDeclaration[]) { + function areTypeParametersIdentical( + declarations: readonly T[], + targetParameters: TypeParameter[], + getTypeParameterDeclarations: (node: T) => readonly TypeParameterDeclaration[], + ) { const maxTypeArgumentCount = length(targetParameters); const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters); @@ -40731,7 +53051,9 @@ namespace ts { const targetConstraint = getConstraintOfTypeParameter(target); // relax check if later interface augmentation has no constraint, it's more broad and is OK to merge with // a more constrained interface (this could be generalized to a full hierarchy check, but that's maybe overkill) - if (sourceConstraint && targetConstraint && !isTypeIdenticalTo(sourceConstraint, targetConstraint)) { + if ( + sourceConstraint && targetConstraint && !isTypeIdenticalTo(sourceConstraint, targetConstraint) + ) { return false; } @@ -40761,11 +53083,21 @@ namespace ts { function checkClassDeclaration(node: ClassDeclaration) { const firstDecorator = find(node.modifiers, isDecorator); - if (firstDecorator && some(node.members, p => hasStaticModifier(p) && isPrivateIdentifierClassElementDeclaration(p))) { - grammarErrorOnNode(firstDecorator, Diagnostics.Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator); + if ( + firstDecorator + && some(node.members, p => hasStaticModifier(p) && isPrivateIdentifierClassElementDeclaration(p)) + ) { + grammarErrorOnNode( + firstDecorator, + Diagnostics + .Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator, + ); } if (!node.name && !hasSyntacticModifier(node, ModifierFlags.Default)) { - grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); + grammarErrorOnFirstToken( + node, + Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name, + ); } checkClassLikeDeclaration(node); forEach(node.members, checkSourceElement); @@ -40815,7 +53147,13 @@ namespace ts { checkSourceElement(baseTypeNode.expression); if (some(baseTypeNode.typeArguments)) { forEach(baseTypeNode.typeArguments, checkSourceElement); - for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode)) { + for ( + const constructor of getConstructorsForTypeArguments( + staticBaseType, + baseTypeNode.typeArguments, + baseTypeNode, + ) + ) { if (!checkTypeArgumentConstraints(baseTypeNode, constructor.typeParameters!)) { break; } @@ -40823,30 +53161,68 @@ namespace ts { } const baseWithThis = getTypeWithThisArgument(baseType, type.thisType); if (!checkTypeAssignableTo(typeWithThis, baseWithThis, /*errorNode*/ undefined)) { - issueMemberSpecificError(node, typeWithThis, baseWithThis, Diagnostics.Class_0_incorrectly_extends_base_class_1); + issueMemberSpecificError( + node, + typeWithThis, + baseWithThis, + Diagnostics.Class_0_incorrectly_extends_base_class_1, + ); } else { // Report static side error only when instance type is assignable - checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node, Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); + checkTypeAssignableTo( + staticType, + getTypeWithoutSignatures(staticBaseType), + node.name || node, + Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1, + ); } if (baseConstructorType.flags & TypeFlags.TypeVariable) { if (!isMixinConstructorType(staticType)) { - error(node.name || node, Diagnostics.A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any); + error( + node.name || node, + Diagnostics + .A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any, + ); } else { - const constructSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); - if (constructSignatures.some(signature => signature.flags & SignatureFlags.Abstract) && !hasSyntacticModifier(node, ModifierFlags.Abstract)) { - error(node.name || node, Diagnostics.A_mixin_class_that_extends_from_a_type_variable_containing_an_abstract_construct_signature_must_also_be_declared_abstract); + const constructSignatures = getSignaturesOfType( + baseConstructorType, + SignatureKind.Construct, + ); + if ( + constructSignatures.some(signature => signature.flags & SignatureFlags.Abstract) + && !hasSyntacticModifier(node, ModifierFlags.Abstract) + ) { + error( + node.name || node, + Diagnostics + .A_mixin_class_that_extends_from_a_type_variable_containing_an_abstract_construct_signature_must_also_be_declared_abstract, + ); } } } - if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) && !(baseConstructorType.flags & TypeFlags.TypeVariable)) { + if ( + !(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) + && !(baseConstructorType.flags & TypeFlags.TypeVariable) + ) { // When the static base type is a "class-like" constructor function (but not actually a class), we verify // that all instantiated base constructor signatures return the same type. - const constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode); - if (forEach(constructors, sig => !isJSConstructor(sig.declaration) && !isTypeIdenticalTo(getReturnTypeOfSignature(sig), baseType))) { - error(baseTypeNode.expression, Diagnostics.Base_constructors_must_all_have_the_same_return_type); + const constructors = getInstantiatedConstructorsForTypeArguments( + staticBaseType, + baseTypeNode.typeArguments, + baseTypeNode, + ); + if ( + forEach(constructors, sig => + !isJSConstructor(sig.declaration) + && !isTypeIdenticalTo(getReturnTypeOfSignature(sig), baseType)) + ) { + error( + baseTypeNode.expression, + Diagnostics.Base_constructors_must_all_have_the_same_return_type, + ); } } checkKindsOfPropertyMemberOverrides(type, baseType); @@ -40860,7 +53236,11 @@ namespace ts { if (implementedTypeNodes) { for (const typeRefNode of implementedTypeNodes) { if (!isEntityNameExpression(typeRefNode.expression) || isOptionalChain(typeRefNode.expression)) { - error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments); + error( + typeRefNode.expression, + Diagnostics + .A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments, + ); } checkTypeReferenceNode(typeRefNode); addLazyDiagnostic(createImplementsDiagnostics(typeRefNode)); @@ -40879,26 +53259,37 @@ namespace ts { const t = getReducedType(getTypeFromTypeNode(typeRefNode)); if (!isErrorType(t)) { if (isValidBaseType(t)) { - const genericDiag = t.symbol && t.symbol.flags & SymbolFlags.Class ? - Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass : - Diagnostics.Class_0_incorrectly_implements_interface_1; + const genericDiag = t.symbol && t.symbol.flags & SymbolFlags.Class + ? Diagnostics + .Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass + : Diagnostics.Class_0_incorrectly_implements_interface_1; const baseWithThis = getTypeWithThisArgument(t, type.thisType); if (!checkTypeAssignableTo(typeWithThis, baseWithThis, /*errorNode*/ undefined)) { issueMemberSpecificError(node, typeWithThis, baseWithThis, genericDiag); } } else { - error(typeRefNode, Diagnostics.A_class_can_only_implement_an_object_type_or_intersection_of_object_types_with_statically_known_members); + error( + typeRefNode, + Diagnostics + .A_class_can_only_implement_an_object_type_or_intersection_of_object_types_with_statically_known_members, + ); } } }; } } - function checkMembersForOverrideModifier(node: ClassLikeDeclaration, type: InterfaceType, typeWithThis: Type, staticType: ObjectType) { + function checkMembersForOverrideModifier( + node: ClassLikeDeclaration, + type: InterfaceType, + typeWithThis: Type, + staticType: ObjectType, + ) { const baseTypeNode = getEffectiveBaseTypeNode(node); const baseTypes = baseTypeNode && getBaseTypes(type); - const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) : undefined; + const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) + : undefined; const baseStaticType = getBaseConstructorTypeOfClass(type); for (const member of node.members) { @@ -41008,26 +53399,32 @@ namespace ts { if (prop && !baseProp && memberHasOverrideModifier) { if (errorNode) { const suggestion = getSuggestedSymbolForNonexistentClassMember(memberName, baseType); // Again, using symbol name: note that's different from `symbol.escapedName` - suggestion ? - error( + suggestion + ? error( errorNode, - isJs ? - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1 : - Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1, + isJs + ? Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1 + : Diagnostics + .This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1, baseClassName, symbolToString(suggestion), - ) : - error( + ) + : error( errorNode, - isJs ? - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 : - Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, + isJs + ? Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 + : Diagnostics + .This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, baseClassName, ); } return MemberOverrideStatus.HasInvalidOverride; } - else if (prop && baseProp?.declarations && compilerOptions.noImplicitOverride && !nodeInAmbientContext) { + else if ( + prop && baseProp?.declarations && compilerOptions.noImplicitOverride && !nodeInAmbientContext + ) { const baseHasAbstract = some(baseProp.declarations, hasAbstractModifier); if (memberHasOverrideModifier) { return MemberOverrideStatus.Ok; @@ -41035,20 +53432,29 @@ namespace ts { if (!baseHasAbstract) { if (errorNode) { - const diag = memberIsParameterProperty ? - isJs ? - Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 : - Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 : - isJs ? - Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 : - Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0; + const diag = memberIsParameterProperty + ? isJs + ? Diagnostics + .This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + : Diagnostics + .This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 + : isJs + ? Diagnostics + .This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + : Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0; error(errorNode, diag, baseClassName); } return MemberOverrideStatus.NeedsOverride; } else if (memberHasAbstractModifier && baseHasAbstract) { if (errorNode) { - error(errorNode, Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0, baseClassName); + error( + errorNode, + Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0, + baseClassName, + ); } return MemberOverrideStatus.NeedsOverride; } @@ -41059,9 +53465,11 @@ namespace ts { const className = typeToString(type); error( errorNode, - isJs ? - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class : - Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class, + isJs + ? Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class + : Diagnostics + .This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class, className, ); } @@ -41071,7 +53479,12 @@ namespace ts { return MemberOverrideStatus.Ok; } - function issueMemberSpecificError(node: ClassLikeDeclaration, typeWithThis: Type, baseWithThis: Type, broadDiag: DiagnosticMessage) { + function issueMemberSpecificError( + node: ClassLikeDeclaration, + typeWithThis: Type, + baseWithThis: Type, + broadDiag: DiagnosticMessage, + ) { // iterate over all implemented properties and issue errors on each one which isn't compatible, rather than the class as a whole, if possible let issuedMemberError = false; for (const member of node.members) { @@ -41091,7 +53504,15 @@ namespace ts { typeToString(typeWithThis), typeToString(baseWithThis), ); - if (!checkTypeAssignableTo(getTypeOfSymbol(prop), getTypeOfSymbol(baseProp), member.name || member, /*message*/ undefined, rootChain)) { + if ( + !checkTypeAssignableTo( + getTypeOfSymbol(prop), + getTypeOfSymbol(baseProp), + member.name || member, + /*message*/ undefined, + rootChain, + ) + ) { issuedMemberError = true; } } @@ -41110,7 +53531,11 @@ namespace ts { if (declaration && hasEffectiveModifier(declaration, ModifierFlags.Private)) { const typeClassDeclaration = getClassLikeDeclarationOfSymbol(type.symbol)!; if (!isNodeWithinClass(node, typeClassDeclaration)) { - error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, getFullyQualifiedName(type.symbol)); + error( + node, + Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, + getFullyQualifiedName(type.symbol), + ); } } } @@ -41122,7 +53547,10 @@ namespace ts { * @param member Member declaration node. * Note: `member` can be a synthetic node without a parent. */ - function getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement): MemberOverrideStatus { + function getMemberOverrideModifierStatus( + node: ClassLikeDeclaration, + member: ClassElement, + ): MemberOverrideStatus { if (!member.name) { return MemberOverrideStatus.Ok; } @@ -41134,7 +53562,8 @@ namespace ts { const baseTypeNode = getEffectiveBaseTypeNode(node); const baseTypes = baseTypeNode && getBaseTypes(type); - const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) : undefined; + const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) + : undefined; const baseStaticType = getBaseConstructorTypeOfClass(type); const memberHasOverrideModifier = member.parent @@ -41165,7 +53594,11 @@ namespace ts { } function getClassOrInterfaceDeclarationsOfSymbol(symbol: Symbol) { - return filter(symbol.declarations, (d: Declaration): d is ClassDeclaration | InterfaceDeclaration => d.kind === SyntaxKind.ClassDeclaration || d.kind === SyntaxKind.InterfaceDeclaration); + return filter( + symbol.declarations, + (d: Declaration): d is ClassDeclaration | InterfaceDeclaration => + d.kind === SyntaxKind.ClassDeclaration || d.kind === SyntaxKind.InterfaceDeclaration, + ); } function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: BaseType): void { @@ -41199,7 +53632,10 @@ namespace ts { const derived = getTargetSymbol(baseSymbol); const baseDeclarationFlags = getDeclarationModifierFlagsFromSymbol(base); - Debug.assert(!!derived, "derived should point to something, even if it is the base class' declaration."); + Debug.assert( + !!derived, + "derived should point to something, even if it is the base class' declaration.", + ); // In order to resolve whether the inherited method was overridden in the base class or not, // we compare the Symbols obtained. Since getTargetSymbol returns the symbol on the *uninstantiated* @@ -41211,7 +53647,10 @@ namespace ts { // It is an error to inherit an abstract member without implementing it or being declared abstract. // If there is no declaration for the derived class (as in the case of class expressions), // then the class cannot be declared abstract. - if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !hasSyntacticModifier(derivedClassDecl, ModifierFlags.Abstract))) { + if ( + baseDeclarationFlags & ModifierFlags.Abstract + && (!derivedClassDecl || !hasSyntacticModifier(derivedClassDecl, ModifierFlags.Abstract)) + ) { // Searches other base types for a declaration that would satisfy the inherited abstract member. // (The class may have more than one base type via declaration merging with an interface with the // same name.) @@ -41225,17 +53664,32 @@ namespace ts { } if (derivedClassDecl.kind === SyntaxKind.ClassExpression) { - error(derivedClassDecl, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, symbolToString(baseProperty), typeToString(baseType)); + error( + derivedClassDecl, + Diagnostics + .Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, + symbolToString(baseProperty), + typeToString(baseType), + ); } else { - error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2, typeToString(type), symbolToString(baseProperty), typeToString(baseType)); + error( + derivedClassDecl, + Diagnostics + .Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2, + typeToString(type), + symbolToString(baseProperty), + typeToString(baseType), + ); } } } else { // derived overrides base. const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived); - if (baseDeclarationFlags & ModifierFlags.Private || derivedDeclarationFlags & ModifierFlags.Private) { + if ( + baseDeclarationFlags & ModifierFlags.Private || derivedDeclarationFlags & ModifierFlags.Private + ) { // either base or derived property is private - not override, skip it continue; } @@ -41258,16 +53712,28 @@ namespace ts { continue; } - const overriddenInstanceProperty = basePropertyFlags !== SymbolFlags.Property && derivedPropertyFlags === SymbolFlags.Property; - const overriddenInstanceAccessor = basePropertyFlags === SymbolFlags.Property && derivedPropertyFlags !== SymbolFlags.Property; + const overriddenInstanceProperty = basePropertyFlags !== SymbolFlags.Property + && derivedPropertyFlags === SymbolFlags.Property; + const overriddenInstanceAccessor = basePropertyFlags === SymbolFlags.Property + && derivedPropertyFlags !== SymbolFlags.Property; if (overriddenInstanceProperty || overriddenInstanceAccessor) { - const errorMessage = overriddenInstanceProperty ? - Diagnostics._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property : - Diagnostics._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor; - error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, symbolToString(base), typeToString(baseType), typeToString(type)); + const errorMessage = overriddenInstanceProperty + ? Diagnostics + ._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property + : Diagnostics + ._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor; + error( + getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, + errorMessage, + symbolToString(base), + typeToString(baseType), + typeToString(type), + ); } else if (useDefineForClassFields) { - const uninitialized = derived.declarations?.find(d => d.kind === SyntaxKind.PropertyDeclaration && !(d as PropertyDeclaration).initializer); + const uninitialized = derived.declarations?.find(d => + d.kind === SyntaxKind.PropertyDeclaration && !(d as PropertyDeclaration).initializer + ); if ( uninitialized && !(derived.flags & SymbolFlags.Transient) @@ -41275,7 +53741,9 @@ namespace ts { && !(derivedDeclarationFlags & ModifierFlags.Abstract) && !derived.declarations?.some(d => !!(d.flags & NodeFlags.Ambient)) ) { - const constructor = findConstructorDeclaration(getClassLikeDeclarationOfSymbol(type.symbol)!); + const constructor = findConstructorDeclaration( + getClassLikeDeclarationOfSymbol(type.symbol)!, + ); const propName = (uninitialized as PropertyDeclaration).name; if ( (uninitialized as PropertyDeclaration).exclamationToken @@ -41284,8 +53752,14 @@ namespace ts { || !strictNullChecks || !isPropertyInitializedInConstructor(propName, type, constructor) ) { - const errorMessage = Diagnostics.Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration; - error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, symbolToString(base), typeToString(baseType)); + const errorMessage = Diagnostics + .Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration; + error( + getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, + errorMessage, + symbolToString(base), + typeToString(baseType), + ); } } } @@ -41300,23 +53774,33 @@ namespace ts { } else { Debug.assert(!!(derived.flags & SymbolFlags.Accessor)); - errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor; + errorMessage = Diagnostics + .Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor; } } else if (base.flags & SymbolFlags.Accessor) { - errorMessage = Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function; + errorMessage = Diagnostics + .Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function; } else { - errorMessage = Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function; + errorMessage = Diagnostics + .Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function; } - error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type)); + error( + getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, + errorMessage, + typeToString(baseType), + symbolToString(base), + typeToString(type), + ); } } } function isPropertyAbstractOrInterface(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { - return baseDeclarationFlags & ModifierFlags.Abstract && (!isPropertyDeclaration(declaration) || !declaration.initializer) + return baseDeclarationFlags & ModifierFlags.Abstract + && (!isPropertyDeclaration(declaration) || !declaration.initializer) || isInterfaceDeclaration(declaration.parent); } @@ -41373,8 +53857,20 @@ namespace ts { const typeName1 = typeToString(existing.containingType); const typeName2 = typeToString(base); - let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, symbolToString(prop), typeName1, typeName2); - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2); + let errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, + symbolToString(prop), + typeName1, + typeName2, + ); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, + typeToString(type), + typeName1, + typeName2, + ); diagnostics.add(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo)); } } @@ -41399,7 +53895,12 @@ namespace ts { const type = getTypeOfSymbol(getSymbolOfNode(member)); if (!(type.flags & TypeFlags.AnyOrUnknown || containsUndefinedType(type))) { if (!constructor || !isPropertyInitializedInConstructor(propName, type, constructor)) { - error(member.name, Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, declarationNameToString(propName)); + error( + member.name, + Diagnostics + .Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, + declarationNameToString(propName), + ); } } } @@ -41408,13 +53909,19 @@ namespace ts { } function isPropertyWithoutInitializer(node: Node) { - return node.kind === SyntaxKind.PropertyDeclaration && - !hasAbstractModifier(node) && - !(node as PropertyDeclaration).exclamationToken && - !(node as PropertyDeclaration).initializer; - } - - function isPropertyInitializedInStaticBlocks(propName: Identifier | PrivateIdentifier, propType: Type, staticBlocks: readonly ClassStaticBlockDeclaration[], startPos: number, endPos: number) { + return node.kind === SyntaxKind.PropertyDeclaration + && !hasAbstractModifier(node) + && !(node as PropertyDeclaration).exclamationToken + && !(node as PropertyDeclaration).initializer; + } + + function isPropertyInitializedInStaticBlocks( + propName: Identifier | PrivateIdentifier, + propType: Type, + staticBlocks: readonly ClassStaticBlockDeclaration[], + startPos: number, + endPos: number, + ) { for (const staticBlock of staticBlocks) { // static block must be within the provided range as they are evaluated in document order (unlike constructors) if (staticBlock.pos >= startPos && staticBlock.pos <= endPos) { @@ -41431,7 +53938,11 @@ namespace ts { return false; } - function isPropertyInitializedInConstructor(propName: Identifier | PrivateIdentifier | ComputedPropertyName, propType: Type, constructor: ConstructorDeclaration) { + function isPropertyInitializedInConstructor( + propName: Identifier | PrivateIdentifier | ComputedPropertyName, + propType: Type, + constructor: ConstructorDeclaration, + ) { const reference = isComputedPropertyName(propName) ? factory.createElementAccessExpression(factory.createThis(), propName.expression) : factory.createPropertyAccessExpression(factory.createThis(), propName); @@ -41455,14 +53966,22 @@ namespace ts { checkTypeParameterListsIdentical(symbol); // Only check this symbol once - const firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); + const firstInterfaceDecl = getDeclarationOfKind( + symbol, + SyntaxKind.InterfaceDeclaration, + ); if (node === firstInterfaceDecl) { const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; const typeWithThis = getTypeWithThisArgument(type); // run subsequent checks only if first set succeeded if (checkInheritedPropertiesAreIdentical(type, node.name)) { for (const baseType of getBaseTypes(type)) { - checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(baseType, type.thisType), node.name, Diagnostics.Interface_0_incorrectly_extends_interface_1); + checkTypeAssignableTo( + typeWithThis, + getTypeWithThisArgument(baseType, type.thisType), + node.name, + Diagnostics.Interface_0_incorrectly_extends_interface_1, + ); } checkIndexConstraints(type, symbol); } @@ -41470,8 +53989,14 @@ namespace ts { checkObjectTypeForDuplicateDeclarations(node); }); forEach(getInterfaceBaseTypeNodes(node), heritageElement => { - if (!isEntityNameExpression(heritageElement.expression) || isOptionalChain(heritageElement.expression)) { - error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments); + if ( + !isEntityNameExpression(heritageElement.expression) || isOptionalChain(heritageElement.expression) + ) { + error( + heritageElement.expression, + Diagnostics + .An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments, + ); } checkTypeReferenceNode(heritageElement); }); @@ -41492,7 +54017,10 @@ namespace ts { checkTypeParameters(node.typeParameters); if (node.type.kind === SyntaxKind.IntrinsicKeyword) { if (!intrinsicTypeKinds.has(node.name.escapedText as string) || length(node.typeParameters) !== 1) { - error(node.type, Diagnostics.The_intrinsic_keyword_can_only_be_used_to_declare_compiler_provided_intrinsic_types); + error( + node.type, + Diagnostics.The_intrinsic_keyword_can_only_be_used_to_declare_compiler_provided_intrinsic_types, + ); } } else { @@ -41529,7 +54057,10 @@ namespace ts { } // In ambient non-const numeric enum declarations, enum members without initializers are // considered computed members (as opposed to having auto-incremented values). - if (member.parent.flags & NodeFlags.Ambient && !isEnumConst(member.parent) && getEnumKind(getSymbolOfNode(member.parent)) === EnumKind.Numeric) { + if ( + member.parent.flags & NodeFlags.Ambient && !isEnumConst(member.parent) + && getEnumKind(getSymbolOfNode(member.parent)) === EnumKind.Numeric + ) { return undefined; } // If the member declaration specifies no value, the member is considered a constant enum member. @@ -41547,14 +54078,15 @@ namespace ts { const enumKind = getEnumKind(getSymbolOfNode(member.parent)); const isConstEnum = isEnumConst(member.parent); const initializer = member.initializer!; - const value = enumKind === EnumKind.Literal && !isLiteralEnumMember(member) ? undefined : evaluate(initializer); + const value = enumKind === EnumKind.Literal && !isLiteralEnumMember(member) ? undefined + : evaluate(initializer); if (value !== undefined) { if (isConstEnum && typeof value === "number" && !isFinite(value)) { error( initializer, - isNaN(value) ? - Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN : - Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value, + isNaN(value) + ? Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN + : Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value, ); } } @@ -41563,19 +54095,36 @@ namespace ts { return 0; } else if (isConstEnum) { - error(initializer, Diagnostics.const_enum_member_initializers_can_only_contain_literal_values_and_other_computed_enum_values); + error( + initializer, + Diagnostics + .const_enum_member_initializers_can_only_contain_literal_values_and_other_computed_enum_values, + ); } else if (member.parent.flags & NodeFlags.Ambient) { - error(initializer, Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression); + error( + initializer, + Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression, + ); } else { // Only here do we need to check that the initializer is assignable to the enum type. const source = checkExpression(initializer); if (!isTypeAssignableToKind(source, TypeFlags.NumberLike)) { - error(initializer, Diagnostics.Only_numeric_enums_can_have_computed_members_but_this_expression_has_type_0_If_you_do_not_need_exhaustiveness_checks_consider_using_an_object_literal_instead, typeToString(source)); + error( + initializer, + Diagnostics + .Only_numeric_enums_can_have_computed_members_but_this_expression_has_type_0_If_you_do_not_need_exhaustiveness_checks_consider_using_an_object_literal_instead, + typeToString(source), + ); } else { - checkTypeAssignableTo(source, getDeclaredTypeOfSymbol(getSymbolOfNode(member.parent)), initializer, /*headMessage*/ undefined); + checkTypeAssignableTo( + source, + getDeclaredTypeOfSymbol(getSymbolOfNode(member.parent)), + initializer, + /*headMessage*/ undefined, + ); } } return value; @@ -41626,7 +54175,10 @@ namespace ts { return left ** right; } } - else if (typeof left === "string" && typeof right === "string" && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken) { + else if ( + typeof left === "string" && typeof right === "string" + && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken + ) { return left + right; } break; @@ -41643,7 +54195,8 @@ namespace ts { if (isInfinityOrNaNString(identifier.escapedText)) { return +(identifier.escapedText); } - return nodeIsMissing(expr) ? 0 : evaluateEnumMember(expr, getSymbolOfNode(member.parent), identifier.escapedText); + return nodeIsMissing(expr) ? 0 + : evaluateEnumMember(expr, getSymbolOfNode(member.parent), identifier.escapedText); case SyntaxKind.ElementAccessExpression: case SyntaxKind.PropertyAccessExpression: if (isConstantMemberAccess(expr)) { @@ -41654,7 +54207,9 @@ namespace ts { name = expr.name.escapedText; } else { - name = escapeLeadingUnderscores(cast(expr.argumentExpression, isLiteralExpression).text); + name = escapeLeadingUnderscores( + cast(expr.argumentExpression, isLiteralExpression).text, + ); } return evaluateEnumMember(expr, type.symbol, name); } @@ -41669,10 +54224,17 @@ namespace ts { if (memberSymbol) { const declaration = memberSymbol.valueDeclaration; if (declaration !== member) { - if (declaration && isBlockScopedNameDeclaredBeforeUse(declaration, member) && isEnumDeclaration(declaration.parent)) { + if ( + declaration && isBlockScopedNameDeclaredBeforeUse(declaration, member) + && isEnumDeclaration(declaration.parent) + ) { return getEnumMemberValue(declaration as EnumMember); } - error(expr, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums); + error( + expr, + Diagnostics + .A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums, + ); return 0; } else { @@ -41689,10 +54251,12 @@ namespace ts { return false; } - return node.kind === SyntaxKind.Identifier || - node.kind === SyntaxKind.PropertyAccessExpression && isConstantMemberAccess((node as PropertyAccessExpression).expression) || - node.kind === SyntaxKind.ElementAccessExpression && isConstantMemberAccess((node as ElementAccessExpression).expression) && - isStringLiteralLike((node as ElementAccessExpression).argumentExpression); + return node.kind === SyntaxKind.Identifier + || node.kind === SyntaxKind.PropertyAccessExpression + && isConstantMemberAccess((node as PropertyAccessExpression).expression) + || node.kind === SyntaxKind.ElementAccessExpression + && isConstantMemberAccess((node as ElementAccessExpression).expression) + && isStringLiteralLike((node as ElementAccessExpression).argumentExpression); } function checkEnumDeclaration(node: EnumDeclaration) { @@ -41723,7 +54287,10 @@ namespace ts { // check that const is placed\omitted on all enum declarations forEach(enumSymbol.declarations, decl => { if (isEnumDeclaration(decl) && isEnumConst(decl) !== enumIsConst) { - error(getNameOfDeclaration(decl), Diagnostics.Enum_declarations_must_all_be_const_or_non_const); + error( + getNameOfDeclaration(decl), + Diagnostics.Enum_declarations_must_all_be_const_or_non_const, + ); } }); } @@ -41743,7 +54310,11 @@ namespace ts { const firstEnumMember = enumDeclaration.members[0]; if (!firstEnumMember.initializer) { if (seenEnumMissingInitialInitializer) { - error(firstEnumMember.name, Diagnostics.In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element); + error( + firstEnumMember.name, + Diagnostics + .In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element, + ); } else { seenEnumMissingInitialInitializer = true; @@ -41764,9 +54335,10 @@ namespace ts { if (declarations) { for (const declaration of declarations) { if ( - (declaration.kind === SyntaxKind.ClassDeclaration || - (declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((declaration as FunctionLikeDeclaration).body))) && - !(declaration.flags & NodeFlags.Ambient) + (declaration.kind === SyntaxKind.ClassDeclaration + || (declaration.kind === SyntaxKind.FunctionDeclaration + && nodeIsPresent((declaration as FunctionLikeDeclaration).body))) + && !(declaration.flags & NodeFlags.Ambient) ) { return declaration; } @@ -41804,7 +54376,11 @@ namespace ts { const isGlobalAugmentation = isGlobalScopeAugmentation(node); const inAmbientContext = node.flags & NodeFlags.Ambient; if (isGlobalAugmentation && !inAmbientContext) { - error(node.name, Diagnostics.Augmentations_for_the_global_scope_should_have_declare_modifier_unless_they_appear_in_already_ambient_context); + error( + node.name, + Diagnostics + .Augmentations_for_the_global_scope_should_have_declare_modifier_unless_they_appear_in_already_ambient_context, + ); } const isAmbientExternalModule: boolean = isAmbientModule(node); @@ -41840,10 +54416,18 @@ namespace ts { const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); if (firstNonAmbientClassOrFunc) { if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) { - error(node.name, Diagnostics.A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged); + error( + node.name, + Diagnostics + .A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged, + ); } else if (node.pos < firstNonAmbientClassOrFunc.pos) { - error(node.name, Diagnostics.A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged); + error( + node.name, + Diagnostics + .A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged, + ); } } @@ -41851,8 +54435,8 @@ namespace ts { // we need to track this to ensure the correct emit. const mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration); if ( - mergedClass && - inSameLexicalScope(node, mergedClass) + mergedClass + && inSameLexicalScope(node, mergedClass) ) { getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass; } @@ -41874,20 +54458,34 @@ namespace ts { } else if (isGlobalSourceFile(node.parent)) { if (isGlobalAugmentation) { - error(node.name, Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations); + error( + node.name, + Diagnostics + .Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations, + ); } else if (isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(node.name))) { - error(node.name, Diagnostics.Ambient_module_declaration_cannot_specify_relative_module_name); + error( + node.name, + Diagnostics.Ambient_module_declaration_cannot_specify_relative_module_name, + ); } } else { if (isGlobalAugmentation) { - error(node.name, Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations); + error( + node.name, + Diagnostics + .Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations, + ); } else { // Node is not an augmentation and is not located on the script level. // This means that this is declaration of ambient module that is located in other module or namespace which is prohibited. - error(node.name, Diagnostics.Ambient_modules_cannot_be_nested_in_other_modules_or_namespaces); + error( + node.name, + Diagnostics.Ambient_modules_cannot_be_nested_in_other_modules_or_namespaces, + ); } } } @@ -41904,11 +54502,18 @@ namespace ts { break; case SyntaxKind.ExportAssignment: case SyntaxKind.ExportDeclaration: - grammarErrorOnFirstToken(node, Diagnostics.Exports_and_export_assignments_are_not_permitted_in_module_augmentations); + grammarErrorOnFirstToken( + node, + Diagnostics.Exports_and_export_assignments_are_not_permitted_in_module_augmentations, + ); break; case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.ImportDeclaration: - grammarErrorOnFirstToken(node, Diagnostics.Imports_are_not_permitted_in_module_augmentations_Consider_moving_them_to_the_enclosing_external_module); + grammarErrorOnFirstToken( + node, + Diagnostics + .Imports_are_not_permitted_in_module_augmentations_Consider_moving_them_to_the_enclosing_external_module, + ); break; case SyntaxKind.BindingElement: case SyntaxKind.VariableDeclaration: @@ -41939,7 +54544,8 @@ namespace ts { let reportError = !(symbol.flags & SymbolFlags.Transient); if (!reportError) { // symbol should not originate in augmentation - reportError = !!symbol.parent?.declarations && isExternalModuleAugmentation(symbol.parent.declarations[0]); + reportError = !!symbol.parent?.declarations + && isExternalModuleAugmentation(symbol.parent.declarations[0]); } } break; @@ -41968,7 +54574,9 @@ namespace ts { } } - function checkExternalImportOrExportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): boolean { + function checkExternalImportOrExportDeclaration( + node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration, + ): boolean { const moduleName = getExternalModuleName(node); if (!moduleName || nodeIsMissing(moduleName)) { // Should be a parse error. @@ -41978,13 +54586,14 @@ namespace ts { error(moduleName, Diagnostics.String_literal_expected); return false; } - const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); + const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock + && isAmbientModule(node.parent.parent); if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule) { error( moduleName, - node.kind === SyntaxKind.ExportDeclaration ? - Diagnostics.Export_declarations_are_not_permitted_in_a_namespace : - Diagnostics.Import_declarations_in_a_namespace_cannot_reference_a_module, + node.kind === SyntaxKind.ExportDeclaration + ? Diagnostics.Export_declarations_are_not_permitted_in_a_namespace + : Diagnostics.Import_declarations_in_a_namespace_cannot_reference_a_module, ); return false; } @@ -41996,7 +54605,11 @@ namespace ts { // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference // other external modules only through top - level external module names. // Relative external module names are not permitted. - error(node, Diagnostics.Import_or_export_declaration_in_an_ambient_module_declaration_cannot_reference_module_through_relative_module_name); + error( + node, + Diagnostics + .Import_or_export_declaration_in_an_ambient_module_declaration_cannot_reference_module_through_relative_module_name, + ); return false; } } @@ -42013,7 +54626,17 @@ namespace ts { return true; } - function checkAliasSymbol(node: ImportEqualsDeclaration | VariableDeclaration | ImportClause | NamespaceImport | ImportSpecifier | ExportSpecifier | NamespaceExport | BindingElement) { + function checkAliasSymbol( + node: + | ImportEqualsDeclaration + | VariableDeclaration + | ImportClause + | NamespaceImport + | ImportSpecifier + | ExportSpecifier + | NamespaceExport + | BindingElement, + ) { let symbol = getSymbolOfNode(node); const target = resolveAlias(symbol); @@ -42027,15 +54650,23 @@ namespace ts { symbol = getMergedSymbol(symbol.exportSymbol || symbol); // A type-only import/export will already have a grammar error in a JS file, so no need to issue more errors within - if (isInJSFile(node) && !(target.flags & SymbolFlags.Value) && !isTypeOnlyImportOrExportDeclaration(node)) { - const errorNode = isImportOrExportSpecifier(node) ? node.propertyName || node.name : - isNamedDeclaration(node) ? node.name : - node; + if ( + isInJSFile(node) && !(target.flags & SymbolFlags.Value) + && !isTypeOnlyImportOrExportDeclaration(node) + ) { + const errorNode = isImportOrExportSpecifier(node) ? node.propertyName || node.name + : isNamedDeclaration(node) ? node.name + : node; Debug.assert(node.kind !== SyntaxKind.NamespaceExport); if (node.kind === SyntaxKind.ExportSpecifier) { - const diag = error(errorNode, Diagnostics.Types_cannot_appear_in_export_declarations_in_JavaScript_files); - const alreadyExportedSymbol = getSourceFileOfNode(node).symbol?.exports?.get((node.propertyName || node.name).escapedText); + const diag = error( + errorNode, + Diagnostics.Types_cannot_appear_in_export_declarations_in_JavaScript_files, + ); + const alreadyExportedSymbol = getSourceFileOfNode(node).symbol?.exports?.get( + (node.propertyName || node.name).escapedText, + ); if (alreadyExportedSymbol === target) { const exportingDeclaration = alreadyExportedSymbol.declarations?.find(isJSDocNode); if (exportingDeclaration) { @@ -42052,12 +54683,20 @@ namespace ts { } else { Debug.assert(node.kind !== SyntaxKind.VariableDeclaration); - const importDeclaration = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration)); - const moduleSpecifier = (importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration)?.text) ?? "..."; - const importedIdentifier = unescapeLeadingUnderscores(isIdentifier(errorNode) ? errorNode.escapedText : symbol.escapedName); + const importDeclaration = findAncestor( + node, + or(isImportDeclaration, isImportEqualsDeclaration), + ); + const moduleSpecifier = + (importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration)?.text) + ?? "..."; + const importedIdentifier = unescapeLeadingUnderscores( + isIdentifier(errorNode) ? errorNode.escapedText : symbol.escapedName, + ); error( errorNode, - Diagnostics._0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation, + Diagnostics + ._0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation, importedIdentifier, `import("${moduleSpecifier}").${importedIdentifier}`, ); @@ -42066,13 +54705,14 @@ namespace ts { } const targetFlags = getAllSymbolFlags(target); - const excludedMeanings = (symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) ? SymbolFlags.Value : 0) | - (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) | - (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); + const excludedMeanings = + (symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) ? SymbolFlags.Value : 0) + | (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) + | (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); if (targetFlags & excludedMeanings) { - const message = node.kind === SyntaxKind.ExportSpecifier ? - Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 : - Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0; + const message = node.kind === SyntaxKind.ExportSpecifier + ? Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 + : Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0; error(node, message, symbolToString(symbol)); } @@ -42089,19 +54729,34 @@ namespace ts { case SyntaxKind.ImportSpecifier: case SyntaxKind.ImportEqualsDeclaration: { if (compilerOptions.preserveValueImports) { - Debug.assertIsDefined(node.name, "An ImportClause with a symbol should have a name"); + Debug.assertIsDefined( + node.name, + "An ImportClause with a symbol should have a name", + ); const message = isType - ? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled - : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled; - const name = idText(node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name : node.name); + ? Diagnostics + ._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled + : Diagnostics + ._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled; + const name = idText( + node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name + : node.name, + ); addTypeOnlyDeclarationRelatedInfo( error(node, message, name), isType ? undefined : typeOnlyAlias, name, ); } - if (isType && node.kind === SyntaxKind.ImportEqualsDeclaration && hasEffectiveModifier(node, ModifierFlags.Export)) { - error(node, Diagnostics.Cannot_use_export_import_on_a_type_or_type_only_namespace_when_the_isolatedModules_flag_is_provided); + if ( + isType && node.kind === SyntaxKind.ImportEqualsDeclaration + && hasEffectiveModifier(node, ModifierFlags.Export) + ) { + error( + node, + Diagnostics + .Cannot_use_export_import_on_a_type_or_type_only_namespace_when_the_isolatedModules_flag_is_provided, + ); } break; } @@ -42111,8 +54766,10 @@ namespace ts { // because single-file analysis can determine that the export should be dropped. if (getSourceFileOfNode(typeOnlyAlias) !== getSourceFileOfNode(node)) { const message = isType - ? Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type - : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_isolatedModules_is_enabled; + ? Diagnostics + .Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type + : Diagnostics + ._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_isolatedModules_is_enabled; const name = idText(node.propertyName || node.name); addTypeOnlyDeclarationRelatedInfo( error(node, message, name), @@ -42136,7 +54793,8 @@ namespace ts { } function isDeprecatedAliasedSymbol(symbol: Symbol) { - return !!symbol.declarations && every(symbol.declarations, d => !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated)); + return !!symbol.declarations + && every(symbol.declarations, d => !!(getCombinedNodeFlags(d) & NodeFlags.Deprecated)); } function checkDeprecatedAliasedSymbol(symbol: Symbol, location: Node) { @@ -42171,10 +54829,12 @@ namespace ts { checkCollisionsForDeclarationName(node, node.name); checkAliasSymbol(node); if ( - node.kind === SyntaxKind.ImportSpecifier && - idText(node.propertyName || node.name) === "default" && - getESModuleInterop(compilerOptions) && - moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + node.kind === SyntaxKind.ImportSpecifier + && idText(node.propertyName || node.name) === "default" + && getESModuleInterop(compilerOptions) + && moduleKind !== ModuleKind.System + && (moduleKind < ModuleKind.ES2015 + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault); } @@ -42183,40 +54843,69 @@ namespace ts { function checkAssertClause(declaration: ImportDeclaration | ExportDeclaration) { if (declaration.assertClause) { const validForTypeAssertions = isExclusivelyTypeOnlyImportOrExport(declaration); - const override = getResolutionModeOverrideForClause(declaration.assertClause, validForTypeAssertions ? grammarErrorOnNode : undefined); + const override = getResolutionModeOverrideForClause( + declaration.assertClause, + validForTypeAssertions ? grammarErrorOnNode : undefined, + ); if (validForTypeAssertions && override) { if (!isNightly()) { - grammarErrorOnNode(declaration.assertClause, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next); + grammarErrorOnNode( + declaration.assertClause, + Diagnostics + .resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next, + ); } - if (getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) { - return grammarErrorOnNode(declaration.assertClause, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext); + if ( + getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 + && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext + ) { + return grammarErrorOnNode( + declaration.assertClause, + Diagnostics + .resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext, + ); } return; // Other grammar checks do not apply to type-only imports with resolution mode assertions } - const mode = (moduleKind === ModuleKind.NodeNext) && declaration.moduleSpecifier && getUsageModeForExpression(declaration.moduleSpecifier); + const mode = (moduleKind === ModuleKind.NodeNext) && declaration.moduleSpecifier + && getUsageModeForExpression(declaration.moduleSpecifier); if (mode !== ModuleKind.ESNext && moduleKind !== ModuleKind.ESNext) { return grammarErrorOnNode( declaration.assertClause, moduleKind === ModuleKind.NodeNext - ? Diagnostics.Import_assertions_are_not_allowed_on_statements_that_transpile_to_commonjs_require_calls - : Diagnostics.Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_or_nodenext, + ? Diagnostics + .Import_assertions_are_not_allowed_on_statements_that_transpile_to_commonjs_require_calls + : Diagnostics + .Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_or_nodenext, ); } if (isImportDeclaration(declaration) ? declaration.importClause?.isTypeOnly : declaration.isTypeOnly) { - return grammarErrorOnNode(declaration.assertClause, Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports); + return grammarErrorOnNode( + declaration.assertClause, + Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports, + ); } if (override) { - return grammarErrorOnNode(declaration.assertClause, Diagnostics.resolution_mode_can_only_be_set_for_type_only_imports); + return grammarErrorOnNode( + declaration.assertClause, + Diagnostics.resolution_mode_can_only_be_set_for_type_only_imports, + ); } } } function checkImportDeclaration(node: ImportDeclaration) { - if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) { + if ( + checkGrammarModuleElementContext( + node, + isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module + : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module, + ) + ) { // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. return; } @@ -42232,7 +54921,12 @@ namespace ts { if (importClause.namedBindings) { if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { checkImportBinding(importClause.namedBindings); - if (moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && getESModuleInterop(compilerOptions)) { + if ( + moduleKind !== ModuleKind.System + && (moduleKind < ModuleKind.ES2015 + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + && getESModuleInterop(compilerOptions) + ) { // import * as ns from "foo"; checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportStar); } @@ -42250,7 +54944,13 @@ namespace ts { } function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) { - if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) { + if ( + checkGrammarModuleElementContext( + node, + isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module + : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module, + ) + ) { // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. return; } @@ -42268,8 +54968,15 @@ namespace ts { if (targetFlags & SymbolFlags.Value) { // Target is a value symbol, check that it is not hidden by a local declaration with the same name const moduleName = getFirstIdentifier(node.moduleReference); - if (!(resolveEntityName(moduleName, SymbolFlags.Value | SymbolFlags.Namespace)!.flags & SymbolFlags.Namespace)) { - error(moduleName, Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, declarationNameToString(moduleName)); + if ( + !(resolveEntityName(moduleName, SymbolFlags.Value | SymbolFlags.Namespace)!.flags + & SymbolFlags.Namespace) + ) { + error( + moduleName, + Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, + declarationNameToString(moduleName), + ); } } if (targetFlags & SymbolFlags.Type) { @@ -42281,16 +54988,29 @@ namespace ts { } } else { - if (moduleKind >= ModuleKind.ES2015 && getSourceFileOfNode(node).impliedNodeFormat === undefined && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient)) { + if ( + moduleKind >= ModuleKind.ES2015 && getSourceFileOfNode(node).impliedNodeFormat === undefined + && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient) + ) { // Import equals declaration is deprecated in es6 or above - grammarErrorOnNode(node, Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead); + grammarErrorOnNode( + node, + Diagnostics + .Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead, + ); } } } } function checkExportDeclaration(node: ExportDeclaration) { - if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) { + if ( + checkGrammarModuleElementContext( + node, + isInJSFile(node) ? Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_module + : Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module, + ) + ) { // If we hit an export in an illegal context, just bail out to avoid cascading errors. return; } @@ -42299,7 +55019,10 @@ namespace ts { grammarErrorOnFirstToken(node, Diagnostics.An_export_declaration_cannot_have_modifiers); } - if (node.moduleSpecifier && node.exportClause && isNamedExports(node.exportClause) && length(node.exportClause.elements) && languageVersion === ScriptTarget.ES3) { + if ( + node.moduleSpecifier && node.exportClause && isNamedExports(node.exportClause) + && length(node.exportClause.elements) && languageVersion === ScriptTarget.ES3 + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.CreateBinding); } @@ -42309,10 +55032,15 @@ namespace ts { // export { x, y } // export { x, y } from "foo" forEach(node.exportClause.elements, checkExportSpecifier); - const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); - const inAmbientNamespaceDeclaration = !inAmbientExternalModule && node.parent.kind === SyntaxKind.ModuleBlock && - !node.moduleSpecifier && node.flags & NodeFlags.Ambient; - if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule && !inAmbientNamespaceDeclaration) { + const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock + && isAmbientModule(node.parent.parent); + const inAmbientNamespaceDeclaration = !inAmbientExternalModule + && node.parent.kind === SyntaxKind.ModuleBlock + && !node.moduleSpecifier && node.flags & NodeFlags.Ambient; + if ( + node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule + && !inAmbientNamespaceDeclaration + ) { error(node, Diagnostics.Export_declarations_are_not_permitted_in_a_namespace); } } @@ -42321,12 +55049,20 @@ namespace ts { // export * as ns from "foo"; const moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier!); if (moduleSymbol && hasExportAssignmentSymbol(moduleSymbol)) { - error(node.moduleSpecifier, Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, symbolToString(moduleSymbol)); + error( + node.moduleSpecifier, + Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, + symbolToString(moduleSymbol), + ); } else if (node.exportClause) { checkAliasSymbol(node.exportClause); } - if (moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) { + if ( + moduleKind !== ModuleKind.System + && (moduleKind < ModuleKind.ES2015 + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + ) { if (node.exportClause) { // export * as ns from "foo"; // For ES2015 modules, we emit it as a pair of `import * as a_1 ...; export { a_1 as ns }` and don't need the helper. @@ -42358,7 +55094,8 @@ namespace ts { } function checkGrammarModuleElementContext(node: Statement, errorMessage: DiagnosticMessage): boolean { - const isInAppropriateContext = node.parent.kind === SyntaxKind.SourceFile || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.ModuleDeclaration; + const isInAppropriateContext = node.parent.kind === SyntaxKind.SourceFile + || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.ModuleDeclaration; if (!isInAppropriateContext) { grammarErrorOnFirstToken(node, errorMessage); } @@ -42378,29 +55115,33 @@ namespace ts { } function canConvertImportDeclarationToTypeOnly(statement: Statement) { - return isImportDeclaration(statement) && - statement.importClause && - !statement.importClause.isTypeOnly && - importClauseContainsReferencedImport(statement.importClause) && - !isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true) && - !importClauseContainsConstEnumUsedAsValue(statement.importClause); + return isImportDeclaration(statement) + && statement.importClause + && !statement.importClause.isTypeOnly + && importClauseContainsReferencedImport(statement.importClause) + && !isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true) + && !importClauseContainsConstEnumUsedAsValue(statement.importClause); } function canConvertImportEqualsDeclarationToTypeOnly(statement: Statement) { - return isImportEqualsDeclaration(statement) && - isExternalModuleReference(statement.moduleReference) && - !statement.isTypeOnly && - getSymbolOfNode(statement).isReferenced && - !isReferencedAliasDeclaration(statement, /*checkChildren*/ false) && - !getSymbolLinks(getSymbolOfNode(statement)).constEnumReferenced; + return isImportEqualsDeclaration(statement) + && isExternalModuleReference(statement.moduleReference) + && !statement.isTypeOnly + && getSymbolOfNode(statement).isReferenced + && !isReferencedAliasDeclaration(statement, /*checkChildren*/ false) + && !getSymbolLinks(getSymbolOfNode(statement)).constEnumReferenced; } function checkImportsForTypeOnlyConversion(sourceFile: SourceFile) { for (const statement of sourceFile.statements) { - if (canConvertImportDeclarationToTypeOnly(statement) || canConvertImportEqualsDeclarationToTypeOnly(statement)) { + if ( + canConvertImportDeclarationToTypeOnly(statement) + || canConvertImportEqualsDeclarationToTypeOnly(statement) + ) { error( statement, - Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error, + Diagnostics + .This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error, ); } } @@ -42414,9 +55155,24 @@ namespace ts { if (!node.parent.parent.moduleSpecifier) { const exportedName = node.propertyName || node.name; // find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases) - const symbol = resolveName(exportedName, exportedName.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); - if (symbol && (symbol === undefinedSymbol || symbol === globalThisSymbol || symbol.declarations && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0])))) { - error(exportedName, Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, idText(exportedName)); + const symbol = resolveName( + exportedName, + exportedName.escapedText, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + ); + if ( + symbol + && (symbol === undefinedSymbol || symbol === globalThisSymbol + || symbol.declarations && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0]))) + ) { + error( + exportedName, + Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, + idText(exportedName), + ); } else { if (!node.isTypeOnly && !node.parent.parent.isTypeOnly) { @@ -42430,10 +55186,11 @@ namespace ts { } else { if ( - getESModuleInterop(compilerOptions) && - moduleKind !== ModuleKind.System && - (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && - idText(node.propertyName || node.name) === "default" + getESModuleInterop(compilerOptions) + && moduleKind !== ModuleKind.System + && (moduleKind < ModuleKind.ES2015 + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + && idText(node.propertyName || node.name) === "default" ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault); } @@ -42449,7 +55206,8 @@ namespace ts { return; } - const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent as ModuleDeclaration; + const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent + : node.parent.parent as ModuleDeclaration; if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) { if (node.isExportEquals) { error(node, Diagnostics.An_export_assignment_cannot_be_used_in_a_namespace); @@ -42467,12 +55225,22 @@ namespace ts { const typeAnnotationNode = getEffectiveTypeAnnotationNode(node); if (typeAnnotationNode) { - checkTypeAssignableTo(checkExpressionCached(node.expression), getTypeFromTypeNode(typeAnnotationNode), node.expression); + checkTypeAssignableTo( + checkExpressionCached(node.expression), + getTypeFromTypeNode(typeAnnotationNode), + node.expression, + ); } if (node.expression.kind === SyntaxKind.Identifier) { const id = node.expression as Identifier; - const sym = resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, node); + const sym = resolveEntityName( + id, + SymbolFlags.All, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + node, + ); if (sym) { markAliasReferenced(sym, id); // If not a value, we're interpreting the identifier as a type export, along the lines of (`export { Id as default }`) @@ -42497,13 +55265,24 @@ namespace ts { checkExternalModuleExports(container); if ((node.flags & NodeFlags.Ambient) && !isEntityNameExpression(node.expression)) { - grammarErrorOnNode(node.expression, Diagnostics.The_expression_of_an_export_assignment_must_be_an_identifier_or_qualified_name_in_an_ambient_context); + grammarErrorOnNode( + node.expression, + Diagnostics + .The_expression_of_an_export_assignment_must_be_an_identifier_or_qualified_name_in_an_ambient_context, + ); } if (node.isExportEquals && !(node.flags & NodeFlags.Ambient)) { - if (moduleKind >= ModuleKind.ES2015 && getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.CommonJS) { + if ( + moduleKind >= ModuleKind.ES2015 + && getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.CommonJS + ) { // export assignment is not supported in es6 modules - grammarErrorOnNode(node, Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead); + grammarErrorOnNode( + node, + Diagnostics + .Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead, + ); } else if (moduleKind === ModuleKind.System) { // system modules does not support export assignment @@ -42522,9 +55301,15 @@ namespace ts { if (!links.exportsChecked) { const exportEqualsSymbol = moduleSymbol.exports!.get("export=" as __String); if (exportEqualsSymbol && hasExportedMembers(moduleSymbol)) { - const declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) || exportEqualsSymbol.valueDeclaration; - if (declaration && !isTopLevelInExternalModuleAugmentation(declaration) && !isInJSFile(declaration)) { - error(declaration, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements); + const declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) + || exportEqualsSymbol.valueDeclaration; + if ( + declaration && !isTopLevelInExternalModuleAugmentation(declaration) && !isInJSFile(declaration) + ) { + error( + declaration, + Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements, + ); } } // Checks for export * conflicts @@ -42539,7 +55324,10 @@ namespace ts { if (flags & (SymbolFlags.Namespace | SymbolFlags.Enum)) { return; } - const exportedDeclarationsCount = countWhere(declarations, and(isNotOverloadAndNotAccessor, not(isInterfaceDeclaration))); + const exportedDeclarationsCount = countWhere( + declarations, + and(isNotOverloadAndNotAccessor, not(isInterfaceDeclaration)), + ); if (flags & SymbolFlags.TypeAlias && exportedDeclarationsCount <= 2) { // it is legal to merge type alias with other values // so count should be either 1 (just type alias) or 2 (type alias + merged value) @@ -42549,7 +55337,13 @@ namespace ts { if (!isDuplicatedCommonJSExport(declarations)) { for (const declaration of declarations!) { if (isNotOverload(declaration)) { - diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Cannot_redeclare_exported_variable_0, unescapeLeadingUnderscores(id))); + diagnostics.add( + createDiagnosticForNode( + declaration, + Diagnostics.Cannot_redeclare_exported_variable_0, + unescapeLeadingUnderscores(id), + ), + ); } } } @@ -42563,7 +55357,10 @@ namespace ts { function isDuplicatedCommonJSExport(declarations: Declaration[] | undefined) { return declarations && declarations.length > 1 - && declarations.every(d => isInJSFile(d) && isAccessExpression(d) && (isExportsIdentifier(d.expression) || isModuleExportsAccessExpression(d.expression))); + && declarations.every(d => + isInJSFile(d) && isAccessExpression(d) + && (isExportsIdentifier(d.expression) || isModuleExportsAccessExpression(d.expression)) + ); } function checkSourceElement(node: Node | undefined): void { @@ -42599,8 +55396,15 @@ namespace ts { cancellationToken.throwIfCancellationRequested(); } } - if (kind >= SyntaxKind.FirstStatement && kind <= SyntaxKind.LastStatement && node.flowNode && !isReachableFlowNode(node.flowNode)) { - errorOrSuggestion(compilerOptions.allowUnreachableCode === false, node, Diagnostics.Unreachable_code_detected); + if ( + kind >= SyntaxKind.FirstStatement && kind <= SyntaxKind.LastStatement && node.flowNode + && !isReachableFlowNode(node.flowNode) + ) { + errorOrSuggestion( + compilerOptions.allowUnreachableCode === false, + node, + Diagnostics.Unreachable_code_detected, + ); } switch (kind) { @@ -42700,7 +55504,9 @@ namespace ts { case SyntaxKind.JSDocPublicTag: case SyntaxKind.JSDocProtectedTag: case SyntaxKind.JSDocPrivateTag: - return checkJSDocAccessibilityModifiers(node as JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag); + return checkJSDocAccessibilityModifiers( + node as JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag, + ); case SyntaxKind.IndexedAccessType: return checkIndexedAccessType(node as IndexedAccessTypeNode); case SyntaxKind.MappedType: @@ -42840,12 +55646,14 @@ namespace ts { Because `a` will just be of type `number | undefined`. A synthetic `...args` will also be added, which *will* get an array type. */ const lastParamDeclaration = isCallbackTag - ? lastOrUndefined((paramTag.parent.parent as unknown as JSDocCallbackTag).typeExpression.parameters) + ? lastOrUndefined( + (paramTag.parent.parent as unknown as JSDocCallbackTag).typeExpression.parameters, + ) : lastOrUndefined(host!.parameters); const symbol = getParameterSymbolFromJSDoc(paramTag); if ( - !lastParamDeclaration || - symbol && lastParamDeclaration.symbol === symbol && isRestParameter(lastParamDeclaration) + !lastParamDeclaration + || symbol && lastParamDeclaration.symbol === symbol && isRestParameter(lastParamDeclaration) ) { return createArrayType(type); } @@ -42883,7 +55691,12 @@ namespace ts { } function checkDeferredNode(node: Node) { - tracing?.push(tracing.Phase.Check, "checkDeferredNode", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); + tracing?.push(tracing.Phase.Check, "checkDeferredNode", { + kind: node.kind, + pos: node.pos, + end: node.end, + path: (node as TracingNode).tracingPath, + }); const saveCurrentNode = currentNode; currentNode = node; instantiationCount = 0; @@ -42980,9 +55793,15 @@ namespace ts { addLazyDiagnostic(() => { // This relies on the results of other lazy diagnostics, so must be computed after them - if (!node.isDeclarationFile && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters)) { + if ( + !node.isDeclarationFile + && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters) + ) { checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(node), (containingNode, kind, diag) => { - if (!containsParseError(containingNode) && unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient))) { + if ( + !containsParseError(containingNode) + && unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient)) + ) { diagnostics.add(diag); } }); @@ -42993,9 +55812,9 @@ namespace ts { }); if ( - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error && - !node.isDeclarationFile && - isExternalModule(node) + compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error + && !node.isDeclarationFile + && isExternalModule(node) ) { checkImportsForTypeOnlyConversion(node); } @@ -43077,7 +55896,11 @@ namespace ts { const currentGlobalDiagnostics = diagnostics.getGlobalDiagnostics(); if (currentGlobalDiagnostics !== previousGlobalDiagnostics) { // If the arrays are not the same reference, new diagnostics were added. - const deferredGlobalDiagnostics = relativeComplement(previousGlobalDiagnostics, currentGlobalDiagnostics, compareDiagnostics); + const deferredGlobalDiagnostics = relativeComplement( + previousGlobalDiagnostics, + currentGlobalDiagnostics, + compareDiagnostics, + ); return concatenate(deferredGlobalDiagnostics, semanticDiagnostics); } else if (previousGlobalDiagnosticsSize === 0 && currentGlobalDiagnostics.length > 0) { @@ -43128,10 +55951,16 @@ namespace ts { if (!isExternalModule(location as SourceFile)) break; // falls through case SyntaxKind.ModuleDeclaration: - copyLocallyVisibleExportSymbols(getSymbolOfNode(location as ModuleDeclaration | SourceFile).exports!, meaning & SymbolFlags.ModuleMember); + copyLocallyVisibleExportSymbols( + getSymbolOfNode(location as ModuleDeclaration | SourceFile).exports!, + meaning & SymbolFlags.ModuleMember, + ); break; case SyntaxKind.EnumDeclaration: - copySymbols(getSymbolOfNode(location as EnumDeclaration).exports!, meaning & SymbolFlags.EnumMember); + copySymbols( + getSymbolOfNode(location as EnumDeclaration).exports!, + meaning & SymbolFlags.EnumMember, + ); break; case SyntaxKind.ClassExpression: const className = (location as ClassExpression).name; @@ -43149,7 +55978,12 @@ namespace ts { // (type parameters of classDeclaration/classExpression and interface are in member property of the symbol. // Note: that the memberFlags come from previous iteration. if (!isStaticSymbol) { - copySymbols(getMembersOfSymbol(getSymbolOfNode(location as ClassDeclaration | InterfaceDeclaration)), meaning & SymbolFlags.Type); + copySymbols( + getMembersOfSymbol( + getSymbolOfNode(location as ClassDeclaration | InterfaceDeclaration), + ), + meaning & SymbolFlags.Type, + ); } break; case SyntaxKind.FunctionExpression: @@ -43202,7 +56036,10 @@ namespace ts { if (meaning) { source.forEach(symbol => { // Similar condition as in `resolveNameHelper` - if (!getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier) && !getDeclarationOfKind(symbol, SyntaxKind.NamespaceExport)) { + if ( + !getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier) + && !getDeclarationOfKind(symbol, SyntaxKind.NamespaceExport) + ) { copySymbol(symbol, meaning); } }); @@ -43211,9 +56048,9 @@ namespace ts { } function isTypeDeclarationName(name: Node): boolean { - return name.kind === SyntaxKind.Identifier && - isTypeDeclaration(name.parent) && - getNameOfDeclaration(name.parent) === name; + return name.kind === SyntaxKind.Identifier + && isTypeDeclaration(name.parent) + && getNameOfDeclaration(name.parent) === name; } // True if the given identifier is part of a type reference @@ -43247,7 +56084,9 @@ namespace ts { function isNodeUsedDuringClassInitialization(node: Node) { return !!findAncestor(node, element => { - if (isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) { + if ( + isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element) + ) { return true; } else if (isClassLike(element) || isFunctionLikeDeclaration(element)) { @@ -43262,17 +56101,21 @@ namespace ts { return !!forEachEnclosingClass(node, n => n === classDeclaration); } - function getLeftSideOfImportEqualsOrExportAssignment(nodeOnRightSide: EntityName): ImportEqualsDeclaration | ExportAssignment | undefined { + function getLeftSideOfImportEqualsOrExportAssignment( + nodeOnRightSide: EntityName, + ): ImportEqualsDeclaration | ExportAssignment | undefined { while (nodeOnRightSide.parent.kind === SyntaxKind.QualifiedName) { nodeOnRightSide = nodeOnRightSide.parent as QualifiedName; } if (nodeOnRightSide.parent.kind === SyntaxKind.ImportEqualsDeclaration) { - return (nodeOnRightSide.parent as ImportEqualsDeclaration).moduleReference === nodeOnRightSide ? nodeOnRightSide.parent as ImportEqualsDeclaration : undefined; + return (nodeOnRightSide.parent as ImportEqualsDeclaration).moduleReference === nodeOnRightSide + ? nodeOnRightSide.parent as ImportEqualsDeclaration : undefined; } if (nodeOnRightSide.parent.kind === SyntaxKind.ExportAssignment) { - return (nodeOnRightSide.parent as ExportAssignment).expression === nodeOnRightSide as Node ? nodeOnRightSide.parent as ExportAssignment : undefined; + return (nodeOnRightSide.parent as ExportAssignment).expression === nodeOnRightSide as Node + ? nodeOnRightSide.parent as ExportAssignment : undefined; } return undefined; @@ -43283,7 +56126,9 @@ namespace ts { } function getSpecialPropertyAssignmentSymbolFromEntityName(entityName: EntityName | PropertyAccessExpression) { - const specialPropertyAssignmentKind = getAssignmentDeclarationKind(entityName.parent.parent as BinaryExpression); + const specialPropertyAssignmentKind = getAssignmentDeclarationKind( + entityName.parent.parent as BinaryExpression, + ); switch (specialPropertyAssignmentKind) { case AssignmentDeclarationKind.ExportsProperty: case AssignmentDeclarationKind.PrototypeProperty: @@ -43307,15 +56152,17 @@ namespace ts { return undefined; } - function getSymbolOfNameOrPropertyAccessExpression(name: EntityName | PrivateIdentifier | PropertyAccessExpression | JSDocMemberName): Symbol | undefined { + function getSymbolOfNameOrPropertyAccessExpression( + name: EntityName | PrivateIdentifier | PropertyAccessExpression | JSDocMemberName, + ): Symbol | undefined { if (isDeclarationName(name)) { return getSymbolOfNode(name.parent); } if ( - isInJSFile(name) && - name.parent.kind === SyntaxKind.PropertyAccessExpression && - name.parent === (name.parent.parent as BinaryExpression).left + isInJSFile(name) + && name.parent.kind === SyntaxKind.PropertyAccessExpression + && name.parent === (name.parent.parent as BinaryExpression).left ) { // Check if this is a special property assignment if (!isPrivateIdentifier(name) && !isJSDocMemberName(name)) { @@ -43328,7 +56175,11 @@ namespace ts { if (name.parent.kind === SyntaxKind.ExportAssignment && isEntityNameExpression(name)) { // Even an entity name expression that doesn't resolve as an entityname may still typecheck as a property access expression - const success = resolveEntityName(name, /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*ignoreErrors*/ true); + const success = resolveEntityName( + name, + /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + /*ignoreErrors*/ true, + ); if (success && success !== unknownSymbol) { return success; } @@ -43379,9 +56230,13 @@ namespace ts { return getParameterSymbolFromJSDoc(name.parent as JSDocParameterTag); } - if (name.parent.kind === SyntaxKind.TypeParameter && name.parent.parent.kind === SyntaxKind.JSDocTemplateTag) { + if ( + name.parent.kind === SyntaxKind.TypeParameter && name.parent.parent.kind === SyntaxKind.JSDocTemplateTag + ) { Debug.assert(!isInJSFile(name)); // Otherwise `isDeclarationName` would have been true. - const typeParameter = getTypeParameterFromJsDoc(name.parent as TypeParameterDeclaration & { parent: JSDocTemplateTag; }); + const typeParameter = getTypeParameterFromJsDoc( + name.parent as TypeParameterDeclaration & { parent: JSDocTemplateTag; }, + ); return typeParameter && typeParameter.symbol; } @@ -43392,13 +56247,20 @@ namespace ts { } const isJSDoc = findAncestor(name, or(isJSDocLinkLike, isJSDocNameReference, isJSDocMemberName)); - const meaning = isJSDoc ? SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value : SymbolFlags.Value; + const meaning = isJSDoc ? SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value + : SymbolFlags.Value; if (name.kind === SyntaxKind.Identifier) { if (isJSXTagName(name) && isJsxIntrinsicIdentifier(name)) { const symbol = getIntrinsicTagSymbol(name.parent as JsxOpeningLikeElement); return symbol === unknownSymbol ? undefined : symbol; } - const result = resolveEntityName(name, meaning, /*ignoreErrors*/ false, /* dontResolveAlias */ true, getHostSignatureFromJSDoc(name)); + const result = resolveEntityName( + name, + meaning, + /*ignoreErrors*/ false, + /* dontResolveAlias */ true, + getHostSignatureFromJSDoc(name), + ); if (!result && isJSDoc) { const container = findAncestor(name, or(isClassLike, isInterfaceDeclaration)); if (container) { @@ -43408,7 +56270,13 @@ namespace ts { if (result && isJSDoc) { const container = getJSDocHost(name); if (container && isEnumMember(container) && container === result.valueDeclaration) { - return resolveEntityName(name, meaning, /*ignoreErrors*/ true, /* dontResolveAlias */ true, getSourceFileOfNode(container)) || result; + return resolveEntityName( + name, + meaning, + /*ignoreErrors*/ true, + /* dontResolveAlias */ true, + getSourceFileOfNode(container), + ) || result; } } return result; @@ -43426,7 +56294,10 @@ namespace ts { checkPropertyAccessExpression(name, CheckMode.Normal); if (!links.resolvedSymbol) { const expressionType = checkExpressionCached(name.expression); - const infos = getApplicableIndexInfos(expressionType, getLiteralTypeFromPropertyName(name.name)); + const infos = getApplicableIndexInfos( + expressionType, + getLiteralTypeFromPropertyName(name.name), + ); if (infos.length && (expressionType as ObjectType).members) { const resolved = resolveStructuredTypeMembers(expressionType as ObjectType); const symbol = resolved.members.get(InternalSymbolName.Index); @@ -43446,7 +56317,9 @@ namespace ts { else { const copy = createSymbol(SymbolFlags.Signature, InternalSymbolName.Index); copy.declarations = mapDefined(infos, i => i.declaration); - copy.parent = expressionType.aliasSymbol ? expressionType.aliasSymbol : expressionType.symbol ? expressionType.symbol : getSymbolAtLocation(copy.declarations[0].parent); + copy.parent = expressionType.aliasSymbol ? expressionType.aliasSymbol + : expressionType.symbol ? expressionType.symbol + : getSymbolAtLocation(copy.declarations[0].parent); symbolLinks.filteredIndexSymbolCache.set(nodeListId, copy); links.resolvedSymbol = symbolLinks.filteredIndexSymbolCache.get(nodeListId)!; } @@ -43467,9 +56340,16 @@ namespace ts { } } else if (isTypeReferenceIdentifier(name as EntityName)) { - const meaning = name.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; - const symbol = resolveEntityName(name as EntityName, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ true); - return symbol && symbol !== unknownSymbol ? symbol : getUnresolvedSymbolForEntityName(name as EntityName); + const meaning = name.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type + : SymbolFlags.Namespace; + const symbol = resolveEntityName( + name as EntityName, + meaning, + /*ignoreErrors*/ false, + /*dontResolveAlias*/ true, + ); + return symbol && symbol !== unknownSymbol ? symbol + : getUnresolvedSymbolForEntityName(name as EntityName); } if (name.parent.kind === SyntaxKind.TypePredicate) { return resolveEntityName(name as Identifier, /*meaning*/ SymbolFlags.FunctionScopedVariable); @@ -43486,11 +56366,21 @@ namespace ts { * * For unqualified names, a container K may be provided as a second argument. */ - function resolveJSDocMemberName(name: EntityName | JSDocMemberName, ignoreErrors?: boolean, container?: Symbol): Symbol | undefined { + function resolveJSDocMemberName( + name: EntityName | JSDocMemberName, + ignoreErrors?: boolean, + container?: Symbol, + ): Symbol | undefined { if (isEntityName(name)) { // resolve static values first const meaning = SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value; - let symbol = resolveEntityName(name, meaning, ignoreErrors, /*dontResolveAlias*/ true, getHostSignatureFromJSDoc(name)); + let symbol = resolveEntityName( + name, + meaning, + ignoreErrors, + /*dontResolveAlias*/ true, + getHostSignatureFromJSDoc(name), + ); if (!symbol && isIdentifier(name) && container) { symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(container), name.escapedText, meaning)); } @@ -43501,7 +56391,8 @@ namespace ts { const left = isIdentifier(name) ? container : resolveJSDocMemberName(name.left, ignoreErrors, container); const right = isIdentifier(name) ? name.escapedText : name.right.escapedText; if (left) { - const proto = left.flags & SymbolFlags.Value && getPropertyOfType(getTypeOfSymbol(left), "prototype" as __String); + const proto = left.flags & SymbolFlags.Value + && getPropertyOfType(getTypeOfSymbol(left), "prototype" as __String); const t = proto ? getTypeOfSymbol(proto) : getDeclaredTypeOfSymbol(left); return getPropertyOfType(t, right); } @@ -43535,9 +56426,9 @@ namespace ts { return getSymbolOfNameOrPropertyAccessExpression(node as Identifier); } else if ( - parent.kind === SyntaxKind.BindingElement && - grandParent.kind === SyntaxKind.ObjectBindingPattern && - node === (parent as BindingElement).propertyName + parent.kind === SyntaxKind.BindingElement + && grandParent.kind === SyntaxKind.ObjectBindingPattern + && node === (parent as BindingElement).propertyName ) { const typeOfPattern = getTypeOfNode(grandParent); const propertyDeclaration = getPropertyOfType(typeOfPattern, (node as Identifier).escapedText); @@ -43569,7 +56460,9 @@ namespace ts { case SyntaxKind.PropertyAccessExpression: case SyntaxKind.QualifiedName: if (!isThisInTypeQuery(node)) { - return getSymbolOfNameOrPropertyAccessExpression(node as EntityName | PrivateIdentifier | PropertyAccessExpression); + return getSymbolOfNameOrPropertyAccessExpression( + node as EntityName | PrivateIdentifier | PropertyAccessExpression, + ); } // falls through @@ -43607,14 +56500,22 @@ namespace ts { // 3). Dynamic import call or require in javascript // 4). type A = import("./f/*gotToDefinitionHere*/oo") if ( - (isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) || - ((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && (node.parent as ImportDeclaration).moduleSpecifier === node) || - ((isInJSFile(node) && isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false)) || isImportCall(node.parent)) || - (isLiteralTypeNode(node.parent) && isLiteralImportTypeNode(node.parent.parent) && node.parent.parent.argument === node.parent) + (isExternalModuleImportEqualsDeclaration(node.parent.parent) + && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) + || ((node.parent.kind === SyntaxKind.ImportDeclaration + || node.parent.kind === SyntaxKind.ExportDeclaration) + && (node.parent as ImportDeclaration).moduleSpecifier === node) + || ((isInJSFile(node) && isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false)) + || isImportCall(node.parent)) + || (isLiteralTypeNode(node.parent) && isLiteralImportTypeNode(node.parent.parent) + && node.parent.parent.argument === node.parent) ) { return resolveExternalModuleName(node, node as LiteralExpression, ignoreErrors); } - if (isCallExpression(parent) && isBindableObjectDefinePropertyCall(parent) && parent.arguments[1] === node) { + if ( + isCallExpression(parent) && isBindableObjectDefinePropertyCall(parent) + && parent.arguments[1] === node + ) { return getSymbolOfNode(parent); } // falls through @@ -43626,7 +56527,11 @@ namespace ts { : isLiteralTypeNode(parent) && isIndexedAccessTypeNode(grandParent) ? getTypeFromTypeNode(grandParent.objectType) : undefined; - return objectType && getPropertyOfType(objectType, escapeLeadingUnderscores((node as StringLiteral | NumericLiteral).text)); + return objectType + && getPropertyOfType( + objectType, + escapeLeadingUnderscores((node as StringLiteral | NumericLiteral).text), + ); case SyntaxKind.DefaultKeyword: case SyntaxKind.FunctionKeyword: @@ -43634,7 +56539,8 @@ namespace ts { case SyntaxKind.ClassKeyword: return getSymbolOfNode(node.parent); case SyntaxKind.ImportType: - return isLiteralImportTypeNode(node) ? getSymbolAtLocation(node.argument.literal, ignoreErrors) : undefined; + return isLiteralImportTypeNode(node) ? getSymbolAtLocation(node.argument.literal, ignoreErrors) + : undefined; case SyntaxKind.ExportKeyword: return isExportAssignment(node.parent) ? Debug.checkDefined(node.parent.symbol) : undefined; @@ -43655,14 +56561,20 @@ namespace ts { const keyType = getLiteralTypeFromPropertyName(node); const objectType = getTypeOfExpression(node.parent.expression); const objectTypes = objectType.flags & TypeFlags.Union ? (objectType as UnionType).types : [objectType]; - return flatMap(objectTypes, t => filter(getIndexInfosOfType(t), info => isApplicableIndexType(keyType, info.keyType))); + return flatMap( + objectTypes, + t => filter(getIndexInfosOfType(t), info => isApplicableIndexType(keyType, info.keyType)), + ); } return undefined; } function getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined { if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) { - return resolveEntityName((location as ShorthandPropertyAssignment).name, SymbolFlags.Value | SymbolFlags.Alias); + return resolveEntityName( + (location as ShorthandPropertyAssignment).name, + SymbolFlags.Value | SymbolFlags.Alias, + ); } return undefined; } @@ -43670,12 +56582,18 @@ namespace ts { /** Returns the target of an export specifier without following aliases */ function getExportSpecifierLocalTargetSymbol(node: ExportSpecifier | Identifier): Symbol | undefined { if (isExportSpecifier(node)) { - return node.parent.parent.moduleSpecifier ? - getExternalModuleMember(node.parent.parent, node) : - resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); + return node.parent.parent.moduleSpecifier + ? getExternalModuleMember(node.parent.parent, node) + : resolveEntityName( + node.propertyName || node.name, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + ); } else { - return resolveEntityName(node, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); + return resolveEntityName( + node, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + ); } } @@ -43733,7 +56651,8 @@ namespace ts { } if (isBindingPattern(node)) { - return getTypeForVariableLikeDeclaration(node.parent, /*includeOptionality*/ true, CheckMode.Normal) || errorType; + return getTypeForVariableLikeDeclaration(node.parent, /*includeOptionality*/ true, CheckMode.Normal) + || errorType; } if (isInRightSideOfImportOrExportAssignment(node as Identifier)) { @@ -43758,7 +56677,9 @@ namespace ts { // [ a ] from // [a] = [ some array ...] function getTypeOfAssignmentPattern(expr: AssignmentPattern): Type | undefined { - Debug.assert(expr.kind === SyntaxKind.ObjectLiteralExpression || expr.kind === SyntaxKind.ArrayLiteralExpression); + Debug.assert( + expr.kind === SyntaxKind.ObjectLiteralExpression || expr.kind === SyntaxKind.ArrayLiteralExpression, + ); // If this is from "for of" // for ( { a } of elems) { // } @@ -43778,14 +56699,28 @@ namespace ts { const node = cast(expr.parent.parent, isObjectLiteralExpression); const typeOfParentObjectLiteral = getTypeOfAssignmentPattern(node) || errorType; const propertyIndex = indexOfNode(node.properties, expr.parent); - return checkObjectLiteralDestructuringPropertyAssignment(node, typeOfParentObjectLiteral, propertyIndex); + return checkObjectLiteralDestructuringPropertyAssignment( + node, + typeOfParentObjectLiteral, + propertyIndex, + ); } // Array literal assignment - array destructuring pattern const node = cast(expr.parent, isArrayLiteralExpression); // [{ property1: p1, property2 }] = elems; const typeOfArrayLiteral = getTypeOfAssignmentPattern(node) || errorType; - const elementType = checkIteratedTypeOrElementType(IterationUse.Destructuring, typeOfArrayLiteral, undefinedType, expr.parent) || errorType; - return checkArrayLiteralDestructuringElementAssignment(node, typeOfArrayLiteral, node.elements.indexOf(expr), elementType); + const elementType = checkIteratedTypeOrElementType( + IterationUse.Destructuring, + typeOfArrayLiteral, + undefinedType, + expr.parent, + ) || errorType; + return checkArrayLiteralDestructuringElementAssignment( + node, + typeOfArrayLiteral, + node.elements.indexOf(expr), + elementType, + ); } // Gets the property symbol corresponding to the property in destructuring assignment @@ -43839,9 +56774,9 @@ namespace ts { function getAugmentedPropertiesOfType(type: Type): Symbol[] { type = getApparentType(type); const propsByName = createSymbolTable(getPropertiesOfType(type)); - const functionType = getSignaturesOfType(type, SignatureKind.Call).length ? globalCallableFunctionType : - getSignaturesOfType(type, SignatureKind.Construct).length ? globalNewableFunctionType : - undefined; + const functionType = getSignaturesOfType(type, SignatureKind.Call).length ? globalCallableFunctionType + : getSignaturesOfType(type, SignatureKind.Construct).length ? globalNewableFunctionType + : undefined; if (functionType) { forEach(getPropertiesOfType(functionType), p => { if (!propsByName.has(p.escapedName)) { @@ -43862,7 +56797,10 @@ namespace ts { } function getImmediateRootSymbols(symbol: Symbol): readonly Symbol[] | undefined { if (getCheckFlags(symbol) & CheckFlags.Synthetic) { - return mapDefined(getSymbolLinks(symbol).containingType!.types, type => getPropertyOfType(type, symbol.escapedName)); + return mapDefined( + getSymbolLinks(symbol).containingType!.types, + type => getPropertyOfType(type, symbol.escapedName), + ); } else if (symbol.flags & SymbolFlags.Transient) { const { leftSpread, rightSpread, syntheticOrigin } = symbol as TransientSymbol; @@ -43931,35 +56869,51 @@ namespace ts { // When resolved as an expression identifier, if the given node references an exported entity, return the declaration // node of the exported entity's container. Otherwise, return undefined. - function getReferencedExportContainer(nodeIn: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration | undefined { + function getReferencedExportContainer( + nodeIn: Identifier, + prefixLocals?: boolean, + ): SourceFile | ModuleDeclaration | EnumDeclaration | undefined { const node = getParseTreeNode(nodeIn, isIdentifier); if (node) { // When resolving the export container for the name of a module or enum // declaration, we need to start resolution at the declaration's container. // Otherwise, we could incorrectly resolve the export container as the // declaration if it contains an exported member with the same name. - let symbol = getReferencedValueSymbol(node, /*startInDeclarationContainer*/ isNameOfModuleOrEnumDeclaration(node)); + let symbol = getReferencedValueSymbol( + node, + /*startInDeclarationContainer*/ isNameOfModuleOrEnumDeclaration(node), + ); if (symbol) { if (symbol.flags & SymbolFlags.ExportValue) { // If we reference an exported entity within the same module declaration, then whether // we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the // kinds that we do NOT prefix. const exportSymbol = getMergedSymbol(symbol.exportSymbol!); - if (!prefixLocals && exportSymbol.flags & SymbolFlags.ExportHasLocal && !(exportSymbol.flags & SymbolFlags.Variable)) { + if ( + !prefixLocals && exportSymbol.flags & SymbolFlags.ExportHasLocal + && !(exportSymbol.flags & SymbolFlags.Variable) + ) { return undefined; } symbol = exportSymbol; } const parentSymbol = getParentOfSymbol(symbol); if (parentSymbol) { - if (parentSymbol.flags & SymbolFlags.ValueModule && parentSymbol.valueDeclaration?.kind === SyntaxKind.SourceFile) { + if ( + parentSymbol.flags & SymbolFlags.ValueModule + && parentSymbol.valueDeclaration?.kind === SyntaxKind.SourceFile + ) { const symbolFile = parentSymbol.valueDeclaration as SourceFile; const referenceFile = getSourceFileOfNode(node); // If `node` accesses an export and that export isn't in the same file, then symbol is a namespace export, so return undefined. const symbolIsUmdExport = symbolFile !== referenceFile; return symbolIsUmdExport ? undefined : symbolFile; } - return findAncestor(node.parent, (n): n is ModuleDeclaration | EnumDeclaration => isModuleOrEnumDeclaration(n) && getSymbolOfNode(n) === parentSymbol); + return findAncestor( + node.parent, + (n): n is ModuleDeclaration | EnumDeclaration => + isModuleOrEnumDeclaration(n) && getSymbolOfNode(n) === parentSymbol, + ); } } } @@ -43977,7 +56931,10 @@ namespace ts { // We should only get the declaration of an alias if there isn't a local value // declaration for the symbol - if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)) { + if ( + isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) + && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value) + ) { return getDeclarationOfAliasSymbol(symbol); } } @@ -43992,13 +56949,25 @@ namespace ts { } function isSymbolOfDeclarationWithCollidingName(symbol: Symbol): boolean { - if (symbol.flags & SymbolFlags.BlockScoped && symbol.valueDeclaration && !isSourceFile(symbol.valueDeclaration)) { + if ( + symbol.flags & SymbolFlags.BlockScoped && symbol.valueDeclaration + && !isSourceFile(symbol.valueDeclaration) + ) { const links = getSymbolLinks(symbol); if (links.isDeclarationWithCollidingName === undefined) { const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); if (isStatementWithLocals(container) || isSymbolOfDestructuredElementOfCatchBinding(symbol)) { const nodeLinks = getNodeLinks(symbol.valueDeclaration); - if (resolveName(container.parent, symbol.escapedName, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)) { + if ( + resolveName( + container.parent, + symbol.escapedName, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ) + ) { // redeclaration - always should be renamed links.isDeclarationWithCollidingName = true; } @@ -44019,10 +56988,15 @@ namespace ts { // * variables that are declared immediately in loop body will become top level variable after loop is rewritten and thus // they will not collide with anything const isDeclaredInLoop = nodeLinks.flags & NodeCheckFlags.BlockScopedBindingInLoop; - const inLoopInitializer = isIterationStatement(container, /*lookInLabeledStatements*/ false); - const inLoopBodyBlock = container.kind === SyntaxKind.Block && isIterationStatement(container.parent, /*lookInLabeledStatements*/ false); + const inLoopInitializer = isIterationStatement( + container, + /*lookInLabeledStatements*/ false, + ); + const inLoopBodyBlock = container.kind === SyntaxKind.Block + && isIterationStatement(container.parent, /*lookInLabeledStatements*/ false); - links.isDeclarationWithCollidingName = !isBlockScopedContainerTopLevel(container) && (!isDeclaredInLoop || (!inLoopInitializer && !inLoopBodyBlock)); + links.isDeclarationWithCollidingName = !isBlockScopedContainerTopLevel(container) + && (!isDeclaredInLoop || (!inLoopInitializer && !inLoopBodyBlock)); } else { links.isDeclarationWithCollidingName = false; @@ -44074,24 +57048,29 @@ namespace ts { case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: const symbol = getSymbolOfNode(node); - return !!symbol && isAliasResolvedToValue(symbol) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value); + return !!symbol && isAliasResolvedToValue(symbol) + && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value); case SyntaxKind.ExportDeclaration: const exportClause = (node as ExportDeclaration).exportClause; return !!exportClause && ( - isNamespaceExport(exportClause) || - some(exportClause.elements, isValueAliasDeclaration) + isNamespaceExport(exportClause) + || some(exportClause.elements, isValueAliasDeclaration) ); case SyntaxKind.ExportAssignment: - return (node as ExportAssignment).expression && (node as ExportAssignment).expression.kind === SyntaxKind.Identifier ? - isAliasResolvedToValue(getSymbolOfNode(node)) : - true; + return (node as ExportAssignment).expression + && (node as ExportAssignment).expression.kind === SyntaxKind.Identifier + ? isAliasResolvedToValue(getSymbolOfNode(node)) + : true; } return false; } function isTopLevelValueImportEqualsWithEntityName(nodeIn: ImportEqualsDeclaration): boolean { const node = getParseTreeNode(nodeIn, isImportEqualsDeclaration); - if (node === undefined || node.parent.kind !== SyntaxKind.SourceFile || !isInternalModuleImportEqualsDeclaration(node)) { + if ( + node === undefined || node.parent.kind !== SyntaxKind.SourceFile + || !isInternalModuleImportEqualsDeclaration(node) + ) { // parent is not source file or it is not reference to internal module return false; } @@ -44110,8 +57089,8 @@ namespace ts { } // const enums and modules that contain only const enums are not considered values from the emit perspective // unless 'preserveConstEnums' option is set to true - return !!((getAllSymbolFlags(target) ?? -1) & SymbolFlags.Value) && - (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)); + return !!((getAllSymbolFlags(target) ?? -1) & SymbolFlags.Value) + && (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)); } function isConstEnumOrConstEnumOnlyModule(s: Symbol): boolean { @@ -44127,9 +57106,9 @@ namespace ts { } const target = getSymbolLinks(symbol!).aliasTarget; // TODO: GH#18217 if ( - target && getEffectiveModifierFlags(node) & ModifierFlags.Export && - getAllSymbolFlags(target) & SymbolFlags.Value && - (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)) + target && getEffectiveModifierFlags(node) & ModifierFlags.Export + && getAllSymbolFlags(target) & SymbolFlags.Value + && (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)) ) { // An `export import ... =` of a value symbol is always considered referenced return true; @@ -44153,30 +57132,30 @@ namespace ts { // function foo(a: any) { // This is implementation of the overloads // return a; // } - return signaturesOfSymbol.length > 1 || + return signaturesOfSymbol.length > 1 // If there is single signature for the symbol, it is overload if that signature isn't coming from the node // e.g.: function foo(a: string): string; // function foo(a: any) { // This is implementation of the overloads // return a; // } - (signaturesOfSymbol.length === 1 && signaturesOfSymbol[0].declaration !== node); + || (signaturesOfSymbol.length === 1 && signaturesOfSymbol[0].declaration !== node); } return false; } function isRequiredInitializedParameter(parameter: ParameterDeclaration | JSDocParameterTag): boolean { - return !!strictNullChecks && - !isOptionalParameter(parameter) && - !isJSDocParameterTag(parameter) && - !!parameter.initializer && - !hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); + return !!strictNullChecks + && !isOptionalParameter(parameter) + && !isJSDocParameterTag(parameter) + && !!parameter.initializer + && !hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); } function isOptionalUninitializedParameterProperty(parameter: ParameterDeclaration) { - return strictNullChecks && - isOptionalParameter(parameter) && - !parameter.initializer && - hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); + return strictNullChecks + && isOptionalParameter(parameter) + && !parameter.initializer + && hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); } function isExpandoFunctionDeclaration(node: Declaration): boolean { @@ -44188,7 +57167,11 @@ namespace ts { if (!symbol || !(symbol.flags & SymbolFlags.Function)) { return false; } - return !!forEachEntry(getExportsOfSymbol(symbol), p => p.flags & SymbolFlags.Value && p.valueDeclaration && isPropertyAccessExpression(p.valueDeclaration)); + return !!forEachEntry( + getExportsOfSymbol(symbol), + p => p.flags & SymbolFlags.Value && p.valueDeclaration + && isPropertyAccessExpression(p.valueDeclaration), + ); } function getPropertiesOfContainerFunction(node: Declaration): Symbol[] { @@ -44242,7 +57225,10 @@ namespace ts { return !!(type.flags & TypeFlags.Object) && getSignaturesOfType(type, SignatureKind.Call).length > 0; } - function getTypeReferenceSerializationKind(typeNameIn: EntityName, location?: Node): TypeReferenceSerializationKind { + function getTypeReferenceSerializationKind( + typeNameIn: EntityName, + location?: Node, + ): TypeReferenceSerializationKind { // ensure both `typeName` and `location` are parse tree nodes. const typeName = getParseTreeNode(typeNameIn, isEntityName); if (!typeName) return TypeReferenceSerializationKind.Unknown; @@ -44255,15 +57241,34 @@ namespace ts { // Resolve the symbol as a value to ensure the type can be reached at runtime during emit. let isTypeOnly = false; if (isQualifiedName(typeName)) { - const rootValueSymbol = resolveEntityName(getFirstIdentifier(typeName), SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); + const rootValueSymbol = resolveEntityName( + getFirstIdentifier(typeName), + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + location, + ); isTypeOnly = !!rootValueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration); } - const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); - const resolvedSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) : valueSymbol; + const valueSymbol = resolveEntityName( + typeName, + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + location, + ); + const resolvedSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) + : valueSymbol; isTypeOnly ||= !!valueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration); // Resolve the symbol as a type so that we can provide a more useful hint for the type serializer. - const typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location); + const typeSymbol = resolveEntityName( + typeName, + SymbolFlags.Type, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ false, + location, + ); if (resolvedSymbol && resolvedSymbol === typeSymbol) { const globalPromiseSymbol = getGlobalPromiseConstructorSymbol(/*reportErrors*/ false); if (globalPromiseSymbol && resolvedSymbol === globalPromiseSymbol) { @@ -44272,7 +57277,8 @@ namespace ts { const constructorType = getTypeOfSymbol(resolvedSymbol); if (constructorType && isConstructorType(constructorType)) { - return isTypeOnly ? TypeReferenceSerializationKind.TypeWithCallSignature : TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue; + return isTypeOnly ? TypeReferenceSerializationKind.TypeWithCallSignature + : TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue; } } @@ -44319,7 +57325,13 @@ namespace ts { } } - function createTypeOfDeclaration(declarationIn: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean) { + function createTypeOfDeclaration( + declarationIn: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + addUndefined?: boolean, + ) { const declaration = getParseTreeNode(declarationIn, isVariableLikeOrAccessor); if (!declaration) { return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; @@ -44330,40 +57342,68 @@ namespace ts { ? getWidenedLiteralType(getTypeOfSymbol(symbol)) : errorType; if ( - type.flags & TypeFlags.UniqueESSymbol && - type.symbol === symbol + type.flags & TypeFlags.UniqueESSymbol + && type.symbol === symbol ) { flags |= NodeBuilderFlags.AllowUniqueESSymbolType; } if (addUndefined) { type = getOptionalType(type); } - return nodeBuilder.typeToTypeNode(type, enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, tracker); + return nodeBuilder.typeToTypeNode( + type, + enclosingDeclaration, + flags | NodeBuilderFlags.MultilineObjectLiterals, + tracker, + ); } - function createReturnTypeOfSignatureDeclaration(signatureDeclarationIn: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker) { + function createReturnTypeOfSignatureDeclaration( + signatureDeclarationIn: SignatureDeclaration, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + ) { const signatureDeclaration = getParseTreeNode(signatureDeclarationIn, isFunctionLike); if (!signatureDeclaration) { return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; } const signature = getSignatureFromDeclaration(signatureDeclaration); - return nodeBuilder.typeToTypeNode(getReturnTypeOfSignature(signature), enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, tracker); + return nodeBuilder.typeToTypeNode( + getReturnTypeOfSignature(signature), + enclosingDeclaration, + flags | NodeBuilderFlags.MultilineObjectLiterals, + tracker, + ); } - function createTypeOfExpression(exprIn: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker) { + function createTypeOfExpression( + exprIn: Expression, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + ) { const expr = getParseTreeNode(exprIn, isExpression); if (!expr) { return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; } const type = getWidenedType(getRegularTypeOfExpression(expr)); - return nodeBuilder.typeToTypeNode(type, enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, tracker); + return nodeBuilder.typeToTypeNode( + type, + enclosingDeclaration, + flags | NodeBuilderFlags.MultilineObjectLiterals, + tracker, + ); } function hasGlobalName(name: string): boolean { return globals.has(escapeLeadingUnderscores(name)); } - function getReferencedValueSymbol(reference: Identifier, startInDeclarationContainer?: boolean): Symbol | undefined { + function getReferencedValueSymbol( + reference: Identifier, + startInDeclarationContainer?: boolean, + ): Symbol | undefined { const resolvedSymbol = getNodeLinks(reference).resolvedSymbol; if (resolvedSymbol) { return resolvedSymbol; @@ -44379,7 +57419,14 @@ namespace ts { } } - return resolveName(location, reference.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); + return resolveName( + location, + reference.escapedText, + SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, + /*nodeNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + ); } /** @@ -44421,7 +57468,9 @@ namespace ts { return undefined; } - function isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean { + function isLiteralConstDeclaration( + node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, + ): boolean { if (isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConst(node)) { return isFreshLiteralType(getTypeOfSymbol(getSymbolOfNode(node))); } @@ -44429,22 +57478,34 @@ namespace ts { } function literalTypeToNode(type: FreshableType, enclosing: Node, tracker: SymbolTracker): Expression { - const enumResult = type.flags & TypeFlags.EnumLiteral ? nodeBuilder.symbolToExpression(type.symbol, SymbolFlags.Value, enclosing, /*flags*/ undefined, tracker) + const enumResult = type.flags & TypeFlags.EnumLiteral + ? nodeBuilder.symbolToExpression( + type.symbol, + SymbolFlags.Value, + enclosing, + /*flags*/ undefined, + tracker, + ) : type === trueType ? factory.createTrue() : type === falseType && factory.createFalse(); if (enumResult) return enumResult; const literalValue = (type as LiteralType).value; - return typeof literalValue === "object" ? factory.createBigIntLiteral(literalValue) : - typeof literalValue === "number" ? factory.createNumericLiteral(literalValue) : - factory.createStringLiteral(literalValue); + return typeof literalValue === "object" ? factory.createBigIntLiteral(literalValue) + : typeof literalValue === "number" ? factory.createNumericLiteral(literalValue) + : factory.createStringLiteral(literalValue); } - function createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker) { + function createLiteralConstValue( + node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, + tracker: SymbolTracker, + ) { const type = getTypeOfSymbol(getSymbolOfNode(node)); return literalTypeToNode(type as FreshableType, node, tracker); } function getJsxFactoryEntity(location: Node): EntityName | undefined { - return location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity; + return location + ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) + : _jsxFactoryEntity; } function getJsxFragmentFactoryEntity(location: Node): EntityName | undefined { @@ -44457,7 +57518,10 @@ namespace ts { const jsxFragPragmas = file.pragmas.get("jsxfrag"); const jsxFragPragma = isArray(jsxFragPragmas) ? jsxFragPragmas[0] : jsxFragPragmas; if (jsxFragPragma) { - file.localJsxFragmentFactory = parseIsolatedEntityName(jsxFragPragma.arguments.factory, languageVersion); + file.localJsxFragmentFactory = parseIsolatedEntityName( + jsxFragPragma.arguments.factory, + languageVersion, + ); return file.localJsxFragmentFactory; } } @@ -44475,7 +57539,10 @@ namespace ts { let fileToDirective: ESMap; if (resolvedTypeReferenceDirectives) { // populate reverse mapping: file path -> type reference directive that was resolved to this file - fileToDirective = new Map(); + fileToDirective = new Map< + string, + [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined] + >(); resolvedTypeReferenceDirectives.forEach((resolvedDirective, key, mode) => { if (!resolvedDirective || !resolvedDirective.resolvedFileName) { return; @@ -44548,12 +57615,20 @@ namespace ts { getJsxFragmentFactoryEntity, getAllAccessorDeclarations(accessor: AccessorDeclaration): AllAccessorDeclarations { accessor = getParseTreeNode(accessor, isGetOrSetAccessorDeclaration)!; // TODO: GH#18217 - const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor; - const otherAccessor = getDeclarationOfKind(getSymbolOfNode(accessor), otherKind); - const firstAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? otherAccessor : accessor; - const secondAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? accessor : otherAccessor; - const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor : otherAccessor as SetAccessorDeclaration; - const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor : otherAccessor as GetAccessorDeclaration; + const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor + : SyntaxKind.SetAccessor; + const otherAccessor = getDeclarationOfKind( + getSymbolOfNode(accessor), + otherKind, + ); + const firstAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? otherAccessor + : accessor; + const secondAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? accessor + : otherAccessor; + const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor + : otherAccessor as SetAccessorDeclaration; + const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor + : otherAccessor as GetAccessorDeclaration; return { firstAccessor, secondAccessor, @@ -44561,20 +57636,34 @@ namespace ts { getAccessor, }; }, - getSymbolOfExternalModuleSpecifier: moduleName => resolveExternalModuleNameWorker(moduleName, moduleName, /*moduleNotFoundError*/ undefined), + getSymbolOfExternalModuleSpecifier: moduleName => + resolveExternalModuleNameWorker(moduleName, moduleName, /*moduleNotFoundError*/ undefined), isBindingCapturedByNode: (node, decl) => { const parseNode = getParseTreeNode(node); const parseDecl = getParseTreeNode(decl); - return !!parseNode && !!parseDecl && (isVariableDeclaration(parseDecl) || isBindingElement(parseDecl)) && isBindingCapturedByNode(parseNode, parseDecl); + return !!parseNode && !!parseDecl + && (isVariableDeclaration(parseDecl) || isBindingElement(parseDecl)) + && isBindingCapturedByNode(parseNode, parseDecl); }, getDeclarationStatementsForSourceFile: (node, flags, tracker, bundled) => { const n = getParseTreeNode(node) as SourceFile; - Debug.assert(n && n.kind === SyntaxKind.SourceFile, "Non-sourcefile node passed into getDeclarationsForSourceFile"); + Debug.assert( + n && n.kind === SyntaxKind.SourceFile, + "Non-sourcefile node passed into getDeclarationsForSourceFile", + ); const sym = getSymbolOfNode(node); if (!sym) { - return !node.locals ? [] : nodeBuilder.symbolTableToDeclarationStatements(node.locals, node, flags, tracker, bundled); + return !node.locals ? [] + : nodeBuilder.symbolTableToDeclarationStatements( + node.locals, + node, + flags, + tracker, + bundled, + ); } - return !sym.exports ? [] : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker, bundled); + return !sym.exports ? [] + : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker, bundled); }, isImportRequiredByAugmentation, }; @@ -44603,11 +57692,14 @@ namespace ts { } function isInHeritageClause(node: PropertyAccessEntityNameExpression) { - return node.parent && node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && node.parent.parent && node.parent.parent.kind === SyntaxKind.HeritageClause; + return node.parent && node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && node.parent.parent + && node.parent.parent.kind === SyntaxKind.HeritageClause; } // defined here to avoid outer scope pollution - function getTypeReferenceDirectivesForEntityName(node: EntityNameOrEntityNameExpression): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined { + function getTypeReferenceDirectivesForEntityName( + node: EntityNameOrEntityNameExpression, + ): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined { // program does not have any files with type reference directives - bail out if (!fileToDirective) { return undefined; @@ -44622,23 +57714,32 @@ namespace ts { } else { meaning = SymbolFlags.Type | SymbolFlags.Namespace; - if ((node.kind === SyntaxKind.Identifier && isInTypeQuery(node)) || (node.kind === SyntaxKind.PropertyAccessExpression && !isInHeritageClause(node))) { + if ( + (node.kind === SyntaxKind.Identifier && isInTypeQuery(node)) + || (node.kind === SyntaxKind.PropertyAccessExpression && !isInHeritageClause(node)) + ) { meaning = SymbolFlags.Value | SymbolFlags.ExportValue; } } const symbol = resolveEntityName(node, meaning, /*ignoreErrors*/ true); - return symbol && symbol !== unknownSymbol ? getTypeReferenceDirectivesForSymbol(symbol, meaning) : undefined; + return symbol && symbol !== unknownSymbol ? getTypeReferenceDirectivesForSymbol(symbol, meaning) + : undefined; } // defined here to avoid outer scope pollution - function getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined { + function getTypeReferenceDirectivesForSymbol( + symbol: Symbol, + meaning?: SymbolFlags, + ): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined { // program does not have any files with type reference directives - bail out if (!fileToDirective || !isSymbolFromTypeDeclarationFile(symbol)) { return undefined; } // check what declarations in the symbol can contribute to the target meaning - let typeReferenceDirectives: [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined; + let typeReferenceDirectives: + | [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] + | undefined; for (const decl of symbol.declarations!) { // check meaning of the local symbol to see if declaration needs to be analyzed further if (decl.symbol && decl.symbol.flags & meaning!) { @@ -44675,7 +57776,10 @@ namespace ts { } } - if (current.valueDeclaration && current.valueDeclaration.kind === SyntaxKind.SourceFile && current.flags & SymbolFlags.ValueModule) { + if ( + current.valueDeclaration && current.valueDeclaration.kind === SyntaxKind.SourceFile + && current.flags & SymbolFlags.ValueModule + ) { return false; } @@ -44689,22 +57793,37 @@ namespace ts { return false; } - function addReferencedFilesToTypeDirective(file: SourceFile, key: string, mode: SourceFile["impliedNodeFormat"] | undefined) { + function addReferencedFilesToTypeDirective( + file: SourceFile, + key: string, + mode: SourceFile["impliedNodeFormat"] | undefined, + ) { if (fileToDirective.has(file.path)) return; fileToDirective.set(file.path, [key, mode]); for (const { fileName, resolutionMode } of file.referencedFiles) { const resolvedFile = resolveTripleslashReference(fileName, file.fileName); const referencedFile = host.getSourceFile(resolvedFile); if (referencedFile) { - addReferencedFilesToTypeDirective(referencedFile, key, resolutionMode || file.impliedNodeFormat); + addReferencedFilesToTypeDirective( + referencedFile, + key, + resolutionMode || file.impliedNodeFormat, + ); } } } } - function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall): SourceFile | undefined { - const specifier = declaration.kind === SyntaxKind.ModuleDeclaration ? tryCast(declaration.name, isStringLiteral) : getExternalModuleName(declaration); - const moduleSymbol = resolveExternalModuleNameWorker(specifier!, specifier!, /*moduleNotFoundError*/ undefined); // TODO: GH#18217 + function getExternalModuleFileFromDeclaration( + declaration: AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall, + ): SourceFile | undefined { + const specifier = declaration.kind === SyntaxKind.ModuleDeclaration + ? tryCast(declaration.name, isStringLiteral) : getExternalModuleName(declaration); + const moduleSymbol = resolveExternalModuleNameWorker( + specifier!, + specifier!, + /*moduleNotFoundError*/ undefined, + ); // TODO: GH#18217 if (!moduleSymbol) { return undefined; } @@ -44731,7 +57850,13 @@ namespace ts { const fileGlobalThisSymbol = file.locals!.get("globalThis" as __String); if (fileGlobalThisSymbol?.declarations) { for (const declaration of fileGlobalThisSymbol.declarations) { - diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, "globalThis")); + diagnostics.add( + createDiagnosticForNode( + declaration, + Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, + "globalThis", + ), + ); } } mergeSymbolTable(globals, file.locals!); @@ -44774,10 +57899,18 @@ namespace ts { } // Setup global builtins - addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0); + addToSymbolTable( + globals, + builtinGlobals, + Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, + ); getSymbolLinks(undefinedSymbol).type = undefinedWideningType; - getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments" as __String, /*arity*/ 0, /*reportErrors*/ true); + getSymbolLinks(argumentsSymbol).type = getGlobalType( + "IArguments" as __String, + /*arity*/ 0, + /*reportErrors*/ true, + ); getSymbolLinks(unknownSymbol).type = errorType; getSymbolLinks(globalThisSymbol).type = createObjectType(ObjectFlags.Anonymous, globalThisSymbol); @@ -44785,8 +57918,12 @@ namespace ts { globalArrayType = getGlobalType("Array" as __String, /*arity*/ 1, /*reportErrors*/ true); globalObjectType = getGlobalType("Object" as __String, /*arity*/ 0, /*reportErrors*/ true); globalFunctionType = getGlobalType("Function" as __String, /*arity*/ 0, /*reportErrors*/ true); - globalCallableFunctionType = strictBindCallApply && getGlobalType("CallableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) || globalFunctionType; - globalNewableFunctionType = strictBindCallApply && getGlobalType("NewableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) || globalFunctionType; + globalCallableFunctionType = + strictBindCallApply && getGlobalType("CallableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) + || globalFunctionType; + globalNewableFunctionType = + strictBindCallApply && getGlobalType("NewableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) + || globalFunctionType; globalStringType = getGlobalType("String" as __String, /*arity*/ 0, /*reportErrors*/ true); globalNumberType = getGlobalType("Number" as __String, /*arity*/ 0, /*reportErrors*/ true); globalBooleanType = getGlobalType("Boolean" as __String, /*arity*/ 0, /*reportErrors*/ true); @@ -44799,8 +57936,10 @@ namespace ts { autoArrayType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray); } - globalReadonlyArrayType = getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1) as GenericType || globalArrayType; - anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType; + globalReadonlyArrayType = getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1) as GenericType + || globalArrayType; + anyReadonlyArrayType = globalReadonlyArrayType + ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType; globalThisType = getGlobalTypeOrUndefined("ThisType" as __String, /*arity*/ 1) as GenericType; if (augmentations) { @@ -44817,25 +57956,38 @@ namespace ts { amalgamatedDuplicates.forEach(({ firstFile, secondFile, conflictingSymbols }) => { // If not many things conflict, issue individual errors if (conflictingSymbols.size < 8) { - conflictingSymbols.forEach(({ isBlockScoped, firstFileLocations, secondFileLocations }, symbolName) => { - const message = isBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; - for (const node of firstFileLocations) { - addDuplicateDeclarationError(node, message, symbolName, secondFileLocations); - } - for (const node of secondFileLocations) { - addDuplicateDeclarationError(node, message, symbolName, firstFileLocations); - } - }); + conflictingSymbols.forEach( + ({ isBlockScoped, firstFileLocations, secondFileLocations }, symbolName) => { + const message = isBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 + : Diagnostics.Duplicate_identifier_0; + for (const node of firstFileLocations) { + addDuplicateDeclarationError(node, message, symbolName, secondFileLocations); + } + for (const node of secondFileLocations) { + addDuplicateDeclarationError(node, message, symbolName, firstFileLocations); + } + }, + ); } else { // Otherwise issue top-level error since the files appear very identical in terms of what they contain const list = arrayFrom(conflictingSymbols.keys()).join(", "); diagnostics.add(addRelatedInfo( - createDiagnosticForNode(firstFile, Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, list), + createDiagnosticForNode( + firstFile, + Diagnostics + .Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, + list, + ), createDiagnosticForNode(secondFile, Diagnostics.Conflicts_are_in_this_file), )); diagnostics.add(addRelatedInfo( - createDiagnosticForNode(secondFile, Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, list), + createDiagnosticForNode( + secondFile, + Diagnostics + .Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, + list, + ), createDiagnosticForNode(firstFile, Diagnostics.Conflicts_are_in_this_file), )); } @@ -44850,26 +58002,76 @@ namespace ts { const helpersModule = resolveHelpersModule(sourceFile, location); if (helpersModule !== unknownSymbol) { const uncheckedHelpers = helpers & ~requestedExternalEmitHelpers; - for (let helper = ExternalEmitHelpers.FirstEmitHelper; helper <= ExternalEmitHelpers.LastEmitHelper; helper <<= 1) { + for ( + let helper = ExternalEmitHelpers.FirstEmitHelper; + helper <= ExternalEmitHelpers.LastEmitHelper; + helper <<= 1 + ) { if (uncheckedHelpers & helper) { const name = getHelperName(helper); - const symbol = getSymbol(helpersModule.exports!, escapeLeadingUnderscores(name), SymbolFlags.Value); + const symbol = getSymbol( + helpersModule.exports!, + escapeLeadingUnderscores(name), + SymbolFlags.Value, + ); if (!symbol) { - error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_which_does_not_exist_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name); + error( + location, + Diagnostics + .This_syntax_requires_an_imported_helper_named_1_which_does_not_exist_in_0_Consider_upgrading_your_version_of_0, + externalHelpersModuleNameText, + name, + ); } else if (helper & ExternalEmitHelpers.ClassPrivateFieldGet) { - if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 3)) { - error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 4); + if ( + !some( + getSignaturesOfSymbol(symbol), + signature => getParameterCount(signature) > 3, + ) + ) { + error( + location, + Diagnostics + .This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, + externalHelpersModuleNameText, + name, + 4, + ); } } else if (helper & ExternalEmitHelpers.ClassPrivateFieldSet) { - if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 4)) { - error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 5); + if ( + !some( + getSignaturesOfSymbol(symbol), + signature => getParameterCount(signature) > 4, + ) + ) { + error( + location, + Diagnostics + .This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, + externalHelpersModuleNameText, + name, + 5, + ); } } else if (helper & ExternalEmitHelpers.SpreadArray) { - if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 2)) { - error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 3); + if ( + !some( + getSignaturesOfSymbol(symbol), + signature => getParameterCount(signature) > 2, + ) + ) { + error( + location, + Diagnostics + .This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, + externalHelpersModuleNameText, + name, + 3, + ); } } } @@ -44935,13 +58137,20 @@ namespace ts { function resolveHelpersModule(node: SourceFile, errorNode: Node) { if (!externalHelpersModule) { - externalHelpersModule = resolveExternalModule(node, externalHelpersModuleNameText, Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, errorNode) || unknownSymbol; + externalHelpersModule = resolveExternalModule( + node, + externalHelpersModuleNameText, + Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, + errorNode, + ) || unknownSymbol; } return externalHelpersModule; } // GRAMMAR CHECKING - function checkGrammarDecoratorsAndModifiers(node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators): boolean { + function checkGrammarDecoratorsAndModifiers( + node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators, + ): boolean { return checkGrammarDecorators(node) || checkGrammarModifiers(node); } @@ -44954,16 +58163,25 @@ namespace ts { } if (!nodeCanBeDecorated(node, node.parent, node.parent.parent)) { if (node.kind === SyntaxKind.MethodDeclaration && !nodeIsPresent(node.body)) { - return grammarErrorOnFirstToken(node, Diagnostics.A_decorator_can_only_decorate_a_method_implementation_not_an_overload); + return grammarErrorOnFirstToken( + node, + Diagnostics.A_decorator_can_only_decorate_a_method_implementation_not_an_overload, + ); } else { return grammarErrorOnFirstToken(node, Diagnostics.Decorators_are_not_valid_here); } } else if (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor) { - const accessors = getAllAccessorDeclarations((node.parent as ClassDeclaration).members, node as AccessorDeclaration); + const accessors = getAllAccessorDeclarations( + (node.parent as ClassDeclaration).members, + node as AccessorDeclaration, + ); if (hasDecorators(accessors.firstAccessor) && node === accessors.secondAccessor) { - return grammarErrorOnFirstToken(node, Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name); + return grammarErrorOnFirstToken( + node, + Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name, + ); } } return false; @@ -44975,27 +58193,49 @@ namespace ts { return quickResult; } - let lastStatic: Node | undefined, lastDeclare: Node | undefined, lastAsync: Node | undefined, lastOverride: Node | undefined; + let lastStatic: Node | undefined, + lastDeclare: Node | undefined, + lastAsync: Node | undefined, + lastOverride: Node | undefined; let flags = ModifierFlags.None; for (const modifier of node.modifiers!) { if (isDecorator(modifier)) continue; if (modifier.kind !== SyntaxKind.ReadonlyKeyword) { if (node.kind === SyntaxKind.PropertySignature || node.kind === SyntaxKind.MethodSignature) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_member, tokenToString(modifier.kind)); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_type_member, + tokenToString(modifier.kind), + ); } - if (node.kind === SyntaxKind.IndexSignature && (modifier.kind !== SyntaxKind.StaticKeyword || !isClassLike(node.parent))) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_index_signature, tokenToString(modifier.kind)); + if ( + node.kind === SyntaxKind.IndexSignature + && (modifier.kind !== SyntaxKind.StaticKeyword || !isClassLike(node.parent)) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_an_index_signature, + tokenToString(modifier.kind), + ); } } if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword) { if (node.kind === SyntaxKind.TypeParameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, tokenToString(modifier.kind)); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, + tokenToString(modifier.kind), + ); } } switch (modifier.kind) { case SyntaxKind.ConstKeyword: if (node.kind !== SyntaxKind.EnumDeclaration) { - return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); + return grammarErrorOnNode( + node, + Diagnostics.A_class_member_cannot_have_the_0_keyword, + tokenToString(SyntaxKind.ConstKeyword), + ); } break; case SyntaxKind.OverrideKeyword: @@ -45004,16 +58244,36 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); } else if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "override", "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "override", + "declare", + ); } else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "readonly"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "override", + "readonly", + ); } else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "override", + "accessor", + ); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "override", + "async", + ); } flags |= ModifierFlags.Override; lastOverride = modifier; @@ -45028,33 +58288,77 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics.Accessibility_modifier_already_seen); } else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "override", + ); } else if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "static"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "static", + ); } else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "accessor", + ); } else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "readonly"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "readonly", + ); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "async", + ); } - else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, text); + else if ( + node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, + text, + ); } else if (flags & ModifierFlags.Abstract) { if (modifier.kind === SyntaxKind.PrivateKeyword) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, text, "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + text, + "abstract", + ); } else { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "abstract", + ); } } else if (isPrivateIdentifierClassElementDeclaration(node)) { - return grammarErrorOnNode(modifier, Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier); + return grammarErrorOnNode( + modifier, + Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier, + ); } flags |= modifierToFlag(modifier.kind); break; @@ -45064,25 +58368,60 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "static"); } else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "readonly"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "readonly", + ); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "async", + ); } else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "accessor", + ); } - else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "static"); + else if ( + node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, + "static", + ); } else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "static"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "static", + ); } else if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "static", + "abstract", + ); } else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "override", + ); } flags |= ModifierFlags.Static; lastStatic = modifier; @@ -45093,13 +58432,26 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "accessor"); } else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "accessor", "readonly"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "accessor", + "readonly", + ); } else if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "accessor", "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "accessor", + "declare", + ); } else if (node.kind !== SyntaxKind.PropertyDeclaration) { - return grammarErrorOnNode(modifier, Diagnostics.accessor_modifier_can_only_appear_on_a_property_declaration); + return grammarErrorOnNode( + modifier, + Diagnostics.accessor_modifier_can_only_appear_on_a_property_declaration, + ); } flags |= ModifierFlags.Accessor; @@ -45109,9 +58461,16 @@ namespace ts { if (flags & ModifierFlags.Readonly) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "readonly"); } - else if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature && node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.Parameter) { + else if ( + node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature + && node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.Parameter + ) { // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. - return grammarErrorOnNode(modifier, Diagnostics.readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature); + return grammarErrorOnNode( + modifier, + Diagnostics + .readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature, + ); } flags |= ModifierFlags.Readonly; break; @@ -45121,29 +58480,60 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "export"); } else if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "declare", + ); } else if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "abstract", + ); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "async", + ); } else if (isClassLike(node.parent)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, "export"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, + "export", + ); } else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "export"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "export", + ); } flags |= ModifierFlags.Export; break; case SyntaxKind.DefaultKeyword: const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent; if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) { - return grammarErrorOnNode(modifier, Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module); + return grammarErrorOnNode( + modifier, + Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module, + ); } else if (!(flags & ModifierFlags.Export)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "default"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "default", + ); } flags |= ModifierFlags.Default; @@ -45153,22 +58543,47 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "declare"); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, + "async", + ); } else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, + "override", + ); } else if (isClassLike(node.parent) && !isPropertyDeclaration(node)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, + "declare", + ); } else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "declare", + ); } - else if ((node.parent.flags & NodeFlags.Ambient) && node.parent.kind === SyntaxKind.ModuleBlock) { - return grammarErrorOnNode(modifier, Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context); + else if ( + (node.parent.flags & NodeFlags.Ambient) && node.parent.kind === SyntaxKind.ModuleBlock + ) { + return grammarErrorOnNode( + modifier, + Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context, + ); } else if (isPrivateIdentifierClassElementDeclaration(node)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, + "declare", + ); } flags |= ModifierFlags.Ambient; lastDeclare = modifier; @@ -45179,38 +58594,77 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "abstract"); } if ( - node.kind !== SyntaxKind.ClassDeclaration && - node.kind !== SyntaxKind.ConstructorType + node.kind !== SyntaxKind.ClassDeclaration + && node.kind !== SyntaxKind.ConstructorType ) { if ( - node.kind !== SyntaxKind.MethodDeclaration && - node.kind !== SyntaxKind.PropertyDeclaration && - node.kind !== SyntaxKind.GetAccessor && - node.kind !== SyntaxKind.SetAccessor + node.kind !== SyntaxKind.MethodDeclaration + && node.kind !== SyntaxKind.PropertyDeclaration + && node.kind !== SyntaxKind.GetAccessor + && node.kind !== SyntaxKind.SetAccessor ) { - return grammarErrorOnNode(modifier, Diagnostics.abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration); + return grammarErrorOnNode( + modifier, + Diagnostics + .abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration, + ); } - if (!(node.parent.kind === SyntaxKind.ClassDeclaration && hasSyntacticModifier(node.parent, ModifierFlags.Abstract))) { - return grammarErrorOnNode(modifier, Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class); + if ( + !(node.parent.kind === SyntaxKind.ClassDeclaration + && hasSyntacticModifier(node.parent, ModifierFlags.Abstract)) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class, + ); } if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "static", + "abstract", + ); } if (flags & ModifierFlags.Private) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "private", + "abstract", + ); } if (flags & ModifierFlags.Async && lastAsync) { - return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "async", "abstract"); + return grammarErrorOnNode( + lastAsync, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "async", + "abstract", + ); } if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "abstract", "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "abstract", + "override", + ); } if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "abstract", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "abstract", + "accessor", + ); } } if (isNamedDeclaration(node) && node.name.kind === SyntaxKind.PrivateIdentifier) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, + "abstract", + ); } flags |= ModifierFlags.Abstract; @@ -45221,13 +58675,26 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async"); } else if (flags & ModifierFlags.Ambient || node.parent.flags & NodeFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, + "async", + ); } else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "async", + ); } if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "async", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "async", + "abstract", + ); } flags |= ModifierFlags.Async; lastAsync = modifier; @@ -45237,14 +58704,28 @@ namespace ts { case SyntaxKind.OutKeyword: const inOutFlag = modifier.kind === SyntaxKind.InKeyword ? ModifierFlags.In : ModifierFlags.Out; const inOutText = modifier.kind === SyntaxKind.InKeyword ? "in" : "out"; - if (node.kind !== SyntaxKind.TypeParameter || !(isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent))) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, inOutText); + if ( + node.kind !== SyntaxKind.TypeParameter + || !(isInterfaceDeclaration(node.parent) || isClassLike(node.parent) + || isTypeAliasDeclaration(node.parent)) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics + ._0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, + inOutText, + ); } if (flags & inOutFlag) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, inOutText); } if (inOutFlag & ModifierFlags.In && flags & ModifierFlags.Out) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "in", "out"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "in", + "out", + ); } flags |= inOutFlag; break; @@ -45253,24 +58734,55 @@ namespace ts { if (node.kind === SyntaxKind.Constructor) { if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(lastStatic!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "static"); + return grammarErrorOnNode( + lastStatic!, + Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, + "static", + ); } if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(lastOverride!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "override"); // TODO: GH#18217 + return grammarErrorOnNode( + lastOverride!, + Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, + "override", + ); // TODO: GH#18217 } if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(lastAsync!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async"); + return grammarErrorOnNode( + lastAsync!, + Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, + "async", + ); } return false; } - else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(lastDeclare!, Diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, "declare"); + else if ( + (node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) + && flags & ModifierFlags.Ambient + ) { + return grammarErrorOnNode( + lastDeclare!, + Diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, + "declare", + ); } - else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && isBindingPattern(node.name)) { - return grammarErrorOnNode(node, Diagnostics.A_parameter_property_may_not_be_declared_using_a_binding_pattern); + else if ( + node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) + && isBindingPattern(node.name) + ) { + return grammarErrorOnNode( + node, + Diagnostics.A_parameter_property_may_not_be_declared_using_a_binding_pattern, + ); } - else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && node.dotDotDotToken) { - return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter); + else if ( + node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) + && node.dotDotDotToken + ) { + return grammarErrorOnNode( + node, + Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter, + ); } if (flags & ModifierFlags.Async) { return checkGrammarAsyncModifier(node, lastAsync!); @@ -45360,14 +58872,20 @@ namespace ts { return grammarErrorOnNode(asyncModifier, Diagnostics._0_modifier_cannot_be_used_here, "async"); } - function checkGrammarForDisallowedTrailingComma(list: NodeArray | undefined, diag = Diagnostics.Trailing_comma_not_allowed): boolean { + function checkGrammarForDisallowedTrailingComma( + list: NodeArray | undefined, + diag = Diagnostics.Trailing_comma_not_allowed, + ): boolean { if (list && list.hasTrailingComma) { return grammarErrorAtPos(list[0], list.end - ",".length, ",".length, diag); } return false; } - function checkGrammarTypeParameterList(typeParameters: NodeArray | undefined, file: SourceFile): boolean { + function checkGrammarTypeParameterList( + typeParameters: NodeArray | undefined, + file: SourceFile, + ): boolean { if (typeParameters && typeParameters.length === 0) { const start = typeParameters.pos - "<".length; const end = skipTrivia(file.text, typeParameters.end) + ">".length; @@ -45384,39 +58902,61 @@ namespace ts { const parameter = parameters[i]; if (parameter.dotDotDotToken) { if (i !== (parameterCount - 1)) { - return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); + return grammarErrorOnNode( + parameter.dotDotDotToken, + Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list, + ); } if (!(parameter.flags & NodeFlags.Ambient)) { // Allow `...foo,` in ambient declarations; see GH#23070 - checkGrammarForDisallowedTrailingComma(parameters, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + parameters, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, + ); } if (parameter.questionToken) { - return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_rest_parameter_cannot_be_optional); + return grammarErrorOnNode( + parameter.questionToken, + Diagnostics.A_rest_parameter_cannot_be_optional, + ); } if (parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_have_an_initializer); + return grammarErrorOnNode( + parameter.name, + Diagnostics.A_rest_parameter_cannot_have_an_initializer, + ); } } else if (isOptionalParameter(parameter)) { seenOptionalParameter = true; if (parameter.questionToken && parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer); + return grammarErrorOnNode( + parameter.name, + Diagnostics.Parameter_cannot_have_question_mark_and_initializer, + ); } } else if (seenOptionalParameter && !parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter); + return grammarErrorOnNode( + parameter.name, + Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter, + ); } } } function getNonSimpleParameters(parameters: readonly ParameterDeclaration[]): readonly ParameterDeclaration[] { - return filter(parameters, parameter => !!parameter.initializer || isBindingPattern(parameter.name) || isRestParameter(parameter)); + return filter( + parameters, + parameter => !!parameter.initializer || isBindingPattern(parameter.name) || isRestParameter(parameter), + ); } function checkGrammarForUseStrictSimpleParameterList(node: FunctionLikeDeclaration): boolean { if (languageVersion >= ScriptTarget.ES2016) { - const useStrictDirective = node.body && isBlock(node.body) && findUseStrictPrologue(node.body.statements); + const useStrictDirective = node.body && isBlock(node.body) + && findUseStrictPrologue(node.body.statements); if (useStrictDirective) { const nonSimpleParameters = getNonSimpleParameters(node.parameters); if (length(nonSimpleParameters)) { @@ -45428,9 +58968,17 @@ namespace ts { }); const diagnostics = nonSimpleParameters.map((parameter, index) => ( - index === 0 ? createDiagnosticForNode(parameter, Diagnostics.Non_simple_parameter_declared_here) : createDiagnosticForNode(parameter, Diagnostics.and_here) + index === 0 + ? createDiagnosticForNode(parameter, Diagnostics.Non_simple_parameter_declared_here) + : createDiagnosticForNode(parameter, Diagnostics.and_here) )) as [DiagnosticWithLocation, ...DiagnosticWithLocation[]]; - addRelatedInfo(error(useStrictDirective, Diagnostics.use_strict_directive_cannot_be_used_with_non_simple_parameter_list), ...diagnostics); + addRelatedInfo( + error( + useStrictDirective, + Diagnostics.use_strict_directive_cannot_be_used_with_non_simple_parameter_list, + ), + ...diagnostics, + ); return true; } } @@ -45441,17 +58989,17 @@ namespace ts { function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration | MethodSignature): boolean { // Prevent cascading error by short-circuit const file = getSourceFileOfNode(node); - return checkGrammarDecoratorsAndModifiers(node) || - checkGrammarTypeParameterList(node.typeParameters, file) || - checkGrammarParameterList(node.parameters) || - checkGrammarArrowFunction(node, file) || - (isFunctionLikeDeclaration(node) && checkGrammarForUseStrictSimpleParameterList(node)); + return checkGrammarDecoratorsAndModifiers(node) + || checkGrammarTypeParameterList(node.typeParameters, file) + || checkGrammarParameterList(node.parameters) + || checkGrammarArrowFunction(node, file) + || (isFunctionLikeDeclaration(node) && checkGrammarForUseStrictSimpleParameterList(node)); } function checkGrammarClassLikeDeclaration(node: ClassLikeDeclaration): boolean { const file = getSourceFileOfNode(node); - return checkGrammarClassDeclarationHeritageClauses(node) || - checkGrammarTypeParameterList(node.typeParameters, file); + return checkGrammarClassDeclarationHeritageClauses(node) + || checkGrammarTypeParameterList(node.typeParameters, file); } function checkGrammarArrowFunction(node: Node, file: SourceFile): boolean { @@ -45459,50 +59007,88 @@ namespace ts { return false; } - if (node.typeParameters && !(length(node.typeParameters) > 1 || node.typeParameters.hasTrailingComma || node.typeParameters[0].constraint)) { + if ( + node.typeParameters + && !(length(node.typeParameters) > 1 || node.typeParameters.hasTrailingComma + || node.typeParameters[0].constraint) + ) { if (file && fileExtensionIsOneOf(file.fileName, [Extension.Mts, Extension.Cts])) { - grammarErrorOnNode(node.typeParameters[0], Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Add_a_trailing_comma_or_explicit_constraint); + grammarErrorOnNode( + node.typeParameters[0], + Diagnostics + .This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Add_a_trailing_comma_or_explicit_constraint, + ); } } const { equalsGreaterThanToken } = node; const startLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.pos).line; const endLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.end).line; - return startLine !== endLine && grammarErrorOnNode(equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); + return startLine !== endLine + && grammarErrorOnNode(equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); } function checkGrammarIndexSignatureParameters(node: SignatureDeclaration): boolean { const parameter = node.parameters[0]; if (node.parameters.length !== 1) { if (parameter) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_must_have_exactly_one_parameter); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_must_have_exactly_one_parameter, + ); } else { return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_exactly_one_parameter); } } - checkGrammarForDisallowedTrailingComma(node.parameters, Diagnostics.An_index_signature_cannot_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + node.parameters, + Diagnostics.An_index_signature_cannot_have_a_trailing_comma, + ); if (parameter.dotDotDotToken) { - return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.An_index_signature_cannot_have_a_rest_parameter); + return grammarErrorOnNode( + parameter.dotDotDotToken, + Diagnostics.An_index_signature_cannot_have_a_rest_parameter, + ); } if (hasEffectiveModifiers(parameter)) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier, + ); } if (parameter.questionToken) { - return grammarErrorOnNode(parameter.questionToken, Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark); + return grammarErrorOnNode( + parameter.questionToken, + Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark, + ); } if (parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_initializer); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_cannot_have_an_initializer, + ); } if (!parameter.type) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_must_have_a_type_annotation, + ); } const type = getTypeFromTypeNode(parameter.type); if (someType(type, t => !!(t.flags & TypeFlags.StringOrNumberLiteralOrUnique)) || isGenericType(type)) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead); + return grammarErrorOnNode( + parameter.name, + Diagnostics + .An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead, + ); } if (!everyType(type, isValidIndexKeyType)) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type); + return grammarErrorOnNode( + parameter.name, + Diagnostics + .An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type, + ); } if (!node.type) { return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_a_type_annotation); @@ -45515,24 +59101,35 @@ namespace ts { return checkGrammarDecoratorsAndModifiers(node) || checkGrammarIndexSignatureParameters(node); } - function checkGrammarForAtLeastOneTypeArgument(node: Node, typeArguments: NodeArray | undefined): boolean { + function checkGrammarForAtLeastOneTypeArgument( + node: Node, + typeArguments: NodeArray | undefined, + ): boolean { if (typeArguments && typeArguments.length === 0) { const sourceFile = getSourceFileOfNode(node); const start = typeArguments.pos - "<".length; const end = skipTrivia(sourceFile.text, typeArguments.end) + ">".length; - return grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.Type_argument_list_cannot_be_empty); + return grammarErrorAtPos( + sourceFile, + start, + end - start, + Diagnostics.Type_argument_list_cannot_be_empty, + ); } return false; } function checkGrammarTypeArguments(node: Node, typeArguments: NodeArray | undefined): boolean { - return checkGrammarForDisallowedTrailingComma(typeArguments) || - checkGrammarForAtLeastOneTypeArgument(node, typeArguments); + return checkGrammarForDisallowedTrailingComma(typeArguments) + || checkGrammarForAtLeastOneTypeArgument(node, typeArguments); } function checkGrammarTaggedTemplateChain(node: TaggedTemplateExpression): boolean { if (node.questionDotToken || node.flags & NodeFlags.OptionalChain) { - return grammarErrorOnNode(node.template, Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain); + return grammarErrorOnNode( + node.template, + Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain, + ); } return false; } @@ -45551,7 +59148,11 @@ namespace ts { function checkGrammarExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode) { if (isExpressionWithTypeArguments(node) && isImportKeyword(node.expression) && node.typeArguments) { - return grammarErrorOnNode(node, Diagnostics.This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments); + return grammarErrorOnNode( + node, + Diagnostics + .This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments, + ); } return checkGrammarTypeArguments(node, node.typeArguments); } @@ -45568,11 +59169,17 @@ namespace ts { } if (seenImplementsClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_must_precede_implements_clause); + return grammarErrorOnFirstToken( + heritageClause, + Diagnostics.extends_clause_must_precede_implements_clause, + ); } if (heritageClause.types.length > 1) { - return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_can_only_extend_a_single_class); + return grammarErrorOnFirstToken( + heritageClause.types[1], + Diagnostics.Classes_can_only_extend_a_single_class, + ); } seenExtendsClause = true; @@ -45606,7 +59213,10 @@ namespace ts { } else { Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword); - return grammarErrorOnFirstToken(heritageClause, Diagnostics.Interface_declaration_cannot_have_implements_clause); + return grammarErrorOnFirstToken( + heritageClause, + Diagnostics.Interface_declaration_cannot_have_implements_clause, + ); } // Grammar checking heritageClause inside class declaration @@ -45623,8 +59233,14 @@ namespace ts { } const computedPropertyName = node as ComputedPropertyName; - if (computedPropertyName.expression.kind === SyntaxKind.BinaryExpression && (computedPropertyName.expression as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken) { - return grammarErrorOnNode(computedPropertyName.expression, Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name); + if ( + computedPropertyName.expression.kind === SyntaxKind.BinaryExpression + && (computedPropertyName.expression as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken + ) { + return grammarErrorOnNode( + computedPropertyName.expression, + Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name, + ); } return false; } @@ -45632,24 +59248,36 @@ namespace ts { function checkGrammarForGenerator(node: FunctionLikeDeclaration) { if (node.asteriskToken) { Debug.assert( - node.kind === SyntaxKind.FunctionDeclaration || - node.kind === SyntaxKind.FunctionExpression || - node.kind === SyntaxKind.MethodDeclaration, + node.kind === SyntaxKind.FunctionDeclaration + || node.kind === SyntaxKind.FunctionExpression + || node.kind === SyntaxKind.MethodDeclaration, ); if (node.flags & NodeFlags.Ambient) { - return grammarErrorOnNode(node.asteriskToken, Diagnostics.Generators_are_not_allowed_in_an_ambient_context); + return grammarErrorOnNode( + node.asteriskToken, + Diagnostics.Generators_are_not_allowed_in_an_ambient_context, + ); } if (!node.body) { - return grammarErrorOnNode(node.asteriskToken, Diagnostics.An_overload_signature_cannot_be_declared_as_a_generator); + return grammarErrorOnNode( + node.asteriskToken, + Diagnostics.An_overload_signature_cannot_be_declared_as_a_generator, + ); } } } - function checkGrammarForInvalidQuestionMark(questionToken: QuestionToken | undefined, message: DiagnosticMessage): boolean { + function checkGrammarForInvalidQuestionMark( + questionToken: QuestionToken | undefined, + message: DiagnosticMessage, + ): boolean { return !!questionToken && grammarErrorOnNode(questionToken, message); } - function checkGrammarForInvalidExclamationToken(exclamationToken: ExclamationToken | undefined, message: DiagnosticMessage): boolean { + function checkGrammarForInvalidExclamationToken( + exclamationToken: ExclamationToken | undefined, + message: DiagnosticMessage, + ): boolean { return !!exclamationToken && grammarErrorOnNode(exclamationToken, message); } @@ -45662,7 +59290,10 @@ namespace ts { // a rest property cannot be destructured any further const expression = skipParentheses(prop.expression); if (isArrayLiteralExpression(expression) || isObjectLiteralExpression(expression)) { - return grammarErrorOnNode(prop.expression, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern); + return grammarErrorOnNode( + prop.expression, + Diagnostics.A_rest_element_cannot_contain_a_binding_pattern, + ); } } continue; @@ -45673,10 +59304,17 @@ namespace ts { checkGrammarComputedPropertyName(name); } - if (prop.kind === SyntaxKind.ShorthandPropertyAssignment && !inDestructuring && prop.objectAssignmentInitializer) { + if ( + prop.kind === SyntaxKind.ShorthandPropertyAssignment && !inDestructuring + && prop.objectAssignmentInitializer + ) { // having objectAssignmentInitializer is only valid in ObjectAssignmentPattern // outside of destructuring it is a syntax error - grammarErrorOnNode(prop.equalsToken!, Diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern); + grammarErrorOnNode( + prop.equalsToken!, + Diagnostics + .Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern, + ); } if (name.kind === SyntaxKind.PrivateIdentifier) { @@ -45686,7 +59324,10 @@ namespace ts { // Modifiers are never allowed on properties except for 'async' on a method declaration if (canHaveModifiers(prop) && prop.modifiers) { for (const mod of prop.modifiers) { - if (isModifier(mod) && (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration)) { + if ( + isModifier(mod) + && (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration) + ) { grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); } } @@ -45710,8 +59351,14 @@ namespace ts { case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.PropertyAssignment: // Grammar checking for computedPropertyName and shorthandPropertyAssignment - checkGrammarForInvalidExclamationToken(prop.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context); - checkGrammarForInvalidQuestionMark(prop.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); + checkGrammarForInvalidExclamationToken( + prop.exclamationToken, + Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context, + ); + checkGrammarForInvalidQuestionMark( + prop.questionToken, + Diagnostics.An_object_member_cannot_be_declared_optional, + ); if (name.kind === SyntaxKind.NumericLiteral) { checkGrammarNumericLiteral(name); } @@ -45744,19 +59391,36 @@ namespace ts { if ((currentKind & DeclarationMeaning.Method) && (existingKind & DeclarationMeaning.Method)) { grammarErrorOnNode(name, Diagnostics.Duplicate_identifier_0, getTextOfNode(name)); } - else if ((currentKind & DeclarationMeaning.PropertyAssignment) && (existingKind & DeclarationMeaning.PropertyAssignment)) { - grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name, getTextOfNode(name)); + else if ( + (currentKind & DeclarationMeaning.PropertyAssignment) + && (existingKind & DeclarationMeaning.PropertyAssignment) + ) { + grammarErrorOnNode( + name, + Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name, + getTextOfNode(name), + ); } - else if ((currentKind & DeclarationMeaning.GetOrSetAccessor) && (existingKind & DeclarationMeaning.GetOrSetAccessor)) { + else if ( + (currentKind & DeclarationMeaning.GetOrSetAccessor) + && (existingKind & DeclarationMeaning.GetOrSetAccessor) + ) { if (existingKind !== DeclarationMeaning.GetOrSetAccessor && currentKind !== existingKind) { seen.set(effectiveName, currentKind | existingKind); } else { - return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name); + return grammarErrorOnNode( + name, + Diagnostics + .An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name, + ); } } else { - return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name); + return grammarErrorOnNode( + name, + Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name, + ); } } } @@ -45778,11 +59442,17 @@ namespace ts { seen.set(name.escapedText, true); } else { - return grammarErrorOnNode(name, Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name); + return grammarErrorOnNode( + name, + Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name, + ); } if (initializer && initializer.kind === SyntaxKind.JsxExpression && !initializer.expression) { - return grammarErrorOnNode(initializer, Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression); + return grammarErrorOnNode( + initializer, + Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression, + ); } } } @@ -45806,14 +59476,20 @@ namespace ts { function checkGrammarJsxNestedIdentifier(name: MemberName | ThisExpression) { if (isIdentifier(name) && idText(name).indexOf(":") !== -1) { - return grammarErrorOnNode(name, Diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names); + return grammarErrorOnNode( + name, + Diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names, + ); } } } function checkGrammarJsxExpression(node: JsxExpression) { if (node.expression && isCommaSequence(node.expression)) { - return grammarErrorOnNode(node.expression, Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array); + return grammarErrorOnNode( + node.expression, + Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array, + ); } } @@ -45828,14 +59504,24 @@ namespace ts { if (isInTopLevelContext(forInOrOfStatement)) { if (!hasParseDiagnostics(sourceFile)) { if (!isEffectiveExternalModule(sourceFile, compilerOptions)) { - diagnostics.add(createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module)); + diagnostics.add( + createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics + .for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module, + ), + ); } switch (moduleKind) { case ModuleKind.Node16: case ModuleKind.NodeNext: if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) { diagnostics.add( - createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level), + createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics + .The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level, + ), ); break; } @@ -45849,7 +59535,11 @@ namespace ts { // fallthrough default: diagnostics.add( - createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher), + createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics + .Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher, + ), ); break; } @@ -45858,11 +59548,21 @@ namespace ts { else { // use of 'for-await-of' in non-async function if (!hasParseDiagnostics(sourceFile)) { - const diagnostic = createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules); + const diagnostic = createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics + .for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules, + ); const func = getContainingFunction(forInOrOfStatement); if (func && func.kind !== SyntaxKind.Constructor) { - Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function."); - const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async); + Debug.assert( + (getFunctionFlags(func) & FunctionFlags.Async) === 0, + "Enclosing function should never be an async function.", + ); + const relatedInfo = createDiagnosticForNode( + func, + Diagnostics.Did_you_mean_to_mark_this_function_as_async, + ); addRelatedInfo(diagnostic, relatedInfo); } diagnostics.add(diagnostic); @@ -45874,10 +59574,14 @@ namespace ts { } if ( - isForOfStatement(forInOrOfStatement) && !(forInOrOfStatement.flags & NodeFlags.AwaitContext) && - isIdentifier(forInOrOfStatement.initializer) && forInOrOfStatement.initializer.escapedText === "async" + isForOfStatement(forInOrOfStatement) && !(forInOrOfStatement.flags & NodeFlags.AwaitContext) + && isIdentifier(forInOrOfStatement.initializer) + && forInOrOfStatement.initializer.escapedText === "async" ) { - grammarErrorOnNode(forInOrOfStatement.initializer, Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async); + grammarErrorOnNode( + forInOrOfStatement.initializer, + Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async, + ); return false; } @@ -45924,12 +59628,21 @@ namespace ts { } function checkGrammarAccessor(accessor: AccessorDeclaration): boolean { - if (!(accessor.flags & NodeFlags.Ambient) && (accessor.parent.kind !== SyntaxKind.TypeLiteral) && (accessor.parent.kind !== SyntaxKind.InterfaceDeclaration)) { + if ( + !(accessor.flags & NodeFlags.Ambient) && (accessor.parent.kind !== SyntaxKind.TypeLiteral) + && (accessor.parent.kind !== SyntaxKind.InterfaceDeclaration) + ) { if (languageVersion < ScriptTarget.ES5) { - return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher); + return grammarErrorOnNode( + accessor.name, + Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher, + ); } if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(accessor.name)) { - return grammarErrorOnNode(accessor.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); + return grammarErrorOnNode( + accessor.name, + Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher, + ); } if (accessor.body === undefined && !hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { return grammarErrorAtPos(accessor, accessor.end - 1, ";".length, Diagnostics._0_expected, "{"); @@ -45939,8 +59652,14 @@ namespace ts { if (hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation); } - if (accessor.parent.kind === SyntaxKind.TypeLiteral || accessor.parent.kind === SyntaxKind.InterfaceDeclaration) { - return grammarErrorOnNode(accessor.body, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); + if ( + accessor.parent.kind === SyntaxKind.TypeLiteral + || accessor.parent.kind === SyntaxKind.InterfaceDeclaration + ) { + return grammarErrorOnNode( + accessor.body, + Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts, + ); } } if (accessor.typeParameters) { @@ -45949,24 +59668,39 @@ namespace ts { if (!doesAccessorHaveCorrectParameterCount(accessor)) { return grammarErrorOnNode( accessor.name, - accessor.kind === SyntaxKind.GetAccessor ? - Diagnostics.A_get_accessor_cannot_have_parameters : - Diagnostics.A_set_accessor_must_have_exactly_one_parameter, + accessor.kind === SyntaxKind.GetAccessor + ? Diagnostics.A_get_accessor_cannot_have_parameters + : Diagnostics.A_set_accessor_must_have_exactly_one_parameter, ); } if (accessor.kind === SyntaxKind.SetAccessor) { if (accessor.type) { - return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation); + return grammarErrorOnNode( + accessor.name, + Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation, + ); } - const parameter = Debug.checkDefined(getSetAccessorValueParameter(accessor), "Return value does not match parameter count assertion."); + const parameter = Debug.checkDefined( + getSetAccessorValueParameter(accessor), + "Return value does not match parameter count assertion.", + ); if (parameter.dotDotDotToken) { - return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_set_accessor_cannot_have_rest_parameter); + return grammarErrorOnNode( + parameter.dotDotDotToken, + Diagnostics.A_set_accessor_cannot_have_rest_parameter, + ); } if (parameter.questionToken) { - return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_set_accessor_cannot_have_an_optional_parameter); + return grammarErrorOnNode( + parameter.questionToken, + Diagnostics.A_set_accessor_cannot_have_an_optional_parameter, + ); } if (parameter.initializer) { - return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer); + return grammarErrorOnNode( + accessor.name, + Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer, + ); } } return false; @@ -45977,7 +59711,8 @@ namespace ts { * A set accessor has one parameter or a `this` parameter and one more parameter. */ function doesAccessorHaveCorrectParameterCount(accessor: AccessorDeclaration) { - return getAccessorThisParameter(accessor) || accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 0 : 1); + return getAccessorThisParameter(accessor) + || accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 0 : 1); } function getAccessorThisParameter(accessor: AccessorDeclaration): ParameterDeclaration | undefined { @@ -45989,7 +59724,11 @@ namespace ts { function checkGrammarTypeOperatorNode(node: TypeOperatorNode) { if (node.operator === SyntaxKind.UniqueKeyword) { if (node.type.kind !== SyntaxKind.SymbolKeyword) { - return grammarErrorOnNode(node.type, Diagnostics._0_expected, tokenToString(SyntaxKind.SymbolKeyword)); + return grammarErrorOnNode( + node.type, + Diagnostics._0_expected, + tokenToString(SyntaxKind.SymbolKeyword), + ); } let parent = walkUpParenthesizedTypes(node.parent); if (isInJSFile(parent) && isJSDocTypeExpression(parent)) { @@ -46002,28 +59741,46 @@ namespace ts { case SyntaxKind.VariableDeclaration: const decl = parent as VariableDeclaration; if (decl.name.kind !== SyntaxKind.Identifier) { - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name); + return grammarErrorOnNode( + node, + Diagnostics + .unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name, + ); } if (!isVariableDeclarationInVariableStatement(decl)) { - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement); + return grammarErrorOnNode( + node, + Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement, + ); } if (!(decl.parent.flags & NodeFlags.Const)) { - return grammarErrorOnNode((parent as VariableDeclaration).name, Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const); + return grammarErrorOnNode( + (parent as VariableDeclaration).name, + Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const, + ); } break; case SyntaxKind.PropertyDeclaration: if ( - !isStatic(parent) || - !hasEffectiveReadonlyModifier(parent) + !isStatic(parent) + || !hasEffectiveReadonlyModifier(parent) ) { - return grammarErrorOnNode((parent as PropertyDeclaration).name, Diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly); + return grammarErrorOnNode( + (parent as PropertyDeclaration).name, + Diagnostics + .A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly, + ); } break; case SyntaxKind.PropertySignature: if (!hasSyntacticModifier(parent, ModifierFlags.Readonly)) { - return grammarErrorOnNode((parent as PropertySignature).name, Diagnostics.A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly); + return grammarErrorOnNode( + (parent as PropertySignature).name, + Diagnostics + .A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly, + ); } break; @@ -46033,7 +59790,11 @@ namespace ts { } else if (node.operator === SyntaxKind.ReadonlyKeyword) { if (node.type.kind !== SyntaxKind.ArrayType && node.type.kind !== SyntaxKind.TupleType) { - return grammarErrorOnFirstToken(node, Diagnostics.readonly_type_modifier_is_only_permitted_on_array_and_tuple_literal_types, tokenToString(SyntaxKind.SymbolKeyword)); + return grammarErrorOnFirstToken( + node, + Diagnostics.readonly_type_modifier_is_only_permitted_on_array_and_tuple_literal_types, + tokenToString(SyntaxKind.SymbolKeyword), + ); } } } @@ -46052,13 +59813,26 @@ namespace ts { if (node.kind === SyntaxKind.MethodDeclaration) { if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { // We only disallow modifier on a method declaration if it is a property of object-literal-expression - if (node.modifiers && !(node.modifiers.length === 1 && first(node.modifiers).kind === SyntaxKind.AsyncKeyword)) { + if ( + node.modifiers + && !(node.modifiers.length === 1 && first(node.modifiers).kind === SyntaxKind.AsyncKeyword) + ) { return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); } - else if (checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional)) { + else if ( + checkGrammarForInvalidQuestionMark( + node.questionToken, + Diagnostics.An_object_member_cannot_be_declared_optional, + ) + ) { return true; } - else if (checkGrammarForInvalidExclamationToken(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context)) { + else if ( + checkGrammarForInvalidExclamationToken( + node.exclamationToken, + Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context, + ) + ) { return true; } else if (node.body === undefined) { @@ -46072,7 +59846,10 @@ namespace ts { if (isClassLike(node.parent)) { if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(node.name)) { - return grammarErrorOnNode(node.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); + return grammarErrorOnNode( + node.name, + Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher, + ); } // Technically, computed properties in ambient contexts is disallowed // for property declarations and accessors too, not just methods. @@ -46080,17 +59857,33 @@ namespace ts { // and accessors are not allowed in ambient contexts in general, // so this error only really matters for methods. if (node.flags & NodeFlags.Ambient) { - return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_ambient_context_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); + return checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_an_ambient_context_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ); } else if (node.kind === SyntaxKind.MethodDeclaration && !node.body) { - return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_method_overload_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); + return checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_a_method_overload_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ); } } else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { - return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); + return checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ); } else if (node.parent.kind === SyntaxKind.TypeLiteral) { - return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); + return checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ); } } @@ -46107,10 +59900,17 @@ namespace ts { // found matching label - verify that label usage is correct // continue can only target labels that are on iteration statements const isMisplacedContinueLabel = node.kind === SyntaxKind.ContinueStatement - && !isIterationStatement((current as LabeledStatement).statement, /*lookInLabeledStatement*/ true); + && !isIterationStatement( + (current as LabeledStatement).statement, + /*lookInLabeledStatement*/ true, + ); if (isMisplacedContinueLabel) { - return grammarErrorOnNode(node, Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement); + return grammarErrorOnNode( + node, + Diagnostics + .A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement, + ); } return false; @@ -46154,7 +59954,10 @@ namespace ts { if (node !== last(elements)) { return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); } - checkGrammarForDisallowedTrailingComma(elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + elements, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, + ); if (node.propertyName) { return grammarErrorOnNode(node.name, Diagnostics.A_rest_element_cannot_have_a_property_name); @@ -46163,26 +59966,34 @@ namespace ts { if (node.dotDotDotToken && node.initializer) { // Error on equals token which immediately precedes the initializer - return grammarErrorAtPos(node, node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer); + return grammarErrorAtPos( + node, + node.initializer.pos - 1, + 1, + Diagnostics.A_rest_element_cannot_have_an_initializer, + ); } } function isStringOrNumberLiteralExpression(expr: Expression) { - return isStringOrNumericLiteralLike(expr) || - expr.kind === SyntaxKind.PrefixUnaryExpression && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && - (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.NumericLiteral; + return isStringOrNumericLiteralLike(expr) + || expr.kind === SyntaxKind.PrefixUnaryExpression + && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken + && (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.NumericLiteral; } function isBigIntLiteralExpression(expr: Expression) { - return expr.kind === SyntaxKind.BigIntLiteral || - expr.kind === SyntaxKind.PrefixUnaryExpression && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && - (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.BigIntLiteral; + return expr.kind === SyntaxKind.BigIntLiteral + || expr.kind === SyntaxKind.PrefixUnaryExpression + && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken + && (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.BigIntLiteral; } function isSimpleLiteralEnumReference(expr: Expression) { if ( - (isPropertyAccessExpression(expr) || (isElementAccessExpression(expr) && isStringOrNumberLiteralExpression(expr.argumentExpression))) && - isEntityNameExpression(expr.expression) + (isPropertyAccessExpression(expr) + || (isElementAccessExpression(expr) && isStringOrNumberLiteralExpression(expr.argumentExpression))) + && isEntityNameExpression(expr.expression) ) { return !!(checkExpressionCached(expr).flags & TypeFlags.EnumLiteral); } @@ -46192,31 +60003,45 @@ namespace ts { const initializer = node.initializer; if (initializer) { const isInvalidInitializer = !( - isStringOrNumberLiteralExpression(initializer) || - isSimpleLiteralEnumReference(initializer) || - initializer.kind === SyntaxKind.TrueKeyword || initializer.kind === SyntaxKind.FalseKeyword || - isBigIntLiteralExpression(initializer) + isStringOrNumberLiteralExpression(initializer) + || isSimpleLiteralEnumReference(initializer) + || initializer.kind === SyntaxKind.TrueKeyword || initializer.kind === SyntaxKind.FalseKeyword + || isBigIntLiteralExpression(initializer) ); - const isConstOrReadonly = isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConst(node); + const isConstOrReadonly = isDeclarationReadonly(node) + || isVariableDeclaration(node) && isVarConst(node); if (isConstOrReadonly && !node.type) { if (isInvalidInitializer) { - return grammarErrorOnNode(initializer, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_or_literal_enum_reference); + return grammarErrorOnNode( + initializer, + Diagnostics + .A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_or_literal_enum_reference, + ); } } else { - return grammarErrorOnNode(initializer, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); + return grammarErrorOnNode( + initializer, + Diagnostics.Initializers_are_not_allowed_in_ambient_contexts, + ); } } } function checkGrammarVariableDeclaration(node: VariableDeclaration) { - if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) { + if ( + node.parent.parent.kind !== SyntaxKind.ForInStatement + && node.parent.parent.kind !== SyntaxKind.ForOfStatement + ) { if (node.flags & NodeFlags.Ambient) { checkAmbientInitializer(node); } else if (!node.initializer) { if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) { - return grammarErrorOnNode(node, Diagnostics.A_destructuring_declaration_must_have_an_initializer); + return grammarErrorOnNode( + node, + Diagnostics.A_destructuring_declaration_must_have_an_initializer, + ); } if (isVarConst(node)) { return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized); @@ -46224,7 +60049,11 @@ namespace ts { } } - if (node.exclamationToken && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer || node.flags & NodeFlags.Ambient)) { + if ( + node.exclamationToken + && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer + || node.flags & NodeFlags.Ambient) + ) { const message = node.initializer ? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions : !node.type @@ -46234,8 +60063,10 @@ namespace ts { } if ( - (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && moduleKind !== ModuleKind.System && - !(node.parent.parent.flags & NodeFlags.Ambient) && hasSyntacticModifier(node.parent.parent, ModifierFlags.Export) + (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + && moduleKind !== ModuleKind.System + && !(node.parent.parent.flags & NodeFlags.Ambient) + && hasSyntacticModifier(node.parent.parent, ModifierFlags.Export) ) { checkESModuleMarker(node.name); } @@ -46255,7 +60086,12 @@ namespace ts { function checkESModuleMarker(name: Identifier | BindingPattern): boolean { if (name.kind === SyntaxKind.Identifier) { if (idText(name) === "__esModule") { - return grammarErrorOnNodeSkippedOn("noEmit", name, Diagnostics.Identifier_expected_esModule_is_reserved_as_an_exported_marker_when_transforming_ECMAScript_modules); + return grammarErrorOnNodeSkippedOn( + "noEmit", + name, + Diagnostics + .Identifier_expected_esModule_is_reserved_as_an_exported_marker_when_transforming_ECMAScript_modules, + ); } } else { @@ -46272,7 +60108,10 @@ namespace ts { function checkGrammarNameInLetOrConstDeclarations(name: Identifier | BindingPattern): boolean { if (name.kind === SyntaxKind.Identifier) { if (name.originalKeywordKind === SyntaxKind.LetKeyword) { - return grammarErrorOnNode(name, Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations); + return grammarErrorOnNode( + name, + Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations, + ); } } else { @@ -46293,7 +60132,12 @@ namespace ts { } if (!declarationList.declarations.length) { - return grammarErrorAtPos(declarationList, declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty); + return grammarErrorAtPos( + declarationList, + declarations.pos, + declarations.end - declarations.pos, + Diagnostics.Variable_declaration_list_cannot_be_empty, + ); } return false; } @@ -46331,12 +60175,24 @@ namespace ts { switch (node.keywordToken) { case SyntaxKind.NewKeyword: if (escapedText !== "target") { - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, node.name.escapedText, tokenToString(node.keywordToken), "target"); + return grammarErrorOnNode( + node.name, + Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, + node.name.escapedText, + tokenToString(node.keywordToken), + "target", + ); } break; case SyntaxKind.ImportKeyword: if (escapedText !== "meta") { - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, node.name.escapedText, tokenToString(node.keywordToken), "meta"); + return grammarErrorOnNode( + node.name, + Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, + node.name.escapedText, + tokenToString(node.keywordToken), + "meta", + ); } break; } @@ -46346,7 +60202,13 @@ namespace ts { return sourceFile.parseDiagnostics.length > 0; } - function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorOnFirstToken( + node: Node, + message: DiagnosticMessage, + arg0?: any, + arg1?: any, + arg2?: any, + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); @@ -46356,7 +60218,15 @@ namespace ts { return false; } - function grammarErrorAtPos(nodeForSourceFile: Node, start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorAtPos( + nodeForSourceFile: Node, + start: number, + length: number, + message: DiagnosticMessage, + arg0?: any, + arg1?: any, + arg2?: any, + ): boolean { const sourceFile = getSourceFileOfNode(nodeForSourceFile); if (!hasParseDiagnostics(sourceFile)) { diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2)); @@ -46365,7 +60235,14 @@ namespace ts { return false; } - function grammarErrorOnNodeSkippedOn(key: keyof CompilerOptions, node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorOnNodeSkippedOn( + key: keyof CompilerOptions, + node: Node, + message: DiagnosticMessage, + arg0?: any, + arg1?: any, + arg2?: any, + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { errorSkippedOn(key, node, message, arg0, arg1, arg2); @@ -46374,7 +60251,13 @@ namespace ts { return false; } - function grammarErrorOnNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorOnNode( + node: Node, + message: DiagnosticMessage, + arg0?: any, + arg1?: any, + arg2?: any, + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { diagnostics.add(createDiagnosticForNode(node, message, arg0, arg1, arg2)); @@ -46388,7 +60271,12 @@ namespace ts { const range = node.typeParameters || jsdocTypeParameters && firstOrUndefined(jsdocTypeParameters); if (range) { const pos = range.pos === range.end ? range.pos : skipTrivia(getSourceFileOfNode(node).text, range.pos); - return grammarErrorAtPos(node, pos, range.end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); + return grammarErrorAtPos( + node, + pos, + range.end - pos, + Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration, + ); } } @@ -46400,7 +60288,10 @@ namespace ts { } function checkGrammarProperty(node: PropertyDeclaration | PropertySignature) { - if (isComputedPropertyName(node.name) && isBinaryExpression(node.name.expression) && node.name.expression.operatorToken.kind === SyntaxKind.InKeyword) { + if ( + isComputedPropertyName(node.name) && isBinaryExpression(node.name.expression) + && node.name.expression.operatorToken.kind === SyntaxKind.InKeyword + ) { return grammarErrorOnNode( (node.parent as ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode).members[0], Diagnostics.A_mapped_type_may_not_declare_properties_or_methods, @@ -46410,38 +60301,75 @@ namespace ts { if (isStringLiteral(node.name) && node.name.text === "constructor") { return grammarErrorOnNode(node.name, Diagnostics.Classes_may_not_have_a_field_named_constructor); } - if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_have_a_simple_literal_type_or_a_unique_symbol_type)) { + if ( + checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_a_class_property_declaration_must_have_a_simple_literal_type_or_a_unique_symbol_type, + ) + ) { return true; } if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(node.name)) { - return grammarErrorOnNode(node.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); + return grammarErrorOnNode( + node.name, + Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher, + ); } if (languageVersion < ScriptTarget.ES2015 && isAutoAccessorPropertyDeclaration(node)) { - return grammarErrorOnNode(node.name, Diagnostics.Properties_with_the_accessor_modifier_are_only_available_when_targeting_ECMAScript_2015_and_higher); + return grammarErrorOnNode( + node.name, + Diagnostics + .Properties_with_the_accessor_modifier_are_only_available_when_targeting_ECMAScript_2015_and_higher, + ); } - if (isAutoAccessorPropertyDeclaration(node) && checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_accessor_property_cannot_be_declared_optional)) { + if ( + isAutoAccessorPropertyDeclaration(node) + && checkGrammarForInvalidQuestionMark( + node.questionToken, + Diagnostics.An_accessor_property_cannot_be_declared_optional, + ) + ) { return true; } } else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { - if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type)) { + if ( + checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ) + ) { return true; } // Interfaces cannot contain property declarations Debug.assertNode(node, isPropertySignature); if (node.initializer) { - return grammarErrorOnNode(node.initializer, Diagnostics.An_interface_property_cannot_have_an_initializer); + return grammarErrorOnNode( + node.initializer, + Diagnostics.An_interface_property_cannot_have_an_initializer, + ); } } else if (isTypeLiteralNode(node.parent)) { - if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type)) { + if ( + checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ) + ) { return true; } // Type literals cannot contain property declarations Debug.assertNode(node, isPropertySignature); if (node.initializer) { - return grammarErrorOnNode(node.initializer, Diagnostics.A_type_literal_property_cannot_have_an_initializer); + return grammarErrorOnNode( + node.initializer, + Diagnostics.A_type_literal_property_cannot_have_an_initializer, + ); } } @@ -46450,8 +60378,9 @@ namespace ts { } if ( - isPropertyDeclaration(node) && node.exclamationToken && (!isClassLike(node.parent) || !node.type || node.initializer || - node.flags & NodeFlags.Ambient || isStatic(node) || hasAbstractModifier(node)) + isPropertyDeclaration(node) && node.exclamationToken + && (!isClassLike(node.parent) || !node.type || node.initializer + || node.flags & NodeFlags.Ambient || isStatic(node) || hasAbstractModifier(node)) ) { const message = node.initializer ? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions @@ -46476,19 +60405,22 @@ namespace ts { // // TODO: The spec needs to be amended to reflect this grammar. if ( - node.kind === SyntaxKind.InterfaceDeclaration || - node.kind === SyntaxKind.TypeAliasDeclaration || - node.kind === SyntaxKind.ImportDeclaration || - node.kind === SyntaxKind.ImportEqualsDeclaration || - node.kind === SyntaxKind.ExportDeclaration || - node.kind === SyntaxKind.ExportAssignment || - node.kind === SyntaxKind.NamespaceExportDeclaration || - hasSyntacticModifier(node, ModifierFlags.Ambient | ModifierFlags.Export | ModifierFlags.Default) + node.kind === SyntaxKind.InterfaceDeclaration + || node.kind === SyntaxKind.TypeAliasDeclaration + || node.kind === SyntaxKind.ImportDeclaration + || node.kind === SyntaxKind.ImportEqualsDeclaration + || node.kind === SyntaxKind.ExportDeclaration + || node.kind === SyntaxKind.ExportAssignment + || node.kind === SyntaxKind.NamespaceExportDeclaration + || hasSyntacticModifier(node, ModifierFlags.Ambient | ModifierFlags.Export | ModifierFlags.Default) ) { return false; } - return grammarErrorOnFirstToken(node, Diagnostics.Top_level_declarations_in_d_ts_files_must_start_with_either_a_declare_or_export_modifier); + return grammarErrorOnFirstToken( + node, + Diagnostics.Top_level_declarations_in_d_ts_files_must_start_with_either_a_declare_or_export_modifier, + ); } function checkGrammarTopLevelElementsForRequiredDeclareModifier(file: SourceFile): boolean { @@ -46510,8 +60442,14 @@ namespace ts { if (node.flags & NodeFlags.Ambient) { // Find containing block which is either Block, ModuleBlock, SourceFile const links = getNodeLinks(node); - if (!links.hasReportedStatementInAmbientContext && (isFunctionLike(node.parent) || isAccessor(node.parent))) { - return getNodeLinks(node).hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); + if ( + !links.hasReportedStatementInAmbientContext + && (isFunctionLike(node.parent) || isAccessor(node.parent)) + ) { + return getNodeLinks(node).hasReportedStatementInAmbientContext = grammarErrorOnFirstToken( + node, + Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts, + ); } // We are either parented by another statement, or some sort of block. @@ -46519,11 +60457,17 @@ namespace ts { // to prevent noisiness. So use a bit on the block to indicate if // this has already been reported, and don't report if it has. // - if (node.parent.kind === SyntaxKind.Block || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + if ( + node.parent.kind === SyntaxKind.Block || node.parent.kind === SyntaxKind.ModuleBlock + || node.parent.kind === SyntaxKind.SourceFile + ) { const links = getNodeLinks(node.parent); // Check if the containing block ever report this error if (!links.hasReportedStatementInAmbientContext) { - return links.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts); + return links.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken( + node, + Diagnostics.Statements_are_not_allowed_in_ambient_contexts, + ); } } else { @@ -46540,16 +60484,19 @@ namespace ts { if (node.numericLiteralFlags & TokenFlags.Octal) { let diagnosticMessage: DiagnosticMessage | undefined; if (languageVersion >= ScriptTarget.ES5) { - diagnosticMessage = Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher_Use_the_syntax_0; + diagnosticMessage = Diagnostics + .Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher_Use_the_syntax_0; } else if (isChildOfNodeWithKind(node, SyntaxKind.LiteralType)) { diagnosticMessage = Diagnostics.Octal_literal_types_must_use_ES2015_syntax_Use_the_syntax_0; } else if (isChildOfNodeWithKind(node, SyntaxKind.EnumMember)) { - diagnosticMessage = Diagnostics.Octal_literals_are_not_allowed_in_enums_members_initializer_Use_the_syntax_0; + diagnosticMessage = + Diagnostics.Octal_literals_are_not_allowed_in_enums_members_initializer_Use_the_syntax_0; } if (diagnosticMessage) { - const withMinus = isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.MinusToken; + const withMinus = isPrefixUnaryExpression(node.parent) + && node.parent.operator === SyntaxKind.MinusToken; const literal = (withMinus ? "-" : "") + "0o" + node.text; return grammarErrorOnNode(withMinus ? node.parent : node, diagnosticMessage, literal); } @@ -46583,15 +60530,27 @@ namespace ts { return; } - addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(node, Diagnostics.Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers)); + addErrorOrSuggestion( + /*isError*/ false, + createDiagnosticForNode( + node, + Diagnostics + .Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers, + ), + ); } function checkGrammarBigIntLiteral(node: BigIntLiteral): boolean { - const literalType = isLiteralTypeNode(node.parent) || - isPrefixUnaryExpression(node.parent) && isLiteralTypeNode(node.parent.parent); + const literalType = isLiteralTypeNode(node.parent) + || isPrefixUnaryExpression(node.parent) && isLiteralTypeNode(node.parent.parent); if (!literalType) { if (languageVersion < ScriptTarget.ES2020) { - if (grammarErrorOnNode(node, Diagnostics.BigInt_literals_are_not_available_when_targeting_lower_than_ES2020)) { + if ( + grammarErrorOnNode( + node, + Diagnostics.BigInt_literals_are_not_available_when_targeting_lower_than_ES2020, + ) + ) { return true; } } @@ -46599,11 +60558,19 @@ namespace ts { return false; } - function grammarErrorAfterFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorAfterFirstToken( + node: Node, + message: DiagnosticMessage, + arg0?: any, + arg1?: any, + arg2?: any, + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); - diagnostics.add(createFileDiagnostic(sourceFile, textSpanEnd(span), /*length*/ 0, message, arg0, arg1, arg2)); + diagnostics.add( + createFileDiagnostic(sourceFile, textSpanEnd(span), /*length*/ 0, message, arg0, arg1, arg2), + ); return true; } return false; @@ -46624,7 +60591,10 @@ namespace ts { function checkGrammarImportClause(node: ImportClause): boolean { if (node.isTypeOnly && node.name && node.namedBindings) { - return grammarErrorOnNode(node, Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both); + return grammarErrorOnNode( + node, + Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both, + ); } if (node.isTypeOnly && node.namedBindings?.kind === SyntaxKind.NamedImports) { return checkGrammarNamedImportsOrExports(node.namedBindings); @@ -46638,8 +60608,10 @@ namespace ts { return grammarErrorOnFirstToken( specifier, specifier.kind === SyntaxKind.ImportSpecifier - ? Diagnostics.The_type_modifier_cannot_be_used_on_a_named_import_when_import_type_is_used_on_its_import_statement - : Diagnostics.The_type_modifier_cannot_be_used_on_a_named_export_when_export_type_is_used_on_its_export_statement, + ? Diagnostics + .The_type_modifier_cannot_be_used_on_a_named_import_when_import_type_is_used_on_its_import_statement + : Diagnostics + .The_type_modifier_cannot_be_used_on_a_named_export_when_export_type_is_used_on_its_export_statement, ); } }); @@ -46647,40 +60619,65 @@ namespace ts { function checkGrammarImportCallExpression(node: ImportCall): boolean { if (moduleKind === ModuleKind.ES2015) { - return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_or_nodenext); + return grammarErrorOnNode( + node, + Diagnostics + .Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_or_nodenext, + ); } if (node.typeArguments) { - return grammarErrorOnNode(node, Diagnostics.This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments); + return grammarErrorOnNode( + node, + Diagnostics + .This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments, + ); } const nodeArguments = node.arguments; - if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.NodeNext && moduleKind !== ModuleKind.Node16) { + if ( + moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.NodeNext + && moduleKind !== ModuleKind.Node16 + ) { // We are allowed trailing comma after proposal-import-assertions. checkGrammarForDisallowedTrailingComma(nodeArguments); if (nodeArguments.length > 1) { const assertionArgument = nodeArguments[1]; - return grammarErrorOnNode(assertionArgument, Diagnostics.Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_or_nodenext); + return grammarErrorOnNode( + assertionArgument, + Diagnostics + .Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_or_nodenext, + ); } } if (nodeArguments.length === 0 || nodeArguments.length > 2) { - return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments); + return grammarErrorOnNode( + node, + Diagnostics + .Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments, + ); } // see: parseArgumentOrArrayLiteralElement...we use this function which parse arguments of callExpression to parse specifier for dynamic import. // parseArgumentOrArrayLiteralElement allows spread element to be in an argument list which is not allowed as specifier in dynamic import. const spreadElement = find(nodeArguments, isSpreadElement); if (spreadElement) { - return grammarErrorOnNode(spreadElement, Diagnostics.Argument_of_dynamic_import_cannot_be_spread_element); + return grammarErrorOnNode( + spreadElement, + Diagnostics.Argument_of_dynamic_import_cannot_be_spread_element, + ); } return false; } function findMatchingTypeReferenceOrTypeAliasReference(source: Type, unionTarget: UnionOrIntersectionType) { const sourceObjectFlags = getObjectFlags(source); - if (sourceObjectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous) && unionTarget.flags & TypeFlags.Union) { + if ( + sourceObjectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous) + && unionTarget.flags & TypeFlags.Union + ) { return find(unionTarget.types, target => { if (target.flags & TypeFlags.Object) { const overlapObjFlags = sourceObjectFlags & getObjectFlags(target); @@ -46688,7 +60685,8 @@ namespace ts { return (source as TypeReference).target === (target as TypeReference).target; } if (overlapObjFlags & ObjectFlags.Anonymous) { - return !!(source as AnonymousType).aliasSymbol && (source as AnonymousType).aliasSymbol === (target as AnonymousType).aliasSymbol; + return !!(source as AnonymousType).aliasSymbol + && (source as AnonymousType).aliasSymbol === (target as AnonymousType).aliasSymbol; } } return false; @@ -46704,8 +60702,8 @@ namespace ts { function findBestTypeForInvokable(source: Type, unionTarget: UnionOrIntersectionType) { let signatureKind = SignatureKind.Call; - const hasSignatures = getSignaturesOfType(source, signatureKind).length > 0 || - (signatureKind = SignatureKind.Construct, getSignaturesOfType(source, signatureKind).length > 0); + const hasSignatures = getSignaturesOfType(source, signatureKind).length > 0 + || (signatureKind = SignatureKind.Construct, getSignaturesOfType(source, signatureKind).length > 0); if (hasSignatures) { return find(unionTarget.types, t => getSignaturesOfType(t, signatureKind).length > 0); } @@ -46726,7 +60724,8 @@ namespace ts { // We only want to account for literal types otherwise. // If we have a union of index types, it seems likely that we // needed to elaborate between two generic mapped types anyway. - const len = overlap.flags & TypeFlags.Union ? countWhere((overlap as UnionType).types, isUnitType) : 1; + const len = overlap.flags & TypeFlags.Union + ? countWhere((overlap as UnionType).types, isUnitType) : 1; if (len >= matchingCount) { bestMatch = target; matchingCount = len; @@ -46749,7 +60748,12 @@ namespace ts { } // Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly - function findMatchingDiscriminantType(source: Type, target: Type, isRelatedTo: (source: Type, target: Type) => Ternary, skipPartial?: boolean) { + function findMatchingDiscriminantType( + source: Type, + target: Type, + isRelatedTo: (source: Type, target: Type) => Ternary, + skipPartial?: boolean, + ) { if (target.flags & TypeFlags.Union && source.flags & (TypeFlags.Intersection | TypeFlags.Object)) { const match = getMatchingUnionConstituentForType(target as UnionType, source); if (match) { @@ -46759,7 +60763,16 @@ namespace ts { if (sourceProperties) { const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target); if (sourcePropertiesFiltered) { - return discriminateTypeByDiscriminableItems(target as UnionType, map(sourcePropertiesFiltered, p => ([() => getTypeOfSymbol(p), p.escapedName] as [() => Type, __String])), isRelatedTo, /*defaultValue*/ undefined, skipPartial); + return discriminateTypeByDiscriminableItems( + target as UnionType, + map( + sourcePropertiesFiltered, + p => ([() => getTypeOfSymbol(p), p.escapedName] as [() => Type, __String]), + ), + isRelatedTo, + /*defaultValue*/ undefined, + skipPartial, + ); } } } @@ -46773,8 +60786,9 @@ namespace ts { } function isNotOverload(declaration: Declaration): boolean { - return (declaration.kind !== SyntaxKind.FunctionDeclaration && declaration.kind !== SyntaxKind.MethodDeclaration) || - !!(declaration as FunctionDeclaration).body; + return (declaration.kind !== SyntaxKind.FunctionDeclaration + && declaration.kind !== SyntaxKind.MethodDeclaration) + || !!(declaration as FunctionDeclaration).body; } /** Like 'isDeclarationName', but returns true for LHS of `import { x as y }` or `export { x as y }`. */ diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 4b1b3a9007bf4..235c0b2f8419c 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -15,7 +15,9 @@ namespace ts { })); /* @internal */ - export const inverseJsxOptionMap = new Map(arrayFrom(mapIterator(jsxOptionMap.entries(), ([key, value]: [string, JsxEmit]) => ["" + value, key] as const))); + export const inverseJsxOptionMap = new Map( + arrayFrom(mapIterator(jsxOptionMap.entries(), ([key, value]: [string, JsxEmit]) => ["" + value, key] as const)), + ); // NOTE: The order here is important to default lib ordering as entries will have the same // order in the generated program (see `getDefaultLibPriority` in program.ts). This @@ -137,7 +139,8 @@ namespace ts { fixedchunksizepolling: WatchDirectoryKind.FixedChunkSizePolling, })), category: Diagnostics.Watch_and_Build_Modes, - description: Diagnostics.Specify_how_directories_are_watched_on_systems_that_lack_recursive_file_watching_functionality, + description: Diagnostics + .Specify_how_directories_are_watched_on_systems_that_lack_recursive_file_watching_functionality, defaultValueDescription: WatchDirectoryKind.UseFsEvents, }, { @@ -149,14 +152,16 @@ namespace ts { fixedchunksize: PollingWatchKind.FixedChunkSize, })), category: Diagnostics.Watch_and_Build_Modes, - description: Diagnostics.Specify_what_approach_the_watcher_should_use_if_the_system_runs_out_of_native_file_watchers, + description: + Diagnostics.Specify_what_approach_the_watcher_should_use_if_the_system_runs_out_of_native_file_watchers, defaultValueDescription: PollingWatchKind.PriorityInterval, }, { name: "synchronousWatchDirectory", type: "boolean", category: Diagnostics.Watch_and_Build_Modes, - description: Diagnostics.Synchronously_call_callbacks_and_update_the_state_of_directory_watchers_on_platforms_that_don_t_support_recursive_watching_natively, + description: Diagnostics + .Synchronously_call_callbacks_and_update_the_state_of_directory_watchers_on_platforms_that_don_t_support_recursive_watching_natively, defaultValueDescription: false, }, { @@ -249,7 +254,8 @@ namespace ts { type: "boolean", showInSimplifiedHelpView: true, category: Diagnostics.Output_Formatting, - description: Diagnostics.Enable_color_and_formatting_in_TypeScript_s_output_to_make_compiler_errors_easier_to_read, + description: + Diagnostics.Enable_color_and_formatting_in_TypeScript_s_output_to_make_compiler_errors_easier_to_read, defaultValueDescription: true, }, { @@ -307,7 +313,8 @@ namespace ts { affectsEmit: true, affectsMultiFileEmitBuildInfo: true, category: Diagnostics.Watch_and_Build_Modes, - description: Diagnostics.Have_recompiles_in_projects_that_use_incremental_and_watch_mode_assume_that_changes_within_a_file_will_only_affect_files_directly_depending_on_it, + description: Diagnostics + .Have_recompiles_in_projects_that_use_incremental_and_watch_mode_assume_that_changes_within_a_file_will_only_affect_files_directly_depending_on_it, defaultValueDescription: false, }, { @@ -345,7 +352,8 @@ namespace ts { paramType: Diagnostics.VERSION, showInSimplifiedHelpView: true, category: Diagnostics.Language_and_Environment, - description: Diagnostics.Set_the_JavaScript_language_version_for_emitted_JavaScript_and_include_compatible_library_declarations, + description: Diagnostics + .Set_the_JavaScript_language_version_for_emitted_JavaScript_and_include_compatible_library_declarations, defaultValueDescription: ScriptTarget.ES3, }; @@ -412,7 +420,8 @@ namespace ts { showInSimplifiedHelpView: true, category: Diagnostics.Command_line_Options, paramType: Diagnostics.FILE_OR_DIRECTORY, - description: Diagnostics.Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json, + description: Diagnostics + .Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json, }, { name: "build", @@ -458,7 +467,8 @@ namespace ts { affectsProgramStructure: true, showInSimplifiedHelpView: true, category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_a_set_of_bundled_library_declaration_files_that_describe_the_target_runtime_environment, + description: Diagnostics + .Specify_a_set_of_bundled_library_declaration_files_that_describe_the_target_runtime_environment, transpileOptionValue: undefined, }, { @@ -467,7 +477,8 @@ namespace ts { affectsModuleResolution: true, showInSimplifiedHelpView: true, category: Diagnostics.JavaScript_Support, - description: Diagnostics.Allow_JavaScript_files_to_be_a_part_of_your_program_Use_the_checkJS_option_to_get_errors_from_these_files, + description: Diagnostics + .Allow_JavaScript_files_to_be_a_part_of_your_program_Use_the_checkJS_option_to_get_errors_from_these_files, defaultValueDescription: false, }, { @@ -547,7 +558,8 @@ namespace ts { paramType: Diagnostics.FILE, showInSimplifiedHelpView: true, category: Diagnostics.Emit, - description: Diagnostics.Specify_a_file_that_bundles_all_outputs_into_one_JavaScript_file_If_declaration_is_true_also_designates_a_file_that_bundles_all_d_ts_output, + description: Diagnostics + .Specify_a_file_that_bundles_all_outputs_into_one_JavaScript_file_If_declaration_is_true_also_designates_a_file_that_bundles_all_d_ts_output, transpileOptionValue: undefined, }, { @@ -584,7 +596,8 @@ namespace ts { category: Diagnostics.Projects, transpileOptionValue: undefined, defaultValueDescription: false, - description: Diagnostics.Enable_constraints_that_allow_a_TypeScript_project_to_be_used_with_project_references, + description: + Diagnostics.Enable_constraints_that_allow_a_TypeScript_project_to_be_used_with_project_references, }, { name: "tsBuildInfoFile", @@ -624,7 +637,8 @@ namespace ts { affectsEmit: true, affectsMultiFileEmitBuildInfo: true, category: Diagnostics.Emit, - description: Diagnostics.Allow_importing_helper_functions_from_tslib_once_per_project_instead_of_including_them_per_file, + description: Diagnostics + .Allow_importing_helper_functions_from_tslib_once_per_project_instead_of_including_them_per_file, defaultValueDescription: false, }, { @@ -700,7 +714,8 @@ namespace ts { affectsMultiFileEmitBuildInfo: true, strictFlag: true, category: Diagnostics.Type_Checking, - description: Diagnostics.When_assigning_functions_check_to_ensure_parameters_and_the_return_values_are_subtype_compatible, + description: Diagnostics + .When_assigning_functions_check_to_ensure_parameters_and_the_return_values_are_subtype_compatible, defaultValueDescription: Diagnostics.false_unless_strict_is_set, }, { @@ -710,7 +725,8 @@ namespace ts { affectsMultiFileEmitBuildInfo: true, strictFlag: true, category: Diagnostics.Type_Checking, - description: Diagnostics.Check_that_the_arguments_for_bind_call_and_apply_methods_match_the_original_function, + description: + Diagnostics.Check_that_the_arguments_for_bind_call_and_apply_methods_match_the_original_function, defaultValueDescription: Diagnostics.false_unless_strict_is_set, }, { @@ -904,7 +920,8 @@ namespace ts { affectsProgramStructure: true, showInSimplifiedHelpView: true, category: Diagnostics.Modules, - description: Diagnostics.Specify_type_package_names_to_be_included_without_being_referenced_in_a_source_file, + description: + Diagnostics.Specify_type_package_names_to_be_included_without_being_referenced_in_a_source_file, transpileOptionValue: undefined, }, { @@ -924,14 +941,16 @@ namespace ts { affectsMultiFileEmitBuildInfo: true, showInSimplifiedHelpView: true, category: Diagnostics.Interop_Constraints, - description: Diagnostics.Emit_additional_JavaScript_to_ease_support_for_importing_CommonJS_modules_This_enables_allowSyntheticDefaultImports_for_type_compatibility, + description: Diagnostics + .Emit_additional_JavaScript_to_ease_support_for_importing_CommonJS_modules_This_enables_allowSyntheticDefaultImports_for_type_compatibility, defaultValueDescription: false, }, { name: "preserveSymlinks", type: "boolean", category: Diagnostics.Interop_Constraints, - description: Diagnostics.Disable_resolving_symlinks_to_their_realpath_This_correlates_to_the_same_flag_in_node, + description: + Diagnostics.Disable_resolving_symlinks_to_their_realpath_This_correlates_to_the_same_flag_in_node, defaultValueDescription: false, }, { @@ -973,7 +992,8 @@ namespace ts { affectsMultiFileEmitBuildInfo: true, paramType: Diagnostics.LOCATION, category: Diagnostics.Emit, - description: Diagnostics.Specify_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations, + description: + Diagnostics.Specify_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations, }, { name: "inlineSourceMap", @@ -1020,14 +1040,16 @@ namespace ts { name: "jsxFactory", type: "string", category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_the_JSX_factory_function_used_when_targeting_React_JSX_emit_e_g_React_createElement_or_h, + description: Diagnostics + .Specify_the_JSX_factory_function_used_when_targeting_React_JSX_emit_e_g_React_createElement_or_h, defaultValueDescription: "`React.createElement`", }, { name: "jsxFragmentFactory", type: "string", category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_the_JSX_Fragment_reference_used_for_fragments_when_targeting_React_JSX_emit_e_g_React_Fragment_or_Fragment, + description: Diagnostics + .Specify_the_JSX_Fragment_reference_used_for_fragments_when_targeting_React_JSX_emit_e_g_React_Fragment_or_Fragment, defaultValueDescription: "React.Fragment", }, { @@ -1038,7 +1060,8 @@ namespace ts { affectsMultiFileEmitBuildInfo: true, affectsModuleResolution: true, category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_module_specifier_used_to_import_the_JSX_factory_functions_when_using_jsx_Colon_react_jsx_Asterisk, + description: Diagnostics + .Specify_module_specifier_used_to_import_the_JSX_factory_functions_when_using_jsx_Colon_react_jsx_Asterisk, defaultValueDescription: "react", }, { @@ -1070,7 +1093,8 @@ namespace ts { affectsEmit: true, affectsMultiFileEmitBuildInfo: true, category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_the_object_invoked_for_createElement_This_only_applies_when_targeting_react_JSX_emit, + description: Diagnostics + .Specify_the_object_invoked_for_createElement_This_only_applies_when_targeting_react_JSX_emit, defaultValueDescription: "`React`", }, { @@ -1086,7 +1110,8 @@ namespace ts { name: "charset", type: "string", category: Diagnostics.Backwards_Compatibility, - description: Diagnostics.No_longer_supported_In_early_versions_manually_set_the_text_encoding_for_reading_files, + description: + Diagnostics.No_longer_supported_In_early_versions_manually_set_the_text_encoding_for_reading_files, defaultValueDescription: "utf8", }, { @@ -1136,7 +1161,8 @@ namespace ts { type: "boolean", affectsModuleResolution: true, category: Diagnostics.Modules, - description: Diagnostics.Disallow_import_s_require_s_or_reference_s_from_expanding_the_number_of_files_TypeScript_should_add_to_a_project, + description: Diagnostics + .Disallow_import_s_require_s_or_reference_s_from_expanding_the_number_of_files_TypeScript_should_add_to_a_project, // We are not doing a full typecheck, we are not resolving the whole context, // so pass --noResolve to avoid reporting missing file errors. transpileOptionValue: true, @@ -1156,7 +1182,8 @@ namespace ts { type: "boolean", affectsProgramStructure: true, category: Diagnostics.Editor_Support, - description: Diagnostics.Remove_the_20mb_cap_on_total_source_code_size_for_JavaScript_files_in_the_TypeScript_language_server, + description: Diagnostics + .Remove_the_20mb_cap_on_total_source_code_size_for_JavaScript_files_in_the_TypeScript_language_server, defaultValueDescription: false, }, { @@ -1164,7 +1191,8 @@ namespace ts { type: "boolean", isTSConfigOnly: true, category: Diagnostics.Projects, - description: Diagnostics.Disable_preferring_source_files_instead_of_declaration_files_when_referencing_composite_projects, + description: Diagnostics + .Disable_preferring_source_files_instead_of_declaration_files_when_referencing_composite_projects, defaultValueDescription: false, }, { @@ -1292,7 +1320,8 @@ namespace ts { type: "number", affectsModuleResolution: true, category: Diagnostics.JavaScript_Support, - description: Diagnostics.Specify_the_maximum_folder_depth_used_for_checking_JavaScript_files_from_node_modules_Only_applicable_with_allowJs, + description: Diagnostics + .Specify_the_maximum_folder_depth_used_for_checking_JavaScript_files_from_node_modules_Only_applicable_with_allowJs, defaultValueDescription: 0, }, { @@ -1320,7 +1349,8 @@ namespace ts { affectsEmit: true, affectsMultiFileEmitBuildInfo: true, category: Diagnostics.Emit, - description: Diagnostics.Preserve_unused_imported_values_in_the_JavaScript_output_that_would_otherwise_be_removed, + description: + Diagnostics.Preserve_unused_imported_values_in_the_JavaScript_output_that_would_otherwise_be_removed, defaultValueDescription: false, }, @@ -1353,7 +1383,8 @@ namespace ts { affectsModuleResolution: true, description: Diagnostics.Control_what_method_is_used_to_detect_module_format_JS_files, category: Diagnostics.Language_and_Environment, - defaultValueDescription: Diagnostics.auto_Colon_Treat_files_with_imports_exports_import_meta_jsx_with_jsx_Colon_react_jsx_or_esm_format_with_module_Colon_node16_as_modules, + defaultValueDescription: Diagnostics + .auto_Colon_Treat_files_with_imports_exports_import_meta_jsx_with_jsx_Colon_react_jsx_or_esm_format_with_module_Colon_node16_as_modules, }, ]; @@ -1364,25 +1395,39 @@ namespace ts { ]; /* @internal */ - export const semanticDiagnosticsOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsSemanticDiagnostics); + export const semanticDiagnosticsOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter( + option => !!option.affectsSemanticDiagnostics, + ); /* @internal */ - export const affectsEmitOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsEmit); + export const affectsEmitOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => + !!option.affectsEmit + ); /* @internal */ - export const affectsDeclarationPathOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsDeclarationPath); + export const affectsDeclarationPathOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter( + option => !!option.affectsDeclarationPath, + ); /* @internal */ - export const moduleResolutionOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsModuleResolution); + export const moduleResolutionOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => + !!option.affectsModuleResolution + ); /* @internal */ - export const sourceFileAffectingCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics); + export const sourceFileAffectingCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => + !!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics + ); /* @internal */ - export const optionsAffectingProgramStructure: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsProgramStructure); + export const optionsAffectingProgramStructure: readonly CommandLineOption[] = optionDeclarations.filter(option => + !!option.affectsProgramStructure + ); /* @internal */ - export const transpileOptionValueCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => hasProperty(option, "transpileOptionValue")); + export const transpileOptionValueCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => + hasProperty(option, "transpileOptionValue") + ); // Build related options /* @internal */ @@ -1509,7 +1554,9 @@ namespace ts { /* @internal */ export function convertEnableAutoDiscoveryToEnable(typeAcquisition: TypeAcquisition): TypeAcquisition { // Convert deprecated typingOptions.enableAutoDiscovery to typeAcquisition.enable - if (typeAcquisition && typeAcquisition.enableAutoDiscovery !== undefined && typeAcquisition.enable === undefined) { + if ( + typeAcquisition && typeAcquisition.enableAutoDiscovery !== undefined && typeAcquisition.enable === undefined + ) { return { enable: typeAcquisition.enableAutoDiscovery, include: typeAcquisition.include || [], @@ -1524,7 +1571,10 @@ namespace ts { return createDiagnosticForInvalidCustomType(opt, createCompilerDiagnostic); } - function createDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType, createDiagnostic: (message: DiagnosticMessage, arg0: string, arg1: string) => Diagnostic): Diagnostic { + function createDiagnosticForInvalidCustomType( + opt: CommandLineOptionOfCustomType, + createDiagnostic: (message: DiagnosticMessage, arg0: string, arg1: string) => Diagnostic, + ): Diagnostic { const namesOfType = arrayFrom(opt.type.keys()).map(key => `'${key}'`).join(", "); return createDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, namesOfType); } @@ -1535,7 +1585,11 @@ namespace ts { } /* @internal */ - export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Push): (string | number)[] | undefined { + export function parseListTypeOption( + opt: CommandLineOptionOfListType, + value = "", + errors: Push, + ): (string | number)[] | undefined { value = trimString(value); if (startsWith(value, "-")) { return undefined; @@ -1550,7 +1604,10 @@ namespace ts { case "string": return mapDefined(values, v => validateJsonOptionValue(opt.element, v || "", errors)); default: - return mapDefined(values, v => parseCustomTypeOption(opt.element as CommandLineOptionOfCustomType, v, errors)); + return mapDefined( + values, + v => parseCustomTypeOption(opt.element as CommandLineOptionOfCustomType, v, errors), + ); } } @@ -1580,9 +1637,13 @@ namespace ts { } const possibleOption = getSpellingSuggestion(unknownOption, diagnostics.optionDeclarations, getOptionName); - return possibleOption ? - createDiagnostics(diagnostics.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) : - createDiagnostics(diagnostics.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption); + return possibleOption + ? createDiagnostics( + diagnostics.unknownDidYouMeanDiagnostic, + unknownOptionErrorText || unknownOption, + possibleOption.name, + ) + : createDiagnostics(diagnostics.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption); } /*@internal*/ @@ -1614,17 +1675,34 @@ namespace ts { } else if (s.charCodeAt(0) === CharacterCodes.minus) { const inputOptionName = s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1); - const opt = getOptionDeclarationFromName(diagnostics.getOptionsNameMap, inputOptionName, /*allowShort*/ true); + const opt = getOptionDeclarationFromName( + diagnostics.getOptionsNameMap, + inputOptionName, + /*allowShort*/ true, + ); if (opt) { i = parseOptionValue(args, i, diagnostics, opt, options, errors); } else { - const watchOpt = getOptionDeclarationFromName(watchOptionsDidYouMeanDiagnostics.getOptionsNameMap, inputOptionName, /*allowShort*/ true); + const watchOpt = getOptionDeclarationFromName( + watchOptionsDidYouMeanDiagnostics.getOptionsNameMap, + inputOptionName, + /*allowShort*/ true, + ); if (watchOpt) { - i = parseOptionValue(args, i, watchOptionsDidYouMeanDiagnostics, watchOpt, watchOptions || (watchOptions = {}), errors); + i = parseOptionValue( + args, + i, + watchOptionsDidYouMeanDiagnostics, + watchOpt, + watchOptions || (watchOptions = {}), + errors, + ); } else { - errors.push(createUnknownOptionError(inputOptionName, diagnostics, createCompilerDiagnostic, s)); + errors.push( + createUnknownOptionError(inputOptionName, diagnostics, createCompilerDiagnostic, s), + ); } } } @@ -1655,7 +1733,12 @@ namespace ts { pos++; } else { - errors.push(createCompilerDiagnostic(Diagnostics.Unterminated_quoted_string_in_response_file_0, fileName)); + errors.push( + createCompilerDiagnostic( + Diagnostics.Unterminated_quoted_string_in_response_file_0, + fileName, + ), + ); } } else { @@ -1688,18 +1771,35 @@ namespace ts { } else { if (optValue === "true") i++; - errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_false_or_null_on_command_line, opt.name)); + errors.push( + createCompilerDiagnostic( + Diagnostics + .Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_false_or_null_on_command_line, + opt.name, + ), + ); } } else { - errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_null_on_command_line, opt.name)); + errors.push( + createCompilerDiagnostic( + Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_null_on_command_line, + opt.name, + ), + ); if (optValue && !startsWith(optValue, "-")) i++; } } else { // Check to see if no argument was provided (e.g. "--locale" is the last command-line argument). if (!args[i] && opt.type !== "boolean") { - errors.push(createCompilerDiagnostic(diagnostics.optionTypeMismatchDiagnostic, opt.name, getCompilerOptionValueTypeString(opt))); + errors.push( + createCompilerDiagnostic( + diagnostics.optionTypeMismatchDiagnostic, + opt.name, + getCompilerOptionValueTypeString(opt), + ), + ); } if (args[i] !== "null") { @@ -1730,7 +1830,11 @@ namespace ts { break; // If not a primitive, the possible types are specified in what is effectively a map of options. default: - options[opt.name] = parseCustomTypeOption(opt as CommandLineOptionOfCustomType, args[i], errors); + options[opt.name] = parseCustomTypeOption( + opt as CommandLineOptionOfCustomType, + args[i], + errors, + ); i++; break; } @@ -1752,7 +1856,10 @@ namespace ts { unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument, }; - export function parseCommandLine(commandLine: readonly string[], readFile?: (path: string) => string | undefined): ParsedCommandLine { + export function parseCommandLine( + commandLine: readonly string[], + readFile?: (path: string) => string | undefined, + ): ParsedCommandLine { return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile); } @@ -1761,7 +1868,11 @@ namespace ts { return getOptionDeclarationFromName(getOptionsNameMap, optionName, allowShort); } - function getOptionDeclarationFromName(getOptionNameMap: () => OptionsNameMap, optionName: string, allowShort = false): CommandLineOption | undefined { + function getOptionDeclarationFromName( + getOptionNameMap: () => OptionsNameMap, + optionName: string, + allowShort = false, + ): CommandLineOption | undefined { optionName = optionName.toLowerCase(); const { optionsNameMap, shortOptionNames } = getOptionNameMap(); // Try to translate short option names to their full equivalents. @@ -1894,9 +2005,13 @@ namespace ts { * Read tsconfig.json file * @param fileName The path to the config file */ - export function readConfigFile(fileName: string, readFile: (path: string) => string | undefined): { config?: any; error?: Diagnostic; } { + export function readConfigFile( + fileName: string, + readFile: (path: string) => string | undefined, + ): { config?: any; error?: Diagnostic; } { const textOrDiagnostic = tryReadFile(fileName, readFile); - return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic }; + return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) + : { config: {}, error: textOrDiagnostic }; } /** @@ -1904,10 +2019,18 @@ namespace ts { * @param fileName The path to the config file * @param jsonText The text of the config file */ - export function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic; } { + export function parseConfigFileTextToJson( + fileName: string, + jsonText: string, + ): { config?: any; error?: Diagnostic; } { const jsonSourceFile = parseJsonText(fileName, jsonText); return { - config: convertConfigFileToObject(jsonSourceFile, jsonSourceFile.parseDiagnostics, /*reportOptionsErrors*/ false, /*optionsIterator*/ undefined), + config: convertConfigFileToObject( + jsonSourceFile, + jsonSourceFile.parseDiagnostics, + /*reportOptionsErrors*/ false, + /*optionsIterator*/ undefined, + ), error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined, }; } @@ -1916,9 +2039,13 @@ namespace ts { * Read tsconfig.json file * @param fileName The path to the config file */ - export function readJsonConfigFile(fileName: string, readFile: (path: string) => string | undefined): TsConfigSourceFile { + export function readJsonConfigFile( + fileName: string, + readFile: (path: string) => string | undefined, + ): TsConfigSourceFile { const textOrDiagnostic = tryReadFile(fileName, readFile); - return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : { fileName, parseDiagnostics: [textOrDiagnostic] } as TsConfigSourceFile; + return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) + : { fileName, parseDiagnostics: [textOrDiagnostic] } as TsConfigSourceFile; } /*@internal*/ @@ -1957,15 +2084,18 @@ namespace ts { let commandLineCompilerOptionsMapCache: ESMap; function getCommandLineCompilerOptionsMap() { - return commandLineCompilerOptionsMapCache || (commandLineCompilerOptionsMapCache = commandLineOptionsToMap(optionDeclarations)); + return commandLineCompilerOptionsMapCache + || (commandLineCompilerOptionsMapCache = commandLineOptionsToMap(optionDeclarations)); } let commandLineWatchOptionsMapCache: ESMap; function getCommandLineWatchOptionsMap() { - return commandLineWatchOptionsMapCache || (commandLineWatchOptionsMapCache = commandLineOptionsToMap(optionsForWatch)); + return commandLineWatchOptionsMapCache + || (commandLineWatchOptionsMapCache = commandLineOptionsToMap(optionsForWatch)); } let commandLineTypeAcquisitionMapCache: ESMap; function getCommandLineTypeAcquisitionMap() { - return commandLineTypeAcquisitionMapCache || (commandLineTypeAcquisitionMapCache = commandLineOptionsToMap(typeAcquisitionDeclarations)); + return commandLineTypeAcquisitionMapCache + || (commandLineTypeAcquisitionMapCache = commandLineOptionsToMap(typeAcquisitionDeclarations)); } let _tsconfigRootOptions: TsConfigOnlyOption; @@ -2030,7 +2160,8 @@ namespace ts { type: "string", }, category: Diagnostics.File_Management, - defaultValueDescription: Diagnostics.if_files_is_specified_otherwise_Asterisk_Asterisk_Slash_Asterisk, + defaultValueDescription: + Diagnostics.if_files_is_specified_otherwise_Asterisk_Asterisk_Slash_Asterisk, }, { name: "exclude", @@ -2040,7 +2171,8 @@ namespace ts { type: "string", }, category: Diagnostics.File_Management, - defaultValueDescription: Diagnostics.node_modules_bower_components_jspm_packages_plus_the_value_of_outDir_if_one_is_specified, + defaultValueDescription: Diagnostics + .node_modules_bower_components_jspm_packages_plus_the_value_of_outDir_if_one_is_specified, }, compileOnSaveCommandLineOption, ]), @@ -2059,7 +2191,11 @@ namespace ts { * @param option option declaration which is being set with the value * @param value value of the option */ - onSetValidOptionKeyValueInParent(parentOption: string, option: CommandLineOption, value: CompilerOptionsValue): void; + onSetValidOptionKeyValueInParent( + parentOption: string, + option: CommandLineOption, + value: CompilerOptionsValue, + ): void; /** * Notify when valid root key value option is being set * @param key option key @@ -2067,7 +2203,12 @@ namespace ts { * @param value computed value of the key * @param ValueNode node corresponding to value in the source file */ - onSetValidOptionKeyValueInRoot(key: string, keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression): void; + onSetValidOptionKeyValueInRoot( + key: string, + keyNode: PropertyName, + value: CompilerOptionsValue, + valueNode: Expression, + ): void; /** * Notify when unknown root key value option is being set * @param key option key @@ -2075,10 +2216,20 @@ namespace ts { * @param value computed value of the key * @param ValueNode node corresponding to value in the source file */ - onSetUnknownOptionKeyValueInRoot(key: string, keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression): void; + onSetUnknownOptionKeyValueInRoot( + key: string, + keyNode: PropertyName, + value: CompilerOptionsValue, + valueNode: Expression, + ): void; } - function convertConfigFileToObject(sourceFile: JsonSourceFile, errors: Push, reportOptionsErrors: boolean, optionsIterator: JsonConversionNotifier | undefined): any { + function convertConfigFileToObject( + sourceFile: JsonSourceFile, + errors: Push, + reportOptionsErrors: boolean, + optionsIterator: JsonConversionNotifier | undefined, + ): any { const rootExpression: Expression | undefined = sourceFile.statements[0]?.expression; const knownRootOptions = reportOptionsErrors ? getTsconfigRootOptionsMap() : undefined; if (rootExpression && rootExpression.kind !== SyntaxKind.ObjectLiteralExpression) { @@ -2094,19 +2245,40 @@ namespace ts { if (isArrayLiteralExpression(rootExpression)) { const firstObject = find(rootExpression.elements, isObjectLiteralExpression); if (firstObject) { - return convertToObjectWorker(sourceFile, firstObject, errors, /*returnValue*/ true, knownRootOptions, optionsIterator); + return convertToObjectWorker( + sourceFile, + firstObject, + errors, + /*returnValue*/ true, + knownRootOptions, + optionsIterator, + ); } } return {}; } - return convertToObjectWorker(sourceFile, rootExpression, errors, /*returnValue*/ true, knownRootOptions, optionsIterator); + return convertToObjectWorker( + sourceFile, + rootExpression, + errors, + /*returnValue*/ true, + knownRootOptions, + optionsIterator, + ); } /** * Convert the json syntax tree into the json value */ export function convertToObject(sourceFile: JsonSourceFile, errors: Push): any { - return convertToObjectWorker(sourceFile, sourceFile.statements[0]?.expression, errors, /*returnValue*/ true, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined); + return convertToObjectWorker( + sourceFile, + sourceFile.statements[0]?.expression, + errors, + /*returnValue*/ true, + /*knownRootOptions*/ undefined, + /*jsonConversionNotifier*/ undefined, + ); } /** @@ -2142,18 +2314,38 @@ namespace ts { const result: any = returnValue ? {} : undefined; for (const element of node.properties) { if (element.kind !== SyntaxKind.PropertyAssignment) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element, Diagnostics.Property_assignment_expected)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + element, + Diagnostics.Property_assignment_expected, + ), + ); continue; } if (element.questionToken) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.questionToken, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?")); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + element.questionToken, + Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, + "?", + ), + ); } if (!isDoubleQuotedString(element.name)) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, Diagnostics.String_literal_with_double_quotes_expected)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + element.name, + Diagnostics.String_literal_with_double_quotes_expected, + ), + ); } - const textOfKey = isComputedNonLiteralName(element.name) ? undefined : getTextOfPropertyName(element.name); + const textOfKey = isComputedNonLiteralName(element.name) ? undefined + : getTextOfPropertyName(element.name); const keyText = textOfKey && unescapeLeadingUnderscores(textOfKey); const option = keyText && knownOptions ? knownOptions.get(keyText) : undefined; if (keyText && extraKeyDiagnostics && !option) { @@ -2161,11 +2353,19 @@ namespace ts { errors.push(createUnknownOptionError( keyText, extraKeyDiagnostics, - (message, arg0, arg1) => createDiagnosticForNodeInSourceFile(sourceFile, element.name, message, arg0, arg1), + (message, arg0, arg1) => + createDiagnosticForNodeInSourceFile(sourceFile, element.name, message, arg0, arg1), )); } else { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, extraKeyDiagnostics.unknownOptionDiagnostic, keyText)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + element.name, + extraKeyDiagnostics.unknownOptionDiagnostic, + keyText, + ), + ); } } const value = convertPropertyValueToJson(element.initializer, option); @@ -2175,9 +2375,9 @@ namespace ts { } // Notify key value set, if user asked for it if ( - jsonConversionNotifier && + jsonConversionNotifier // Current callbacks are only on known parent option or if we are setting values in the root - (parentOption || isRootOptionMap(knownOptions)) + && (parentOption || isRootOptionMap(knownOptions)) ) { const isValidOptionValue = isCompilerOptionsValue(option, value); if (parentOption) { @@ -2189,11 +2389,21 @@ namespace ts { else if (isRootOptionMap(knownOptions)) { if (isValidOptionValue) { // Notify about the valid root key value being set - jsonConversionNotifier.onSetValidOptionKeyValueInRoot(keyText, element.name, value, element.initializer); + jsonConversionNotifier.onSetValidOptionKeyValueInRoot( + keyText, + element.name, + value, + element.initializer, + ); } else if (!option) { // Notify about the unknown root key value being set - jsonConversionNotifier.onSetUnknownOptionKeyValueInRoot(keyText, element.name, value, element.initializer); + jsonConversionNotifier.onSetUnknownOptionKeyValueInRoot( + keyText, + element.name, + value, + element.initializer, + ); } } } @@ -2212,7 +2422,10 @@ namespace ts { } // Filter out invalid values - return filter(elements.map(element => convertPropertyValueToJson(element, elementOption)), v => v !== undefined); + return filter( + elements.map(element => convertPropertyValueToJson(element, elementOption)), + v => v !== undefined, + ); } function convertPropertyValueToJson(valueExpression: Expression, option: CommandLineOption | undefined): any { @@ -2232,7 +2445,13 @@ namespace ts { case SyntaxKind.StringLiteral: if (!isDoubleQuotedString(valueExpression)) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.String_literal_with_double_quotes_expected)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + valueExpression, + Diagnostics.String_literal_with_double_quotes_expected, + ), + ); } reportInvalidOptionValue(option && (isString(option.type) && option.type !== "string")); const text = (valueExpression as StringLiteral).text; @@ -2243,7 +2462,14 @@ namespace ts { errors.push( createDiagnosticForInvalidCustomType( customOption, - (message, arg0, arg1) => createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, message, arg0, arg1), + (message, arg0, arg1) => + createDiagnosticForNodeInSourceFile( + sourceFile, + valueExpression, + message, + arg0, + arg1, + ), ), ); invalidReported = true; @@ -2256,11 +2482,16 @@ namespace ts { return validateValue(Number((valueExpression as NumericLiteral).text)); case SyntaxKind.PrefixUnaryExpression: - if ((valueExpression as PrefixUnaryExpression).operator !== SyntaxKind.MinusToken || (valueExpression as PrefixUnaryExpression).operand.kind !== SyntaxKind.NumericLiteral) { + if ( + (valueExpression as PrefixUnaryExpression).operator !== SyntaxKind.MinusToken + || (valueExpression as PrefixUnaryExpression).operand.kind !== SyntaxKind.NumericLiteral + ) { break; // not valid JSON syntax } reportInvalidOptionValue(option && option.type !== "number"); - return validateValue(-Number(((valueExpression as PrefixUnaryExpression).operand as NumericLiteral).text)); + return validateValue( + -Number(((valueExpression as PrefixUnaryExpression).operand as NumericLiteral).text), + ); case SyntaxKind.ObjectLiteralExpression: reportInvalidOptionValue(option && option.type !== "object"); @@ -2274,7 +2505,14 @@ namespace ts { // If need arises, we can modify this interface and callbacks as needed if (option) { const { elementOptions, extraKeyDiagnostics, name: optionName } = option as TsConfigOnlyOption; - return validateValue(convertObjectLiteralExpressionToJson(objectLiteralExpression, elementOptions, extraKeyDiagnostics, optionName)); + return validateValue( + convertObjectLiteralExpressionToJson( + objectLiteralExpression, + elementOptions, + extraKeyDiagnostics, + optionName, + ), + ); } else { return validateValue(convertObjectLiteralExpressionToJson( @@ -2298,7 +2536,14 @@ namespace ts { reportInvalidOptionValue(/*isError*/ true); } else { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Property_value_can_only_be_string_literal_numeric_literal_true_false_null_object_literal_or_array_literal)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + valueExpression, + Diagnostics + .Property_value_can_only_be_string_literal_numeric_literal_true_false_null_object_literal_or_array_literal, + ), + ); } return undefined; @@ -2316,7 +2561,15 @@ namespace ts { function reportInvalidOptionValue(isError: boolean | undefined) { if (isError) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Compiler_option_0_requires_a_value_of_type_1, option!.name, getCompilerOptionValueTypeString(option!))); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + valueExpression, + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + option!.name, + getCompilerOptionValueTypeString(option!), + ), + ); invalidReported = true; } } @@ -2328,9 +2581,9 @@ namespace ts { } function getCompilerOptionValueTypeString(option: CommandLineOption) { - return option.type === "list" ? - "Array" : - isString(option.type) ? option.type : "string"; + return option.type === "list" + ? "Array" + : isString(option.type) ? option.type : "string"; } function isCompilerOptionsValue(option: CommandLineOption | undefined, value: any): value is CompilerOptionsValue { @@ -2368,21 +2621,33 @@ namespace ts { * @param host provides current directory and case sensitivity services */ /** @internal */ - export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: ConvertToTSConfigHost): TSConfig { + export function convertToTSConfig( + configParseResult: ParsedCommandLine, + configFileName: string, + host: ConvertToTSConfigHost, + ): TSConfig { const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames); const files = map( filter( configParseResult.fileNames, - !configParseResult.options.configFile?.configFileSpecs?.validatedIncludeSpecs ? returnTrue : matchesSpecs( - configFileName, - configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs, - configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs, - host, - ), + !configParseResult.options.configFile?.configFileSpecs?.validatedIncludeSpecs ? returnTrue + : matchesSpecs( + configFileName, + configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs, + configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs, + host, + ), + ), + f => getRelativePathFromFile( + getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), + getNormalizedAbsolutePath(f, host.getCurrentDirectory()), + getCanonicalFileName, ), - f => getRelativePathFromFile(getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), getNormalizedAbsolutePath(f, host.getCurrentDirectory()), getCanonicalFileName), ); - const optionMap = serializeCompilerOptions(configParseResult.options, { configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), useCaseSensitiveFileNames: host.useCaseSensitiveFileNames }); + const optionMap = serializeCompilerOptions(configParseResult.options, { + configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), + useCaseSensitiveFileNames: host.useCaseSensitiveFileNames, + }); const watchOptionMap = configParseResult.watchOptions && serializeWatchOptions(configParseResult.watchOptions); const config = { compilerOptions: { @@ -2399,10 +2664,15 @@ namespace ts { version: undefined, }, watchOptions: watchOptionMap && optionMapToObject(watchOptionMap), - references: map(configParseResult.projectReferences, r => ({ ...r, path: r.originalPath ? r.originalPath : "", originalPath: undefined })), + references: map( + configParseResult.projectReferences, + r => ({ ...r, path: r.originalPath ? r.originalPath : "", originalPath: undefined }), + ), files: length(files) ? files : undefined, ...(configParseResult.options.configFile?.configFileSpecs ? { - include: filterSameAsDefaultInclude(configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs), + include: filterSameAsDefaultInclude( + configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs, + ), exclude: configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs, } : {}), compileOnSave: !!configParseResult.compileOnSave ? true : undefined, @@ -2423,11 +2693,24 @@ namespace ts { return specs; } - function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined, excludeSpecs: readonly string[] | undefined, host: ConvertToTSConfigHost): (path: string) => boolean { + function matchesSpecs( + path: string, + includeSpecs: readonly string[] | undefined, + excludeSpecs: readonly string[] | undefined, + host: ConvertToTSConfigHost, + ): (path: string) => boolean { if (!includeSpecs) return returnTrue; - const patterns = getFileMatcherPatterns(path, excludeSpecs, includeSpecs, host.useCaseSensitiveFileNames, host.getCurrentDirectory()); - const excludeRe = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, host.useCaseSensitiveFileNames); - const includeRe = patterns.includeFilePattern && getRegexFromPattern(patterns.includeFilePattern, host.useCaseSensitiveFileNames); + const patterns = getFileMatcherPatterns( + path, + excludeSpecs, + includeSpecs, + host.useCaseSensitiveFileNames, + host.getCurrentDirectory(), + ); + const excludeRe = patterns.excludePattern + && getRegexFromPattern(patterns.excludePattern, host.useCaseSensitiveFileNames); + const includeRe = patterns.includeFilePattern + && getRegexFromPattern(patterns.includeFilePattern, host.useCaseSensitiveFileNames); if (includeRe) { if (excludeRe) { return path => !(includeRe.test(path) && !excludeRe.test(path)); @@ -2440,8 +2723,13 @@ namespace ts { return returnTrue; } - function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): ESMap | undefined { - if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean" || optionDefinition.type === "object") { + function getCustomTypeMapOfCommandLineOption( + optionDefinition: CommandLineOption, + ): ESMap | undefined { + if ( + optionDefinition.type === "string" || optionDefinition.type === "number" + || optionDefinition.type === "boolean" || optionDefinition.type === "object" + ) { // this is of a type CommandLineOptionOfPrimitiveType return undefined; } @@ -2454,7 +2742,10 @@ namespace ts { } /* @internal */ - export function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: ESMap): string | undefined { + export function getNameOfCompilerOptionValue( + value: CompilerOptionsValue, + customTypeMap: ESMap, + ): string | undefined { // There is a typeMap associated with this command-line option so use it to map value back to its name return forEachEntry(customTypeMap, (mapValue, key) => { if (mapValue === value) { @@ -2486,7 +2777,11 @@ namespace ts { if (hasProperty(options, name)) { // tsconfig only options cannot be specified via command line, // so we can assume that only types that can appear here string | number | boolean - if (optionsNameMap.has(name) && (optionsNameMap.get(name)!.category === Diagnostics.Command_line_Options || optionsNameMap.get(name)!.category === Diagnostics.Output_Formatting)) { + if ( + optionsNameMap.has(name) + && (optionsNameMap.get(name)!.category === Diagnostics.Command_line_Options + || optionsNameMap.get(name)!.category === Diagnostics.Output_Formatting) + ) { continue; } const value = options[name] as CompilerOptionsValue; @@ -2497,7 +2792,17 @@ namespace ts { // There is no map associated with this compiler option then use the value as-is // This is the case if the value is expect to be string, number, boolean or list of string if (pathOptions && optionDefinition.isFilePath) { - result.set(name, getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(value as string, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName!)); + result.set( + name, + getRelativePathFromFile( + pathOptions.configFilePath, + getNormalizedAbsolutePath( + value as string, + getDirectoryPath(pathOptions.configFilePath), + ), + getCanonicalFileName!, + ), + ); } else { result.set(name, value); @@ -2505,7 +2810,12 @@ namespace ts { } else { if (optionDefinition.type === "list") { - result.set(name, (value as readonly (string | number)[]).map(element => getNameOfCompilerOptionValue(element, customTypeMap)!)); // TODO: GH#18217 + result.set( + name, + (value as readonly (string | number)[]).map(element => + getNameOfCompilerOptionValue(element, customTypeMap)! + ), + ); // TODO: GH#18217 } else { // There is a typeMap associated with this command-line option so use it to map value back to its name @@ -2575,8 +2885,16 @@ namespace ts { function isAllowedOptionForOutput({ category, name, isCommandLineOnly }: CommandLineOption): boolean { // Skip options which do not have a category or have categories which are more niche - const categoriesToSkip = [Diagnostics.Command_line_Options, Diagnostics.Editor_Support, Diagnostics.Compiler_Diagnostics, Diagnostics.Backwards_Compatibility, Diagnostics.Watch_and_Build_Modes, Diagnostics.Output_Formatting]; - return !isCommandLineOnly && category !== undefined && (!categoriesToSkip.includes(category) || compilerOptionsMap.has(name)); + const categoriesToSkip = [ + Diagnostics.Command_line_Options, + Diagnostics.Editor_Support, + Diagnostics.Compiler_Diagnostics, + Diagnostics.Backwards_Compatibility, + Diagnostics.Watch_and_Build_Modes, + Diagnostics.Output_Formatting, + ]; + return !isCommandLineOnly && category !== undefined + && (!categoriesToSkip.includes(category) || compilerOptionsMap.has(name)); } function writeConfigurations() { @@ -2602,14 +2920,18 @@ namespace ts { for (const option of options) { let optionName; if (compilerOptionsMap.has(option.name)) { - optionName = `"${option.name}": ${JSON.stringify(compilerOptionsMap.get(option.name))}${(seenKnownKeys += 1) === compilerOptionsMap.size ? "" : ","}`; + optionName = `"${option.name}": ${JSON.stringify(compilerOptionsMap.get(option.name))}${ + (seenKnownKeys += 1) === compilerOptionsMap.size ? "" : "," + }`; } else { optionName = `// "${option.name}": ${JSON.stringify(getDefaultValueForOption(option))},`; } entries.push({ value: optionName, - description: `/* ${option.description && getLocaleSpecificMessage(option.description) || option.name} */`, + description: `/* ${ + option.description && getLocaleSpecificMessage(option.description) || option.name + } */`, }); marginLength = Math.max(optionName.length, marginLength); } @@ -2620,12 +2942,23 @@ namespace ts { const result: string[] = []; result.push(`{`); result.push(`${tab}"compilerOptions": {`); - result.push(`${tab}${tab}/* ${getLocaleSpecificMessage(Diagnostics.Visit_https_Colon_Slash_Slashaka_ms_Slashtsconfig_to_read_more_about_this_file)} */`); + result.push( + `${tab}${tab}/* ${ + getLocaleSpecificMessage( + Diagnostics.Visit_https_Colon_Slash_Slashaka_ms_Slashtsconfig_to_read_more_about_this_file, + ) + } */`, + ); result.push(""); // Print out each row, aligning all the descriptions on the same column. for (const entry of entries) { const { value, description = "" } = entry; - result.push(value && `${tab}${tab}${value}${description && (makePadding(marginLength - value.length + 2) + description)}`); + result.push( + value + && `${tab}${tab}${value}${ + description && (makePadding(marginLength - value.length + 2) + description) + }`, + ); } if (fileNames.length) { result.push(`${tab}},`); @@ -2645,7 +2978,10 @@ namespace ts { } /* @internal */ - export function convertToOptionsWithAbsolutePaths(options: CompilerOptions, toAbsolutePath: (path: string) => string) { + export function convertToOptionsWithAbsolutePaths( + options: CompilerOptions, + toAbsolutePath: (path: string) => string, + ) { const result: CompilerOptions = {}; const optionsNameMap = getOptionsNameMap().optionsNameMap; @@ -2664,7 +3000,11 @@ namespace ts { return result; } - function convertToOptionValueWithAbsolutePaths(option: CommandLineOption | undefined, value: CompilerOptionsValue, toAbsolutePath: (path: string) => string) { + function convertToOptionValueWithAbsolutePaths( + option: CommandLineOption | undefined, + value: CompilerOptionsValue, + toAbsolutePath: (path: string) => string, + ) { if (option && !isNullOrUndefined(value)) { if (option.type === "list") { const values = value as readonly (string | number)[]; @@ -2686,8 +3026,29 @@ namespace ts { * @param basePath A root directory to resolve relative path entries in the config * file to. e.g. outDir */ - export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: readonly FileExtensionInfo[], extendedConfigCache?: Map, existingWatchOptions?: WatchOptions): ParsedCommandLine { - return parseJsonConfigFileContentWorker(json, /*sourceFile*/ undefined, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); + export function parseJsonConfigFileContent( + json: any, + host: ParseConfigHost, + basePath: string, + existingOptions?: CompilerOptions, + configFileName?: string, + resolutionStack?: Path[], + extraFileExtensions?: readonly FileExtensionInfo[], + extendedConfigCache?: Map, + existingWatchOptions?: WatchOptions, + ): ParsedCommandLine { + return parseJsonConfigFileContentWorker( + json, + /*sourceFile*/ undefined, + host, + basePath, + existingOptions, + existingWatchOptions, + configFileName, + resolutionStack, + extraFileExtensions, + extendedConfigCache, + ); } /** @@ -2697,9 +3058,30 @@ namespace ts { * @param basePath A root directory to resolve relative path entries in the config * file to. e.g. outDir */ - export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: readonly FileExtensionInfo[], extendedConfigCache?: Map, existingWatchOptions?: WatchOptions): ParsedCommandLine { + export function parseJsonSourceFileConfigFileContent( + sourceFile: TsConfigSourceFile, + host: ParseConfigHost, + basePath: string, + existingOptions?: CompilerOptions, + configFileName?: string, + resolutionStack?: Path[], + extraFileExtensions?: readonly FileExtensionInfo[], + extendedConfigCache?: Map, + existingWatchOptions?: WatchOptions, + ): ParsedCommandLine { tracing?.push(tracing.Phase.Parse, "parseJsonSourceFileConfigFileContent", { path: sourceFile.fileName }); - const result = parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); + const result = parseJsonConfigFileContentWorker( + /*json*/ undefined, + sourceFile, + host, + basePath, + existingOptions, + existingWatchOptions, + configFileName, + resolutionStack, + extraFileExtensions, + extendedConfigCache, + ); tracing?.pop(); return result; } @@ -2745,22 +3127,35 @@ namespace ts { extraFileExtensions: readonly FileExtensionInfo[] = [], extendedConfigCache?: ESMap, ): ParsedCommandLine { - Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined)); + Debug.assert( + (json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined), + ); const errors: Diagnostic[] = []; - const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors, extendedConfigCache); + const parsedConfig = parseConfig( + json, + sourceFile, + host, + basePath, + configFileName, + resolutionStack, + errors, + extendedConfigCache, + ); const { raw } = parsedConfig; const options = extend(existingOptions, parsedConfig.options || {}); - const watchOptions = existingWatchOptions && parsedConfig.watchOptions ? - extend(existingWatchOptions, parsedConfig.watchOptions) : - parsedConfig.watchOptions || existingWatchOptions; + const watchOptions = existingWatchOptions && parsedConfig.watchOptions + ? extend(existingWatchOptions, parsedConfig.watchOptions) + : parsedConfig.watchOptions || existingWatchOptions; options.configFilePath = configFileName && normalizeSlashes(configFileName); const configFileSpecs = getConfigFileSpecs(); if (sourceFile) sourceFile.configFileSpecs = configFileSpecs; setConfigFileInOptions(options, sourceFile); - const basePathForFileNames = normalizePath(configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath); + const basePathForFileNames = normalizePath( + configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath, + ); return { options, watchOptions, @@ -2773,28 +3168,43 @@ namespace ts { // file map that marks whether it was a regular wildcard match (with a `*` or `?` token), // or a recursive directory. This information is used by filesystem watchers to monitor for // new entries in these paths. - wildcardDirectories: getWildcardDirectories(configFileSpecs, basePathForFileNames, host.useCaseSensitiveFileNames), + wildcardDirectories: getWildcardDirectories( + configFileSpecs, + basePathForFileNames, + host.useCaseSensitiveFileNames, + ), compileOnSave: !!raw.compileOnSave, }; function getConfigFileSpecs(): ConfigFileSpecs { - const referencesOfRaw = getPropFromRaw("references", element => typeof element === "object", "object"); + const referencesOfRaw = getPropFromRaw( + "references", + element => typeof element === "object", + "object", + ); const filesSpecs = toPropValue(getSpecsFromRaw("files")); if (filesSpecs) { - const hasZeroOrNoReferences = referencesOfRaw === "no-prop" || isArray(referencesOfRaw) && referencesOfRaw.length === 0; + const hasZeroOrNoReferences = referencesOfRaw === "no-prop" + || isArray(referencesOfRaw) && referencesOfRaw.length === 0; const hasExtends = hasProperty(raw, "extends"); if (filesSpecs.length === 0 && hasZeroOrNoReferences && !hasExtends) { if (sourceFile) { const fileName = configFileName || "tsconfig.json"; const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty; - const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer); + const nodeValue = firstDefined( + getTsConfigPropArray(sourceFile, "files"), + property => property.initializer, + ); const error = nodeValue ? createDiagnosticForNodeInSourceFile(sourceFile, nodeValue, diagnosticMessage, fileName) : createCompilerDiagnostic(diagnosticMessage, fileName); errors.push(error); } else { - createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json"); + createCompilerDiagnosticOnlyIfJson( + Diagnostics.The_files_list_in_config_file_0_is_empty, + configFileName || "tsconfig.json", + ); } } } @@ -2817,18 +3227,31 @@ namespace ts { includeSpecs = [defaultIncludeSpec]; isDefaultIncludeSpec = true; } - let validatedIncludeSpecs: readonly string[] | undefined, validatedExcludeSpecs: readonly string[] | undefined; + let validatedIncludeSpecs: readonly string[] | undefined, + validatedExcludeSpecs: readonly string[] | undefined; // The exclude spec list is converted into a regular expression, which allows us to quickly // test whether a file or directory should be excluded before recursively traversing the // file system. if (includeSpecs) { - validatedIncludeSpecs = validateSpecs(includeSpecs, errors, /*disallowTrailingRecursion*/ true, sourceFile, "include"); + validatedIncludeSpecs = validateSpecs( + includeSpecs, + errors, + /*disallowTrailingRecursion*/ true, + sourceFile, + "include", + ); } if (excludeSpecs) { - validatedExcludeSpecs = validateSpecs(excludeSpecs, errors, /*disallowTrailingRecursion*/ false, sourceFile, "exclude"); + validatedExcludeSpecs = validateSpecs( + excludeSpecs, + errors, + /*disallowTrailingRecursion*/ false, + sourceFile, + "exclude", + ); } return { @@ -2844,7 +3267,13 @@ namespace ts { } function getFileNames(basePath: string): string[] { - const fileNames = getFileNamesFromConfigSpecs(configFileSpecs, basePath, options, host, extraFileExtensions); + const fileNames = getFileNamesFromConfigSpecs( + configFileSpecs, + basePath, + options, + host, + extraFileExtensions, + ); if (shouldReportNoInputFiles(fileNames, canJsonReportNoInputFiles(raw), resolutionStack)) { errors.push(getErrorForNoInputFiles(configFileSpecs, configFileName)); } @@ -2853,11 +3282,19 @@ namespace ts { function getProjectReferences(basePath: string): readonly ProjectReference[] | undefined { let projectReferences: ProjectReference[] | undefined; - const referencesOfRaw = getPropFromRaw("references", element => typeof element === "object", "object"); + const referencesOfRaw = getPropFromRaw( + "references", + element => typeof element === "object", + "object", + ); if (isArray(referencesOfRaw)) { for (const ref of referencesOfRaw) { if (typeof ref.path !== "string") { - createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string"); + createCompilerDiagnosticOnlyIfJson( + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + "reference.path", + "string", + ); } else { (projectReferences || (projectReferences = [])).push({ @@ -2881,17 +3318,31 @@ namespace ts { return getPropFromRaw(prop, isString, "string"); } - function getPropFromRaw(prop: "files" | "include" | "exclude" | "references", validateElement: (value: unknown) => boolean, elementTypeName: string): PropOfRaw { + function getPropFromRaw( + prop: "files" | "include" | "exclude" | "references", + validateElement: (value: unknown) => boolean, + elementTypeName: string, + ): PropOfRaw { if (hasProperty(raw, prop) && !isNullOrUndefined(raw[prop])) { if (isArray(raw[prop])) { const result = raw[prop] as T[]; if (!sourceFile && !every(result, validateElement)) { - errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, elementTypeName)); + errors.push( + createCompilerDiagnostic( + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + prop, + elementTypeName, + ), + ); } return result; } else { - createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, "Array"); + createCompilerDiagnosticOnlyIfJson( + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + prop, + "Array", + ); return "not-array"; } } @@ -2906,10 +3357,15 @@ namespace ts { } function isErrorNoInputFiles(error: Diagnostic) { - return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code; + return error.code + === Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code; } - function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) { + function getErrorForNoInputFiles( + { includeSpecs, excludeSpecs }: ConfigFileSpecs, + configFileName: string | undefined, + ) { return createCompilerDiagnostic( Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, configFileName || "tsconfig.json", @@ -2918,7 +3374,11 @@ namespace ts { ); } - function shouldReportNoInputFiles(fileNames: string[], canJsonReportNoInutFiles: boolean, resolutionStack?: Path[]) { + function shouldReportNoInputFiles( + fileNames: string[], + canJsonReportNoInutFiles: boolean, + resolutionStack?: Path[], + ) { return fileNames.length === 0 && canJsonReportNoInutFiles && (!resolutionStack || resolutionStack.length === 0); } @@ -2928,7 +3388,13 @@ namespace ts { } /*@internal*/ - export function updateErrorForNoInputFiles(fileNames: string[], configFileName: string, configFileSpecs: ConfigFileSpecs, configParseDiagnostics: Diagnostic[], canJsonReportNoInutFiles: boolean) { + export function updateErrorForNoInputFiles( + fileNames: string[], + configFileName: string, + configFileSpecs: ConfigFileSpecs, + configParseDiagnostics: Diagnostic[], + canJsonReportNoInutFiles: boolean, + ) { const existingErrors = configParseDiagnostics.length; if (shouldReportNoInputFiles(fileNames, canJsonReportNoInutFiles)) { configParseDiagnostics.push(getErrorForNoInputFiles(configFileSpecs, configFileName)); @@ -2972,13 +3438,18 @@ namespace ts { const resolvedPath = getNormalizedAbsolutePath(configFileName || "", basePath); if (resolutionStack.indexOf(resolvedPath) >= 0) { - errors.push(createCompilerDiagnostic(Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, [...resolutionStack, resolvedPath].join(" -> "))); + errors.push( + createCompilerDiagnostic( + Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, + [...resolutionStack, resolvedPath].join(" -> "), + ), + ); return { raw: json || convertToObject(sourceFile!, errors) }; } - const ownConfig = json ? - parseOwnConfigOfJson(json, host, basePath, configFileName, errors) : - parseOwnConfigOfJsonSourceFile(sourceFile!, host, basePath, configFileName, errors); + const ownConfig = json + ? parseOwnConfigOfJson(json, host, basePath, configFileName, errors) + : parseOwnConfigOfJsonSourceFile(sourceFile!, host, basePath, configFileName, errors); if (ownConfig.options?.paths) { // If we end up needing to resolve relative paths from 'paths' relative to @@ -2990,18 +3461,32 @@ namespace ts { if (ownConfig.extendedConfigPath) { // copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios. resolutionStack = resolutionStack.concat([resolvedPath]); - const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, resolutionStack, errors, extendedConfigCache); + const extendedConfig = getExtendedConfig( + sourceFile, + ownConfig.extendedConfigPath, + host, + resolutionStack, + errors, + extendedConfigCache, + ); if (extendedConfig && isSuccessfulParsedTsconfig(extendedConfig)) { const baseRaw = extendedConfig.raw; const raw = ownConfig.raw; let relativeDifference: string | undefined; const setPropertyInRawIfNotUndefined = (propertyName: string) => { if (!raw[propertyName] && baseRaw[propertyName]) { - raw[propertyName] = map(baseRaw[propertyName], (path: string) => - isRootedDiskPath(path) ? path : combinePaths( - relativeDifference ||= convertToRelativePath(getDirectoryPath(ownConfig.extendedConfigPath!), basePath, createGetCanonicalFileName(host.useCaseSensitiveFileNames)), - path, - )); + raw[propertyName] = map( + baseRaw[propertyName], + (path: string) => + isRootedDiskPath(path) ? path : combinePaths( + relativeDifference ||= convertToRelativePath( + getDirectoryPath(ownConfig.extendedConfigPath!), + basePath, + createGetCanonicalFileName(host.useCaseSensitiveFileNames), + ), + path, + ), + ); } }; setPropertyInRawIfNotUndefined("include"); @@ -3011,9 +3496,9 @@ namespace ts { raw.compileOnSave = baseRaw.compileOnSave; } ownConfig.options = assign({}, extendedConfig.options, ownConfig.options); - ownConfig.watchOptions = ownConfig.watchOptions && extendedConfig.watchOptions ? - assign({}, extendedConfig.watchOptions, ownConfig.watchOptions) : - ownConfig.watchOptions || extendedConfig.watchOptions; + ownConfig.watchOptions = ownConfig.watchOptions && extendedConfig.watchOptions + ? assign({}, extendedConfig.watchOptions, ownConfig.watchOptions) + : ownConfig.watchOptions || extendedConfig.watchOptions; // TODO extend type typeAcquisition } } @@ -3035,18 +3520,35 @@ namespace ts { const options = convertCompilerOptionsFromJsonWorker(json.compilerOptions, basePath, errors, configFileName); // typingOptions has been deprecated and is only supported for backward compatibility purposes. // It should be removed in future releases - use typeAcquisition instead. - const typeAcquisition = convertTypeAcquisitionFromJsonWorker(json.typeAcquisition || json.typingOptions, basePath, errors, configFileName); + const typeAcquisition = convertTypeAcquisitionFromJsonWorker( + json.typeAcquisition || json.typingOptions, + basePath, + errors, + configFileName, + ); const watchOptions = convertWatchOptionsFromJsonWorker(json.watchOptions, basePath, errors); json.compileOnSave = convertCompileOnSaveOptionFromJson(json, basePath, errors); let extendedConfigPath: string | undefined; if (json.extends) { if (!isString(json.extends)) { - errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "extends", "string")); + errors.push( + createCompilerDiagnostic( + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + "extends", + "string", + ), + ); } else { const newBase = configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath; - extendedConfigPath = getExtendsConfigPath(json.extends, host, newBase, errors, createCompilerDiagnostic); + extendedConfigPath = getExtendsConfigPath( + json.extends, + host, + newBase, + errors, + createCompilerDiagnostic, + ); } } return { raw: json, options, watchOptions, typeAcquisition, extendedConfigPath }; @@ -3066,7 +3568,11 @@ namespace ts { let rootCompilerOptions: PropertyName[] | undefined; const optionsIterator: JsonConversionNotifier = { - onSetValidOptionKeyValueInParent(parentOption: string, option: CommandLineOption, value: CompilerOptionsValue) { + onSetValidOptionKeyValueInParent( + parentOption: string, + option: CommandLineOption, + value: CompilerOptionsValue, + ) { let currentOption; switch (parentOption) { case "compilerOptions": @@ -3076,10 +3582,12 @@ namespace ts { currentOption = watchOptions || (watchOptions = {}); break; case "typeAcquisition": - currentOption = typeAcquisition || (typeAcquisition = getDefaultTypeAcquisition(configFileName)); + currentOption = typeAcquisition + || (typeAcquisition = getDefaultTypeAcquisition(configFileName)); break; case "typingOptions": - currentOption = typingOptionstypeAcquisition || (typingOptionstypeAcquisition = getDefaultTypeAcquisition(configFileName)); + currentOption = typingOptionstypeAcquisition + || (typingOptionstypeAcquisition = getDefaultTypeAcquisition(configFileName)); break; default: Debug.fail("Unknown option"); @@ -3087,7 +3595,12 @@ namespace ts { currentOption[option.name] = normalizeOptionValue(option, basePath, value); }, - onSetValidOptionKeyValueInRoot(key: string, _keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression) { + onSetValidOptionKeyValueInRoot( + key: string, + _keyNode: PropertyName, + value: CompilerOptionsValue, + valueNode: Expression, + ) { switch (key) { case "extends": const newBase = configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath; @@ -3096,14 +3609,26 @@ namespace ts { host, newBase, errors, - (message, arg0) => createDiagnosticForNodeInSourceFile(sourceFile, valueNode, message, arg0), + (message, arg0) => + createDiagnosticForNodeInSourceFile(sourceFile, valueNode, message, arg0), ); return; } }, - onSetUnknownOptionKeyValueInRoot(key: string, keyNode: PropertyName, _value: CompilerOptionsValue, _valueNode: Expression) { + onSetUnknownOptionKeyValueInRoot( + key: string, + keyNode: PropertyName, + _value: CompilerOptionsValue, + _valueNode: Expression, + ) { if (key === "excludes") { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, keyNode, Diagnostics.Unknown_option_excludes_Did_you_mean_exclude)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + keyNode, + Diagnostics.Unknown_option_excludes_Did_you_mean_exclude, + ), + ); } if (find(commandOptionsWithoutBuild, opt => opt.name === key)) { rootCompilerOptions = append(rootCompilerOptions, keyNode); @@ -3114,13 +3639,13 @@ namespace ts { if (!typeAcquisition) { if (typingOptionstypeAcquisition) { - typeAcquisition = (typingOptionstypeAcquisition.enableAutoDiscovery !== undefined) ? - { + typeAcquisition = (typingOptionstypeAcquisition.enableAutoDiscovery !== undefined) + ? { enable: typingOptionstypeAcquisition.enableAutoDiscovery, include: typingOptionstypeAcquisition.include, exclude: typingOptionstypeAcquisition.exclude, - } : - typingOptionstypeAcquisition; + } + : typingOptionstypeAcquisition; } else { typeAcquisition = getDefaultTypeAcquisition(configFileName); @@ -3128,7 +3653,14 @@ namespace ts { } if (rootCompilerOptions && json && json.compilerOptions === undefined) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, rootCompilerOptions[0], Diagnostics._0_should_be_set_inside_the_compilerOptions_object_of_the_config_json_file, getTextOfPropertyName(rootCompilerOptions[0]) as string)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + rootCompilerOptions[0], + Diagnostics._0_should_be_set_inside_the_compilerOptions_object_of_the_config_json_file, + getTextOfPropertyName(rootCompilerOptions[0]) as string, + ), + ); } return { raw: json, options, watchOptions, typeAcquisition, extendedConfigPath }; @@ -3154,7 +3686,15 @@ namespace ts { return extendedConfigPath; } // If the path isn't a rooted or relative path, resolve like a module - const resolved = nodeModuleNameResolver(extendedConfig, combinePaths(basePath, "tsconfig.json"), { moduleResolution: ModuleResolutionKind.NodeJs }, host, /*cache*/ undefined, /*projectRefs*/ undefined, /*lookupConfig*/ true); + const resolved = nodeModuleNameResolver( + extendedConfig, + combinePaths(basePath, "tsconfig.json"), + { moduleResolution: ModuleResolutionKind.NodeJs }, + host, + /*cache*/ undefined, + /*projectRefs*/ undefined, + /*lookupConfig*/ true, + ); if (resolved.resolvedModule) { return resolved.resolvedModule.resolvedFileName; } @@ -3185,7 +3725,16 @@ namespace ts { else { extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path)); if (!extendedResult.parseDiagnostics.length) { - extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, getDirectoryPath(extendedConfigPath), getBaseFileName(extendedConfigPath), resolutionStack, errors, extendedConfigCache); + extendedConfig = parseConfig( + /*json*/ undefined, + extendedResult, + host, + getDirectoryPath(extendedConfigPath), + getBaseFileName(extendedConfigPath), + resolutionStack, + errors, + extendedConfigCache, + ); } if (extendedConfigCache) { extendedConfigCache.set(path, { extendedResult, extendedConfig }); @@ -3212,13 +3761,21 @@ namespace ts { return typeof result === "boolean" && result; } - export function convertCompilerOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions; errors: Diagnostic[]; } { + export function convertCompilerOptionsFromJson( + jsonOptions: any, + basePath: string, + configFileName?: string, + ): { options: CompilerOptions; errors: Diagnostic[]; } { const errors: Diagnostic[] = []; const options = convertCompilerOptionsFromJsonWorker(jsonOptions, basePath, errors, configFileName); return { options, errors }; } - export function convertTypeAcquisitionFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: TypeAcquisition; errors: Diagnostic[]; } { + export function convertTypeAcquisitionFromJson( + jsonOptions: any, + basePath: string, + configFileName?: string, + ): { options: TypeAcquisition; errors: Diagnostic[]; } { const errors: Diagnostic[] = []; const options = convertTypeAcquisitionFromJsonWorker(jsonOptions, basePath, errors, configFileName); return { options, errors }; @@ -3226,14 +3783,32 @@ namespace ts { function getDefaultCompilerOptions(configFileName?: string) { const options: CompilerOptions = configFileName && getBaseFileName(configFileName) === "jsconfig.json" - ? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true, skipLibCheck: true, noEmit: true } + ? { + allowJs: true, + maxNodeModuleJsDepth: 2, + allowSyntheticDefaultImports: true, + skipLibCheck: true, + noEmit: true, + } : {}; return options; } - function convertCompilerOptionsFromJsonWorker(jsonOptions: any, basePath: string, errors: Push, configFileName?: string): CompilerOptions { + function convertCompilerOptionsFromJsonWorker( + jsonOptions: any, + basePath: string, + errors: Push, + configFileName?: string, + ): CompilerOptions { const options = getDefaultCompilerOptions(configFileName); - convertOptionsFromJson(getCommandLineCompilerOptionsMap(), jsonOptions, basePath, options, compilerOptionsDidYouMeanDiagnostics, errors); + convertOptionsFromJson( + getCommandLineCompilerOptionsMap(), + jsonOptions, + basePath, + options, + compilerOptionsDidYouMeanDiagnostics, + errors, + ); if (configFileName) { options.configFilePath = normalizeSlashes(configFileName); } @@ -3241,24 +3816,72 @@ namespace ts { } function getDefaultTypeAcquisition(configFileName?: string): TypeAcquisition { - return { enable: !!configFileName && getBaseFileName(configFileName) === "jsconfig.json", include: [], exclude: [] }; + return { + enable: !!configFileName && getBaseFileName(configFileName) === "jsconfig.json", + include: [], + exclude: [], + }; } - function convertTypeAcquisitionFromJsonWorker(jsonOptions: any, basePath: string, errors: Push, configFileName?: string): TypeAcquisition { + function convertTypeAcquisitionFromJsonWorker( + jsonOptions: any, + basePath: string, + errors: Push, + configFileName?: string, + ): TypeAcquisition { const options = getDefaultTypeAcquisition(configFileName); const typeAcquisition = convertEnableAutoDiscoveryToEnable(jsonOptions); - convertOptionsFromJson(getCommandLineTypeAcquisitionMap(), typeAcquisition, basePath, options, typeAcquisitionDidYouMeanDiagnostics, errors); + convertOptionsFromJson( + getCommandLineTypeAcquisitionMap(), + typeAcquisition, + basePath, + options, + typeAcquisitionDidYouMeanDiagnostics, + errors, + ); return options; } - function convertWatchOptionsFromJsonWorker(jsonOptions: any, basePath: string, errors: Push): WatchOptions | undefined { - return convertOptionsFromJson(getCommandLineWatchOptionsMap(), jsonOptions, basePath, /*defaultOptions*/ undefined, watchOptionsDidYouMeanDiagnostics, errors); + function convertWatchOptionsFromJsonWorker( + jsonOptions: any, + basePath: string, + errors: Push, + ): WatchOptions | undefined { + return convertOptionsFromJson( + getCommandLineWatchOptionsMap(), + jsonOptions, + basePath, + /*defaultOptions*/ undefined, + watchOptionsDidYouMeanDiagnostics, + errors, + ); } - function convertOptionsFromJson(optionsNameMap: ESMap, jsonOptions: any, basePath: string, defaultOptions: undefined, diagnostics: DidYouMeanOptionsDiagnostics, errors: Push): WatchOptions | undefined; - function convertOptionsFromJson(optionsNameMap: ESMap, jsonOptions: any, basePath: string, defaultOptions: CompilerOptions | TypeAcquisition, diagnostics: DidYouMeanOptionsDiagnostics, errors: Push): CompilerOptions | TypeAcquisition; - function convertOptionsFromJson(optionsNameMap: ESMap, jsonOptions: any, basePath: string, defaultOptions: CompilerOptions | TypeAcquisition | WatchOptions | undefined, diagnostics: DidYouMeanOptionsDiagnostics, errors: Push) { + function convertOptionsFromJson( + optionsNameMap: ESMap, + jsonOptions: any, + basePath: string, + defaultOptions: undefined, + diagnostics: DidYouMeanOptionsDiagnostics, + errors: Push, + ): WatchOptions | undefined; + function convertOptionsFromJson( + optionsNameMap: ESMap, + jsonOptions: any, + basePath: string, + defaultOptions: CompilerOptions | TypeAcquisition, + diagnostics: DidYouMeanOptionsDiagnostics, + errors: Push, + ): CompilerOptions | TypeAcquisition; + function convertOptionsFromJson( + optionsNameMap: ESMap, + jsonOptions: any, + basePath: string, + defaultOptions: CompilerOptions | TypeAcquisition | WatchOptions | undefined, + diagnostics: DidYouMeanOptionsDiagnostics, + errors: Push, + ) { if (!jsonOptions) { return; } @@ -3266,7 +3889,12 @@ namespace ts { for (const id in jsonOptions) { const opt = optionsNameMap.get(id); if (opt) { - (defaultOptions || (defaultOptions = {}))[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors); + (defaultOptions || (defaultOptions = {}))[opt.name] = convertJsonOption( + opt, + jsonOptions[id], + basePath, + errors, + ); } else { errors.push(createUnknownOptionError(id, diagnostics, createCompilerDiagnostic)); @@ -3276,7 +3904,12 @@ namespace ts { } /*@internal*/ - export function convertJsonOption(opt: CommandLineOption, value: any, basePath: string, errors: Push): CompilerOptionsValue { + export function convertJsonOption( + opt: CommandLineOption, + value: any, + basePath: string, + errors: Push, + ): CompilerOptionsValue { if (isCompilerOptionsValue(opt, value)) { const optType = opt.type; if (optType === "list" && isArray(value)) { @@ -3286,10 +3919,17 @@ namespace ts { return convertJsonOptionOfCustomType(opt as CommandLineOptionOfCustomType, value as string, errors); } const validatedValue = validateJsonOptionValue(opt, value, errors); - return isNullOrUndefined(validatedValue) ? validatedValue : normalizeNonListOptionValue(opt, basePath, validatedValue); + return isNullOrUndefined(validatedValue) ? validatedValue + : normalizeNonListOptionValue(opt, basePath, validatedValue); } else { - errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, opt.name, getCompilerOptionValueTypeString(opt))); + errors.push( + createCompilerDiagnostic( + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + opt.name, + getCompilerOptionValueTypeString(opt), + ), + ); } } @@ -3298,7 +3938,10 @@ namespace ts { if (option.type === "list") { const listOption = option; if (listOption.element.isFilePath || !isString(listOption.element.type)) { - return filter(map(value, v => normalizeOptionValue(listOption.element, basePath, v)), v => listOption.listPreserveFalsyValues ? true : !!v) as CompilerOptionsValue; + return filter( + map(value, v => normalizeOptionValue(listOption.element, basePath, v)), + v => listOption.listPreserveFalsyValues ? true : !!v, + ) as CompilerOptionsValue; } return value; } @@ -3308,7 +3951,11 @@ namespace ts { return normalizeNonListOptionValue(option, basePath, value); } - function normalizeNonListOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue { + function normalizeNonListOptionValue( + option: CommandLineOption, + basePath: string, + value: any, + ): CompilerOptionsValue { if (option.isFilePath) { value = getNormalizedAbsolutePath(value, basePath); if (value === "") { @@ -3318,7 +3965,11 @@ namespace ts { return value; } - function validateJsonOptionValue(opt: CommandLineOption, value: T, errors: Push): T | undefined { + function validateJsonOptionValue( + opt: CommandLineOption, + value: T, + errors: Push, + ): T | undefined { if (isNullOrUndefined(value)) return undefined; const d = opt.extraValidation?.(value); if (!d) return value; @@ -3326,7 +3977,11 @@ namespace ts { return undefined; } - function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Push) { + function convertJsonOptionOfCustomType( + opt: CommandLineOptionOfCustomType, + value: string, + errors: Push, + ) { if (isNullOrUndefined(value)) return undefined; const key = value.toLowerCase(); const val = opt.type.get(key); @@ -3338,8 +3993,16 @@ namespace ts { } } - function convertJsonOptionOfListType(option: CommandLineOptionOfListType, values: readonly any[], basePath: string, errors: Push): any[] { - return filter(map(values, v => convertJsonOption(option.element, v, basePath, errors)), v => option.listPreserveFalsyValues ? true : !!v); + function convertJsonOptionOfListType( + option: CommandLineOptionOfListType, + values: readonly any[], + basePath: string, + errors: Push, + ): any[] { + return filter( + map(values, v => convertJsonOption(option.element, v, basePath, errors)), + v => option.listPreserveFalsyValues ? true : !!v, + ); } /** @@ -3409,7 +4072,10 @@ namespace ts { // Rather than re-query this for each file and filespec, we query the supported extensions // once and store it on the expansion context. const supportedExtensions = getSupportedExtensions(options, extraFileExtensions); - const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions); + const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule( + options, + supportedExtensions, + ); // Literal files are always included verbatim. An "include" or "exclude" specification cannot // remove a literal file. @@ -3422,13 +4088,26 @@ namespace ts { let jsonOnlyIncludeRegexes: readonly RegExp[] | undefined; if (validatedIncludeSpecs && validatedIncludeSpecs.length > 0) { - for (const file of host.readDirectory(basePath, flatten(supportedExtensionsWithJsonIfResolveJsonModule), validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) { + for ( + const file of host.readDirectory( + basePath, + flatten(supportedExtensionsWithJsonIfResolveJsonModule), + validatedExcludeSpecs, + validatedIncludeSpecs, + /*depth*/ undefined, + ) + ) { if (fileExtensionIs(file, Extension.Json)) { // Valid only if *.json specified if (!jsonOnlyIncludeRegexes) { const includes = validatedIncludeSpecs.filter(s => endsWith(s, Extension.Json)); - const includeFilePatterns = map(getRegularExpressionsForWildcards(includes, basePath, "files"), pattern => `^${pattern}$`); - jsonOnlyIncludeRegexes = includeFilePatterns ? includeFilePatterns.map(pattern => getRegexFromPattern(pattern, host.useCaseSensitiveFileNames)) : emptyArray; + const includeFilePatterns = map( + getRegularExpressionsForWildcards(includes, basePath, "files"), + pattern => `^${pattern}$`, + ); + jsonOnlyIncludeRegexes = includeFilePatterns ? includeFilePatterns.map(pattern => + getRegexFromPattern(pattern, host.useCaseSensitiveFileNames) + ) : emptyArray; } const includeIndex = findIndex(jsonOnlyIncludeRegexes, re => re.test(file)); if (includeIndex !== -1) { @@ -3445,7 +4124,15 @@ namespace ts { // This handles cases where we may encounter both .ts and // .d.ts (or .js if "allowJs" is enabled) in the same // directory when they are compilation outputs. - if (hasFileWithHigherPriorityExtension(file, literalFileMap, wildcardFileMap, supportedExtensions, keyMapper)) { + if ( + hasFileWithHigherPriorityExtension( + file, + literalFileMap, + wildcardFileMap, + supportedExtensions, + keyMapper, + ) + ) { continue; } @@ -3488,7 +4175,13 @@ namespace ts { } } - return matchesExcludeWorker(pathToCheck, validatedExcludeSpecs, useCaseSensitiveFileNames, currentDirectory, basePath); + return matchesExcludeWorker( + pathToCheck, + validatedExcludeSpecs, + useCaseSensitiveFileNames, + currentDirectory, + basePath, + ); } function invalidDotDotAfterRecursiveWildcard(s: string) { @@ -3527,14 +4220,24 @@ namespace ts { currentDirectory: string, basePath?: string, ) { - const excludePattern = getRegularExpressionForWildcard(excludeSpecs, combinePaths(normalizePath(currentDirectory), basePath), "exclude"); + const excludePattern = getRegularExpressionForWildcard( + excludeSpecs, + combinePaths(normalizePath(currentDirectory), basePath), + "exclude", + ); const excludeRegex = excludePattern && getRegexFromPattern(excludePattern, useCaseSensitiveFileNames); if (!excludeRegex) return false; if (excludeRegex.test(pathToCheck)) return true; return !hasExtension(pathToCheck) && excludeRegex.test(ensureTrailingDirectorySeparator(pathToCheck)); } - function validateSpecs(specs: readonly string[], errors: Push, disallowTrailingRecursion: boolean, jsonSourceFile: TsConfigSourceFile | undefined, specKey: string): readonly string[] { + function validateSpecs( + specs: readonly string[], + errors: Push, + disallowTrailingRecursion: boolean, + jsonSourceFile: TsConfigSourceFile | undefined, + specKey: string, + ): readonly string[] { return specs.filter(spec => { if (!isString(spec)) return false; const diag = specToDiagnostic(spec, disallowTrailingRecursion); @@ -3546,25 +4249,39 @@ namespace ts { function createDiagnostic(message: DiagnosticMessage, spec: string): Diagnostic { const element = getTsConfigPropArrayElementValue(jsonSourceFile, specKey, spec); - return element ? - createDiagnosticForNodeInSourceFile(jsonSourceFile!, element, message, spec) : - createCompilerDiagnostic(message, spec); + return element + ? createDiagnosticForNodeInSourceFile(jsonSourceFile!, element, message, spec) + : createCompilerDiagnostic(message, spec); } } - function specToDiagnostic(spec: string, disallowTrailingRecursion?: boolean): [DiagnosticMessage, string] | undefined { + function specToDiagnostic( + spec: string, + disallowTrailingRecursion?: boolean, + ): [DiagnosticMessage, string] | undefined { if (disallowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) { - return [Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec]; + return [ + Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, + spec, + ]; } else if (invalidDotDotAfterRecursiveWildcard(spec)) { - return [Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec]; + return [ + Diagnostics + .File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, + spec, + ]; } } /** * Gets directories in a set of include patterns that should be watched for changes. */ - function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }: ConfigFileSpecs, path: string, useCaseSensitiveFileNames: boolean): MapLike { + function getWildcardDirectories( + { validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }: ConfigFileSpecs, + path: string, + useCaseSensitiveFileNames: boolean, + ): MapLike { // We watch a directory recursively if it contains a wildcard anywhere in a directory segment // of the pattern: // @@ -3616,7 +4333,10 @@ namespace ts { return wildcardDirectories; } - function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: boolean): { key: string; flags: WatchDirectoryFlags; } | undefined { + function getWildcardDirectoryFromSpec( + spec: string, + useCaseSensitiveFileNames: boolean, + ): { key: string; flags: WatchDirectoryFlags; } | undefined { const match = wildcardDirectoryPattern.exec(spec); if (match) { // We check this with a few `indexOf` calls because 3 `indexOf`/`lastIndexOf` calls is @@ -3648,7 +4368,13 @@ namespace ts { * * @param file The path to the file. */ - function hasFileWithHigherPriorityExtension(file: string, literalFiles: ESMap, wildcardFiles: ESMap, extensions: readonly string[][], keyMapper: (value: string) => string) { + function hasFileWithHigherPriorityExtension( + file: string, + literalFiles: ESMap, + wildcardFiles: ESMap, + extensions: readonly string[][], + keyMapper: (value: string) => string, + ) { const extensionGroup = forEach(extensions, group => fileExtensionIsOneOf(file, group) ? group : undefined); if (!extensionGroup) { return false; @@ -3659,7 +4385,10 @@ namespace ts { } const higherPriorityPath = keyMapper(changeExtension(file, ext)); if (literalFiles.has(higherPriorityPath) || wildcardFiles.has(higherPriorityPath)) { - if (ext === Extension.Dts && (fileExtensionIs(file, Extension.Js) || fileExtensionIs(file, Extension.Jsx))) { + if ( + ext === Extension.Dts + && (fileExtensionIs(file, Extension.Js) || fileExtensionIs(file, Extension.Jsx)) + ) { // LEGACY BEHAVIOR: An off-by-one bug somewhere in the extension priority system for wildcard module loading allowed declaration // files to be loaded alongside their js(x) counterparts. We regard this as generally undesirable, but retain the behavior to // prevent breakage. @@ -3678,7 +4407,12 @@ namespace ts { * * @param file The path to the file. */ - function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: ESMap, extensions: readonly string[][], keyMapper: (value: string) => string) { + function removeWildcardFilesWithLowerPriorityExtension( + file: string, + wildcardFiles: ESMap, + extensions: readonly string[][], + keyMapper: (value: string) => string, + ) { const extensionGroup = forEach(extensions, group => fileExtensionIsOneOf(file, group) ? group : undefined); if (!extensionGroup) { return; @@ -3741,7 +4475,8 @@ namespace ts { return true; case "string": const defaultValue = option.defaultValueDescription; - return option.isFilePath ? `./${defaultValue && typeof defaultValue === "string" ? defaultValue : ""}` : ""; + return option.isFilePath ? `./${defaultValue && typeof defaultValue === "string" ? defaultValue : ""}` + : ""; case "list": return []; case "object": diff --git a/src/compiler/core.ts b/src/compiler/core.ts index b183cc1e0febc..be75f2dd7d960 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1,17 +1,21 @@ /* @internal */ namespace ts { - export function getIterator | ReadonlyESMap | undefined>(iterable: I): Iterator< - I extends ReadonlyESMap ? [K, V] : - I extends ReadonlySet ? T : - I extends readonly (infer T)[] ? T : - I extends undefined ? undefined : - never + export function getIterator | ReadonlyESMap | undefined>( + iterable: I, + ): Iterator< + I extends ReadonlyESMap ? [K, V] + : I extends ReadonlySet ? T + : I extends readonly (infer T)[] ? T + : I extends undefined ? undefined + : never >; export function getIterator(iterable: ReadonlyESMap): Iterator<[K, V]>; export function getIterator(iterable: ReadonlyESMap | undefined): Iterator<[K, V]> | undefined; export function getIterator(iterable: readonly T[] | ReadonlySet): Iterator; export function getIterator(iterable: readonly T[] | ReadonlySet | undefined): Iterator | undefined; - export function getIterator(iterable: readonly any[] | ReadonlySet | ReadonlyESMap | undefined): Iterator | undefined { + export function getIterator( + iterable: readonly any[] | ReadonlySet | ReadonlyESMap | undefined, + ): Iterator | undefined { if (iterable) { if (isArray(iterable)) return arrayIterator(iterable); if (iterable instanceof Map) return iterable.entries(); @@ -33,7 +37,10 @@ namespace ts { * returns a truthy value, then returns that value. * If no such value is found, the callback is applied to each element of array and undefined is returned. */ - export function forEach(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { + export function forEach( + array: readonly T[] | undefined, + callback: (element: T, index: number) => U | undefined, + ): U | undefined { if (array) { for (let i = 0; i < array.length; i++) { const result = callback(array[i], i); @@ -48,7 +55,10 @@ namespace ts { /** * Like `forEach`, but iterates in reverse order. */ - export function forEachRight(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { + export function forEachRight( + array: readonly T[] | undefined, + callback: (element: T, index: number) => U | undefined, + ): U | undefined { if (array) { for (let i = array.length - 1; i >= 0; i--) { const result = callback(array[i], i); @@ -61,7 +71,10 @@ namespace ts { } /** Like `forEach`, but suitable for use with numbers and strings (which may be falsy). */ - export function firstDefined(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { + export function firstDefined( + array: readonly T[] | undefined, + callback: (element: T, index: number) => U | undefined, + ): U | undefined { if (array === undefined) { return undefined; } @@ -75,7 +88,10 @@ namespace ts { return undefined; } - export function firstDefinedIterator(iter: Iterator, callback: (element: T) => U | undefined): U | undefined { + export function firstDefinedIterator( + iter: Iterator, + callback: (element: T) => U | undefined, + ): U | undefined { while (true) { const iterResult = iter.next(); if (iterResult.done) { @@ -88,7 +104,11 @@ namespace ts { } } - export function reduceLeftIterator(iterator: Iterator | undefined, f: (memo: U, value: T, i: number) => U, initial: U): U { + export function reduceLeftIterator( + iterator: Iterator | undefined, + f: (memo: U, value: T, i: number) => U, + initial: U, + ): U { let result = initial; if (iterator) { for (let step = iterator.next(), pos = 0; !step.done; step = iterator.next(), pos++) { @@ -98,7 +118,11 @@ namespace ts { return result; } - export function zipWith(arrayA: readonly T[], arrayB: readonly U[], callback: (a: T, b: U, index: number) => V): V[] { + export function zipWith( + arrayA: readonly T[], + arrayB: readonly U[], + callback: (a: T, b: U, index: number) => V, + ): V[] { const result: V[] = []; Debug.assertEqual(arrayA.length, arrayB.length); for (let i = 0; i < arrayA.length; i++) { @@ -151,7 +175,10 @@ namespace ts { * returns a falsey value, then returns false. * If no such value is found, the callback is applied to each element of array and `true` is returned. */ - export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean { + export function every( + array: readonly T[] | undefined, + callback: (element: T, index: number) => boolean, + ): boolean { if (array) { for (let i = 0; i < array.length; i++) { if (!callback(array[i], i)) { @@ -164,9 +191,21 @@ namespace ts { } /** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */ - export function find(array: readonly T[] | undefined, predicate: (element: T, index: number) => element is U, startIndex?: number): U | undefined; - export function find(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined; - export function find(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined { + export function find( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => element is U, + startIndex?: number, + ): U | undefined; + export function find( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, + ): T | undefined; + export function find( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, + ): T | undefined { if (array === undefined) return undefined; for (let i = startIndex ?? 0; i < array.length; i++) { const value = array[i]; @@ -177,9 +216,21 @@ namespace ts { return undefined; } - export function findLast(array: readonly T[] | undefined, predicate: (element: T, index: number) => element is U, startIndex?: number): U | undefined; - export function findLast(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined; - export function findLast(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined { + export function findLast( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => element is U, + startIndex?: number, + ): U | undefined; + export function findLast( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, + ): T | undefined; + export function findLast( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, + ): T | undefined { if (array === undefined) return undefined; for (let i = startIndex ?? array.length - 1; i >= 0; i--) { const value = array[i]; @@ -191,7 +242,11 @@ namespace ts { } /** Works like Array.prototype.findIndex, returning `-1` if no element satisfying the predicate is found. */ - export function findIndex(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): number { + export function findIndex( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, + ): number { if (array === undefined) return -1; for (let i = startIndex ?? 0; i < array.length; i++) { if (predicate(array[i], i)) { @@ -201,7 +256,11 @@ namespace ts { return -1; } - export function findLastIndex(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): number { + export function findLastIndex( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, + ): number { if (array === undefined) return -1; for (let i = startIndex ?? array.length - 1; i >= 0; i--) { if (predicate(array[i], i)) { @@ -225,7 +284,11 @@ namespace ts { return Debug.fail(); } - export function contains(array: readonly T[] | undefined, value: T, equalityComparer: EqualityComparer = equateValues): boolean { + export function contains( + array: readonly T[] | undefined, + value: T, + equalityComparer: EqualityComparer = equateValues, + ): boolean { if (array) { for (const v of array) { if (equalityComparer(v, value)) { @@ -236,7 +299,11 @@ namespace ts { return false; } - export function arraysEqual(a: readonly T[], b: readonly T[], equalityComparer: EqualityComparer = equateValues): boolean { + export function arraysEqual( + a: readonly T[], + b: readonly T[], + equalityComparer: EqualityComparer = equateValues, + ): boolean { return a.length === b.length && a.every((x, i) => equalityComparer(x, b[i])); } @@ -272,8 +339,14 @@ namespace ts { export function filter(array: readonly T[], f: (x: T) => boolean): readonly T[]; export function filter(array: T[] | undefined, f: (x: T) => x is U): U[] | undefined; export function filter(array: T[] | undefined, f: (x: T) => boolean): T[] | undefined; - export function filter(array: readonly T[] | undefined, f: (x: T) => x is U): readonly U[] | undefined; - export function filter(array: readonly T[] | undefined, f: (x: T) => boolean): readonly T[] | undefined; + export function filter( + array: readonly T[] | undefined, + f: (x: T) => x is U, + ): readonly U[] | undefined; + export function filter( + array: readonly T[] | undefined, + f: (x: T) => boolean, + ): readonly T[] | undefined; export function filter(array: readonly T[] | undefined, f: (x: T) => boolean): readonly T[] | undefined { if (array) { const len = array.length; @@ -327,7 +400,8 @@ namespace ts { return { next() { const iterRes = iter.next(); - return iterRes.done ? iterRes as { done: true; value: never; } : { value: mapFn(iterRes.value), done: false }; + return iterRes.done ? iterRes as { done: true; value: never; } + : { value: mapFn(iterRes.value), done: false }; }, }; } @@ -381,7 +455,10 @@ namespace ts { * @param array The array to map. * @param mapfn The callback used to map the result into one or more values. */ - export function flatMap(array: readonly T[] | undefined, mapfn: (x: T, i: number) => U | readonly U[] | undefined): readonly U[] { + export function flatMap( + array: readonly T[] | undefined, + mapfn: (x: T, i: number) => U | readonly U[] | undefined, + ): readonly U[] { let result: U[] | undefined; if (array) { for (let i = 0; i < array.length; i++) { @@ -399,7 +476,10 @@ namespace ts { return result || emptyArray; } - export function flatMapToMutable(array: readonly T[] | undefined, mapfn: (x: T, i: number) => U | readonly U[] | undefined): U[] { + export function flatMapToMutable( + array: readonly T[] | undefined, + mapfn: (x: T, i: number) => U | readonly U[] | undefined, + ): U[] { const result: U[] = []; if (array) { for (let i = 0; i < array.length; i++) { @@ -417,7 +497,10 @@ namespace ts { return result; } - export function flatMapIterator(iter: Iterator, mapfn: (x: T) => readonly U[] | Iterator | undefined): Iterator { + export function flatMapIterator( + iter: Iterator, + mapfn: (x: T) => readonly U[] | Iterator | undefined, + ): Iterator { const first = iter.next(); if (first.done) { return emptyIterator; @@ -476,7 +559,10 @@ namespace ts { return result || array; } - export function mapAllOrFail(array: readonly T[], mapFn: (x: T, i: number) => U | undefined): U[] | undefined { + export function mapAllOrFail( + array: readonly T[], + mapFn: (x: T, i: number) => U | undefined, + ): U[] | undefined { const result: U[] = []; for (let i = 0; i < array.length; i++) { const mapped = mapFn(array[i], i); @@ -518,9 +604,18 @@ namespace ts { }; } - export function mapDefinedEntries(map: ReadonlyESMap, f: (key: K1, value: V1) => readonly [K2, V2] | undefined): ESMap; - export function mapDefinedEntries(map: ReadonlyESMap | undefined, f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined): ESMap | undefined; - export function mapDefinedEntries(map: ReadonlyESMap | undefined, f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined): ESMap | undefined { + export function mapDefinedEntries( + map: ReadonlyESMap, + f: (key: K1, value: V1) => readonly [K2, V2] | undefined, + ): ESMap; + export function mapDefinedEntries( + map: ReadonlyESMap | undefined, + f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined, + ): ESMap | undefined; + export function mapDefinedEntries( + map: ReadonlyESMap | undefined, + f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined, + ): ESMap | undefined { if (!map) { return undefined; } @@ -540,8 +635,14 @@ namespace ts { } export function mapDefinedValues(set: ReadonlySet, f: (value: V1) => V2 | undefined): Set; - export function mapDefinedValues(set: ReadonlySet | undefined, f: (value: V1) => V2 | undefined): Set | undefined; - export function mapDefinedValues(set: ReadonlySet | undefined, f: (value: V1) => V2 | undefined): Set | undefined { + export function mapDefinedValues( + set: ReadonlySet | undefined, + f: (value: V1) => V2 | undefined, + ): Set | undefined; + export function mapDefinedValues( + set: ReadonlySet | undefined, + f: (value: V1) => V2 | undefined, + ): Set | undefined { if (set) { const result = new Set(); set.forEach(value => { @@ -591,9 +692,21 @@ namespace ts { * @param keyfn A callback used to select the key for an element. * @param mapfn A callback used to map a contiguous chunk of values to a single value. */ - export function spanMap(array: readonly T[], keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[]; - export function spanMap(array: readonly T[] | undefined, keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] | undefined; - export function spanMap(array: readonly T[] | undefined, keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] | undefined { + export function spanMap( + array: readonly T[], + keyfn: (x: T, i: number) => K, + mapfn: (chunk: T[], key: K, start: number, end: number) => U, + ): U[]; + export function spanMap( + array: readonly T[] | undefined, + keyfn: (x: T, i: number) => K, + mapfn: (chunk: T[], key: K, start: number, end: number) => U, + ): U[] | undefined; + export function spanMap( + array: readonly T[] | undefined, + keyfn: (x: T, i: number) => K, + mapfn: (chunk: T[], key: K, start: number, end: number) => U, + ): U[] | undefined { let result: U[] | undefined; if (array) { result = []; @@ -633,9 +746,18 @@ namespace ts { return result; } - export function mapEntries(map: ReadonlyESMap, f: (key: K1, value: V1) => readonly [K2, V2]): ESMap; - export function mapEntries(map: ReadonlyESMap | undefined, f: (key: K1, value: V1) => readonly [K2, V2]): ESMap | undefined; - export function mapEntries(map: ReadonlyESMap | undefined, f: (key: K1, value: V1) => readonly [K2, V2]): ESMap | undefined { + export function mapEntries( + map: ReadonlyESMap, + f: (key: K1, value: V1) => readonly [K2, V2], + ): ESMap; + export function mapEntries( + map: ReadonlyESMap | undefined, + f: (key: K1, value: V1) => readonly [K2, V2], + ): ESMap | undefined; + export function mapEntries( + map: ReadonlyESMap | undefined, + f: (key: K1, value: V1) => readonly [K2, V2], + ): ESMap | undefined { if (!map) { return undefined; } @@ -667,7 +789,11 @@ namespace ts { } /** Calls the callback with (start, afterEnd) index pairs for each range where 'pred' is true. */ - export function getRangesWhere(arr: readonly T[], pred: (t: T) => boolean, cb: (start: number, afterEnd: number) => void): void { + export function getRangesWhere( + arr: readonly T[], + pred: (t: T) => boolean, + cb: (start: number, afterEnd: number) => void, + ): void { let start: number | undefined; for (let i = 0; i < arr.length; i++) { if (pred(arr[i])) { @@ -701,7 +827,11 @@ namespace ts { return array.map(selectIndex); } - function deduplicateRelational(array: readonly T[], equalityComparer: EqualityComparer, comparer: Comparer) { + function deduplicateRelational( + array: readonly T[], + equalityComparer: EqualityComparer, + comparer: Comparer, + ) { // Perform a stable sort of the array. This ensures the first entry in a list of // duplicates remains the first entry in the result. const indices = indicesOf(array); @@ -737,17 +867,24 @@ namespace ts { * @param comparer An optional `Comparer` used to sort entries before comparison, though the * result will remain in the original order in `array`. */ - export function deduplicate(array: readonly T[], equalityComparer: EqualityComparer, comparer?: Comparer): T[] { - return array.length === 0 ? [] : - array.length === 1 ? array.slice() : - comparer ? deduplicateRelational(array, equalityComparer, comparer) : - deduplicateEquality(array, equalityComparer); + export function deduplicate( + array: readonly T[], + equalityComparer: EqualityComparer, + comparer?: Comparer, + ): T[] { + return array.length === 0 ? [] + : array.length === 1 ? array.slice() + : comparer ? deduplicateRelational(array, equalityComparer, comparer) + : deduplicateEquality(array, equalityComparer); } /** * Deduplicates an array that has already been sorted. */ - function deduplicateSorted(array: SortedReadonlyArray, comparer: EqualityComparer | Comparer): SortedReadonlyArray { + function deduplicateSorted( + array: SortedReadonlyArray, + comparer: EqualityComparer | Comparer, + ): SortedReadonlyArray { if (array.length === 0) return emptyArray as any as SortedReadonlyArray; let last = array[0]; @@ -778,7 +915,12 @@ namespace ts { return [] as any as SortedArray; // TODO: GH#19873 } - export function insertSorted(array: SortedArray, insert: T, compare: Comparer, allowDuplicates?: boolean): boolean { + export function insertSorted( + array: SortedArray, + insert: T, + compare: Comparer, + allowDuplicates?: boolean, + ): boolean { if (array.length === 0) { array.push(insert); return true; @@ -799,9 +941,20 @@ namespace ts { } export function sortAndDeduplicate(array: readonly string[]): SortedReadonlyArray; - export function sortAndDeduplicate(array: readonly T[], comparer: Comparer, equalityComparer?: EqualityComparer): SortedReadonlyArray; - export function sortAndDeduplicate(array: readonly T[], comparer?: Comparer, equalityComparer?: EqualityComparer): SortedReadonlyArray { - return deduplicateSorted(sort(array, comparer), equalityComparer || comparer || compareStringsCaseSensitive as any as Comparer); + export function sortAndDeduplicate( + array: readonly T[], + comparer: Comparer, + equalityComparer?: EqualityComparer, + ): SortedReadonlyArray; + export function sortAndDeduplicate( + array: readonly T[], + comparer?: Comparer, + equalityComparer?: EqualityComparer, + ): SortedReadonlyArray { + return deduplicateSorted( + sort(array, comparer), + equalityComparer || comparer || compareStringsCaseSensitive as any as Comparer, + ); } export function arrayIsSorted(array: readonly T[], comparer: Comparer) { @@ -816,7 +969,11 @@ namespace ts { return true; } - export function arrayIsEqualTo(array1: readonly T[] | undefined, array2: readonly T[] | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean { + export function arrayIsEqualTo( + array1: readonly T[] | undefined, + array2: readonly T[] | undefined, + equalityComparer: (a: T, b: T, index: number) => boolean = equateValues, + ): boolean { if (!array1 || !array2) { return array1 === array2; } @@ -865,7 +1022,11 @@ namespace ts { * are not present in `arrayA` but are present in `arrayB`. Assumes both arrays are sorted * based on the provided comparer. */ - export function relativeComplement(arrayA: T[] | undefined, arrayB: T[] | undefined, comparer: Comparer): T[] | undefined { + export function relativeComplement( + arrayA: T[] | undefined, + arrayB: T[] | undefined, + comparer: Comparer, + ): T[] | undefined { if (!arrayB || !arrayA || arrayB.length === 0 || arrayA.length === 0) return arrayB; const result: T[] = []; loopB: @@ -921,7 +1082,10 @@ namespace ts { * @param value The value to append to the array. If `value` is `undefined`, nothing is * appended. */ - export function append[number] | undefined>(to: TArray, value: TValue): [undefined, undefined] extends [TArray, TValue] ? TArray : NonNullable[number][]; + export function append[number] | undefined>( + to: TArray, + value: TValue, + ): [undefined, undefined] extends [TArray, TValue] ? TArray : NonNullable[number][]; export function append(to: T[], value: T | undefined): T[]; export function append(to: T[] | undefined, value: T): T[]; export function append(to: T[] | undefined, value: T | undefined): T[] | undefined; @@ -945,7 +1109,10 @@ namespace ts { * T[] -> T[] -> T[] (concatenate) * ``` */ - export function combine(xs: T | readonly T[] | undefined, ys: T | readonly T[] | undefined): T | readonly T[] | undefined; + export function combine( + xs: T | readonly T[] | undefined, + ys: T | readonly T[] | undefined, + ): T | readonly T[] | undefined; export function combine(xs: T | T[] | undefined, ys: T | T[] | undefined): T | T[] | undefined; export function combine(xs: T | T[] | undefined, ys: T | T[] | undefined) { if (xs === undefined) return ys; @@ -974,8 +1141,18 @@ namespace ts { * @param end The offset in `from` at which to stop copying values (non-inclusive). */ export function addRange(to: T[], from: readonly T[] | undefined, start?: number, end?: number): T[]; - export function addRange(to: T[] | undefined, from: readonly T[] | undefined, start?: number, end?: number): T[] | undefined; - export function addRange(to: T[] | undefined, from: readonly T[] | undefined, start?: number, end?: number): T[] | undefined { + export function addRange( + to: T[] | undefined, + from: readonly T[] | undefined, + start?: number, + end?: number, + ): T[] | undefined; + export function addRange( + to: T[] | undefined, + from: readonly T[] | undefined, + start?: number, + end?: number, + ): T[] | undefined { if (from === undefined || from.length === 0) return to; if (to === undefined) return from.slice(start, end); start = start === undefined ? 0 : toOffset(from, start); @@ -1160,7 +1337,13 @@ namespace ts { * @param keyComparer A callback used to compare two keys in a sorted array. * @param offset An offset into `array` at which to start the search. */ - export function binarySearch(array: readonly T[], value: T, keySelector: (v: T) => U, keyComparer: Comparer, offset?: number): number { + export function binarySearch( + array: readonly T[], + value: T, + keySelector: (v: T) => U, + keyComparer: Comparer, + offset?: number, + ): number { return binarySearchKey(array, keySelector(value), keySelector, keyComparer, offset); } @@ -1174,7 +1357,13 @@ namespace ts { * @param keyComparer A callback used to compare two keys in a sorted array. * @param offset An offset into `array` at which to start the search. */ - export function binarySearchKey(array: readonly T[], key: U, keySelector: (v: T, i: number) => U, keyComparer: Comparer, offset?: number): number { + export function binarySearchKey( + array: readonly T[], + key: U, + keySelector: (v: T, i: number) => U, + keyComparer: Comparer, + offset?: number, + ): number { if (!some(array)) { return -1; } @@ -1199,9 +1388,21 @@ namespace ts { return ~low; } - export function reduceLeft(array: readonly T[] | undefined, f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U; + export function reduceLeft( + array: readonly T[] | undefined, + f: (memo: U, value: T, i: number) => U, + initial: U, + start?: number, + count?: number, + ): U; export function reduceLeft(array: readonly T[], f: (memo: T, value: T, i: number) => T): T | undefined; - export function reduceLeft(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T, start?: number, count?: number): T | undefined { + export function reduceLeft( + array: T[], + f: (memo: T, value: T, i: number) => T, + initial?: T, + start?: number, + count?: number, + ): T | undefined { if (array && array.length > 0) { const size = array.length; if (size > 0) { @@ -1334,7 +1535,11 @@ namespace ts { * @param left A map-like whose properties should be compared. * @param right A map-like whose properties should be compared. */ - export function equalOwnProperties(left: MapLike | undefined, right: MapLike | undefined, equalityComparer: EqualityComparer = equateValues) { + export function equalOwnProperties( + left: MapLike | undefined, + right: MapLike | undefined, + equalityComparer: EqualityComparer = equateValues, + ) { if (left === right) return true; if (!left || !right) return false; for (const key in left) { @@ -1364,10 +1569,22 @@ namespace ts { * index in the array will be the one associated with the produced key. */ export function arrayToMap(array: readonly V[], makeKey: (value: V) => K | undefined): ESMap; - export function arrayToMap(array: readonly V1[], makeKey: (value: V1) => K | undefined, makeValue: (value: V1) => V2): ESMap; + export function arrayToMap( + array: readonly V1[], + makeKey: (value: V1) => K | undefined, + makeValue: (value: V1) => V2, + ): ESMap; export function arrayToMap(array: readonly T[], makeKey: (value: T) => string | undefined): ESMap; - export function arrayToMap(array: readonly T[], makeKey: (value: T) => string | undefined, makeValue: (value: T) => U): ESMap; - export function arrayToMap(array: readonly V1[], makeKey: (value: V1) => K | undefined, makeValue: (value: V1) => V1 | V2 = identity): ESMap { + export function arrayToMap( + array: readonly T[], + makeKey: (value: T) => string | undefined, + makeValue: (value: T) => U, + ): ESMap; + export function arrayToMap( + array: readonly V1[], + makeKey: (value: V1) => K | undefined, + makeValue: (value: V1) => V1 | V2 = identity, + ): ESMap { const result = new Map(); for (const value of array) { const key = makeKey(value); @@ -1377,8 +1594,16 @@ namespace ts { } export function arrayToNumericMap(array: readonly T[], makeKey: (value: T) => number): T[]; - export function arrayToNumericMap(array: readonly T[], makeKey: (value: T) => number, makeValue: (value: T) => U): U[]; - export function arrayToNumericMap(array: readonly T[], makeKey: (value: T) => number, makeValue: (value: T) => T | U = identity): (T | U)[] { + export function arrayToNumericMap( + array: readonly T[], + makeKey: (value: T) => number, + makeValue: (value: T) => U, + ): U[]; + export function arrayToNumericMap( + array: readonly T[], + makeKey: (value: T) => number, + makeValue: (value: T) => T | U = identity, + ): (T | U)[] { const result: (T | U)[] = []; for (const value of array) { result[makeKey(value)] = makeValue(value); @@ -1387,8 +1612,16 @@ namespace ts { } export function arrayToMultiMap(values: readonly V[], makeKey: (value: V) => K): MultiMap; - export function arrayToMultiMap(values: readonly V[], makeKey: (value: V) => K, makeValue: (value: V) => U): MultiMap; - export function arrayToMultiMap(values: readonly V[], makeKey: (value: V) => K, makeValue: (value: V) => V | U = identity): MultiMap { + export function arrayToMultiMap( + values: readonly V[], + makeKey: (value: V) => K, + makeValue: (value: V) => U, + ): MultiMap; + export function arrayToMultiMap( + values: readonly V[], + makeKey: (value: V) => K, + makeValue: (value: V) => V | U = identity, + ): MultiMap { const result = createMultiMap(); for (const value of values) { result.add(makeKey(value), makeValue(value)); @@ -1397,10 +1630,22 @@ namespace ts { } export function group(values: readonly T[], getGroupId: (value: T) => K): readonly (readonly T[])[]; - export function group(values: readonly T[], getGroupId: (value: T) => K, resultSelector: (values: readonly T[]) => R): R[]; + export function group( + values: readonly T[], + getGroupId: (value: T) => K, + resultSelector: (values: readonly T[]) => R, + ): R[]; export function group(values: readonly T[], getGroupId: (value: T) => string): readonly (readonly T[])[]; - export function group(values: readonly T[], getGroupId: (value: T) => string, resultSelector: (values: readonly T[]) => R): R[]; - export function group(values: readonly T[], getGroupId: (value: T) => K, resultSelector: (values: readonly T[]) => readonly T[] = identity): readonly (readonly T[])[] { + export function group( + values: readonly T[], + getGroupId: (value: T) => string, + resultSelector: (values: readonly T[]) => R, + ): R[]; + export function group( + values: readonly T[], + getGroupId: (value: T) => K, + resultSelector: (values: readonly T[]) => readonly T[] = identity, + ): readonly (readonly T[])[] { return arrayFrom(arrayToMultiMap(values, getGroupId).values(), resultSelector); } @@ -1444,7 +1689,10 @@ namespace ts { } } - export function maybeBind(obj: T, fn: ((this: T, ...args: A) => R) | undefined): ((...args: A) => R) | undefined { + export function maybeBind( + obj: T, + fn: ((this: T, ...args: A) => R) | undefined, + ): ((...args: A) => R) | undefined { return fn ? fn.bind(obj) : undefined; } @@ -1559,7 +1807,10 @@ namespace ts { * To facilitate a perf optimization (lazy allocation of bucket arrays), `TElement` is * assumed not to be an array type. */ - export function createSet(getHashCode: (element: TElement) => THash, equals: EqualityComparer): Set { + export function createSet( + getHashCode: (element: TElement) => THash, + equals: EqualityComparer, + ): Set { const multiMap = new Map(); let size = 0; @@ -1725,16 +1976,24 @@ namespace ts { return typeof x === "number"; } - export function tryCast(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined; + export function tryCast( + value: TIn | undefined, + test: (value: TIn) => value is TOut, + ): TOut | undefined; export function tryCast(value: T, test: (value: T) => boolean): T | undefined; export function tryCast(value: T, test: (value: T) => boolean): T | undefined { return value !== undefined && test(value) ? value : undefined; } - export function cast(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut { + export function cast( + value: TIn | undefined, + test: (value: TIn) => value is TOut, + ): TOut { if (value !== undefined && test(value)) return value; - return Debug.fail(`Invalid cast. The supplied value ${value} did not pass the test '${Debug.getFunctionName(test)}'.`); + return Debug.fail( + `Invalid cast. The supplied value ${value} did not pass the test '${Debug.getFunctionName(test)}'.`, + ); } /** Does nothing. */ @@ -1805,9 +2064,9 @@ namespace ts { * So for this function purpose, we go ahead and assume character I with dot on top it as case sensitive since its very unlikely to use lower case form of that special character */ export function toFileNameLowerCase(x: string) { - return fileNameLowerCaseRegExp.test(x) ? - x.replace(fileNameLowerCaseRegExp, toLowerCase) : - x; + return fileNameLowerCaseRegExp.test(x) + ? x.replace(fileNameLowerCaseRegExp, toLowerCase) + : x; } /** Throws an error because a function is not implemented. */ @@ -1827,7 +2086,9 @@ namespace ts { } /** A version of `memoize` that supports a single primitive argument */ - export function memoizeOne(callback: (arg: A) => T): (arg: A) => T { + export function memoizeOne( + callback: (arg: A) => T, + ): (arg: A) => T { const map = new Map(); return (arg: A) => { const key = `${typeof arg}:${arg}`; @@ -1847,7 +2108,13 @@ namespace ts { * @param args The functions to compose. */ export function compose(...args: ((t: T) => T)[]): (t: T) => T; - export function compose(a: (t: T) => T, b: (t: T) => T, c: (t: T) => T, d: (t: T) => T, e: (t: T) => T): (t: T) => T { + export function compose( + a: (t: T) => T, + b: (t: T) => T, + c: (t: T) => T, + d: (t: T) => T, + e: (t: T) => T, + ): (t: T) => T { if (!!e) { const args: ((t: T) => T)[] = []; for (let i = 0; i < arguments.length; i++) { @@ -1919,11 +2186,11 @@ namespace ts { function compareComparableValues(a: string | undefined, b: string | undefined): Comparison; function compareComparableValues(a: number | undefined, b: number | undefined): Comparison; function compareComparableValues(a: string | number | undefined, b: string | number | undefined) { - return a === b ? Comparison.EqualTo : - a === undefined ? Comparison.LessThan : - b === undefined ? Comparison.GreaterThan : - a < b ? Comparison.LessThan : - Comparison.GreaterThan; + return a === b ? Comparison.EqualTo + : a === undefined ? Comparison.LessThan + : b === undefined ? Comparison.GreaterThan + : a < b ? Comparison.LessThan + : Comparison.GreaterThan; } /** @@ -1994,7 +2261,11 @@ namespace ts { const stringComparerFactory = getStringComparerFactory(); return createStringComparer; - function compareWithCallback(a: string | undefined, b: string | undefined, comparer: (a: string, b: string) => number) { + function compareWithCallback( + a: string | undefined, + b: string | undefined, + comparer: (a: string, b: string) => number, + ) { if (a === b) return Comparison.EqualTo; if (a === undefined) return Comparison.LessThan; if (b === undefined) return Comparison.GreaterThan; @@ -2048,9 +2319,9 @@ namespace ts { // If the host does not support Intl, we fall back to localeCompare. // localeCompare in Node v0.10 is just an ordinal comparison, so don't use it. if ( - typeof String.prototype.localeCompare === "function" && - typeof String.prototype.toLocaleUpperCase === "function" && - "a".localeCompare("B") < 0 + typeof String.prototype.localeCompare === "function" + && typeof String.prototype.toLocaleUpperCase === "function" + && "a".localeCompare("B") < 0 ) { return createLocaleCompareStringComparer; } @@ -2103,11 +2374,16 @@ namespace ts { return comparer(a, b); } - export function compareProperties(a: T | undefined, b: T | undefined, key: K, comparer: Comparer): Comparison { - return a === b ? Comparison.EqualTo : - a === undefined ? Comparison.LessThan : - b === undefined ? Comparison.GreaterThan : - comparer(a[key], b[key]); + export function compareProperties( + a: T | undefined, + b: T | undefined, + key: K, + comparer: Comparer, + ): Comparison { + return a === b ? Comparison.EqualTo + : a === undefined ? Comparison.LessThan + : b === undefined ? Comparison.GreaterThan + : comparer(a[key], b[key]); } /** True is greater than false. */ @@ -2127,13 +2403,19 @@ namespace ts { * (0.4 allows 1 substitution/transposition for every 5 characters, * and 1 insertion/deletion at 3 characters) */ - export function getSpellingSuggestion(name: string, candidates: T[], getName: (candidate: T) => string | undefined): T | undefined { + export function getSpellingSuggestion( + name: string, + candidates: T[], + getName: (candidate: T) => string | undefined, + ): T | undefined { const maximumLengthDifference = Math.max(2, Math.floor(name.length * 0.34)); let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result is worse than this, don't bother. let bestCandidate: T | undefined; for (const candidate of candidates) { const candidateName = getName(candidate); - if (candidateName !== undefined && Math.abs(candidateName.length - name.length) <= maximumLengthDifference) { + if ( + candidateName !== undefined && Math.abs(candidateName.length - name.length) <= maximumLengthDifference + ) { if (candidateName === name) { continue; } @@ -2183,7 +2465,11 @@ namespace ts { : (previous[j - 1] + 2); const dist = c1 === s2.charCodeAt(j - 1) ? previous[j - 1] - : Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ substitutionDistance); + : Math.min( + /*delete*/ previous[j] + 1, + /*insert*/ current[j - 1] + 1, + /*substitute*/ substitutionDistance, + ); current[j] = dist; colMin = Math.min(colMin, dist); } @@ -2340,7 +2626,11 @@ namespace ts { } /** Return the object corresponding to the best pattern to match `candidate`. */ - export function findBestPatternMatch(values: readonly T[], getPattern: (value: T) => Pattern, candidate: string): T | undefined { + export function findBestPatternMatch( + values: readonly T[], + getPattern: (value: T) => Pattern, + candidate: string, + ): T | undefined { let matchedValue: T | undefined; // use length of prefix as betterness criteria let longestMatchPrefixLength = -1; @@ -2364,22 +2654,34 @@ namespace ts { return startsWith(str, prefix) ? str.substr(prefix.length) : str; } - export function tryRemovePrefix(str: string, prefix: string, getCanonicalFileName: GetCanonicalFileName = identity): string | undefined { - return startsWith(getCanonicalFileName(str), getCanonicalFileName(prefix)) ? str.substring(prefix.length) : undefined; + export function tryRemovePrefix( + str: string, + prefix: string, + getCanonicalFileName: GetCanonicalFileName = identity, + ): string | undefined { + return startsWith(getCanonicalFileName(str), getCanonicalFileName(prefix)) ? str.substring(prefix.length) + : undefined; } export function isPatternMatch({ prefix, suffix }: Pattern, candidate: string) { - return candidate.length >= prefix.length + suffix.length && - startsWith(candidate, prefix) && - endsWith(candidate, suffix); + return candidate.length >= prefix.length + suffix.length + && startsWith(candidate, prefix) + && endsWith(candidate, suffix); } export function and(f: (arg: T) => boolean, g: (arg: T) => boolean) { return (arg: T) => f(arg) && g(arg); } - export function or(f1: (p1: P) => p1 is R1, f2: (p2: P) => p2 is R2): (p: P) => p is R1 | R2; - export function or(f1: (p1: P) => p1 is R1, f2: (p2: P) => p2 is R2, f3: (p3: P) => p3 is R3): (p: P) => p is R1 | R2 | R3; + export function or( + f1: (p1: P) => p1 is R1, + f2: (p2: P) => p2 is R2, + ): (p: P) => p is R1 | R2; + export function or( + f1: (p1: P) => p1 is R1, + f2: (p2: P) => p2 is R2, + f3: (p3: P) => p3 is R3, + ): (p: P) => p is R1 | R2 | R3; export function or(...fs: ((...args: T) => U)[]): (...args: T) => U; export function or(...fs: ((...args: T) => U)[]): (...args: T) => U { return (...args) => { @@ -2404,7 +2706,14 @@ namespace ts { return t === undefined ? undefined : [t]; } - export function enumerateInsertsAndDeletes(newItems: readonly T[], oldItems: readonly U[], comparer: (a: T, b: U) => Comparison, inserted: (newItem: T) => void, deleted: (oldItem: U) => void, unchanged?: (oldItem: U, newItem: T) => void) { + export function enumerateInsertsAndDeletes( + newItems: readonly T[], + oldItems: readonly U[], + comparer: (a: T, b: U) => Comparison, + inserted: (newItem: T) => void, + deleted: (oldItem: U) => void, + unchanged?: (oldItem: U, newItem: T) => void, + ) { unchanged = unchanged || noop; let newIndex = 0; let oldIndex = 0; @@ -2456,7 +2765,12 @@ namespace ts { return result; } - function cartesianProductWorker(arrays: readonly (readonly T[])[], result: (readonly T[])[], outer: readonly T[] | undefined, index: number) { + function cartesianProductWorker( + arrays: readonly (readonly T[])[], + result: (readonly T[])[], + outer: readonly T[] | undefined, + index: number, + ) { for (const element of arrays[index]) { let inner: T[]; if (outer) { @@ -2510,7 +2824,8 @@ namespace ts { /** * Removes the leading and trailing white space and line terminator characters from a string. */ - export const trimString = !!String.prototype.trim ? ((s: string) => s.trim()) : (s: string) => trimStringEnd(trimStringStart(s)); + export const trimString = !!String.prototype.trim ? ((s: string) => s.trim()) + : (s: string) => trimStringEnd(trimStringStart(s)); /** * Returns a copy with trailing whitespace removed. @@ -2520,7 +2835,8 @@ namespace ts { /** * Returns a copy with leading whitespace removed. */ - export const trimStringStart = !!String.prototype.trimStart ? ((s: string) => s.trimStart()) : (s: string) => s.replace(/^\s+/g, ""); + export const trimStringStart = !!String.prototype.trimStart ? ((s: string) => s.trimStart()) + : (s: string) => s.replace(/^\s+/g, ""); /** * https://jsbench.me/gjkoxld4au/1 diff --git a/src/compiler/corePublic.ts b/src/compiler/corePublic.ts index 78cf4ac8bd20d..17ec08729bdb5 100644 --- a/src/compiler/corePublic.ts +++ b/src/compiler/corePublic.ts @@ -116,10 +116,10 @@ namespace ts { namespace NativeCollections { declare const self: any; - const globals = typeof globalThis !== "undefined" ? globalThis : - typeof global !== "undefined" ? global : - typeof self !== "undefined" ? self : - undefined; + const globals = typeof globalThis !== "undefined" ? globalThis + : typeof global !== "undefined" ? global + : typeof self !== "undefined" ? self + : undefined; /** * Returns the native Map implementation if it is available and compatible (i.e. supports iteration). @@ -128,7 +128,9 @@ namespace ts { // Internet Explorer's Map doesn't support iteration, so don't use it. const gMap = globals?.Map; // eslint-disable-next-line local/no-in-operator - const constructor = typeof gMap !== "undefined" && "entries" in gMap.prototype && new gMap([[0, 0]]).size === 1 ? gMap : undefined; + const constructor = + typeof gMap !== "undefined" && "entries" in gMap.prototype && new gMap([[0, 0]]).size === 1 ? gMap + : undefined; if (!constructor) { throw new Error("No compatible Map implementation found."); } @@ -142,7 +144,8 @@ namespace ts { // Internet Explorer's Set doesn't support iteration, so don't use it. const gSet = globals?.Set; // eslint-disable-next-line local/no-in-operator - const constructor = typeof gSet !== "undefined" && "entries" in gSet.prototype && new gSet([0]).size === 1 ? gSet : undefined; + const constructor = typeof gSet !== "undefined" && "entries" in gSet.prototype && new gSet([0]).size === 1 + ? gSet : undefined; if (!constructor) { throw new Error("No compatible Set implementation found."); } diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index 045d523aa2e29..063d8f18bd122 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -127,11 +127,17 @@ namespace ts { ); } - export function assert(expression: unknown, message?: string, verboseDebugInfo?: string | (() => string), stackCrawlMark?: AnyFunction): asserts expression { + export function assert( + expression: unknown, + message?: string, + verboseDebugInfo?: string | (() => string), + stackCrawlMark?: AnyFunction, + ): asserts expression { if (!expression) { message = message ? `False expression: ${message}` : "False expression."; if (verboseDebugInfo) { - message += "\r\nVerbose Debug Information: " + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo()); + message += "\r\nVerbose Debug Information: " + + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo()); } fail(message, stackCrawlMark || assert); } @@ -162,42 +168,93 @@ namespace ts { } } - export function assertIsDefined(value: T, message?: string, stackCrawlMark?: AnyFunction): asserts value is NonNullable { + export function assertIsDefined( + value: T, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts value is NonNullable { // eslint-disable-next-line no-null/no-null if (value === undefined || value === null) { fail(message, stackCrawlMark || assertIsDefined); } } - export function checkDefined(value: T | null | undefined, message?: string, stackCrawlMark?: AnyFunction): T { + export function checkDefined( + value: T | null | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): T { assertIsDefined(value, message, stackCrawlMark || checkDefined); return value; } - export function assertEachIsDefined(value: NodeArray, message?: string, stackCrawlMark?: AnyFunction): asserts value is NodeArray; - export function assertEachIsDefined(value: readonly T[], message?: string, stackCrawlMark?: AnyFunction): asserts value is readonly NonNullable[]; + export function assertEachIsDefined( + value: NodeArray, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts value is NodeArray; + export function assertEachIsDefined( + value: readonly T[], + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts value is readonly NonNullable[]; export function assertEachIsDefined(value: readonly T[], message?: string, stackCrawlMark?: AnyFunction) { for (const v of value) { assertIsDefined(v, message, stackCrawlMark || assertEachIsDefined); } } - export function checkEachDefined(value: A, message?: string, stackCrawlMark?: AnyFunction): A { + export function checkEachDefined( + value: A, + message?: string, + stackCrawlMark?: AnyFunction, + ): A { assertEachIsDefined(value, message, stackCrawlMark || checkEachDefined); return value; } export function assertNever(member: never, message = "Illegal value:", stackCrawlMark?: AnyFunction): never { - const detail = typeof member === "object" && hasProperty(member, "kind") && hasProperty(member, "pos") ? "SyntaxKind: " + formatSyntaxKind((member as Node).kind) : JSON.stringify(member); + const detail = typeof member === "object" && hasProperty(member, "kind") && hasProperty(member, "pos") + ? "SyntaxKind: " + formatSyntaxKind((member as Node).kind) : JSON.stringify(member); return fail(`${message} ${detail}`, stackCrawlMark || assertNever); } - export function assertEachNode(nodes: NodeArray, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is NodeArray; - export function assertEachNode(nodes: readonly T[], test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is readonly U[]; - export function assertEachNode(nodes: NodeArray | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is NodeArray | undefined; - export function assertEachNode(nodes: readonly T[] | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is readonly U[] | undefined; - export function assertEachNode(nodes: readonly Node[], test: (node: Node) => boolean, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertEachNode(nodes: readonly Node[] | undefined, test: (node: Node) => boolean, message?: string, stackCrawlMark?: AnyFunction) { + export function assertEachNode( + nodes: NodeArray, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts nodes is NodeArray; + export function assertEachNode( + nodes: readonly T[], + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts nodes is readonly U[]; + export function assertEachNode( + nodes: NodeArray | undefined, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts nodes is NodeArray | undefined; + export function assertEachNode( + nodes: readonly T[] | undefined, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts nodes is readonly U[] | undefined; + export function assertEachNode( + nodes: readonly Node[], + test: (node: Node) => boolean, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertEachNode( + nodes: readonly Node[] | undefined, + test: (node: Node) => boolean, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertEachNode")) { assert( test === undefined || every(nodes, test), @@ -208,9 +265,24 @@ namespace ts { } } - export function assertNode(node: T | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U; - export function assertNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { + export function assertNode( + node: T | undefined, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is U; + export function assertNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertNode")) { assert( node !== undefined && (test === undefined || test(node)), @@ -221,23 +293,59 @@ namespace ts { } } - export function assertNotNode(node: T | undefined, test: (node: Node) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is Exclude; - export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { + export function assertNotNode( + node: T | undefined, + test: (node: Node) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is Exclude; + export function assertNotNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertNotNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertNotNode")) { assert( node === undefined || test === undefined || !test(node), message || "Unexpected node.", - () => `Node ${formatSyntaxKind(node!.kind)} should not have passed test '${getFunctionName(test!)}'.`, + () => + `Node ${formatSyntaxKind(node!.kind)} should not have passed test '${getFunctionName(test!)}'.`, stackCrawlMark || assertNotNode, ); } } - export function assertOptionalNode(node: T, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U; - export function assertOptionalNode(node: T | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U | undefined; - export function assertOptionalNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertOptionalNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { + export function assertOptionalNode( + node: T, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is U; + export function assertOptionalNode( + node: T | undefined, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is U | undefined; + export function assertOptionalNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertOptionalNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertOptionalNode")) { assert( test === undefined || node === undefined || test(node), @@ -248,10 +356,30 @@ namespace ts { } } - export function assertOptionalToken(node: T, kind: K, message?: string, stackCrawlMark?: AnyFunction): asserts node is Extract; - export function assertOptionalToken(node: T | undefined, kind: K, message?: string, stackCrawlMark?: AnyFunction): asserts node is Extract | undefined; - export function assertOptionalToken(node: Node | undefined, kind: SyntaxKind | undefined, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertOptionalToken(node: Node | undefined, kind: SyntaxKind | undefined, message?: string, stackCrawlMark?: AnyFunction) { + export function assertOptionalToken( + node: T, + kind: K, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is Extract; + export function assertOptionalToken( + node: T | undefined, + kind: K, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is Extract | undefined; + export function assertOptionalToken( + node: Node | undefined, + kind: SyntaxKind | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertOptionalToken( + node: Node | undefined, + kind: SyntaxKind | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertOptionalToken")) { assert( kind === undefined || node === undefined || node.kind === kind, @@ -262,7 +390,11 @@ namespace ts { } } - export function assertMissingNode(node: Node | undefined, message?: string, stackCrawlMark?: AnyFunction): asserts node is undefined; + export function assertMissingNode( + node: Node | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is undefined; export function assertMissingNode(node: Node | undefined, message?: string, stackCrawlMark?: AnyFunction) { if (shouldAssertFunction(AssertionLevel.Normal, "assertMissingNode")) { assert( @@ -297,7 +429,9 @@ namespace ts { } export function formatSymbol(symbol: Symbol): string { - return `{ name: ${unescapeLeadingUnderscores(symbol.escapedName)}; flags: ${formatSymbolFlags(symbol.flags)}; declarations: ${map(symbol.declarations, node => formatSyntaxKind(node.kind))} }`; + return `{ name: ${unescapeLeadingUnderscores(symbol.escapedName)}; flags: ${ + formatSymbolFlags(symbol.flags) + }; declarations: ${map(symbol.declarations, node => formatSyntaxKind(node.kind))} }`; } /** @@ -451,18 +585,18 @@ namespace ts { // for use with vscode-js-debug's new customDescriptionGenerator in launch.json __tsDebuggerDisplay: { value(this: FlowNodeBase) { - const flowHeader = this.flags & FlowFlags.Start ? "FlowStart" : - this.flags & FlowFlags.BranchLabel ? "FlowBranchLabel" : - this.flags & FlowFlags.LoopLabel ? "FlowLoopLabel" : - this.flags & FlowFlags.Assignment ? "FlowAssignment" : - this.flags & FlowFlags.TrueCondition ? "FlowTrueCondition" : - this.flags & FlowFlags.FalseCondition ? "FlowFalseCondition" : - this.flags & FlowFlags.SwitchClause ? "FlowSwitchClause" : - this.flags & FlowFlags.ArrayMutation ? "FlowArrayMutation" : - this.flags & FlowFlags.Call ? "FlowCall" : - this.flags & FlowFlags.ReduceLabel ? "FlowReduceLabel" : - this.flags & FlowFlags.Unreachable ? "FlowUnreachable" : - "UnknownFlow"; + const flowHeader = this.flags & FlowFlags.Start ? "FlowStart" + : this.flags & FlowFlags.BranchLabel ? "FlowBranchLabel" + : this.flags & FlowFlags.LoopLabel ? "FlowLoopLabel" + : this.flags & FlowFlags.Assignment ? "FlowAssignment" + : this.flags & FlowFlags.TrueCondition ? "FlowTrueCondition" + : this.flags & FlowFlags.FalseCondition ? "FlowFalseCondition" + : this.flags & FlowFlags.SwitchClause ? "FlowSwitchClause" + : this.flags & FlowFlags.ArrayMutation ? "FlowArrayMutation" + : this.flags & FlowFlags.Call ? "FlowCall" + : this.flags & FlowFlags.ReduceLabel ? "FlowReduceLabel" + : this.flags & FlowFlags.Unreachable ? "FlowUnreachable" + : "UnknownFlow"; const remainingFlags = this.flags & ~(FlowFlags.Referenced - 1); return `${flowHeader}${remainingFlags ? ` (${formatFlowFlags(remainingFlags)})` : ""}`; }, @@ -567,10 +701,12 @@ namespace ts { // for use with vscode-js-debug's new customDescriptionGenerator in launch.json __tsDebuggerDisplay: { value(this: Symbol) { - const symbolHeader = this.flags & SymbolFlags.Transient ? "TransientSymbol" : - "Symbol"; + const symbolHeader = this.flags & SymbolFlags.Transient ? "TransientSymbol" + : "Symbol"; const remainingSymbolFlags = this.flags & ~SymbolFlags.Transient; - return `${symbolHeader} '${symbolName(this)}'${remainingSymbolFlags ? ` (${formatSymbolFlags(remainingSymbolFlags)})` : ""}`; + return `${symbolHeader} '${symbolName(this)}'${ + remainingSymbolFlags ? ` (${formatSymbolFlags(remainingSymbolFlags)})` : "" + }`; }, }, __debugFlags: { @@ -584,31 +720,39 @@ namespace ts { // for use with vscode-js-debug's new customDescriptionGenerator in launch.json __tsDebuggerDisplay: { value(this: Type) { - const typeHeader = this.flags & TypeFlags.Nullable ? "NullableType" : - this.flags & TypeFlags.StringOrNumberLiteral ? `LiteralType ${JSON.stringify((this as LiteralType).value)}` : - this.flags & TypeFlags.BigIntLiteral ? `LiteralType ${(this as BigIntLiteralType).value.negative ? "-" : ""}${(this as BigIntLiteralType).value.base10Value}n` : - this.flags & TypeFlags.UniqueESSymbol ? "UniqueESSymbolType" : - this.flags & TypeFlags.Enum ? "EnumType" : - this.flags & TypeFlags.Intrinsic ? `IntrinsicType ${(this as IntrinsicType).intrinsicName}` : - this.flags & TypeFlags.Union ? "UnionType" : - this.flags & TypeFlags.Intersection ? "IntersectionType" : - this.flags & TypeFlags.Index ? "IndexType" : - this.flags & TypeFlags.IndexedAccess ? "IndexedAccessType" : - this.flags & TypeFlags.Conditional ? "ConditionalType" : - this.flags & TypeFlags.Substitution ? "SubstitutionType" : - this.flags & TypeFlags.TypeParameter ? "TypeParameter" : - this.flags & TypeFlags.Object ? - (this as ObjectType).objectFlags & ObjectFlags.ClassOrInterface ? "InterfaceType" : - (this as ObjectType).objectFlags & ObjectFlags.Reference ? "TypeReference" : - (this as ObjectType).objectFlags & ObjectFlags.Tuple ? "TupleType" : - (this as ObjectType).objectFlags & ObjectFlags.Anonymous ? "AnonymousType" : - (this as ObjectType).objectFlags & ObjectFlags.Mapped ? "MappedType" : - (this as ObjectType).objectFlags & ObjectFlags.ReverseMapped ? "ReverseMappedType" : - (this as ObjectType).objectFlags & ObjectFlags.EvolvingArray ? "EvolvingArrayType" : - "ObjectType" : - "Type"; - const remainingObjectFlags = this.flags & TypeFlags.Object ? (this as ObjectType).objectFlags & ~ObjectFlags.ObjectTypeKindMask : 0; - return `${typeHeader}${this.symbol ? ` '${symbolName(this.symbol)}'` : ""}${remainingObjectFlags ? ` (${formatObjectFlags(remainingObjectFlags)})` : ""}`; + const typeHeader = this.flags & TypeFlags.Nullable ? "NullableType" + : this.flags & TypeFlags.StringOrNumberLiteral + ? `LiteralType ${JSON.stringify((this as LiteralType).value)}` + : this.flags & TypeFlags.BigIntLiteral + ? `LiteralType ${(this as BigIntLiteralType).value.negative ? "-" : ""}${ + (this as BigIntLiteralType).value.base10Value + }n` + : this.flags & TypeFlags.UniqueESSymbol ? "UniqueESSymbolType" + : this.flags & TypeFlags.Enum ? "EnumType" + : this.flags & TypeFlags.Intrinsic + ? `IntrinsicType ${(this as IntrinsicType).intrinsicName}` + : this.flags & TypeFlags.Union ? "UnionType" + : this.flags & TypeFlags.Intersection ? "IntersectionType" + : this.flags & TypeFlags.Index ? "IndexType" + : this.flags & TypeFlags.IndexedAccess ? "IndexedAccessType" + : this.flags & TypeFlags.Conditional ? "ConditionalType" + : this.flags & TypeFlags.Substitution ? "SubstitutionType" + : this.flags & TypeFlags.TypeParameter ? "TypeParameter" + : this.flags & TypeFlags.Object + ? (this as ObjectType).objectFlags & ObjectFlags.ClassOrInterface ? "InterfaceType" + : (this as ObjectType).objectFlags & ObjectFlags.Reference ? "TypeReference" + : (this as ObjectType).objectFlags & ObjectFlags.Tuple ? "TupleType" + : (this as ObjectType).objectFlags & ObjectFlags.Anonymous ? "AnonymousType" + : (this as ObjectType).objectFlags & ObjectFlags.Mapped ? "MappedType" + : (this as ObjectType).objectFlags & ObjectFlags.ReverseMapped ? "ReverseMappedType" + : (this as ObjectType).objectFlags & ObjectFlags.EvolvingArray ? "EvolvingArrayType" + : "ObjectType" + : "Type"; + const remainingObjectFlags = this.flags & TypeFlags.Object + ? (this as ObjectType).objectFlags & ~ObjectFlags.ObjectTypeKindMask : 0; + return `${typeHeader}${this.symbol ? ` '${symbolName(this.symbol)}'` : ""}${ + remainingObjectFlags ? ` (${formatObjectFlags(remainingObjectFlags)})` : "" + }`; }, }, __debugFlags: { @@ -661,43 +805,46 @@ namespace ts { // for use with vscode-js-debug's new customDescriptionGenerator in launch.json __tsDebuggerDisplay: { value(this: Node) { - const nodeHeader = isGeneratedIdentifier(this) ? "GeneratedIdentifier" : - isIdentifier(this) ? `Identifier '${idText(this)}'` : - isPrivateIdentifier(this) ? `PrivateIdentifier '${idText(this)}'` : - isStringLiteral(this) ? `StringLiteral ${JSON.stringify(this.text.length < 10 ? this.text : this.text.slice(10) + "...")}` : - isNumericLiteral(this) ? `NumericLiteral ${this.text}` : - isBigIntLiteral(this) ? `BigIntLiteral ${this.text}n` : - isTypeParameterDeclaration(this) ? "TypeParameterDeclaration" : - isParameter(this) ? "ParameterDeclaration" : - isConstructorDeclaration(this) ? "ConstructorDeclaration" : - isGetAccessorDeclaration(this) ? "GetAccessorDeclaration" : - isSetAccessorDeclaration(this) ? "SetAccessorDeclaration" : - isCallSignatureDeclaration(this) ? "CallSignatureDeclaration" : - isConstructSignatureDeclaration(this) ? "ConstructSignatureDeclaration" : - isIndexSignatureDeclaration(this) ? "IndexSignatureDeclaration" : - isTypePredicateNode(this) ? "TypePredicateNode" : - isTypeReferenceNode(this) ? "TypeReferenceNode" : - isFunctionTypeNode(this) ? "FunctionTypeNode" : - isConstructorTypeNode(this) ? "ConstructorTypeNode" : - isTypeQueryNode(this) ? "TypeQueryNode" : - isTypeLiteralNode(this) ? "TypeLiteralNode" : - isArrayTypeNode(this) ? "ArrayTypeNode" : - isTupleTypeNode(this) ? "TupleTypeNode" : - isOptionalTypeNode(this) ? "OptionalTypeNode" : - isRestTypeNode(this) ? "RestTypeNode" : - isUnionTypeNode(this) ? "UnionTypeNode" : - isIntersectionTypeNode(this) ? "IntersectionTypeNode" : - isConditionalTypeNode(this) ? "ConditionalTypeNode" : - isInferTypeNode(this) ? "InferTypeNode" : - isParenthesizedTypeNode(this) ? "ParenthesizedTypeNode" : - isThisTypeNode(this) ? "ThisTypeNode" : - isTypeOperatorNode(this) ? "TypeOperatorNode" : - isIndexedAccessTypeNode(this) ? "IndexedAccessTypeNode" : - isMappedTypeNode(this) ? "MappedTypeNode" : - isLiteralTypeNode(this) ? "LiteralTypeNode" : - isNamedTupleMember(this) ? "NamedTupleMember" : - isImportTypeNode(this) ? "ImportTypeNode" : - formatSyntaxKind(this.kind); + const nodeHeader = isGeneratedIdentifier(this) ? "GeneratedIdentifier" + : isIdentifier(this) ? `Identifier '${idText(this)}'` + : isPrivateIdentifier(this) ? `PrivateIdentifier '${idText(this)}'` + : isStringLiteral(this) + ? `StringLiteral ${ + JSON.stringify(this.text.length < 10 ? this.text : this.text.slice(10) + "...") + }` + : isNumericLiteral(this) ? `NumericLiteral ${this.text}` + : isBigIntLiteral(this) ? `BigIntLiteral ${this.text}n` + : isTypeParameterDeclaration(this) ? "TypeParameterDeclaration" + : isParameter(this) ? "ParameterDeclaration" + : isConstructorDeclaration(this) ? "ConstructorDeclaration" + : isGetAccessorDeclaration(this) ? "GetAccessorDeclaration" + : isSetAccessorDeclaration(this) ? "SetAccessorDeclaration" + : isCallSignatureDeclaration(this) ? "CallSignatureDeclaration" + : isConstructSignatureDeclaration(this) ? "ConstructSignatureDeclaration" + : isIndexSignatureDeclaration(this) ? "IndexSignatureDeclaration" + : isTypePredicateNode(this) ? "TypePredicateNode" + : isTypeReferenceNode(this) ? "TypeReferenceNode" + : isFunctionTypeNode(this) ? "FunctionTypeNode" + : isConstructorTypeNode(this) ? "ConstructorTypeNode" + : isTypeQueryNode(this) ? "TypeQueryNode" + : isTypeLiteralNode(this) ? "TypeLiteralNode" + : isArrayTypeNode(this) ? "ArrayTypeNode" + : isTupleTypeNode(this) ? "TupleTypeNode" + : isOptionalTypeNode(this) ? "OptionalTypeNode" + : isRestTypeNode(this) ? "RestTypeNode" + : isUnionTypeNode(this) ? "UnionTypeNode" + : isIntersectionTypeNode(this) ? "IntersectionTypeNode" + : isConditionalTypeNode(this) ? "ConditionalTypeNode" + : isInferTypeNode(this) ? "InferTypeNode" + : isParenthesizedTypeNode(this) ? "ParenthesizedTypeNode" + : isThisTypeNode(this) ? "ThisTypeNode" + : isTypeOperatorNode(this) ? "TypeOperatorNode" + : isIndexedAccessTypeNode(this) ? "IndexedAccessTypeNode" + : isMappedTypeNode(this) ? "MappedTypeNode" + : isLiteralTypeNode(this) ? "LiteralTypeNode" + : isNamedTupleMember(this) ? "NamedTupleMember" + : isImportTypeNode(this) ? "ImportTypeNode" + : formatSyntaxKind(this.kind); return `${nodeHeader}${this.flags ? ` (${formatNodeFlags(this.flags)})` : ""}`; }, }, @@ -740,7 +887,8 @@ namespace ts { if (text === undefined) { const parseNode = getParseTreeNode(this); const sourceFile = parseNode && getSourceFileOfNode(parseNode); - text = sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : ""; + text = sourceFile + ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : ""; map?.set(this, text); } return text; @@ -768,23 +916,40 @@ namespace ts { isDebugInfoEnabled = true; } - function formatDeprecationMessage(name: string, error: boolean | undefined, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) { + function formatDeprecationMessage( + name: string, + error: boolean | undefined, + errorAfter: Version | undefined, + since: Version | undefined, + message: string | undefined, + ) { let deprecationMessage = error ? "DeprecationError: " : "DeprecationWarning: "; deprecationMessage += `'${name}' `; deprecationMessage += since ? `has been deprecated since v${since}` : "is deprecated"; - deprecationMessage += error ? " and can no longer be used." : errorAfter ? ` and will no longer be usable after v${errorAfter}.` : "."; + deprecationMessage += error ? " and can no longer be used." + : errorAfter ? ` and will no longer be usable after v${errorAfter}.` : "."; deprecationMessage += message ? ` ${formatStringFromArgs(message, [name], 0)}` : ""; return deprecationMessage; } - function createErrorDeprecation(name: string, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) { + function createErrorDeprecation( + name: string, + errorAfter: Version | undefined, + since: Version | undefined, + message: string | undefined, + ) { const deprecationMessage = formatDeprecationMessage(name, /*error*/ true, errorAfter, since, message); return () => { throw new TypeError(deprecationMessage); }; } - function createWarningDeprecation(name: string, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) { + function createWarningDeprecation( + name: string, + errorAfter: Version | undefined, + since: Version | undefined, + message: string | undefined, + ) { let hasWrittenDeprecation = false; return () => { if (enableDeprecationWarnings && !hasWrittenDeprecation) { @@ -797,15 +962,18 @@ namespace ts { export function createDeprecation(name: string, options: DeprecationOptions & { error: true; }): () => never; export function createDeprecation(name: string, options?: DeprecationOptions): () => void; export function createDeprecation(name: string, options: DeprecationOptions = {}) { - const version = typeof options.typeScriptVersion === "string" ? new Version(options.typeScriptVersion) : options.typeScriptVersion ?? getTypeScriptVersion(); - const errorAfter = typeof options.errorAfter === "string" ? new Version(options.errorAfter) : options.errorAfter; - const warnAfter = typeof options.warnAfter === "string" ? new Version(options.warnAfter) : options.warnAfter; + const version = typeof options.typeScriptVersion === "string" ? new Version(options.typeScriptVersion) + : options.typeScriptVersion ?? getTypeScriptVersion(); + const errorAfter = typeof options.errorAfter === "string" ? new Version(options.errorAfter) + : options.errorAfter; + const warnAfter = typeof options.warnAfter === "string" ? new Version(options.warnAfter) + : options.warnAfter; const since = typeof options.since === "string" ? new Version(options.since) : options.since ?? warnAfter; const error = options.error || errorAfter && version.compareTo(errorAfter) <= 0; const warn = !warnAfter || version.compareTo(warnAfter) >= 0; - return error ? createErrorDeprecation(name, errorAfter, since, options.message) : - warn ? createWarningDeprecation(name, errorAfter, since, options.message) : - noop; + return error ? createErrorDeprecation(name, errorAfter, since, options.message) + : warn ? createWarningDeprecation(name, errorAfter, since, options.message) + : noop; } function wrapFunction any>(deprecation: () => void, func: F): F { @@ -822,11 +990,11 @@ namespace ts { export function formatVariance(varianceFlags: VarianceFlags) { const variance = varianceFlags & VarianceFlags.VarianceMask; - let result = variance === VarianceFlags.Invariant ? "in out" : - variance === VarianceFlags.Bivariant ? "[bivariant]" : - variance === VarianceFlags.Contravariant ? "in" : - variance === VarianceFlags.Covariant ? "out" : - variance === VarianceFlags.Independent ? "[independent]" : ""; + let result = variance === VarianceFlags.Invariant ? "in out" + : variance === VarianceFlags.Bivariant ? "[bivariant]" + : variance === VarianceFlags.Contravariant ? "in" + : variance === VarianceFlags.Covariant ? "out" + : variance === VarianceFlags.Independent ? "[independent]" : ""; if (varianceFlags & VarianceFlags.Unmeasurable) { result += " (unmeasurable)"; } @@ -845,22 +1013,30 @@ namespace ts { case TypeMapKind.Function: return this.debugInfo?.() || "(function mapper)"; case TypeMapKind.Simple: - return `${(this.source as DebugType).__debugTypeToString()} -> ${(this.target as DebugType).__debugTypeToString()}`; + return `${(this.source as DebugType).__debugTypeToString()} -> ${ + (this.target as DebugType).__debugTypeToString() + }`; case TypeMapKind.Array: return zipWith( this.sources as readonly DebugType[], this.targets as readonly DebugType[] || map(this.sources, () => "any"), - (s, t) => `${s.__debugTypeToString()} -> ${typeof t === "string" ? t : t.__debugTypeToString()}`, + (s, t) => + `${s.__debugTypeToString()} -> ${typeof t === "string" ? t : t.__debugTypeToString()}`, ).join(", "); case TypeMapKind.Deferred: return zipWith( this.sources, this.targets, - (s, t) => `${(s as DebugType).__debugTypeToString()} -> ${(t() as DebugType).__debugTypeToString()}`, + (s, t) => + `${(s as DebugType).__debugTypeToString()} -> ${ + (t() as DebugType).__debugTypeToString() + }`, ).join(", "); case TypeMapKind.Merged: case TypeMapKind.Composite: - return `m1: ${(this.mapper1 as unknown as DebugTypeMapper).__debugToString().split("\n").join("\n ")} + return `m1: ${ + (this.mapper1 as unknown as DebugTypeMapper).__debugToString().split("\n").join("\n ") + } m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n").join("\n ")}`; default: return assertNever(this); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 118e684b840a3..6363755bb75c2 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -24,7 +24,8 @@ namespace ts { onlyBuildInfo?: boolean, includeBuildInfo?: boolean, ) { - const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile, forceDtsEmit); + const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile + : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile, forceDtsEmit); const options = host.getCompilerOptions(); if (outFile(options)) { const prepends = host.getPrependNodes(); @@ -64,11 +65,14 @@ namespace ts { else { if (!configFile) return undefined; const configFileExtensionLess = removeFileExtension(configFile); - buildInfoExtensionLess = options.outDir ? - options.rootDir ? - resolvePath(options.outDir, getRelativePathFromDirectory(options.rootDir, configFileExtensionLess, /*ignoreCase*/ true)) : - combinePaths(options.outDir, getBaseFileName(configFileExtensionLess)) : - configFileExtensionLess; + buildInfoExtensionLess = options.outDir + ? options.rootDir + ? resolvePath( + options.outDir, + getRelativePathFromDirectory(options.rootDir, configFileExtensionLess, /*ignoreCase*/ true), + ) + : combinePaths(options.outDir, getBaseFileName(configFileExtensionLess)) + : configFileExtensionLess; } return buildInfoExtensionLess + Extension.TsBuildInfo; } @@ -78,28 +82,47 @@ namespace ts { const outPath = outFile(options)!; const jsFilePath = options.emitDeclarationOnly ? undefined : outPath; const sourceMapFilePath = jsFilePath && getSourceMapFilePath(jsFilePath, options); - const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(outPath) + Extension.Dts : undefined; - const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined; + const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) + ? removeFileExtension(outPath) + Extension.Dts : undefined; + const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) + ? declarationFilePath + ".map" : undefined; const buildInfoPath = getTsBuildInfoEmitOutputFilePath(options); return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }; } /*@internal*/ - export function getOutputPathsFor(sourceFile: SourceFile | Bundle, host: EmitHost, forceDtsPaths: boolean): EmitFileNames { + export function getOutputPathsFor( + sourceFile: SourceFile | Bundle, + host: EmitHost, + forceDtsPaths: boolean, + ): EmitFileNames { const options = host.getCompilerOptions(); if (sourceFile.kind === SyntaxKind.Bundle) { return getOutputPathsForBundle(options, forceDtsPaths); } else { - const ownOutputFilePath = getOwnEmitOutputFilePath(sourceFile.fileName, host, getOutputExtension(sourceFile.fileName, options)); + const ownOutputFilePath = getOwnEmitOutputFilePath( + sourceFile.fileName, + host, + getOutputExtension(sourceFile.fileName, options), + ); const isJsonFile = isJsonSourceFile(sourceFile); // If json file emits to the same location skip writing it, if emitDeclarationOnly skip writing it - const isJsonEmittedToSameLocation = isJsonFile && - comparePaths(sourceFile.fileName, ownOutputFilePath, host.getCurrentDirectory(), !host.useCaseSensitiveFileNames()) === Comparison.EqualTo; - const jsFilePath = options.emitDeclarationOnly || isJsonEmittedToSameLocation ? undefined : ownOutputFilePath; - const sourceMapFilePath = !jsFilePath || isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options); - const declarationFilePath = (forceDtsPaths || (getEmitDeclarations(options) && !isJsonFile)) ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined; - const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined; + const isJsonEmittedToSameLocation = isJsonFile + && comparePaths( + sourceFile.fileName, + ownOutputFilePath, + host.getCurrentDirectory(), + !host.useCaseSensitiveFileNames(), + ) === Comparison.EqualTo; + const jsFilePath = options.emitDeclarationOnly || isJsonEmittedToSameLocation ? undefined + : ownOutputFilePath; + const sourceMapFilePath = !jsFilePath || isJsonSourceFile(sourceFile) ? undefined + : getSourceMapFilePath(jsFilePath, options); + const declarationFilePath = (forceDtsPaths || (getEmitDeclarations(options) && !isJsonFile)) + ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined; + const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) + ? declarationFilePath + ".map" : undefined; return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath: undefined }; } } @@ -110,40 +133,80 @@ namespace ts { /* @internal */ export function getOutputExtension(fileName: string, options: CompilerOptions): Extension { - return fileExtensionIs(fileName, Extension.Json) ? Extension.Json : - options.jsx === JsxEmit.Preserve && fileExtensionIsOneOf(fileName, [Extension.Jsx, Extension.Tsx]) ? Extension.Jsx : - fileExtensionIsOneOf(fileName, [Extension.Mts, Extension.Mjs]) ? Extension.Mjs : - fileExtensionIsOneOf(fileName, [Extension.Cts, Extension.Cjs]) ? Extension.Cjs : - Extension.Js; + return fileExtensionIs(fileName, Extension.Json) ? Extension.Json + : options.jsx === JsxEmit.Preserve && fileExtensionIsOneOf(fileName, [Extension.Jsx, Extension.Tsx]) + ? Extension.Jsx + : fileExtensionIsOneOf(fileName, [Extension.Mts, Extension.Mjs]) ? Extension.Mjs + : fileExtensionIsOneOf(fileName, [Extension.Cts, Extension.Cjs]) ? Extension.Cjs + : Extension.Js; } - function getOutputPathWithoutChangingExt(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, outputDir: string | undefined, getCommonSourceDirectory?: () => string) { - return outputDir ? - resolvePath( + function getOutputPathWithoutChangingExt( + inputFileName: string, + configFile: ParsedCommandLine, + ignoreCase: boolean, + outputDir: string | undefined, + getCommonSourceDirectory?: () => string, + ) { + return outputDir + ? resolvePath( outputDir, - getRelativePathFromDirectory(getCommonSourceDirectory ? getCommonSourceDirectory() : getCommonSourceDirectoryOfConfig(configFile, ignoreCase), inputFileName, ignoreCase), - ) : - inputFileName; + getRelativePathFromDirectory( + getCommonSourceDirectory ? getCommonSourceDirectory() + : getCommonSourceDirectoryOfConfig(configFile, ignoreCase), + inputFileName, + ignoreCase, + ), + ) + : inputFileName; } /* @internal */ - export function getOutputDeclarationFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory?: () => string) { + export function getOutputDeclarationFileName( + inputFileName: string, + configFile: ParsedCommandLine, + ignoreCase: boolean, + getCommonSourceDirectory?: () => string, + ) { return changeExtension( - getOutputPathWithoutChangingExt(inputFileName, configFile, ignoreCase, configFile.options.declarationDir || configFile.options.outDir, getCommonSourceDirectory), + getOutputPathWithoutChangingExt( + inputFileName, + configFile, + ignoreCase, + configFile.options.declarationDir || configFile.options.outDir, + getCommonSourceDirectory, + ), getDeclarationEmitExtensionForPath(inputFileName), ); } - function getOutputJSFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory?: () => string) { + function getOutputJSFileName( + inputFileName: string, + configFile: ParsedCommandLine, + ignoreCase: boolean, + getCommonSourceDirectory?: () => string, + ) { if (configFile.options.emitDeclarationOnly) return undefined; const isJsonFile = fileExtensionIs(inputFileName, Extension.Json); const outputFileName = changeExtension( - getOutputPathWithoutChangingExt(inputFileName, configFile, ignoreCase, configFile.options.outDir, getCommonSourceDirectory), + getOutputPathWithoutChangingExt( + inputFileName, + configFile, + ignoreCase, + configFile.options.outDir, + getCommonSourceDirectory, + ), getOutputExtension(inputFileName, configFile.options), ); - return !isJsonFile || comparePaths(inputFileName, outputFileName, Debug.checkDefined(configFile.options.configFilePath), ignoreCase) !== Comparison.EqualTo ? - outputFileName : - undefined; + return !isJsonFile + || comparePaths( + inputFileName, + outputFileName, + Debug.checkDefined(configFile.options.configFilePath), + ignoreCase, + ) !== Comparison.EqualTo + ? outputFileName + : undefined; } function createAddOutput() { @@ -159,8 +222,12 @@ namespace ts { } } - function getSingleOutputFileNames(configFile: ParsedCommandLine, addOutput: ReturnType["addOutput"]) { - const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = getOutputPathsForBundle(configFile.options, /*forceDtsPaths*/ false); + function getSingleOutputFileNames( + configFile: ParsedCommandLine, + addOutput: ReturnType["addOutput"], + ) { + const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = + getOutputPathsForBundle(configFile.options, /*forceDtsPaths*/ false); addOutput(jsFilePath); addOutput(sourceMapFilePath); addOutput(declarationFilePath); @@ -168,7 +235,13 @@ namespace ts { addOutput(buildInfoPath); } - function getOwnOutputFileNames(configFile: ParsedCommandLine, inputFileName: string, ignoreCase: boolean, addOutput: ReturnType["addOutput"], getCommonSourceDirectory?: () => string) { + function getOwnOutputFileNames( + configFile: ParsedCommandLine, + inputFileName: string, + ignoreCase: boolean, + addOutput: ReturnType["addOutput"], + getCommonSourceDirectory?: () => string, + ) { if (isDeclarationFileName(inputFileName)) return; const js = getOutputJSFileName(inputFileName, configFile, ignoreCase, getCommonSourceDirectory); addOutput(js); @@ -205,7 +278,11 @@ namespace ts { checkSourceFilesBelongToPath?.(commonSourceDirectory); } else { - commonSourceDirectory = computeCommonSourceDirectoryOfFilenames(emittedFiles(), currentDirectory, getCanonicalFileName); + commonSourceDirectory = computeCommonSourceDirectoryOfFilenames( + emittedFiles(), + currentDirectory, + getCanonicalFileName, + ); } if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) { @@ -218,10 +295,19 @@ namespace ts { } /*@internal*/ - export function getCommonSourceDirectoryOfConfig({ options, fileNames }: ParsedCommandLine, ignoreCase: boolean): string { + export function getCommonSourceDirectoryOfConfig( + { options, fileNames }: ParsedCommandLine, + ignoreCase: boolean, + ): string { return getCommonSourceDirectory( options, - () => filter(fileNames, file => !(options.noEmitForJsFiles && fileExtensionIsOneOf(file, supportedJSExtensionsFlat)) && !isDeclarationFileName(file)), + () => + filter( + fileNames, + file => + !(options.noEmitForJsFiles && fileExtensionIsOneOf(file, supportedJSExtensionsFlat)) + && !isDeclarationFileName(file), + ), getDirectoryPath(normalizeSlashes(Debug.checkDefined(options.configFilePath))), createGetCanonicalFileName(!ignoreCase), ); @@ -243,7 +329,11 @@ namespace ts { return getOutputs(); } - export function getOutputFileNames(commandLine: ParsedCommandLine, inputFileName: string, ignoreCase: boolean): readonly string[] { + export function getOutputFileNames( + commandLine: ParsedCommandLine, + inputFileName: string, + ignoreCase: boolean, + ): readonly string[] { inputFileName = normalizePath(inputFileName); Debug.assert(contains(commandLine.fileNames, inputFileName), `Expected fileName to be present in command line`); const { addOutput, getOutputs } = createAddOutput(); @@ -260,7 +350,10 @@ namespace ts { export function getFirstProjectOutput(configFile: ParsedCommandLine, ignoreCase: boolean): string { if (outFile(configFile.options)) { const { jsFilePath } = getOutputPathsForBundle(configFile.options, /*forceDtsPaths*/ false); - return Debug.checkDefined(jsFilePath, `project ${configFile.options.configFilePath} expected to have at least one output`); + return Debug.checkDefined( + jsFilePath, + `project ${configFile.options.configFilePath} expected to have at least one output`, + ); } const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(configFile, ignoreCase)); @@ -280,9 +373,19 @@ namespace ts { /*@internal*/ // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature - export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile | undefined, { scriptTransformers, declarationTransformers }: EmitTransformers, emitOnlyDtsFiles?: boolean, onlyBuildInfo?: boolean, forceDtsEmit?: boolean): EmitResult { + export function emitFiles( + resolver: EmitResolver, + host: EmitHost, + targetSourceFile: SourceFile | undefined, + { scriptTransformers, declarationTransformers }: EmitTransformers, + emitOnlyDtsFiles?: boolean, + onlyBuildInfo?: boolean, + forceDtsEmit?: boolean, + ): EmitResult { const compilerOptions = host.getCompilerOptions(); - const sourceMapDataList: SourceMapEmitResult[] | undefined = (compilerOptions.sourceMap || compilerOptions.inlineSourceMap || getAreDeclarationMapsEnabled(compilerOptions)) ? [] : undefined; + const sourceMapDataList: SourceMapEmitResult[] | undefined = + (compilerOptions.sourceMap || compilerOptions.inlineSourceMap + || getAreDeclarationMapsEnabled(compilerOptions)) ? [] : undefined; const emittedFilesList: string[] | undefined = compilerOptions.listEmittedFiles ? [] : undefined; const emitterDiagnostics = createDiagnosticCollection(); const newLine = getNewLineCharacter(compilerOptions, () => host.getNewLine()); @@ -310,13 +413,20 @@ namespace ts { sourceMaps: sourceMapDataList, }; - function emitSourceFileOrBundle({ jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle | undefined) { + function emitSourceFileOrBundle( + { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }: EmitFileNames, + sourceFileOrBundle: SourceFile | Bundle | undefined, + ) { let buildInfoDirectory: string | undefined; if (buildInfoPath && sourceFileOrBundle && isBundle(sourceFileOrBundle)) { - buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory())); + buildInfoDirectory = getDirectoryPath( + getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory()), + ); bundleBuildInfo = { commonSourceDirectory: relativeToBuildInfo(host.getCommonSourceDirectory()), - sourceFiles: sourceFileOrBundle.sourceFiles.map(file => relativeToBuildInfo(getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory()))), + sourceFiles: sourceFileOrBundle.sourceFiles.map(file => + relativeToBuildInfo(getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory())) + ), }; } tracing?.push(tracing.Phase.Emit, "emitJsFileOrBundle", { jsFilePath }); @@ -324,7 +434,12 @@ namespace ts { tracing?.pop(); tracing?.push(tracing.Phase.Emit, "emitDeclarationFileOrBundle", { declarationFilePath }); - emitDeclarationFileOrBundle(sourceFileOrBundle, declarationFilePath, declarationMapPath, relativeToBuildInfo); + emitDeclarationFileOrBundle( + sourceFileOrBundle, + declarationFilePath, + declarationMapPath, + relativeToBuildInfo, + ); tracing?.pop(); tracing?.push(tracing.Phase.Emit, "emitBuildInfo", { buildInfoPath }); @@ -352,7 +467,9 @@ namespace ts { } function relativeToBuildInfo(path: string) { - return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory!, path, host.getCanonicalFileName)); + return ensurePathIsNonModuleName( + getRelativePathFromDirectory(buildInfoDirectory!, path, host.getCanonicalFileName), + ); } } @@ -367,7 +484,15 @@ namespace ts { const version = ts.version; // Extracted into a const so the form is stable between namespace and module const buildInfo: BuildInfo = { bundle, program, version }; // Pass buildinfo as additional data to avoid having to reparse - writeFile(host, emitterDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), /*writeByteOrderMark*/ false, /*sourceFiles*/ undefined, { buildInfo }); + writeFile( + host, + emitterDiagnostics, + buildInfoPath, + getBuildInfoText(buildInfo), + /*writeByteOrderMark*/ false, + /*sourceFiles*/ undefined, + { buildInfo }, + ); } function emitJsFileOrBundle( @@ -386,7 +511,15 @@ namespace ts { return; } // Transform the source files - const transform = transformNodes(resolver, host, factory, compilerOptions, [sourceFileOrBundle], scriptTransformers, /*allowDtsFiles*/ false); + const transform = transformNodes( + resolver, + host, + factory, + compilerOptions, + [sourceFileOrBundle], + scriptTransformers, + /*allowDtsFiles*/ false, + ); const printerOptions: PrinterOptions = { removeComments: compilerOptions.removeComments, @@ -432,16 +565,29 @@ namespace ts { if (emitOnlyDtsFiles || compilerOptions.emitDeclarationOnly) emitSkipped = true; return; } - const sourceFiles = isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] : sourceFileOrBundle.sourceFiles; + const sourceFiles = isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] + : sourceFileOrBundle.sourceFiles; const filesForEmit = forceDtsEmit ? sourceFiles : filter(sourceFiles, isSourceFileNotJson); // Setup and perform the transformation to retrieve declarations from the input files - const inputListOrBundle = outFile(compilerOptions) ? [factory.createBundle(filesForEmit, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : filesForEmit; + const inputListOrBundle = outFile(compilerOptions) + ? [factory.createBundle( + filesForEmit, + !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined, + )] : filesForEmit; if (emitOnlyDtsFiles && !getEmitDeclarations(compilerOptions)) { // Checker wont collect the linked aliases since thats only done when declaration is enabled. // Do that here when emitting only dts files filesForEmit.forEach(collectLinkedAliases); } - const declarationTransform = transformNodes(resolver, host, factory, compilerOptions, inputListOrBundle, declarationTransformers, /*allowDtsFiles*/ false); + const declarationTransform = transformNodes( + resolver, + host, + factory, + compilerOptions, + inputListOrBundle, + declarationTransformers, + /*allowDtsFiles*/ false, + ); if (length(declarationTransform.diagnostics)) { for (const diagnostic of declarationTransform.diagnostics!) { emitterDiagnostics.add(diagnostic); @@ -472,10 +618,14 @@ namespace ts { isEmitNotificationEnabled: declarationTransform.isEmitNotificationEnabled, substituteNode: declarationTransform.substituteNode, }); - const declBlocked = (!!declarationTransform.diagnostics && !!declarationTransform.diagnostics.length) || !!host.isEmitBlocked(declarationFilePath) || !!compilerOptions.noEmit; + const declBlocked = (!!declarationTransform.diagnostics && !!declarationTransform.diagnostics.length) + || !!host.isEmitBlocked(declarationFilePath) || !!compilerOptions.noEmit; emitSkipped = emitSkipped || declBlocked; if (!declBlocked || forceDtsEmit) { - Debug.assert(declarationTransform.transformed.length === 1, "Should only see one output from the decl transform"); + Debug.assert( + declarationTransform.transformed.length === 1, + "Should only see one output from the decl transform", + ); printSourceFileOrBundle( declarationFilePath, declarationMapPath, @@ -508,7 +658,13 @@ namespace ts { forEachChild(node, collectLinkedAliases); } - function printSourceFileOrBundle(jsFilePath: string, sourceMapFilePath: string | undefined, transform: TransformationResult, printer: Printer, mapOptions: SourceMapOptions) { + function printSourceFileOrBundle( + jsFilePath: string, + sourceMapFilePath: string | undefined, + transform: TransformationResult, + printer: Printer, + mapOptions: SourceMapOptions, + ) { const sourceFileOrBundle = transform.transformed[0]; const bundle = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle : undefined; const sourceFile = sourceFileOrBundle.kind === SyntaxKind.SourceFile ? sourceFileOrBundle : undefined; @@ -558,8 +714,17 @@ namespace ts { // Write the source map if (sourceMapFilePath) { const sourceMap = sourceMapGenerator.toString(); - writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap, /*writeByteOrderMark*/ false, sourceFiles); - if (printer.bundleFileInfo) printer.bundleFileInfo.mapHash = computeSignature(sourceMap, maybeBind(host, host.createHash)); + writeFile( + host, + emitterDiagnostics, + sourceMapFilePath, + sourceMap, + /*writeByteOrderMark*/ false, + sourceFiles, + ); + if (printer.bundleFileInfo) { + printer.bundleFileInfo.mapHash = computeSignature(sourceMap, maybeBind(host, host.createHash)); + } } } else { @@ -568,10 +733,15 @@ namespace ts { // Write the output file const text = writer.getText(); - writeFile(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, { sourceMapUrlPos, diagnostics: transform.diagnostics }); + writeFile(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, { + sourceMapUrlPos, + diagnostics: transform.diagnostics, + }); // We store the hash of the text written in the buildinfo to ensure that text of the referenced d.ts file is same as whats in the buildinfo // This is needed because incremental can be toggled between two runs and we might use stale file text to do text manipulation in prepend mode - if (printer.bundleFileInfo) printer.bundleFileInfo.hash = computeSignature(text, maybeBind(host, host.createHash)); + if (printer.bundleFileInfo) { + printer.bundleFileInfo.hash = computeSignature(text, maybeBind(host, host.createHash)); + } // Reset state writer.clear(); @@ -588,7 +758,8 @@ namespace ts { function shouldEmitSourceMaps(mapOptions: SourceMapOptions, sourceFileOrBundle: SourceFile | Bundle) { return (mapOptions.sourceMap || mapOptions.inlineSourceMap) - && (sourceFileOrBundle.kind !== SyntaxKind.SourceFile || !fileExtensionIs(sourceFileOrBundle.fileName, Extension.Json)); + && (sourceFileOrBundle.kind !== SyntaxKind.SourceFile + || !fileExtensionIs(sourceFileOrBundle.fileName, Extension.Json)); } function getSourceRoot(mapOptions: SourceMapOptions) { @@ -598,7 +769,11 @@ namespace ts { return sourceRoot ? ensureTrailingDirectorySeparator(sourceRoot) : sourceRoot; } - function getSourceMapDirectory(mapOptions: SourceMapOptions, filePath: string, sourceFile: SourceFile | undefined) { + function getSourceMapDirectory( + mapOptions: SourceMapOptions, + filePath: string, + sourceFile: SourceFile | undefined, + ) { if (mapOptions.sourceRoot) return host.getCommonSourceDirectory(); if (mapOptions.mapRoot) { let sourceMapDir = normalizeSlashes(mapOptions.mapRoot); @@ -616,7 +791,13 @@ namespace ts { return getDirectoryPath(normalizePath(filePath)); } - function getSourceMappingURL(mapOptions: SourceMapOptions, sourceMapGenerator: SourceMapGenerator, filePath: string, sourceMapFilePath: string | undefined, sourceFile: SourceFile | undefined) { + function getSourceMappingURL( + mapOptions: SourceMapOptions, + sourceMapGenerator: SourceMapGenerator, + filePath: string, + sourceMapFilePath: string | undefined, + sourceFile: SourceFile | undefined, + ) { if (mapOptions.inlineSourceMap) { // Encode the sourceMap into the sourceMap url const sourceMapText = sourceMapGenerator.toString(); @@ -722,13 +903,21 @@ namespace ts { getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined; } - function createSourceFilesFromBundleBuildInfo(bundle: BundleBuildInfo, buildInfoDirectory: string, host: EmitUsingBuildInfoHost): readonly SourceFile[] { + function createSourceFilesFromBundleBuildInfo( + bundle: BundleBuildInfo, + buildInfoDirectory: string, + host: EmitUsingBuildInfoHost, + ): readonly SourceFile[] { const jsBundle = Debug.checkDefined(bundle.js); - const prologueMap = jsBundle.sources?.prologues && arrayToMap(jsBundle.sources.prologues, prologueInfo => prologueInfo.file); + const prologueMap = jsBundle.sources?.prologues + && arrayToMap(jsBundle.sources.prologues, prologueInfo => prologueInfo.file); return bundle.sourceFiles.map((fileName, index) => { const prologueInfo = prologueMap?.get(index); const statements = prologueInfo?.directives.map(directive => { - const literal = setTextRange(factory.createStringLiteral(directive.expression.text), directive.expression); + const literal = setTextRange( + factory.createStringLiteral(directive.expression.text), + directive.expression, + ); const statement = setTextRange(factory.createExpressionStatement(literal), directive); setParent(literal, statement); return statement; @@ -757,7 +946,8 @@ namespace ts { customTransformers?: CustomTransformers, ): EmitUsingBuildInfoResult { const createHash = maybeBind(host, host.createHash); - const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false); + const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = + getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false); let buildInfo: BuildInfo | undefined; if (host.getBuildInfo) { // If host directly provides buildinfo we can get it directly. This allows host to cache the buildinfo @@ -769,7 +959,9 @@ namespace ts { buildInfo = getBuildInfo(buildInfoPath!, buildInfoText); } if (!buildInfo) return buildInfoPath!; - if (!buildInfo.bundle || !buildInfo.bundle.js || (declarationFilePath && !buildInfo.bundle.dts)) return buildInfoPath!; + if (!buildInfo.bundle || !buildInfo.bundle.js || (declarationFilePath && !buildInfo.bundle.dts)) { + return buildInfoPath!; + } const jsFileText = host.readFile(Debug.checkDefined(jsFilePath)); if (!jsFileText) return jsFilePath!; @@ -777,19 +969,31 @@ namespace ts { if (computeSignature(jsFileText, createHash) !== buildInfo.bundle.js.hash) return jsFilePath!; const sourceMapText = sourceMapFilePath && host.readFile(sourceMapFilePath); // error if no source map or for now if inline sourcemap - if ((sourceMapFilePath && !sourceMapText) || config.options.inlineSourceMap) return sourceMapFilePath || "inline sourcemap decoding"; - if (sourceMapFilePath && computeSignature(sourceMapText!, createHash) !== buildInfo.bundle.js.mapHash) return sourceMapFilePath; + if ((sourceMapFilePath && !sourceMapText) || config.options.inlineSourceMap) { + return sourceMapFilePath || "inline sourcemap decoding"; + } + if (sourceMapFilePath && computeSignature(sourceMapText!, createHash) !== buildInfo.bundle.js.mapHash) { + return sourceMapFilePath; + } // read declaration text const declarationText = declarationFilePath && host.readFile(declarationFilePath); if (declarationFilePath && !declarationText) return declarationFilePath; - if (declarationFilePath && computeSignature(declarationText!, createHash) !== buildInfo.bundle.dts!.hash) return declarationFilePath; + if (declarationFilePath && computeSignature(declarationText!, createHash) !== buildInfo.bundle.dts!.hash) { + return declarationFilePath; + } const declarationMapText = declarationMapPath && host.readFile(declarationMapPath); // error if no source map or for now if inline sourcemap - if ((declarationMapPath && !declarationMapText) || config.options.inlineSourceMap) return declarationMapPath || "inline sourcemap decoding"; - if (declarationMapPath && computeSignature(declarationMapText!, createHash) !== buildInfo.bundle.dts!.mapHash) return declarationMapPath; + if ((declarationMapPath && !declarationMapText) || config.options.inlineSourceMap) { + return declarationMapPath || "inline sourcemap decoding"; + } + if (declarationMapPath && computeSignature(declarationMapText!, createHash) !== buildInfo.bundle.dts!.mapHash) { + return declarationMapPath; + } - const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath!, host.getCurrentDirectory())); + const buildInfoDirectory = getDirectoryPath( + getNormalizedAbsolutePath(buildInfoPath!, host.getCurrentDirectory()), + ); const ownPrependInput = createInputFiles( jsFileText, declarationText!, @@ -811,7 +1015,8 @@ namespace ts { const emitHost: EmitHost = { getPrependNodes: memoize(() => [...prependNodes, ownPrependInput]), getCanonicalFileName: host.getCanonicalFileName, - getCommonSourceDirectory: () => getNormalizedAbsolutePath(buildInfo!.bundle!.commonSourceDirectory, buildInfoDirectory), + getCommonSourceDirectory: () => + getNormalizedAbsolutePath(buildInfo!.bundle!.commonSourceDirectory, buildInfoDirectory), getCompilerOptions: () => config.options, getCurrentDirectory: () => host.getCurrentDirectory(), getNewLine: () => host.getNewLine(), @@ -836,7 +1041,11 @@ namespace ts { newBuildInfo.program = buildInfo!.program; if (newBuildInfo.program && changedDtsText !== undefined && config.options.composite) { // Update the output signature - (newBuildInfo.program as ProgramBundleEmitBuildInfo).outSignature = computeSignature(changedDtsText, createHash, changedDtsData); + (newBuildInfo.program as ProgramBundleEmitBuildInfo).outSignature = computeSignature( + changedDtsText, + createHash, + changedDtsData, + ); } // Update sourceFileInfo const { js, dts, sourceFiles } = buildInfo!.bundle!; @@ -845,7 +1054,12 @@ namespace ts { newBuildInfo.bundle!.dts!.sources = dts.sources; } newBuildInfo.bundle!.sourceFiles = sourceFiles; - outputFiles.push({ name, text: getBuildInfoText(newBuildInfo), writeByteOrderMark, buildInfo: newBuildInfo }); + outputFiles.push({ + name, + text: getBuildInfoText(newBuildInfo), + writeByteOrderMark, + buildInfo: newBuildInfo, + }); return; case declarationFilePath: if (declarationText === text) return; @@ -949,7 +1163,12 @@ namespace ts { let commentsDisabled = !!printerOptions.removeComments; let lastSubstitution: Node | undefined; let currentParenthesizerRule: ((node: Node) => Node) | undefined; - const { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment"); + const { enter: enterComment, exit: exitComment } = performance.createTimerIf( + extendedDiagnostics, + "commentTime", + "beforeComment", + "afterComment", + ); const parenthesizer = factory.parenthesizer; const typeArgumentParenthesizerRuleSelector: OrdinalParentheizerRuleSelector = { select: index => index === 0 ? parenthesizer.parenthesizeLeadingTypeArgument : undefined, @@ -1029,7 +1248,12 @@ namespace ts { writer = previousWriter; } - function writeList(format: ListFormat, nodes: NodeArray, sourceFile: SourceFile | undefined, output: EmitTextWriter) { + function writeList( + format: ListFormat, + nodes: NodeArray, + sourceFile: SourceFile | undefined, + output: EmitTextWriter, + ) { const previousWriter = writer; setWriter(output, /*_sourceMapGenerator*/ undefined); if (sourceFile) { @@ -1056,12 +1280,12 @@ namespace ts { function recordBundleFileInternalSectionStart(node: Node) { if ( - recordInternalSection && - bundleFileInfo && - currentSourceFile && - (isDeclaration(node) || isVariableStatement(node)) && - isInternalDeclaration(node, currentSourceFile) && - sourceFileTextKind !== BundleFileSectionKind.Internal + recordInternalSection + && bundleFileInfo + && currentSourceFile + && (isDeclaration(node) || isVariableStatement(node)) + && isInternalDeclaration(node, currentSourceFile) + && sourceFileTextKind !== BundleFileSectionKind.Internal ) { const prevSourceFileTextKind = sourceFileTextKind; recordBundleFileTextLikeSection(writer.getTextPos()); @@ -1072,7 +1296,9 @@ namespace ts { return undefined; } - function recordBundleFileInternalSectionEnd(prevSourceFileTextKind: ReturnType) { + function recordBundleFileInternalSectionEnd( + prevSourceFileTextKind: ReturnType, + ) { if (prevSourceFileTextKind) { recordBundleFileTextLikeSection(writer.getTextPos()); sourceFileTextPos = getTextPosWithWriteLine(); @@ -1088,7 +1314,11 @@ namespace ts { return false; } - function writeBundle(bundle: Bundle, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) { + function writeBundle( + bundle: Bundle, + output: EmitTextWriter, + sourceMapGenerator: SourceMapGenerator | undefined, + ) { isOwnFileEmit = false; const previousWriter = writer; setWriter(output, sourceMapGenerator); @@ -1155,7 +1385,11 @@ namespace ts { writer = previousWriter; } - function writeFile(sourceFile: SourceFile, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) { + function writeFile( + sourceFile: SourceFile, + output: EmitTextWriter, + sourceMapGenerator: SourceMapGenerator | undefined, + ) { isOwnFileEmit = true; const previousWriter = writer; setWriter(output, sourceMapGenerator); @@ -1241,7 +1475,10 @@ namespace ts { } function emitExpression(node: Expression, parenthesizerRule?: (node: Expression) => Expression): void; - function emitExpression(node: Expression | undefined, parenthesizerRule?: (node: Expression) => Expression): void; + function emitExpression( + node: Expression | undefined, + parenthesizerRule?: (node: Expression) => Expression, + ): void; function emitExpression(node: Expression | undefined, parenthesizerRule?: (node: Expression) => Expression) { if (node === undefined) return; pipelineEmit(EmitHint.Expression, node, parenthesizerRule); @@ -1273,22 +1510,28 @@ namespace ts { } function shouldEmitSourceMaps(node: Node) { - return !sourceMapsDisabled && - !isSourceFile(node) && - !isInJsonFile(node) && - !isUnparsedSource(node) && - !isUnparsedPrepend(node); + return !sourceMapsDisabled + && !isSourceFile(node) + && !isInJsonFile(node) + && !isUnparsedSource(node) + && !isUnparsedPrepend(node); } function getPipelinePhase(phase: PipelinePhase, emitHint: EmitHint, node: Node) { switch (phase) { case PipelinePhase.Notification: - if (onEmitNode !== noEmitNotification && (!isEmitNotificationEnabled || isEmitNotificationEnabled(node))) { + if ( + onEmitNode !== noEmitNotification + && (!isEmitNotificationEnabled || isEmitNotificationEnabled(node)) + ) { return pipelineEmitWithNotification; } // falls through case PipelinePhase.Substitution: - if (substituteNode !== noEmitSubstitution && (lastSubstitution = substituteNode(emitHint, node) || node) !== node) { + if ( + substituteNode !== noEmitSubstitution + && (lastSubstitution = substituteNode(emitHint, node) || node) !== node + ) { if (currentParenthesizerRule) { lastSubstitution = currentParenthesizerRule(lastSubstitution); } @@ -1346,8 +1589,12 @@ namespace ts { } if (hint === EmitHint.SourceFile) return emitSourceFile(cast(node, isSourceFile)); if (hint === EmitHint.IdentifierName) return emitIdentifier(cast(node, isIdentifier)); - if (hint === EmitHint.JsxAttributeValue) return emitLiteral(cast(node, isStringLiteral), /*jsxAttributeEscape*/ true); - if (hint === EmitHint.MappedTypeParameter) return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration)); + if (hint === EmitHint.JsxAttributeValue) { + return emitLiteral(cast(node, isStringLiteral), /*jsxAttributeEscape*/ true); + } + if (hint === EmitHint.MappedTypeParameter) { + return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration)); + } if (hint === EmitHint.EmbeddedStatement) { Debug.assertNode(node, isEmptyStatement); return emitEmptyStatement(/*isEmbeddedStatement*/ true); @@ -1867,9 +2114,12 @@ namespace ts { const numPrepends = bundle ? bundle.prepends.length : 0; const numNodes = bundle ? bundle.sourceFiles.length + numPrepends : 1; for (let i = 0; i < numNodes; i++) { - const currentNode = bundle ? i < numPrepends ? bundle.prepends[i] : bundle.sourceFiles[i - numPrepends] : node; - const sourceFile = isSourceFile(currentNode) ? currentNode : isUnparsedSource(currentNode) ? undefined : currentSourceFile; - const shouldSkip = printerOptions.noEmitHelpers || (!!sourceFile && hasRecordedExternalHelpers(sourceFile)); + const currentNode = bundle ? i < numPrepends ? bundle.prepends[i] : bundle.sourceFiles[i - numPrepends] + : node; + const sourceFile = isSourceFile(currentNode) ? currentNode + : isUnparsedSource(currentNode) ? undefined : currentSourceFile; + const shouldSkip = printerOptions.noEmitHelpers + || (!!sourceFile && hasRecordedExternalHelpers(sourceFile)); const shouldBundle = (isSourceFile(currentNode) || isUnparsedSource(currentNode)) && !isOwnFileEmit; const helpers = isUnparsedSource(currentNode) ? currentNode.helpers : getSortedEmitHelpers(currentNode); if (helpers) { @@ -1901,7 +2151,14 @@ namespace ts { else { writeLines(helper.text(makeFileLevelOptimisticUniqueName)); } - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.EmitHelpers, data: helper.name }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.EmitHelpers, + data: helper.name, + }); + } helpersEmitted = true; } } @@ -1971,9 +2228,9 @@ namespace ts { updateOrPushBundleFileTextLike( pos, writer.getTextPos(), - unparsed.kind === SyntaxKind.UnparsedText ? - BundleFileSectionKind.Text : - BundleFileSectionKind.Internal, + unparsed.kind === SyntaxKind.UnparsedText + ? BundleFileSectionKind.Text + : BundleFileSectionKind.Internal, ); } } @@ -2014,8 +2271,14 @@ namespace ts { function emitTabStop(hint: EmitHint, node: Node, snippet: TabStop) { // A tab stop should only be attached to an empty node, i.e. a node that doesn't emit any text. - Debug.assert(node.kind === SyntaxKind.EmptyStatement, `A tab stop cannot be attached to a node of kind ${Debug.formatSyntaxKind(node.kind)}.`); - Debug.assert(hint !== EmitHint.EmbeddedStatement, `A tab stop cannot be attached to an embedded statement.`); + Debug.assert( + node.kind === SyntaxKind.EmptyStatement, + `A tab stop cannot be attached to a node of kind ${Debug.formatSyntaxKind(node.kind)}.`, + ); + Debug.assert( + hint !== EmitHint.EmbeddedStatement, + `A tab stop cannot be attached to an embedded statement.`, + ); nonEscapingWrite(`\$${snippet.order}`); } @@ -2092,7 +2355,14 @@ namespace ts { emitTypeAnnotation(node.type); } // The comment position has to fallback to any present node within the parameterdeclaration because as it turns out, the parser can make parameter declarations with _just_ an initializer. - emitInitializer(node.initializer, node.type ? node.type.end : node.questionToken ? node.questionToken.end : node.name ? node.name.end : node.modifiers ? node.modifiers.end : node.pos, node, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitInitializer( + node.initializer, + node.type ? node.type.end + : node.questionToken ? node.questionToken.end + : node.name ? node.name.end : node.modifiers ? node.modifiers.end : node.pos, + node, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitDecorator(decorator: Decorator) { @@ -2118,7 +2388,11 @@ namespace ts { emit(node.questionToken); emit(node.exclamationToken); emitTypeAnnotation(node.type); - emitInitializer(node.initializer, node.type ? node.type.end : node.questionToken ? node.questionToken.end : node.name.end, node); + emitInitializer( + node.initializer, + node.type ? node.type.end : node.questionToken ? node.questionToken.end : node.name.end, + node, + ); writeTrailingSemicolon(); } @@ -2276,7 +2550,8 @@ namespace ts { function emitTypeLiteral(node: TypeLiteralNode) { writePunctuation("{"); - const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers; + const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers + : ListFormat.MultiLineTypeLiteralMembers; emitList(node, node.members, flags | ListFormat.NoSpaceIfEmpty); writePunctuation("}"); } @@ -2294,8 +2569,14 @@ namespace ts { function emitTupleType(node: TupleTypeNode) { emitTokenWithComment(SyntaxKind.OpenBracketToken, node.pos, writePunctuation, node); - const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTupleTypeElements : ListFormat.MultiLineTupleTypeElements; - emitList(node, node.elements, flags | ListFormat.NoSpaceIfEmpty, parenthesizer.parenthesizeElementTypeOfTupleType); + const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTupleTypeElements + : ListFormat.MultiLineTupleTypeElements; + emitList( + node, + node.elements, + flags | ListFormat.NoSpaceIfEmpty, + parenthesizer.parenthesizeElementTypeOfTupleType, + ); emitTokenWithComment(SyntaxKind.CloseBracketToken, node.elements.end, writePunctuation, node); } @@ -2314,11 +2595,21 @@ namespace ts { } function emitUnionType(node: UnionTypeNode) { - emitList(node, node.types, ListFormat.UnionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfUnionType); + emitList( + node, + node.types, + ListFormat.UnionTypeConstituents, + parenthesizer.parenthesizeConstituentTypeOfUnionType, + ); } function emitIntersectionType(node: IntersectionTypeNode) { - emitList(node, node.types, ListFormat.IntersectionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfIntersectionType); + emitList( + node, + node.types, + ListFormat.IntersectionTypeConstituents, + parenthesizer.parenthesizeConstituentTypeOfIntersectionType, + ); } function emitConditionalType(node: ConditionalTypeNode) { @@ -2357,9 +2648,9 @@ namespace ts { writeTokenText(node.operator, writeKeyword); writeSpace(); - const parenthesizerRule = node.operator === SyntaxKind.ReadonlyKeyword ? - parenthesizer.parenthesizeOperandOfReadonlyTypeOperator : - parenthesizer.parenthesizeOperandOfTypeOperator; + const parenthesizerRule = node.operator === SyntaxKind.ReadonlyKeyword + ? parenthesizer.parenthesizeOperandOfReadonlyTypeOperator + : parenthesizer.parenthesizeOperandOfTypeOperator; emit(node.type, parenthesizerRule); } @@ -2481,7 +2772,12 @@ namespace ts { writeSpace(); } emit(node.name); - emitInitializer(node.initializer, node.name.end, node, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitInitializer( + node.initializer, + node.name.end, + node, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } // @@ -2491,7 +2787,12 @@ namespace ts { function emitArrayLiteralExpression(node: ArrayLiteralExpression) { const elements = node.elements; const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; - emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitExpressionList( + node, + elements, + ListFormat.ArrayLiteralExpressionElements | preferNewLine, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitObjectLiteralExpression(node: ObjectLiteralExpression) { @@ -2503,8 +2804,13 @@ namespace ts { } const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; - const allowTrailingComma = currentSourceFile && currentSourceFile.languageVersion >= ScriptTarget.ES5 && !isJsonSourceFile(currentSourceFile) ? ListFormat.AllowTrailingComma : ListFormat.None; - emitList(node, node.properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine); + const allowTrailingComma = currentSourceFile && currentSourceFile.languageVersion >= ScriptTarget.ES5 + && !isJsonSourceFile(currentSourceFile) ? ListFormat.AllowTrailingComma : ListFormat.None; + emitList( + node, + node.properties, + ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine, + ); if (indentedFlag) { decreaseIndent(); @@ -2513,16 +2819,21 @@ namespace ts { function emitPropertyAccessExpression(node: PropertyAccessExpression) { emitExpression(node.expression, parenthesizer.parenthesizeLeftSideOfAccess); - const token = node.questionDotToken || setTextRangePosEnd(factory.createToken(SyntaxKind.DotToken) as DotToken, node.expression.end, node.name.pos); + const token = node.questionDotToken + || setTextRangePosEnd( + factory.createToken(SyntaxKind.DotToken) as DotToken, + node.expression.end, + node.name.pos, + ); const linesBeforeDot = getLinesBetweenNodes(node, node.expression, token); const linesAfterDot = getLinesBetweenNodes(node, token, node.name); writeLinesAndIndent(linesBeforeDot, /*writeSpaceIfNotIndenting*/ false); - const shouldEmitDotDot = token.kind !== SyntaxKind.QuestionDotToken && - mayNeedDotDotForPropertyAccess(node.expression) && - !writer.hasTrailingComment() && - !writer.hasTrailingWhitespace(); + const shouldEmitDotDot = token.kind !== SyntaxKind.QuestionDotToken + && mayNeedDotDotForPropertyAccess(node.expression) + && !writer.hasTrailingComment() + && !writer.hasTrailingWhitespace(); if (shouldEmitDotDot) { writePunctuation("."); @@ -2545,7 +2856,11 @@ namespace ts { expression = skipPartiallyEmittedExpressions(expression); if (isNumericLiteral(expression)) { // check if numeric literal is a decimal literal that was originally written with a dot - const text = getLiteralTextOfNode(expression as LiteralExpression, /*neverAsciiEscape*/ true, /*jsxAttributeEscape*/ false); + const text = getLiteralTextOfNode( + expression as LiteralExpression, + /*neverAsciiEscape*/ true, + /*jsxAttributeEscape*/ false, + ); // If he number will be printed verbatim and it doesn't already contain a dot, add one // if the expression doesn't have any comments that will be emitted. return !expression.numericLiteralFlags && !stringContains(text, tokenToString(SyntaxKind.DotToken)!); @@ -2581,7 +2896,12 @@ namespace ts { } emit(node.questionDotToken); emitTypeArguments(node, node.typeArguments); - emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitExpressionList( + node, + node.arguments, + ListFormat.CallExpressionArguments, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitNewExpression(node: NewExpression) { @@ -2589,7 +2909,12 @@ namespace ts { writeSpace(); emitExpression(node.expression, parenthesizer.parenthesizeExpressionOfNew); emitTypeArguments(node, node.typeArguments); - emitExpressionList(node, node.arguments, ListFormat.NewExpressionArguments, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitExpressionList( + node, + node.arguments, + ListFormat.NewExpressionArguments, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitTaggedTemplateExpression(node: TaggedTemplateExpression) { @@ -2622,7 +2947,12 @@ namespace ts { emitExpression(node.expression, /*parenthesizerRules*/ undefined); writeLineSeparatorsAfter(node.expression, node); decreaseIndentIf(indented); - emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression ? node.expression.end : openParenPos, writePunctuation, node); + emitTokenWithComment( + SyntaxKind.CloseParenToken, + node.expression ? node.expression.end : openParenPos, + writePunctuation, + node, + ); } function emitFunctionExpression(node: FunctionExpression) { @@ -2690,8 +3020,12 @@ namespace ts { // The same is true of minus of course. const operand = node.operand; return operand.kind === SyntaxKind.PrefixUnaryExpression - && ((node.operator === SyntaxKind.PlusToken && ((operand as PrefixUnaryExpression).operator === SyntaxKind.PlusToken || (operand as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken)) - || (node.operator === SyntaxKind.MinusToken && ((operand as PrefixUnaryExpression).operator === SyntaxKind.MinusToken || (operand as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken))); + && ((node.operator === SyntaxKind.PlusToken + && ((operand as PrefixUnaryExpression).operator === SyntaxKind.PlusToken + || (operand as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken)) + || (node.operator === SyntaxKind.MinusToken + && ((operand as PrefixUnaryExpression).operator === SyntaxKind.MinusToken + || (operand as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken))); } function emitPostfixUnaryExpression(node: PostfixUnaryExpression) { @@ -2710,7 +3044,14 @@ namespace ts { shouldEmitSourceMapsStack: boolean[]; } - return createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, /*foldState*/ undefined); + return createBinaryExpressionTrampoline( + onEnter, + onLeft, + onOperator, + onRight, + onExit, + /*foldState*/ undefined, + ); function onEnter(node: BinaryExpression, state: WorkArea | undefined) { if (state) { @@ -2720,7 +3061,9 @@ namespace ts { state.containerEndStack[state.stackIndex] = containerEnd; state.declarationListContainerEndStack[state.stackIndex] = declarationListContainerEnd; const emitComments = state.shouldEmitCommentsStack[state.stackIndex] = shouldEmitComments(node); - const emitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex] = shouldEmitSourceMaps(node); + const emitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex] = shouldEmitSourceMaps( + node, + ); onBeforeEmitNode?.(node); if (emitComments) emitCommentsBeforeNode(node); if (emitSourceMaps) emitSourceMapsBeforeNode(node); @@ -2750,7 +3093,10 @@ namespace ts { const linesAfterOperator = getLinesBetweenNodes(node, operatorToken, node.right); writeLinesAndIndent(linesBeforeOperator, isCommaOperator); emitLeadingCommentsOfPosition(operatorToken.pos); - writeTokenNode(operatorToken, operatorToken.kind === SyntaxKind.InKeyword ? writeKeyword : writeOperator); + writeTokenNode( + operatorToken, + operatorToken.kind === SyntaxKind.InKeyword ? writeKeyword : writeOperator, + ); emitTrailingCommentsOfPosition(operatorToken.end, /*prefixSpace*/ true); // Binary operators should have a space before the comment starts writeLinesAndIndent(linesAfterOperator, /*writeSpaceIfNotIndenting*/ true); } @@ -2772,16 +3118,23 @@ namespace ts { const shouldEmitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex]; afterEmitNode(savedPreserveSourceNewlines); if (shouldEmitSourceMaps) emitSourceMapsAfterNode(node); - if (shouldEmitComments) emitCommentsAfterNode(node, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); + if (shouldEmitComments) { + emitCommentsAfterNode( + node, + savedContainerPos, + savedContainerEnd, + savedDeclarationListContainerEnd, + ); + } onAfterEmitNode?.(node); state.stackIndex--; } } function maybeEmitExpression(next: Expression, parent: BinaryExpression, side: "left" | "right") { - const parenthesizerRule = side === "left" ? - parenthesizer.getParenthesizeLeftSideOfBinaryForOperator(parent.operatorToken.kind) : - parenthesizer.getParenthesizeRightSideOfBinaryForOperator(parent.operatorToken.kind); + const parenthesizerRule = side === "left" + ? parenthesizer.getParenthesizeLeftSideOfBinaryForOperator(parent.operatorToken.kind) + : parenthesizer.getParenthesizeRightSideOfBinaryForOperator(parent.operatorToken.kind); let pipelinePhase = getPipelinePhase(PipelinePhase.Notification, EmitHint.Expression, next); if (pipelinePhase === pipelineEmitWithSubstitution) { @@ -2792,9 +3145,9 @@ namespace ts { } if ( - pipelinePhase === pipelineEmitWithComments || - pipelinePhase === pipelineEmitWithSourceMaps || - pipelinePhase === pipelineEmitWithHint + pipelinePhase === pipelineEmitWithComments + || pipelinePhase === pipelineEmitWithSourceMaps + || pipelinePhase === pipelineEmitWithHint ) { if (isBinaryExpression(next)) { return next; @@ -2834,7 +3187,10 @@ namespace ts { function emitYieldExpression(node: YieldExpression) { emitTokenWithComment(SyntaxKind.YieldKeyword, node.pos, writeKeyword, node); emit(node.asteriskToken); - emitExpressionWithLeadingSpace(node.expression && parenthesizeExpressionForNoAsi(node.expression), parenthesizeExpressionForNoAsiAndDisallowedComma); + emitExpressionWithLeadingSpace( + node.expression && parenthesizeExpressionForNoAsi(node.expression), + parenthesizeExpressionForNoAsiAndDisallowedComma, + ); } function emitSpreadElement(node: SpreadElement) { @@ -2902,9 +3258,16 @@ namespace ts { function emitBlockStatements(node: BlockLike, forceSingleLine: boolean) { emitTokenWithComment(SyntaxKind.OpenBraceToken, node.pos, writePunctuation, /*contextNode*/ node); - const format = forceSingleLine || getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineBlockStatements : ListFormat.MultiLineBlockStatements; + const format = forceSingleLine || getEmitFlags(node) & EmitFlags.SingleLine + ? ListFormat.SingleLineBlockStatements : ListFormat.MultiLineBlockStatements; emitList(node, node.statements, format); - emitTokenWithComment(SyntaxKind.CloseBraceToken, node.statements.end, writePunctuation, /*contextNode*/ node, /*indentLeading*/ !!(format & ListFormat.MultiLine)); + emitTokenWithComment( + SyntaxKind.CloseBraceToken, + node.statements.end, + writePunctuation, + /*contextNode*/ node, + /*indentLeading*/ !!(format & ListFormat.MultiLine), + ); } function emitVariableStatement(node: VariableStatement) { @@ -2983,13 +3346,33 @@ namespace ts { function emitForStatement(node: ForStatement) { const openParenPos = emitTokenWithComment(SyntaxKind.ForKeyword, node.pos, writeKeyword, node); writeSpace(); - let pos = emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, /*contextNode*/ node); + let pos = emitTokenWithComment( + SyntaxKind.OpenParenToken, + openParenPos, + writePunctuation, + /*contextNode*/ node, + ); emitForBinding(node.initializer); - pos = emitTokenWithComment(SyntaxKind.SemicolonToken, node.initializer ? node.initializer.end : pos, writePunctuation, node); + pos = emitTokenWithComment( + SyntaxKind.SemicolonToken, + node.initializer ? node.initializer.end : pos, + writePunctuation, + node, + ); emitExpressionWithLeadingSpace(node.condition); - pos = emitTokenWithComment(SyntaxKind.SemicolonToken, node.condition ? node.condition.end : pos, writePunctuation, node); + pos = emitTokenWithComment( + SyntaxKind.SemicolonToken, + node.condition ? node.condition.end : pos, + writePunctuation, + node, + ); emitExpressionWithLeadingSpace(node.incrementor); - emitTokenWithComment(SyntaxKind.CloseParenToken, node.incrementor ? node.incrementor.end : pos, writePunctuation, node); + emitTokenWithComment( + SyntaxKind.CloseParenToken, + node.incrementor ? node.incrementor.end : pos, + writePunctuation, + node, + ); emitEmbeddedStatement(node, node.statement); } @@ -3043,7 +3426,13 @@ namespace ts { writeTrailingSemicolon(); } - function emitTokenWithComment(token: SyntaxKind, pos: number, writer: (s: string) => void, contextNode: Node, indentLeading?: boolean) { + function emitTokenWithComment( + token: SyntaxKind, + pos: number, + writer: (s: string) => void, + contextNode: Node, + indentLeading?: boolean, + ) { const node = getParseTreeNode(contextNode); const isSimilarNode = node && node.kind === contextNode.kind; const startPos = pos; @@ -3051,7 +3440,8 @@ namespace ts { pos = skipTrivia(currentSourceFile.text, pos); } if (isSimilarNode && contextNode.pos !== startPos) { - const needsIndent = indentLeading && currentSourceFile && !positionsAreOnSameLine(startPos, pos, currentSourceFile); + const needsIndent = indentLeading && currentSourceFile + && !positionsAreOnSameLine(startPos, pos, currentSourceFile); if (needsIndent) { increaseIndent(); } @@ -3063,7 +3453,11 @@ namespace ts { pos = writeTokenText(token, writer, pos); if (isSimilarNode && contextNode.end !== pos) { const isJsxExprContext = contextNode.kind === SyntaxKind.JsxExpression; - emitTrailingCommentsOfPosition(pos, /*prefixSpace*/ !isJsxExprContext, /*forceNoNewline*/ isJsxExprContext); + emitTrailingCommentsOfPosition( + pos, + /*prefixSpace*/ !isJsxExprContext, + /*forceNoNewline*/ isJsxExprContext, + ); } return pos; } @@ -3078,7 +3472,12 @@ namespace ts { if (some(getSyntheticLeadingComments(node), commentWillEmitNewLine)) return true; if (isPartiallyEmittedExpression(node)) { if (node.pos !== node.expression.pos) { - if (some(getTrailingCommentRanges(currentSourceFile.text, node.expression.pos), commentWillEmitNewLine)) return true; + if ( + some( + getTrailingCommentRanges(currentSourceFile.text, node.expression.pos), + commentWillEmitNewLine, + ) + ) return true; } return willEmitLeadingNewLine(node.expression); } @@ -3110,7 +3509,10 @@ namespace ts { function emitReturnStatement(node: ReturnStatement) { emitTokenWithComment(SyntaxKind.ReturnKeyword, node.pos, writeKeyword, /*contextNode*/ node); - emitExpressionWithLeadingSpace(node.expression && parenthesizeExpressionForNoAsi(node.expression), parenthesizeExpressionForNoAsi); + emitExpressionWithLeadingSpace( + node.expression && parenthesizeExpressionForNoAsi(node.expression), + parenthesizeExpressionForNoAsi, + ); writeTrailingSemicolon(); } @@ -3142,7 +3544,10 @@ namespace ts { function emitThrowStatement(node: ThrowStatement) { emitTokenWithComment(SyntaxKind.ThrowKeyword, node.pos, writeKeyword, node); - emitExpressionWithLeadingSpace(parenthesizeExpressionForNoAsi(node.expression), parenthesizeExpressionForNoAsi); + emitExpressionWithLeadingSpace( + parenthesizeExpressionForNoAsi(node.expression), + parenthesizeExpressionForNoAsi, + ); writeTrailingSemicolon(); } @@ -3156,7 +3561,12 @@ namespace ts { } if (node.finallyBlock) { writeLineOrSpace(node, node.catchClause || node.tryBlock, node.finallyBlock); - emitTokenWithComment(SyntaxKind.FinallyKeyword, (node.catchClause || node.tryBlock).end, writeKeyword, node); + emitTokenWithComment( + SyntaxKind.FinallyKeyword, + (node.catchClause || node.tryBlock).end, + writeKeyword, + node, + ); writeSpace(); emit(node.finallyBlock); } @@ -3175,7 +3585,12 @@ namespace ts { emit(node.name); emit(node.exclamationToken); emitTypeAnnotation(node.type); - emitInitializer(node.initializer, node.type?.end ?? node.name.emitNode?.typeNode?.end ?? node.name.end, node, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitInitializer( + node.initializer, + node.type?.end ?? node.name.emitNode?.typeNode?.end ?? node.name.end, + node, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitVariableDeclarationList(node: VariableDeclarationList) { @@ -3197,7 +3612,10 @@ namespace ts { emitSignatureAndBody(node, emitSignatureHead); } - function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) { + function emitSignatureAndBody( + node: FunctionLikeDeclaration, + emitSignatureHead: (node: SignatureDeclaration) => void, + ) { const body = node.body; if (body) { if (isBlock(body)) { @@ -3230,7 +3648,14 @@ namespace ts { } } - function emitSignatureHead(node: FunctionDeclaration | FunctionExpression | MethodDeclaration | AccessorDeclaration | ConstructorDeclaration) { + function emitSignatureHead( + node: + | FunctionDeclaration + | FunctionExpression + | MethodDeclaration + | AccessorDeclaration + | ConstructorDeclaration, + ) { emitTypeParameters(node, node.typeParameters); emitParameters(node, node.parameters); emitTypeAnnotation(node.type); @@ -3259,7 +3684,12 @@ namespace ts { if ( getLeadingLineTerminatorCount(body, firstOrUndefined(body.statements), ListFormat.PreserveLines) - || getClosingLineTerminatorCount(body, lastOrUndefined(body.statements), ListFormat.PreserveLines, body.statements) + || getClosingLineTerminatorCount( + body, + lastOrUndefined(body.statements), + ListFormat.PreserveLines, + body.statements, + ) ) { return false; } @@ -3308,7 +3738,13 @@ namespace ts { increaseIndent(); } else { - emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, /*parenthesizerRule*/ undefined, statementOffset); + emitList( + body, + body.statements, + ListFormat.MultiLineFunctionBodyStatements, + /*parenthesizerRule*/ undefined, + statementOffset, + ); } } @@ -3412,12 +3848,23 @@ namespace ts { function emitCaseBlock(node: CaseBlock) { emitTokenWithComment(SyntaxKind.OpenBraceToken, node.pos, writePunctuation, node); emitList(node, node.clauses, ListFormat.CaseBlockClauses); - emitTokenWithComment(SyntaxKind.CloseBraceToken, node.clauses.end, writePunctuation, node, /*indentLeading*/ true); + emitTokenWithComment( + SyntaxKind.CloseBraceToken, + node.clauses.end, + writePunctuation, + node, + /*indentLeading*/ true, + ); } function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) { emitModifiers(node, node.modifiers); - emitTokenWithComment(SyntaxKind.ImportKeyword, node.modifiers ? node.modifiers.end : node.pos, writeKeyword, node); + emitTokenWithComment( + SyntaxKind.ImportKeyword, + node.modifiers ? node.modifiers.end : node.pos, + writeKeyword, + node, + ); writeSpace(); if (node.isTypeOnly) { emitTokenWithComment(SyntaxKind.TypeKeyword, node.pos, writeKeyword, node); @@ -3442,7 +3889,12 @@ namespace ts { function emitImportDeclaration(node: ImportDeclaration) { emitModifiers(node, node.modifiers); - emitTokenWithComment(SyntaxKind.ImportKeyword, node.modifiers ? node.modifiers.end : node.pos, writeKeyword, node); + emitTokenWithComment( + SyntaxKind.ImportKeyword, + node.modifiers ? node.modifiers.end : node.pos, + writeKeyword, + node, + ); writeSpace(); if (node.importClause) { emit(node.importClause); @@ -3498,9 +3950,9 @@ namespace ts { writeSpace(); emitExpression( node.expression, - node.isExportEquals ? - parenthesizer.getParenthesizeRightSideOfBinaryForOperator(SyntaxKind.EqualsToken) : - parenthesizer.parenthesizeExpressionOfExportDefault, + node.isExportEquals + ? parenthesizer.getParenthesizeRightSideOfBinaryForOperator(SyntaxKind.EqualsToken) + : parenthesizer.parenthesizeExpressionOfExportDefault, ); writeTrailingSemicolon(); } @@ -3700,7 +4152,9 @@ namespace ts { function emitJsxExpression(node: JsxExpression) { if (node.expression || (!commentsDisabled && !nodeIsSynthesized(node) && hasCommentsAtPosition(node.pos))) { // preserve empty expressions if they contain comments! - const isMultiline = currentSourceFile && !nodeIsSynthesized(node) && getLineAndCharacterOfPosition(currentSourceFile, node.pos).line !== getLineAndCharacterOfPosition(currentSourceFile, node.end).line; + const isMultiline = currentSourceFile && !nodeIsSynthesized(node) + && getLineAndCharacterOfPosition(currentSourceFile, node.pos).line + !== getLineAndCharacterOfPosition(currentSourceFile, node.end).line; if (isMultiline) { writer.increaseIndent(); } @@ -3741,13 +4195,13 @@ namespace ts { } function emitCaseOrDefaultClauseRest(parentNode: Node, statements: NodeArray, colonPos: number) { - const emitAsSingleStatement = statements.length === 1 && - ( + const emitAsSingleStatement = statements.length === 1 + && ( // treat synthesized nodes as located on the same line for emit purposes - !currentSourceFile || - nodeIsSynthesized(parentNode) || - nodeIsSynthesized(statements[0]) || - rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile) + !currentSourceFile + || nodeIsSynthesized(parentNode) + || nodeIsSynthesized(statements[0]) + || rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile) ); let format = ListFormat.CaseOrDefaultClauseStatements; @@ -3810,7 +4264,10 @@ namespace ts { writeSpace(); writePunctuation("="); writeSpace(); - emitExpression(node.objectAssignmentInitializer, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitExpression( + node.objectAssignmentInitializer, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } } @@ -3827,7 +4284,12 @@ namespace ts { function emitEnumMember(node: EnumMember) { emit(node.name); - emitInitializer(node.initializer, node.name.end, node, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitInitializer( + node.initializer, + node.name.end, + node, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } // @@ -4004,9 +4466,9 @@ namespace ts { const statements = node.statements; // Emit detached comment if there are no prologue directives or if the first node is synthesized. // The synthesized node will have no leading comment so some comments may be missed. - const shouldEmitDetachedComment = statements.length === 0 || - !isPrologueDirective(statements[0]) || - nodeIsSynthesized(statements[0]); + const shouldEmitDetachedComment = statements.length === 0 + || !isPrologueDirective(statements[0]) + || nodeIsSynthesized(statements[0]); if (shouldEmitDetachedComment) { emitBodyWithDetachedComments(node, statements, emitSourceFileWorker); return; @@ -4015,7 +4477,12 @@ namespace ts { } function emitSyntheticTripleSlashReferencesIfNeeded(node: Bundle) { - emitTripleSlashDirectives(!!node.hasNoDefaultLib, node.syntheticFileReferences || [], node.syntheticTypeReferences || [], node.syntheticLibReferences || []); + emitTripleSlashDirectives( + !!node.hasNoDefaultLib, + node.syntheticFileReferences || [], + node.syntheticTypeReferences || [], + node.syntheticLibReferences || [], + ); for (const prepend of node.prepends) { if (isUnparsedSource(prepend) && prepend.syntheticReferences) { for (const ref of prepend.syntheticReferences) { @@ -4027,14 +4494,32 @@ namespace ts { } function emitTripleSlashDirectivesIfNeeded(node: SourceFile) { - if (node.isDeclarationFile) emitTripleSlashDirectives(node.hasNoDefaultLib, node.referencedFiles, node.typeReferenceDirectives, node.libReferenceDirectives); + if (node.isDeclarationFile) { + emitTripleSlashDirectives( + node.hasNoDefaultLib, + node.referencedFiles, + node.typeReferenceDirectives, + node.libReferenceDirectives, + ); + } } - function emitTripleSlashDirectives(hasNoDefaultLib: boolean, files: readonly FileReference[], types: readonly FileReference[], libs: readonly FileReference[]) { + function emitTripleSlashDirectives( + hasNoDefaultLib: boolean, + files: readonly FileReference[], + types: readonly FileReference[], + libs: readonly FileReference[], + ) { if (hasNoDefaultLib) { const pos = writer.getTextPos(); writeComment(`/// `); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.NoDefaultLib }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.NoDefaultLib, + }); + } writeLine(); } if (currentSourceFile && currentSourceFile.moduleName) { @@ -4055,22 +4540,47 @@ namespace ts { for (const directive of files) { const pos = writer.getTextPos(); writeComment(`/// `); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Reference, data: directive.fileName }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.Reference, + data: directive.fileName, + }); + } writeLine(); } for (const directive of types) { const pos = writer.getTextPos(); - const resolutionMode = directive.resolutionMode && directive.resolutionMode !== currentSourceFile?.impliedNodeFormat - ? `resolution-mode="${directive.resolutionMode === ModuleKind.ESNext ? "import" : "require"}"` - : ""; + const resolutionMode = + directive.resolutionMode && directive.resolutionMode !== currentSourceFile?.impliedNodeFormat + ? `resolution-mode="${directive.resolutionMode === ModuleKind.ESNext ? "import" : "require"}"` + : ""; writeComment(`/// `); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: !directive.resolutionMode ? BundleFileSectionKind.Type : directive.resolutionMode === ModuleKind.ESNext ? BundleFileSectionKind.TypeResolutionModeImport : BundleFileSectionKind.TypeResolutionModeRequire, data: directive.fileName }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: !directive.resolutionMode ? BundleFileSectionKind.Type + : directive.resolutionMode === ModuleKind.ESNext + ? BundleFileSectionKind.TypeResolutionModeImport + : BundleFileSectionKind.TypeResolutionModeRequire, + data: directive.fileName, + }); + } writeLine(); } for (const directive of libs) { const pos = writer.getTextPos(); writeComment(`/// `); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Lib, data: directive.fileName }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.Lib, + data: directive.fileName, + }); + } writeLine(); } } @@ -4082,7 +4592,13 @@ namespace ts { emitHelpers(node); const index = findIndex(statements, statement => !isPrologueDirective(statement)); emitTripleSlashDirectivesIfNeeded(node); - emitList(node, statements, ListFormat.MultiLine, /*parenthesizerRule*/ undefined, index === -1 ? statements.length : index); + emitList( + node, + statements, + ListFormat.MultiLine, + /*parenthesizerRule*/ undefined, + index === -1 ? statements.length : index, + ); popNameGenerationScope(node); } @@ -4107,12 +4623,18 @@ namespace ts { * Emits any prologue directives at the start of a Statement list, returning the * number of prologue directives written to the output. */ - function emitPrologueDirectives(statements: readonly Node[], sourceFile?: SourceFile, seenPrologueDirectives?: Set, recordBundleFileSection?: true): number { + function emitPrologueDirectives( + statements: readonly Node[], + sourceFile?: SourceFile, + seenPrologueDirectives?: Set, + recordBundleFileSection?: true, + ): number { let needsToSetSourceFile = !!sourceFile; for (let i = 0; i < statements.length; i++) { const statement = statements[i]; if (isPrologueDirective(statement)) { - const shouldEmitPrologueDirective = seenPrologueDirectives ? !seenPrologueDirectives.has(statement.expression.text) : true; + const shouldEmitPrologueDirective = seenPrologueDirectives + ? !seenPrologueDirectives.has(statement.expression.text) : true; if (shouldEmitPrologueDirective) { if (needsToSetSourceFile) { needsToSetSourceFile = false; @@ -4121,7 +4643,14 @@ namespace ts { writeLine(); const pos = writer.getTextPos(); emit(statement); - if (recordBundleFileSection && bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Prologue, data: statement.expression.text }); + if (recordBundleFileSection && bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.Prologue, + data: statement.expression.text, + }); + } if (seenPrologueDirectives) { seenPrologueDirectives.add(statement.expression.text); } @@ -4142,7 +4671,14 @@ namespace ts { writeLine(); const pos = writer.getTextPos(); emit(prologue); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Prologue, data: prologue.data }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.Prologue, + data: prologue.data, + }); + } if (seenPrologueDirectives) { seenPrologueDirectives.add(prologue.data); } @@ -4160,7 +4696,12 @@ namespace ts { emitUnparsedPrologues((prepend as UnparsedSource).prologues, seenPrologueDirectives); } for (const sourceFile of sourceFileOrBundle.sourceFiles) { - emitPrologueDirectives(sourceFile.statements, sourceFile, seenPrologueDirectives, /*recordBundleFileSection*/ true); + emitPrologueDirectives( + sourceFile.statements, + sourceFile, + seenPrologueDirectives, + /*recordBundleFileSection*/ true, + ); } setSourceFile(undefined); } @@ -4188,7 +4729,13 @@ namespace ts { }); end = end < statement.end ? statement.end : end; } - if (directives) (prologues || (prologues = [])).push({ file: index, text: sourceFile.text.substring(0, end), directives }); + if (directives) { + (prologues || (prologues = [])).push({ + file: index, + text: sourceFile.text.substring(0, end), + directives, + }); + } } return prologues; } @@ -4298,7 +4845,12 @@ namespace ts { } } - function emitInitializer(node: Expression | undefined, equalCommentStartPos: number, container: Node, parenthesizerRule?: (node: Expression) => Expression) { + function emitInitializer( + node: Expression | undefined, + equalCommentStartPos: number, + container: Node, + parenthesizerRule?: (node: Expression) => Expression, + ) { if (node) { writeSpace(); emitTokenWithComment(SyntaxKind.EqualsToken, equalCommentStartPos, writeOperator, container); @@ -4307,7 +4859,12 @@ namespace ts { } } - function emitNodeWithPrefix(prefix: string, prefixWriter: (s: string) => void, node: T | undefined, emit: (node: T) => void) { + function emitNodeWithPrefix( + prefix: string, + prefixWriter: (s: string) => void, + node: T | undefined, + emit: (node: T) => void, + ) { if (node) { prefixWriter(prefix); emit(node); @@ -4321,7 +4878,10 @@ namespace ts { } } - function emitExpressionWithLeadingSpace(node: Expression | undefined, parenthesizerRule?: (node: Expression) => Expression) { + function emitExpressionWithLeadingSpace( + node: Expression | undefined, + parenthesizerRule?: (node: Expression) => Expression, + ) { if (node) { writeSpace(); emitExpression(node, parenthesizerRule); @@ -4361,7 +4921,15 @@ namespace ts { emitList(parentNode, typeArguments, ListFormat.TypeArguments, typeArgumentParenthesizerRuleSelector); } - function emitTypeParameters(parentNode: SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration | ClassDeclaration | ClassExpression, typeParameters: NodeArray | undefined) { + function emitTypeParameters( + parentNode: + | SignatureDeclaration + | InterfaceDeclaration + | TypeAliasDeclaration + | ClassDeclaration + | ClassExpression, + typeParameters: NodeArray | undefined, + ) { if (isFunctionLike(parentNode) && parentNode.typeArguments) { // Quick info uses type arguments in place of type parameters on instantiated signatures return emitTypeArguments(parentNode, parentNode.typeArguments); } @@ -4372,7 +4940,10 @@ namespace ts { emitList(parentNode, parameters, ListFormat.Parameters); } - function canEmitSimpleArrowHead(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray) { + function canEmitSimpleArrowHead( + parentNode: FunctionTypeNode | ArrowFunction, + parameters: NodeArray, + ) { const parameter = singleOrUndefined(parameters); return parameter && parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter @@ -4388,7 +4959,10 @@ namespace ts { && isIdentifier(parameter.name); // parameter name must be identifier } - function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray) { + function emitParametersForArrow( + parentNode: FunctionTypeNode | ArrowFunction, + parameters: NodeArray, + ) { if (canEmitSimpleArrowHead(parentNode, parameters)) { emitList(parentNode, parameters, ListFormat.Parameters & ~ListFormat.Parenthesis); } @@ -4424,15 +4998,37 @@ namespace ts { } } - function emitList(parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { + function emitList( + parentNode: Node | undefined, + children: NodeArray | undefined, + format: ListFormat, + parenthesizerRule?: ParenthesizerRuleOrSelector, + start?: number, + count?: number, + ) { emitNodeList(emit, parentNode, children, format, parenthesizerRule, start, count); } - function emitExpressionList(parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { + function emitExpressionList( + parentNode: Node | undefined, + children: NodeArray | undefined, + format: ListFormat, + parenthesizerRule?: ParenthesizerRuleOrSelector, + start?: number, + count?: number, + ) { emitNodeList(emitExpression, parentNode, children, format, parenthesizerRule, start, count); } - function emitNodeList(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, start = 0, count = children ? children.length - start : 0) { + function emitNodeList( + emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, + parentNode: Node | undefined, + children: NodeArray | undefined, + format: ListFormat, + parenthesizerRule: ParenthesizerRuleOrSelector | undefined, + start = 0, + count = children ? children.length - start : 0, + ) { const isUndefined = children === undefined; if (isUndefined && format & ListFormat.OptionalIfUndefined) { return; @@ -4456,7 +5052,11 @@ namespace ts { if (isEmpty) { // Write a line terminator if the parent node was multi-line - if (format & ListFormat.MultiLine && !(preserveSourceNewlines && (!parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile)))) { + if ( + format & ListFormat.MultiLine + && !(preserveSourceNewlines + && (!parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile))) + ) { writeLine(); } else if (format & ListFormat.SpaceBetweenBraces && !(format & ListFormat.NoSpaceIfEmpty)) { @@ -4464,7 +5064,17 @@ namespace ts { } } else { - emitNodeListItems(emit, parentNode, children, format, parenthesizerRule, start, count, children.hasTrailingComma, children); + emitNodeListItems( + emit, + parentNode, + children, + format, + parenthesizerRule, + start, + count, + children.hasTrailingComma, + children, + ); } onAfterEmitNodeArray?.(children); @@ -4482,7 +5092,17 @@ namespace ts { * * NOTE: You probably don't want to call this directly and should be using `emitList` or `emitExpressionList` instead. */ - function emitNodeListItems(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: readonly Node[], format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, start: number, count: number, hasTrailingComma: boolean, childrenTextRange: TextRange | undefined) { + function emitNodeListItems( + emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, + parentNode: Node | undefined, + children: readonly Node[], + format: ListFormat, + parenthesizerRule: ParenthesizerRuleOrSelector | undefined, + start: number, + count: number, + hasTrailingComma: boolean, + childrenTextRange: TextRange | undefined, + ) { // Write the opening line terminator or leading whitespace. const mayEmitInterveningComments = (format & ListFormat.NoInterveningComments) === 0; let shouldEmitInterveningComments = mayEmitInterveningComments; @@ -4523,14 +5143,20 @@ namespace ts { // a // /* End of parameter a */ -> this comment isn't considered to be trailing comment of parameter "a" due to newline // , - if (format & ListFormat.DelimitersMask && previousSibling.end !== (parentNode ? parentNode.end : -1)) { + if ( + format & ListFormat.DelimitersMask && previousSibling.end !== (parentNode ? parentNode.end : -1) + ) { emitLeadingCommentsOfPosition(previousSibling.end); } writeDelimiter(format); recordBundleFileInternalSectionEnd(previousSourceFileTextKind); // Write either a line terminator or whitespace to separate the elements. - const separatingLineTerminatorCount = getSeparatingLineTerminatorCount(previousSibling, child, format); + const separatingLineTerminatorCount = getSeparatingLineTerminatorCount( + previousSibling, + child, + format, + ); if (separatingLineTerminatorCount > 0) { // If a synthesized node in a single-line list starts on a new // line, we should increase the indent. @@ -4571,7 +5197,8 @@ namespace ts { // Write a trailing comma, if requested. const emitFlags = previousSibling ? getEmitFlags(previousSibling) : 0; const skipTrailingComments = commentsDisabled || !!(emitFlags & EmitFlags.NoTrailingComments); - const emitTrailingComma = hasTrailingComma && (format & ListFormat.AllowTrailingComma) && (format & ListFormat.CommaDelimited); + const emitTrailingComma = hasTrailingComma && (format & ListFormat.AllowTrailingComma) + && (format & ListFormat.CommaDelimited); if (emitTrailingComma) { if (previousSibling && !skipTrailingComments) { emitTokenWithComment(SyntaxKind.CommaToken, previousSibling.end, writePunctuation, previousSibling); @@ -4587,8 +5214,13 @@ namespace ts { // 2 // /* end of element 2 */ // ]; - if (previousSibling && (parentNode ? parentNode.end : -1) !== previousSibling.end && (format & ListFormat.DelimitersMask) && !skipTrailingComments) { - emitLeadingCommentsOfPosition(emitTrailingComma && childrenTextRange?.end ? childrenTextRange.end : previousSibling.end); + if ( + previousSibling && (parentNode ? parentNode.end : -1) !== previousSibling.end + && (format & ListFormat.DelimitersMask) && !skipTrailingComments + ) { + emitLeadingCommentsOfPosition( + emitTrailingComma && childrenTextRange?.end ? childrenTextRange.end : previousSibling.end, + ); } // Decrease the indent, if requested. @@ -4599,7 +5231,12 @@ namespace ts { recordBundleFileInternalSectionEnd(previousSourceFileTextKind); // Write the closing line terminator or closing whitespace. - const closingLineTerminatorCount = getClosingLineTerminatorCount(parentNode, children[start + count - 1], format, childrenTextRange); + const closingLineTerminatorCount = getClosingLineTerminatorCount( + parentNode, + children[start + count - 1], + format, + childrenTextRange, + ); if (closingLineTerminatorCount) { writeLine(closingLineTerminatorCount); } @@ -4759,14 +5396,19 @@ namespace ts { } } - function getLeadingLineTerminatorCount(parentNode: Node | undefined, firstChild: Node | undefined, format: ListFormat): number { + function getLeadingLineTerminatorCount( + parentNode: Node | undefined, + firstChild: Node | undefined, + format: ListFormat, + ): number { if (format & ListFormat.PreserveLines || preserveSourceNewlines) { if (format & ListFormat.PreferNewLine) { return 1; } if (firstChild === undefined) { - return !parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile) ? 0 : 1; + return !parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile) ? 0 + : 1; } if (firstChild.pos === nextListElementPos) { // If this child starts at the beginning of a list item in a parent list, its leading @@ -4791,10 +5433,10 @@ namespace ts { return 0; } if ( - currentSourceFile && parentNode && - !positionIsSynthesized(parentNode.pos) && - !nodeIsSynthesized(firstChild) && - (!firstChild.parent || getOriginalNode(firstChild.parent) === getOriginalNode(parentNode)) + currentSourceFile && parentNode + && !positionIsSynthesized(parentNode.pos) + && !nodeIsSynthesized(firstChild) + && (!firstChild.parent || getOriginalNode(firstChild.parent) === getOriginalNode(parentNode)) ) { if (preserveSourceNewlines) { return getEffectiveLines( @@ -4816,7 +5458,11 @@ namespace ts { return format & ListFormat.MultiLine ? 1 : 0; } - function getSeparatingLineTerminatorCount(previousNode: Node | undefined, nextNode: Node, format: ListFormat): number { + function getSeparatingLineTerminatorCount( + previousNode: Node | undefined, + nextNode: Node, + format: ListFormat, + ): number { if (format & ListFormat.PreserveLines || preserveSourceNewlines) { if (previousNode === undefined || nextNode === undefined) { return 0; @@ -4849,7 +5495,10 @@ namespace ts { // whether new lines are preferred or not. return format & ListFormat.PreferNewLine ? 1 : 0; } - else if (synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format)) { + else if ( + synthesizedNodeStartsOnNewLine(previousNode, format) + || synthesizedNodeStartsOnNewLine(nextNode, format) + ) { return 1; } } @@ -4859,18 +5508,28 @@ namespace ts { return format & ListFormat.MultiLine ? 1 : 0; } - function getClosingLineTerminatorCount(parentNode: Node | undefined, lastChild: Node | undefined, format: ListFormat, childrenTextRange: TextRange | undefined): number { + function getClosingLineTerminatorCount( + parentNode: Node | undefined, + lastChild: Node | undefined, + format: ListFormat, + childrenTextRange: TextRange | undefined, + ): number { if (format & ListFormat.PreserveLines || preserveSourceNewlines) { if (format & ListFormat.PreferNewLine) { return 1; } if (lastChild === undefined) { - return !parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile) ? 0 : 1; + return !parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile) ? 0 + : 1; } - if (currentSourceFile && parentNode && !positionIsSynthesized(parentNode.pos) && !nodeIsSynthesized(lastChild) && (!lastChild.parent || lastChild.parent === parentNode)) { + if ( + currentSourceFile && parentNode && !positionIsSynthesized(parentNode.pos) + && !nodeIsSynthesized(lastChild) && (!lastChild.parent || lastChild.parent === parentNode) + ) { if (preserveSourceNewlines) { - const end = childrenTextRange && !positionIsSynthesized(childrenTextRange.end) ? childrenTextRange.end : lastChild.end; + const end = childrenTextRange && !positionIsSynthesized(childrenTextRange.end) + ? childrenTextRange.end : lastChild.end; return getEffectiveLines( includeComments => getLinesBetweenPositionAndNextNonWhitespaceCharacter( @@ -4918,7 +5577,8 @@ namespace ts { } function writeLineSeparatorsAndIndentBefore(node: Node, parent: Node): boolean { - const leadingNewlines = preserveSourceNewlines && getLeadingLineTerminatorCount(parent, node, ListFormat.None); + const leadingNewlines = preserveSourceNewlines + && getLeadingLineTerminatorCount(parent, node, ListFormat.None); if (leadingNewlines) { writeLinesAndIndent(leadingNewlines, /*writeSpaceIfNotIndenting*/ false); } @@ -4926,7 +5586,8 @@ namespace ts { } function writeLineSeparatorsAfter(node: Node, parent: Node) { - const trailingNewlines = preserveSourceNewlines && getClosingLineTerminatorCount(parent, node, ListFormat.None, /*childrenTextRange*/ undefined); + const trailingNewlines = preserveSourceNewlines + && getClosingLineTerminatorCount(parent, node, ListFormat.None, /*childrenTextRange*/ undefined); if (trailingNewlines) { writeLine(trailingNewlines); } @@ -4959,7 +5620,10 @@ namespace ts { return 1; } - if (currentSourceFile && !nodeIsSynthesized(parent) && !nodeIsSynthesized(node1) && !nodeIsSynthesized(node2)) { + if ( + currentSourceFile && !nodeIsSynthesized(parent) && !nodeIsSynthesized(node1) + && !nodeIsSynthesized(node2) + ) { if (preserveSourceNewlines) { return getEffectiveLines( includeComments => @@ -4990,7 +5654,10 @@ namespace ts { return node; } - function getTextOfNode(node: Identifier | PrivateIdentifier | LiteralExpression, includeTrivia?: boolean): string { + function getTextOfNode( + node: Identifier | PrivateIdentifier | LiteralExpression, + includeTrivia?: boolean, + ): string { if (isGeneratedIdentifier(node) || isGeneratedPrivateIdentifier(node)) { return generateName(node); } @@ -5013,14 +5680,22 @@ namespace ts { return getSourceTextOfNodeFromSourceFile(sourceFile, node, includeTrivia); } - function getLiteralTextOfNode(node: LiteralLikeNode, neverAsciiEscape: boolean | undefined, jsxAttributeEscape: boolean): string { + function getLiteralTextOfNode( + node: LiteralLikeNode, + neverAsciiEscape: boolean | undefined, + jsxAttributeEscape: boolean, + ): string { if (node.kind === SyntaxKind.StringLiteral && (node as StringLiteral).textSourceNode) { const textSourceNode = (node as StringLiteral).textSourceNode!; - if (isIdentifier(textSourceNode) || isPrivateIdentifier(textSourceNode) || isNumericLiteral(textSourceNode)) { + if ( + isIdentifier(textSourceNode) || isPrivateIdentifier(textSourceNode) + || isNumericLiteral(textSourceNode) + ) { const text = isNumericLiteral(textSourceNode) ? textSourceNode.text : getTextOfNode(textSourceNode); - return jsxAttributeEscape ? `"${escapeJsxAttributeString(text)}"` : - neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? `"${escapeString(text)}"` : - `"${escapeNonAsciiString(text)}"`; + return jsxAttributeEscape ? `"${escapeJsxAttributeString(text)}"` + : neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) + ? `"${escapeString(text)}"` + : `"${escapeNonAsciiString(text)}"`; } else { return getLiteralTextOfNode(textSourceNode, neverAsciiEscape, jsxAttributeEscape); @@ -5030,7 +5705,8 @@ namespace ts { const flags = (neverAsciiEscape ? GetLiteralTextFlags.NeverAsciiEscape : 0) | (jsxAttributeEscape ? GetLiteralTextFlags.JsxAttributeEscape : 0) | (printerOptions.terminateUnterminatedLiterals ? GetLiteralTextFlags.TerminateUnterminatedLiterals : 0) - | (printerOptions.target && printerOptions.target === ScriptTarget.ESNext ? GetLiteralTextFlags.AllowNumericSeparator : 0); + | (printerOptions.target && printerOptions.target === ScriptTarget.ESNext + ? GetLiteralTextFlags.AllowNumericSeparator : 0); return getLiteralText(node, currentSourceFile, flags); } @@ -5189,19 +5865,39 @@ namespace ts { if ((name.autoGenerateFlags & GeneratedIdentifierFlags.KindMask) === GeneratedIdentifierFlags.Node) { // Node names generate unique names based on their original node // and are cached based on that node's id. - return generateNameCached(getNodeForGeneratedName(name), isPrivateIdentifier(name), name.autoGenerateFlags, name.autoGeneratePrefix, name.autoGenerateSuffix); + return generateNameCached( + getNodeForGeneratedName(name), + isPrivateIdentifier(name), + name.autoGenerateFlags, + name.autoGeneratePrefix, + name.autoGenerateSuffix, + ); } else { // Auto, Loop, and Unique names are cached based on their unique // autoGenerateId. const autoGenerateId = name.autoGenerateId!; - return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = makeName(name)); + return autoGeneratedIdToGeneratedName[autoGenerateId] + || (autoGeneratedIdToGeneratedName[autoGenerateId] = makeName(name)); } } - function generateNameCached(node: Node, privateName: boolean, flags?: GeneratedIdentifierFlags, prefix?: string | GeneratedNamePart, suffix?: string) { + function generateNameCached( + node: Node, + privateName: boolean, + flags?: GeneratedIdentifierFlags, + prefix?: string | GeneratedNamePart, + suffix?: string, + ) { const nodeId = getNodeId(node); - return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = generateNameForNode(node, privateName, flags ?? GeneratedIdentifierFlags.None, formatGeneratedNamePart(prefix, generateName), formatGeneratedNamePart(suffix))); + return nodeIdToGeneratedName[nodeId] + || (nodeIdToGeneratedName[nodeId] = generateNameForNode( + node, + privateName, + flags ?? GeneratedIdentifierFlags.None, + formatGeneratedNamePart(prefix, generateName), + formatGeneratedNamePart(suffix), + )); } /** @@ -5268,7 +5964,13 @@ namespace ts { * TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name. * Note that names generated by makeTempVariableName and makeUniqueName will never conflict. */ - function makeTempVariableName(flags: TempFlags, reservedInNestedScopes: boolean, privateName: boolean, prefix: string, suffix: string): string { + function makeTempVariableName( + flags: TempFlags, + reservedInNestedScopes: boolean, + privateName: boolean, + prefix: string, + suffix: string, + ): string { if (prefix.length > 0 && prefix.charCodeAt(0) === CharacterCodes.hash) { prefix = prefix.slice(1); } @@ -5317,7 +6019,15 @@ namespace ts { * makeUniqueName are guaranteed to never conflict. * If `optimistic` is set, the first instance will use 'baseName' verbatim instead of 'baseName_1' */ - function makeUniqueName(baseName: string, checkFn: (name: string) => boolean = isUniqueName, optimistic: boolean, scoped: boolean, privateName: boolean, prefix: string, suffix: string): string { + function makeUniqueName( + baseName: string, + checkFn: (name: string) => boolean = isUniqueName, + optimistic: boolean, + scoped: boolean, + privateName: boolean, + prefix: string, + suffix: string, + ): string { if (baseName.length > 0 && baseName.charCodeAt(0) === CharacterCodes.hash) { baseName = baseName.slice(1); } @@ -5357,7 +6067,15 @@ namespace ts { } function makeFileLevelOptimisticUniqueName(name: string) { - return makeUniqueName(name, isFileLevelUniqueName, /*optimistic*/ true, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + return makeUniqueName( + name, + isFileLevelUniqueName, + /*optimistic*/ true, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } /** @@ -5366,7 +6084,16 @@ namespace ts { function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { const name = getTextOfNode(node.name); // Use module/enum name itself if it is unique, otherwise make a unique variation - return isUniqueLocalName(name, node) ? name : makeUniqueName(name, isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + return isUniqueLocalName(name, node) ? name + : makeUniqueName( + name, + isUniqueName, + /*optimistic*/ false, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } /** @@ -5374,26 +6101,55 @@ namespace ts { */ function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { const expr = getExternalModuleName(node)!; // TODO: GH#18217 - const baseName = isStringLiteral(expr) ? - makeIdentifierFromModuleName(expr.text) : "module"; - return makeUniqueName(baseName, isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + const baseName = isStringLiteral(expr) + ? makeIdentifierFromModuleName(expr.text) : "module"; + return makeUniqueName( + baseName, + isUniqueName, + /*optimistic*/ false, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } /** * Generates a unique name for a default export. */ function generateNameForExportDefault() { - return makeUniqueName("default", isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + return makeUniqueName( + "default", + isUniqueName, + /*optimistic*/ false, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } /** * Generates a unique name for a class expression. */ function generateNameForClassExpression() { - return makeUniqueName("class", isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + return makeUniqueName( + "class", + isUniqueName, + /*optimistic*/ false, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } - function generateNameForMethodOrAccessor(node: MethodDeclaration | AccessorDeclaration, privateName: boolean, prefix: string, suffix: string) { + function generateNameForMethodOrAccessor( + node: MethodDeclaration | AccessorDeclaration, + privateName: boolean, + prefix: string, + suffix: string, + ) { if (isIdentifier(node.name)) { return generateNameCached(node.name, privateName); } @@ -5403,7 +6159,13 @@ namespace ts { /** * Generates a unique name from a node. */ - function generateNameForNode(node: Node, privateName: boolean, flags: GeneratedIdentifierFlags, prefix: string, suffix: string): string { + function generateNameForNode( + node: Node, + privateName: boolean, + flags: GeneratedIdentifierFlags, + prefix: string, + suffix: string, + ): string { switch (node.kind) { case SyntaxKind.Identifier: case SyntaxKind.PrivateIdentifier: @@ -5435,11 +6197,28 @@ namespace ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return generateNameForMethodOrAccessor(node as MethodDeclaration | AccessorDeclaration, privateName, prefix, suffix); + return generateNameForMethodOrAccessor( + node as MethodDeclaration | AccessorDeclaration, + privateName, + prefix, + suffix, + ); case SyntaxKind.ComputedPropertyName: - return makeTempVariableName(TempFlags.Auto, /*reserveInNestedScopes*/ true, privateName, prefix, suffix); + return makeTempVariableName( + TempFlags.Auto, + /*reserveInNestedScopes*/ true, + privateName, + prefix, + suffix, + ); default: - return makeTempVariableName(TempFlags.Auto, /*reserveInNestedScopes*/ false, privateName, prefix, suffix); + return makeTempVariableName( + TempFlags.Auto, + /*reserveInNestedScopes*/ false, + privateName, + prefix, + suffix, + ); } } @@ -5451,14 +6230,27 @@ namespace ts { const suffix = formatGeneratedNamePart(name.autoGenerateSuffix); switch (name.autoGenerateFlags & GeneratedIdentifierFlags.KindMask) { case GeneratedIdentifierFlags.Auto: - return makeTempVariableName(TempFlags.Auto, !!(name.autoGenerateFlags & GeneratedIdentifierFlags.ReservedInNestedScopes), isPrivateIdentifier(name), prefix, suffix); + return makeTempVariableName( + TempFlags.Auto, + !!(name.autoGenerateFlags & GeneratedIdentifierFlags.ReservedInNestedScopes), + isPrivateIdentifier(name), + prefix, + suffix, + ); case GeneratedIdentifierFlags.Loop: Debug.assertNode(name, isIdentifier); - return makeTempVariableName(TempFlags._i, !!(name.autoGenerateFlags & GeneratedIdentifierFlags.ReservedInNestedScopes), /*privateName*/ false, prefix, suffix); + return makeTempVariableName( + TempFlags._i, + !!(name.autoGenerateFlags & GeneratedIdentifierFlags.ReservedInNestedScopes), + /*privateName*/ false, + prefix, + suffix, + ); case GeneratedIdentifierFlags.Unique: return makeUniqueName( idText(name), - (name.autoGenerateFlags & GeneratedIdentifierFlags.FileLevel) ? isFileLevelUniqueName : isUniqueName, + (name.autoGenerateFlags & GeneratedIdentifierFlags.FileLevel) ? isFileLevelUniqueName + : isUniqueName, !!(name.autoGenerateFlags & GeneratedIdentifierFlags.Optimistic), !!(name.autoGenerateFlags & GeneratedIdentifierFlags.ReservedInNestedScopes), isPrivateIdentifier(name), @@ -5467,7 +6259,15 @@ namespace ts { ); } - return Debug.fail(`Unsupported GeneratedIdentifierKind: ${Debug.formatEnum(name.autoGenerateFlags & GeneratedIdentifierFlags.KindMask, (ts as any).GeneratedIdentifierFlags, /*isFlags*/ true)}.`); + return Debug.fail( + `Unsupported GeneratedIdentifierKind: ${ + Debug.formatEnum( + name.autoGenerateFlags & GeneratedIdentifierFlags.KindMask, + (ts as any).GeneratedIdentifierFlags, + /*isFlags*/ true, + ) + }.`, + ); } // Comments @@ -5493,7 +6293,12 @@ namespace ts { } } - function emitCommentsAfterNode(node: Node, savedContainerPos: number, savedContainerEnd: number, savedDeclarationListContainerEnd: number) { + function emitCommentsAfterNode( + node: Node, + savedContainerPos: number, + savedContainerEnd: number, + savedDeclarationListContainerEnd: number, + ) { const emitFlags = getEmitFlags(node); const commentRange = getCommentRange(node); @@ -5501,10 +6306,26 @@ namespace ts { if (emitFlags & EmitFlags.NoNestedComments) { commentsDisabled = false; } - emitTrailingCommentsOfNode(node, emitFlags, commentRange.pos, commentRange.end, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); + emitTrailingCommentsOfNode( + node, + emitFlags, + commentRange.pos, + commentRange.end, + savedContainerPos, + savedContainerEnd, + savedDeclarationListContainerEnd, + ); const typeNode = getTypeNode(node); if (typeNode) { - emitTrailingCommentsOfNode(node, emitFlags, typeNode.pos, typeNode.end, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); + emitTrailingCommentsOfNode( + node, + emitFlags, + typeNode.pos, + typeNode.end, + savedContainerPos, + savedContainerEnd, + savedDeclarationListContainerEnd, + ); } } @@ -5514,8 +6335,10 @@ namespace ts { // We have to explicitly check that the node is JsxText because if the compilerOptions.jsx is "preserve" we will not do any transformation. // It is expensive to walk entire tree just to set one kind of node to have no comments. - const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0 || node.kind === SyntaxKind.JsxText; - const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 || node.kind === SyntaxKind.JsxText; + const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0 + || node.kind === SyntaxKind.JsxText; + const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 + || node.kind === SyntaxKind.JsxText; // Save current container state on the stack. if ((pos > 0 || end > 0) && pos !== end) { @@ -5545,9 +6368,18 @@ namespace ts { exitComment(); } - function emitTrailingCommentsOfNode(node: Node, emitFlags: EmitFlags, pos: number, end: number, savedContainerPos: number, savedContainerEnd: number, savedDeclarationListContainerEnd: number) { + function emitTrailingCommentsOfNode( + node: Node, + emitFlags: EmitFlags, + pos: number, + end: number, + savedContainerPos: number, + savedContainerEnd: number, + savedDeclarationListContainerEnd: number, + ) { enterComment(); - const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 || node.kind === SyntaxKind.JsxText; + const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 + || node.kind === SyntaxKind.JsxText; forEach(getSyntheticTrailingComments(node), emitTrailingSynthesizedComment); if ((pos > 0 || end > 0) && pos !== end) { // Restore previous container state. @@ -5599,12 +6431,17 @@ namespace ts { : `//${comment.text}`; } - function emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void) { + function emitBodyWithDetachedComments( + node: Node, + detachedRange: TextRange, + emitCallback: (node: Node) => void, + ) { enterComment(); const { pos, end } = detachedRange; const emitFlags = getEmitFlags(node); const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0; - const skipTrailingComments = commentsDisabled || end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0; + const skipTrailingComments = commentsDisabled || end < 0 + || (emitFlags & EmitFlags.NoTrailingComments) !== 0; if (!skipLeadingComments) { emitDetachedCommentsAndUpdateCommentsInfo(detachedRange); } @@ -5650,7 +6487,8 @@ namespace ts { const parentNodeArray = getContainingNodeArray(previousNode); const prevNodeIndex = parentNodeArray?.indexOf(previousNode); - return prevNodeIndex !== undefined && prevNodeIndex > -1 && parentNodeArray!.indexOf(nextNode) === prevNodeIndex + 1; + return prevNodeIndex !== undefined && prevNodeIndex > -1 + && parentNodeArray!.indexOf(nextNode) === prevNodeIndex + 1; } function emitLeadingComments(pos: number, isEmittedNode: boolean) { @@ -5677,13 +6515,25 @@ namespace ts { } } - function emitTripleSlashLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) { + function emitTripleSlashLeadingComment( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) { if (isTripleSlashComment(commentPos, commentEnd)) { emitLeadingComment(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos); } } - function emitNonTripleSlashLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) { + function emitNonTripleSlashLeadingComment( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) { if (!isTripleSlashComment(commentPos, commentEnd)) { emitLeadingComment(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos); } @@ -5696,7 +6546,13 @@ namespace ts { return true; } - function emitLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) { + function emitLeadingComment( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) { if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return; if (!hasWrittenComment) { emitNewLineBeforeLeadingCommentOfPosition(getCurrentLineMap(), writer, rangePos, commentPos); @@ -5728,7 +6584,12 @@ namespace ts { forEachTrailingCommentToEmit(pos, emitTrailingComment); } - function emitTrailingComment(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) { + function emitTrailingComment( + commentPos: number, + commentEnd: number, + _kind: SyntaxKind, + hasTrailingNewLine: boolean, + ) { if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return; // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment2*/ if (!writer.isAtStartOfLine()) { @@ -5749,7 +6610,11 @@ namespace ts { return; } enterComment(); - forEachTrailingCommentToEmit(pos, prefixSpace ? emitTrailingComment : forceNoNewline ? emitTrailingCommentOfPositionNoNewline : emitTrailingCommentOfPosition); + forEachTrailingCommentToEmit( + pos, + prefixSpace ? emitTrailingComment + : forceNoNewline ? emitTrailingCommentOfPositionNoNewline : emitTrailingCommentOfPosition, + ); exitComment(); } @@ -5766,7 +6631,12 @@ namespace ts { } } - function emitTrailingCommentOfPosition(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) { + function emitTrailingCommentOfPosition( + commentPos: number, + commentEnd: number, + _kind: SyntaxKind, + hasTrailingNewLine: boolean, + ) { if (!currentSourceFile) return; // trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space @@ -5782,7 +6652,16 @@ namespace ts { } } - function forEachLeadingCommentToEmit(pos: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) { + function forEachLeadingCommentToEmit( + pos: number, + cb: ( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) => void, + ) { // Emit the leading comments only if the container's pos doesn't match because the container should take care of emitting these comments if (currentSourceFile && (containerPos === -1 || pos !== containerPos)) { if (hasDetachedComments(pos)) { @@ -5794,9 +6673,15 @@ namespace ts { } } - function forEachTrailingCommentToEmit(end: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void) { + function forEachTrailingCommentToEmit( + end: number, + cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void, + ) { // Emit the trailing comments only if the container's end doesn't match because the container should take care of emitting these comments - if (currentSourceFile && (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd))) { + if ( + currentSourceFile + && (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd)) + ) { forEachTrailingCommentRange(currentSourceFile.text, end, cb); } } @@ -5805,7 +6690,15 @@ namespace ts { return detachedCommentsInfo !== undefined && last(detachedCommentsInfo).nodePos === pos; } - function forEachLeadingCommentWithoutDetachedComments(cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) { + function forEachLeadingCommentWithoutDetachedComments( + cb: ( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) => void, + ) { if (!currentSourceFile) return; // get the leading comments from detachedPos const pos = last(detachedCommentsInfo!).detachedCommentEndPos; @@ -5820,7 +6713,16 @@ namespace ts { } function emitDetachedCommentsAndUpdateCommentsInfo(range: TextRange) { - const currentDetachedCommentInfo = currentSourceFile && emitDetachedComments(currentSourceFile.text, getCurrentLineMap(), writer, emitComment, range, newLine, commentsDisabled); + const currentDetachedCommentInfo = currentSourceFile + && emitDetachedComments( + currentSourceFile.text, + getCurrentLineMap(), + writer, + emitComment, + range, + newLine, + commentsDisabled, + ); if (currentDetachedCommentInfo) { if (detachedCommentsInfo) { detachedCommentsInfo.push(currentDetachedCommentInfo); @@ -5831,7 +6733,14 @@ namespace ts { } } - function emitComment(text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) { + function emitComment( + text: string, + lineMap: number[], + writer: EmitTextWriter, + commentPos: number, + commentEnd: number, + newLine: string, + ) { if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return; emitPos(commentPos); writeCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine); @@ -5844,7 +6753,8 @@ namespace ts { * @return true if the comment is a triple-slash comment else false */ function isTripleSlashComment(commentPos: number, commentEnd: number) { - return !!currentSourceFile && isRecognizedTripleSlashComment(currentSourceFile.text, commentPos, commentEnd); + return !!currentSourceFile + && isRecognizedTripleSlashComment(currentSourceFile.text, commentPos, commentEnd); } // Source Maps @@ -5889,7 +6799,10 @@ namespace ts { && (emitFlags & EmitFlags.NoLeadingSourceMap) === 0 && sourceMapRange.pos >= 0 ) { - emitSourcePos(sourceMapRange.source || sourceMapSource, skipSourceTrivia(source, sourceMapRange.pos)); + emitSourcePos( + sourceMapRange.source || sourceMapSource, + skipSourceTrivia(source, sourceMapRange.pos), + ); } if (emitFlags & EmitFlags.NoNestedSourceMaps) { sourceMapsDisabled = true; @@ -5936,7 +6849,10 @@ namespace ts { return; } - const { line: sourceLine, character: sourceCharacter } = getLineAndCharacterOfPosition(sourceMapSource, pos); + const { line: sourceLine, character: sourceCharacter } = getLineAndCharacterOfPosition( + sourceMapSource, + pos, + ); sourceMapGenerator!.addMapping( writer.getLine(), writer.getColumn(), @@ -5968,7 +6884,13 @@ namespace ts { * @param tokenStartPos The start pos of the token. * @param emitCallback The callback used to emit the token. */ - function emitTokenWithSourceMap(node: Node | undefined, token: SyntaxKind, writer: (s: string) => void, tokenPos: number, emitCallback: (token: SyntaxKind, writer: (s: string) => void, tokenStartPos: number) => number) { + function emitTokenWithSourceMap( + node: Node | undefined, + token: SyntaxKind, + writer: (s: string) => void, + tokenPos: number, + emitCallback: (token: SyntaxKind, writer: (s: string) => void, tokenStartPos: number) => number, + ) { if (sourceMapsDisabled || node && isInJsonFile(node)) { return emitCallback(token, writer, tokenPos); } @@ -6062,21 +6984,44 @@ namespace ts { type ParenthesizerRuleOrSelector = OrdinalParentheizerRuleSelector | ParenthesizerRule; - function emitListItemNoParenthesizer(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, _parenthesizerRule: ParenthesizerRuleOrSelector | undefined, _index: number) { + function emitListItemNoParenthesizer( + node: Node, + emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, + _parenthesizerRule: ParenthesizerRuleOrSelector | undefined, + _index: number, + ) { emit(node); } - function emitListItemWithParenthesizerRuleSelector(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRuleSelector: OrdinalParentheizerRuleSelector, index: number) { + function emitListItemWithParenthesizerRuleSelector( + node: Node, + emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, + parenthesizerRuleSelector: OrdinalParentheizerRuleSelector, + index: number, + ) { emit(node, parenthesizerRuleSelector.select(index)); } - function emitListItemWithParenthesizerRule(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: ParenthesizerRule | undefined, _index: number) { + function emitListItemWithParenthesizerRule( + node: Node, + emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, + parenthesizerRule: ParenthesizerRule | undefined, + _index: number, + ) { emit(node, parenthesizerRule); } - function getEmitListItem | undefined>(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R): (node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R, index: number) => void { - return emit.length === 1 ? emitListItemNoParenthesizer : - typeof parenthesizerRule === "object" ? emitListItemWithParenthesizerRuleSelector : - emitListItemWithParenthesizerRule; + function getEmitListItem | undefined>( + emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, + parenthesizerRule: R, + ): ( + node: Node, + emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, + parenthesizerRule: R, + index: number, + ) => void { + return emit.length === 1 ? emitListItemNoParenthesizer + : typeof parenthesizerRule === "object" ? emitListItemWithParenthesizerRuleSelector + : emitListItemWithParenthesizerRule; } } diff --git a/src/compiler/factory/baseNodeFactory.ts b/src/compiler/factory/baseNodeFactory.ts index 73c4c20ac952f..b1ed10dabe517 100644 --- a/src/compiler/factory/baseNodeFactory.ts +++ b/src/compiler/factory/baseNodeFactory.ts @@ -34,23 +34,44 @@ namespace ts { }; function createBaseSourceFileNode(kind: SyntaxKind): Node { - return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } function createBaseIdentifierNode(kind: SyntaxKind): Node { - return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } function createBasePrivateIdentifierNode(kind: SyntaxKind): Node { - return new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (PrivateIdentifierConstructor + || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } function createBaseTokenNode(kind: SyntaxKind): Node { - return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } function createBaseNode(kind: SyntaxKind): Node { - return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } } } diff --git a/src/compiler/factory/emitHelpers.ts b/src/compiler/factory/emitHelpers.ts index a74412e254437..9159210fd0b60 100644 --- a/src/compiler/factory/emitHelpers.ts +++ b/src/compiler/factory/emitHelpers.ts @@ -3,7 +3,12 @@ namespace ts { export interface EmitHelperFactory { getUnscopedHelperName(name: string): Identifier; // TypeScript Helpers - createDecorateHelper(decoratorExpressions: readonly Expression[], target: Expression, memberName?: Expression, descriptor?: Expression): Expression; + createDecorateHelper( + decoratorExpressions: readonly Expression[], + target: Expression, + memberName?: Expression, + descriptor?: Expression, + ): Expression; createMetadataHelper(metadataKey: string, metadataValue: Expression): Expression; createParamHelper(expression: Expression, parameterOffset: number): Expression; // ES2018 Helpers @@ -13,9 +18,19 @@ namespace ts { createAsyncDelegatorHelper(expression: Expression): Expression; createAsyncValuesHelper(expression: Expression): Expression; // ES2018 Destructuring Helpers - createRestHelper(value: Expression, elements: readonly BindingOrAssignmentElement[], computedTempVariables: readonly Expression[] | undefined, location: TextRange): Expression; + createRestHelper( + value: Expression, + elements: readonly BindingOrAssignmentElement[], + computedTempVariables: readonly Expression[] | undefined, + location: TextRange, + ): Expression; // ES2017 Helpers - createAwaiterHelper(hasLexicalThis: boolean, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression | undefined, body: Block): Expression; + createAwaiterHelper( + hasLexicalThis: boolean, + hasLexicalArguments: boolean, + promiseConstructor: EntityName | Expression | undefined, + body: Block, + ): Expression; // ES2015 Helpers createExtendsHelper(name: Identifier): Expression; createTemplateObjectHelper(cooked: ArrayLiteralExpression, raw: ArrayLiteralExpression): Expression; @@ -26,14 +41,29 @@ namespace ts { // ES2015 Generator Helpers createGeneratorHelper(body: FunctionExpression): Expression; // ES Module Helpers - createCreateBindingHelper(module: Expression, inputName: Expression, outputName: Expression | undefined): Expression; + createCreateBindingHelper( + module: Expression, + inputName: Expression, + outputName: Expression | undefined, + ): Expression; createImportStarHelper(expression: Expression): Expression; createImportStarCallbackHelper(): Expression; createImportDefaultHelper(expression: Expression): Expression; createExportStarHelper(moduleExpression: Expression, exportsExpression?: Expression): Expression; // Class Fields Helpers - createClassPrivateFieldGetHelper(receiver: Expression, state: Identifier, kind: PrivateIdentifierKind, f: Identifier | undefined): Expression; - createClassPrivateFieldSetHelper(receiver: Expression, state: Identifier, value: Expression, kind: PrivateIdentifierKind, f: Identifier | undefined): Expression; + createClassPrivateFieldGetHelper( + receiver: Expression, + state: Identifier, + kind: PrivateIdentifierKind, + f: Identifier | undefined, + ): Expression; + createClassPrivateFieldSetHelper( + receiver: Expression, + state: Identifier, + value: Expression, + kind: PrivateIdentifierKind, + f: Identifier | undefined, + ): Expression; createClassPrivateFieldInHelper(state: Identifier, receiver: Expression): Expression; } @@ -88,7 +118,12 @@ namespace ts { // TypeScript Helpers - function createDecorateHelper(decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression) { + function createDecorateHelper( + decoratorExpressions: Expression[], + target: Expression, + memberName?: Expression, + descriptor?: Expression, + ) { context.requestEmitHelper(decorateHelper); const argumentsArray: Expression[] = []; @@ -139,7 +174,11 @@ namespace ts { function createAssignHelper(attributesSegments: Expression[]) { if (getEmitScriptTarget(context.getCompilerOptions()) >= ScriptTarget.ES2015) { - return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("Object"), "assign"), /*typeArguments*/ undefined, attributesSegments); + return factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier("Object"), "assign"), + /*typeArguments*/ undefined, + attributesSegments, + ); } context.requestEmitHelper(assignHelper); return factory.createCallExpression( @@ -151,7 +190,9 @@ namespace ts { function createAwaitHelper(expression: Expression) { context.requestEmitHelper(awaitHelper); - return factory.createCallExpression(getUnscopedHelperName("__await"), /*typeArguments*/ undefined, [expression]); + return factory.createCallExpression(getUnscopedHelperName("__await"), /*typeArguments*/ undefined, [ + expression, + ]); } function createAsyncGeneratorHelper(generatorFunc: FunctionExpression, hasLexicalThis: boolean) { @@ -159,7 +200,8 @@ namespace ts { context.requestEmitHelper(asyncGeneratorHelper); // Mark this node as originally an async function - (generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody | EmitFlags.ReuseTempVariableScope; + (generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody + | EmitFlags.ReuseTempVariableScope; return factory.createCallExpression( getUnscopedHelperName("__asyncGenerator"), @@ -196,7 +238,12 @@ namespace ts { /** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement * `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);` */ - function createRestHelper(value: Expression, elements: readonly BindingOrAssignmentElement[], computedTempVariables: readonly Expression[] | undefined, location: TextRange): Expression { + function createRestHelper( + value: Expression, + elements: readonly BindingOrAssignmentElement[], + computedTempVariables: readonly Expression[] | undefined, + location: TextRange, + ): Expression { context.requestEmitHelper(restHelper); const propertyNames: Expression[] = []; let computedTempVariableOffset = 0; @@ -204,7 +251,10 @@ namespace ts { const propertyName = getPropertyNameOfBindingOrAssignmentElement(elements[i]); if (propertyName) { if (isComputedPropertyName(propertyName)) { - Debug.assertIsDefined(computedTempVariables, "Encountered computed property name but 'computedTempVariables' argument was not provided."); + Debug.assertIsDefined( + computedTempVariables, + "Encountered computed property name but 'computedTempVariables' argument was not provided.", + ); const temp = computedTempVariables[computedTempVariableOffset]; computedTempVariableOffset++; // typeof _tmp === "symbol" ? _tmp : _tmp + "" @@ -238,7 +288,12 @@ namespace ts { // ES2017 Helpers - function createAwaiterHelper(hasLexicalThis: boolean, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression | undefined, body: Block) { + function createAwaiterHelper( + hasLexicalThis: boolean, + hasLexicalArguments: boolean, + promiseConstructor: EntityName | Expression | undefined, + body: Block, + ) { context.requestEmitHelper(awaiterHelper); const generatorFunc = factory.createFunctionExpression( @@ -252,7 +307,8 @@ namespace ts { ); // Mark this node as originally an async function - (generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody | EmitFlags.ReuseTempVariableScope; + (generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody + | EmitFlags.ReuseTempVariableScope; return factory.createCallExpression( getUnscopedHelperName("__awaiter"), @@ -260,7 +316,8 @@ namespace ts { [ hasLexicalThis ? factory.createThis() : factory.createVoidZero(), hasLexicalArguments ? factory.createIdentifier("arguments") : factory.createVoidZero(), - promiseConstructor ? createExpressionFromEntityName(factory, promiseConstructor) : factory.createVoidZero(), + promiseConstructor ? createExpressionFromEntityName(factory, promiseConstructor) + : factory.createVoidZero(), generatorFunc, ], ); @@ -273,7 +330,13 @@ namespace ts { return factory.createCallExpression( getUnscopedHelperName("__extends"), /*typeArguments*/ undefined, - [name, factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)], + [ + name, + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + ], ); } @@ -330,7 +393,11 @@ namespace ts { // ES Module Helpers - function createCreateBindingHelper(module: Expression, inputName: Expression, outputName: Expression | undefined) { + function createCreateBindingHelper( + module: Expression, + inputName: Expression, + outputName: Expression | undefined, + ) { context.requestEmitHelper(createBindingHelper); return factory.createCallExpression( getUnscopedHelperName("__createBinding"), @@ -362,7 +429,10 @@ namespace ts { ); } - function createExportStarHelper(moduleExpression: Expression, exportsExpression: Expression = factory.createIdentifier("exports")) { + function createExportStarHelper( + moduleExpression: Expression, + exportsExpression: Expression = factory.createIdentifier("exports"), + ) { context.requestEmitHelper(exportStarHelper); context.requestEmitHelper(createBindingHelper); return factory.createCallExpression( @@ -374,7 +444,12 @@ namespace ts { // Class Fields Helpers - function createClassPrivateFieldGetHelper(receiver: Expression, state: Identifier, kind: PrivateIdentifierKind, f: Identifier | undefined) { + function createClassPrivateFieldGetHelper( + receiver: Expression, + state: Identifier, + kind: PrivateIdentifierKind, + f: Identifier | undefined, + ) { context.requestEmitHelper(classPrivateFieldGetHelper); let args; if (!f) { @@ -383,10 +458,20 @@ namespace ts { else { args = [receiver, state, factory.createStringLiteral(kind), f]; } - return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldGet"), /*typeArguments*/ undefined, args); + return factory.createCallExpression( + getUnscopedHelperName("__classPrivateFieldGet"), + /*typeArguments*/ undefined, + args, + ); } - function createClassPrivateFieldSetHelper(receiver: Expression, state: Identifier, value: Expression, kind: PrivateIdentifierKind, f: Identifier | undefined) { + function createClassPrivateFieldSetHelper( + receiver: Expression, + state: Identifier, + value: Expression, + kind: PrivateIdentifierKind, + f: Identifier | undefined, + ) { context.requestEmitHelper(classPrivateFieldSetHelper); let args; if (!f) { @@ -395,12 +480,20 @@ namespace ts { else { args = [receiver, state, value, factory.createStringLiteral(kind), f]; } - return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldSet"), /*typeArguments*/ undefined, args); + return factory.createCallExpression( + getUnscopedHelperName("__classPrivateFieldSet"), + /*typeArguments*/ undefined, + args, + ); } function createClassPrivateFieldInHelper(state: Identifier, receiver: Expression) { context.requestEmitHelper(classPrivateFieldInHelper); - return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldIn"), /* typeArguments*/ undefined, [state, receiver]); + return factory.createCallExpression( + getUnscopedHelperName("__classPrivateFieldIn"), + /* typeArguments*/ undefined, + [state, receiver], + ); } } diff --git a/src/compiler/factory/emitNode.ts b/src/compiler/factory/emitNode.ts index 19ebfd53ba2ba..2a25d25b72170 100644 --- a/src/compiler/factory/emitNode.ts +++ b/src/compiler/factory/emitNode.ts @@ -14,7 +14,8 @@ namespace ts { return node.emitNode = { annotatedNodes: [node] } as EmitNode; } - const sourceFile = getSourceFileOfNode(getParseTreeNode(getSourceFileOfNode(node))) ?? Debug.fail("Could not determine parsed source file."); + const sourceFile = getSourceFileOfNode(getParseTreeNode(getSourceFileOfNode(node))) + ?? Debug.fail("Could not determine parsed source file."); getOrCreateEmitNode(sourceFile).annotatedNodes!.push(node); } @@ -100,7 +101,11 @@ namespace ts { /** * Sets the TextRange to use for source maps for a token of a node. */ - export function setTokenSourceMapRange(node: T, token: SyntaxKind, range: SourceMapRange | undefined) { + export function setTokenSourceMapRange( + node: T, + token: SyntaxKind, + range: SourceMapRange | undefined, + ) { const emitNode = getOrCreateEmitNode(node); const tokenSourceMapRanges = emitNode.tokenSourceMapRanges ?? (emitNode.tokenSourceMapRanges = []); tokenSourceMapRanges[token] = range; @@ -148,8 +153,22 @@ namespace ts { return node; } - export function addSyntheticLeadingComment(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) { - return setSyntheticLeadingComments(node, append(getSyntheticLeadingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text })); + export function addSyntheticLeadingComment( + node: T, + kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, + text: string, + hasTrailingNewLine?: boolean, + ) { + return setSyntheticLeadingComments( + node, + append(getSyntheticLeadingComments(node), { + kind, + pos: -1, + end: -1, + hasTrailingNewLine, + text, + }), + ); } export function getSyntheticTrailingComments(node: Node): SynthesizedComment[] | undefined { @@ -161,8 +180,22 @@ namespace ts { return node; } - export function addSyntheticTrailingComment(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) { - return setSyntheticTrailingComments(node, append(getSyntheticTrailingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text })); + export function addSyntheticTrailingComment( + node: T, + kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, + text: string, + hasTrailingNewLine?: boolean, + ) { + return setSyntheticTrailingComments( + node, + append(getSyntheticTrailingComments(node), { + kind, + pos: -1, + end: -1, + hasTrailingNewLine, + text, + }), + ); } export function moveSyntheticComments(node: T, original: Node): T { diff --git a/src/compiler/factory/nodeConverters.ts b/src/compiler/factory/nodeConverters.ts index ab499c7c04ead..a610b100d17ca 100644 --- a/src/compiler/factory/nodeConverters.ts +++ b/src/compiler/factory/nodeConverters.ts @@ -64,14 +64,30 @@ namespace ts { if (isBindingElement(element)) { if (element.dotDotDotToken) { Debug.assertNode(element.name, isIdentifier); - return setOriginalNode(setTextRange(factory.createSpreadAssignment(element.name), element), element); + return setOriginalNode( + setTextRange(factory.createSpreadAssignment(element.name), element), + element, + ); } if (element.propertyName) { const expression = convertToAssignmentElementTarget(element.name); - return setOriginalNode(setTextRange(factory.createPropertyAssignment(element.propertyName, element.initializer ? factory.createAssignment(expression, element.initializer) : expression), element), element); + return setOriginalNode( + setTextRange( + factory.createPropertyAssignment( + element.propertyName, + element.initializer ? factory.createAssignment(expression, element.initializer) + : expression, + ), + element, + ), + element, + ); } Debug.assertNode(element.name, isIdentifier); - return setOriginalNode(setTextRange(factory.createShorthandPropertyAssignment(element.name, element.initializer), element), element); + return setOriginalNode( + setTextRange(factory.createShorthandPropertyAssignment(element.name, element.initializer), element), + element, + ); } return cast(element, isObjectLiteralElementLike); diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index e4d8f9a5ef57c..391424d61070f 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -24,22 +24,74 @@ namespace ts { const update = flags & NodeFactoryFlags.NoOriginalNode ? updateWithoutOriginal : updateWithOriginal; // Lazily load the parenthesizer, node converters, and some factory methods until they are used. - const parenthesizerRules = memoize(() => flags & NodeFactoryFlags.NoParenthesizerRules ? nullParenthesizerRules : createParenthesizerRules(factory)); - const converters = memoize(() => flags & NodeFactoryFlags.NoNodeConverters ? nullNodeConverters : createNodeConverters(factory)); + const parenthesizerRules = memoize(() => + flags & NodeFactoryFlags.NoParenthesizerRules ? nullParenthesizerRules : createParenthesizerRules(factory) + ); + const converters = memoize(() => + flags & NodeFactoryFlags.NoNodeConverters ? nullNodeConverters : createNodeConverters(factory) + ); // lazy initializaton of common operator factories - const getBinaryCreateFunction = memoizeOne((operator: BinaryOperator) => (left: Expression, right: Expression) => createBinaryExpression(left, operator, right)); - const getPrefixUnaryCreateFunction = memoizeOne((operator: PrefixUnaryOperator) => (operand: Expression) => createPrefixUnaryExpression(operator, operand)); - const getPostfixUnaryCreateFunction = memoizeOne((operator: PostfixUnaryOperator) => (operand: Expression) => createPostfixUnaryExpression(operand, operator)); - const getJSDocPrimaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => () => createJSDocPrimaryTypeWorker(kind)); - const getJSDocUnaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => (type: T["type"]) => createJSDocUnaryTypeWorker(kind, type)); - const getJSDocUnaryTypeUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocUnaryTypeWorker(kind, node, type)); - const getJSDocPrePostfixUnaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => (type: T["type"], postfix?: boolean) => createJSDocPrePostfixUnaryTypeWorker(kind, type, postfix)); - const getJSDocPrePostfixUnaryTypeUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocPrePostfixUnaryTypeWorker(kind, node, type)); - const getJSDocSimpleTagCreateFunction = memoizeOne((kind: T["kind"]) => (tagName: Identifier | undefined, comment?: NodeArray) => createJSDocSimpleTagWorker(kind, tagName, comment)); - const getJSDocSimpleTagUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, tagName: Identifier | undefined, comment?: NodeArray) => updateJSDocSimpleTagWorker(kind, node, tagName, comment)); - const getJSDocTypeLikeTagCreateFunction = memoizeOne((kind: T["kind"]) => (tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: NodeArray) => createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment)); - const getJSDocTypeLikeTagUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: NodeArray) => updateJSDocTypeLikeTagWorker(kind, node, tagName, typeExpression, comment)); + const getBinaryCreateFunction = memoizeOne( + (operator: BinaryOperator) => (left: Expression, right: Expression) => + createBinaryExpression(left, operator, right), + ); + const getPrefixUnaryCreateFunction = memoizeOne((operator: PrefixUnaryOperator) => (operand: Expression) => + createPrefixUnaryExpression(operator, operand) + ); + const getPostfixUnaryCreateFunction = memoizeOne((operator: PostfixUnaryOperator) => (operand: Expression) => + createPostfixUnaryExpression(operand, operator) + ); + const getJSDocPrimaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => () => + createJSDocPrimaryTypeWorker(kind) + ); + const getJSDocUnaryTypeCreateFunction = memoizeOne( + (kind: T["kind"]) => (type: T["type"]) => + createJSDocUnaryTypeWorker(kind, type), + ); + const getJSDocUnaryTypeUpdateFunction = memoizeOne( + (kind: T["kind"]) => + (node: T, type: T["type"]) => updateJSDocUnaryTypeWorker(kind, node, type), + ); + const getJSDocPrePostfixUnaryTypeCreateFunction = memoizeOne( + ( + kind: T["kind"], + ) => + (type: T["type"], postfix?: boolean) => createJSDocPrePostfixUnaryTypeWorker(kind, type, postfix), + ); + const getJSDocPrePostfixUnaryTypeUpdateFunction = memoizeOne( + ( + kind: T["kind"], + ) => + (node: T, type: T["type"]) => updateJSDocPrePostfixUnaryTypeWorker(kind, node, type), + ); + const getJSDocSimpleTagCreateFunction = memoizeOne( + (kind: T["kind"]) => + (tagName: Identifier | undefined, comment?: NodeArray) => + createJSDocSimpleTagWorker(kind, tagName, comment), + ); + const getJSDocSimpleTagUpdateFunction = memoizeOne( + (kind: T["kind"]) => + (node: T, tagName: Identifier | undefined, comment?: NodeArray) => + updateJSDocSimpleTagWorker(kind, node, tagName, comment), + ); + const getJSDocTypeLikeTagCreateFunction = memoizeOne( + (kind: T["kind"]) => + ( + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression, + comment?: NodeArray, + ) => createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment), + ); + const getJSDocTypeLikeTagUpdateFunction = memoizeOne( + (kind: T["kind"]) => + ( + node: T, + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression, + comment?: NodeArray, + ) => updateJSDocTypeLikeTagWorker(kind, node, tagName, typeExpression, comment), + ); const factory: NodeFactory = { get parenthesizer() { @@ -164,13 +216,15 @@ namespace ts { updateArrayLiteralExpression, createObjectLiteralExpression, updateObjectLiteralExpression, - createPropertyAccessExpression: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess ? - (expression, name) => setEmitFlags(createPropertyAccessExpression(expression, name), EmitFlags.NoIndentation) : - createPropertyAccessExpression, + createPropertyAccessExpression: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess + ? (expression, name) => + setEmitFlags(createPropertyAccessExpression(expression, name), EmitFlags.NoIndentation) + : createPropertyAccessExpression, updatePropertyAccessExpression, - createPropertyAccessChain: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess ? - (expression, questionDotToken, name) => setEmitFlags(createPropertyAccessChain(expression, questionDotToken, name), EmitFlags.NoIndentation) : - createPropertyAccessChain, + createPropertyAccessChain: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess + ? (expression, questionDotToken, name) => + setEmitFlags(createPropertyAccessChain(expression, questionDotToken, name), EmitFlags.NoIndentation) + : createPropertyAccessChain, updatePropertyAccessChain, createElementAccessExpression, updateElementAccessExpression, @@ -737,7 +791,15 @@ namespace ts { function createBaseNamedDeclaration( kind: T["kind"], modifiers: readonly ModifierLike[] | undefined, - name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined, + name: + | Identifier + | PrivateIdentifier + | StringLiteralLike + | NumericLiteral + | ComputedPropertyName + | BindingPattern + | string + | undefined, ) { const node = createBaseDeclaration(kind); name = asName(name); @@ -771,10 +833,20 @@ namespace ts { return node; } - function createBaseGenericNamedDeclaration; }>( + function createBaseGenericNamedDeclaration< + T extends NamedDeclaration & { typeParameters?: NodeArray; }, + >( kind: T["kind"], modifiers: readonly ModifierLike[] | undefined, - name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined, + name: + | Identifier + | PrivateIdentifier + | StringLiteralLike + | NumericLiteral + | ComputedPropertyName + | BindingPattern + | string + | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, ) { const node = createBaseNamedDeclaration( @@ -791,7 +863,15 @@ namespace ts { function createBaseSignatureDeclaration( kind: T["kind"], modifiers: readonly ModifierLike[] | undefined, - name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined, + name: + | Identifier + | PrivateIdentifier + | StringLiteralLike + | NumericLiteral + | ComputedPropertyName + | BindingPattern + | string + | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined, @@ -804,8 +884,8 @@ namespace ts { ); node.parameters = createNodeArray(parameters); node.type = type; - node.transformFlags |= propagateChildrenFlags(node.parameters) | - propagateChildFlags(node.type); + node.transformFlags |= propagateChildrenFlags(node.parameters) + | propagateChildFlags(node.type); if (type) node.transformFlags |= TransformFlags.ContainsTypeScript; // The following properties are used for quick info @@ -813,7 +893,10 @@ namespace ts { return node; } - function finishUpdateBaseSignatureDeclaration(updated: Mutable, original: T) { + function finishUpdateBaseSignatureDeclaration( + updated: Mutable, + original: T, + ) { if (updated !== original) { // copy children used for quick info updated.typeArguments = original.typeArguments; @@ -824,7 +907,15 @@ namespace ts { function createBaseFunctionLikeDeclaration( kind: T["kind"], modifiers: readonly ModifierLike[] | undefined, - name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined, + name: + | Identifier + | PrivateIdentifier + | StringLiteralLike + | NumericLiteral + | ComputedPropertyName + | BindingPattern + | string + | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined, @@ -882,7 +973,9 @@ namespace ts { return node; } - function createBaseBindingLikeDeclaration( + function createBaseBindingLikeDeclaration< + T extends PropertyDeclaration | VariableDeclaration | ParameterDeclaration | BindingElement, + >( kind: T["kind"], modifiers: readonly ModifierLike[] | undefined, name: string | T["name"] | undefined, @@ -898,7 +991,9 @@ namespace ts { return node; } - function createBaseVariableLikeDeclaration( + function createBaseVariableLikeDeclaration< + T extends PropertyDeclaration | VariableDeclaration | ParameterDeclaration, + >( kind: T["kind"], modifiers: readonly ModifierLike[] | undefined, name: string | T["name"] | undefined, @@ -931,16 +1026,27 @@ namespace ts { } // @api - function createNumericLiteral(value: string | number, numericLiteralFlags: TokenFlags = TokenFlags.None): NumericLiteral { - const node = createBaseLiteral(SyntaxKind.NumericLiteral, typeof value === "number" ? value + "" : value); + function createNumericLiteral( + value: string | number, + numericLiteralFlags: TokenFlags = TokenFlags.None, + ): NumericLiteral { + const node = createBaseLiteral( + SyntaxKind.NumericLiteral, + typeof value === "number" ? value + "" : value, + ); node.numericLiteralFlags = numericLiteralFlags; - if (numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier) node.transformFlags |= TransformFlags.ContainsES2015; + if (numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier) { + node.transformFlags |= TransformFlags.ContainsES2015; + } return node; } // @api function createBigIntLiteral(value: string | PseudoBigInt): BigIntLiteral { - const node = createBaseLiteral(SyntaxKind.BigIntLiteral, typeof value === "string" ? value : pseudoBigIntToString(value) + "n"); + const node = createBaseLiteral( + SyntaxKind.BigIntLiteral, + typeof value === "string" ? value : pseudoBigIntToString(value) + "n", + ); node.transformFlags |= TransformFlags.ContainsESNext; return node; } @@ -952,7 +1058,11 @@ namespace ts { } // @api - function createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean): StringLiteral { + function createStringLiteral( + text: string, + isSingleQuote?: boolean, + hasExtendedUnicodeEscape?: boolean, + ): StringLiteral { const node = createBaseStringLiteral(text, isSingleQuote); node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape; if (hasExtendedUnicodeEscape) node.transformFlags |= TransformFlags.ContainsES2015; @@ -973,7 +1083,10 @@ namespace ts { } // @api - function createLiteralLikeNode(kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, text: string): LiteralToken { + function createLiteralLikeNode( + kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, + text: string, + ): LiteralToken { switch (kind) { case SyntaxKind.NumericLiteral: return createNumericLiteral(text, /*numericLiteralFlags*/ 0); @@ -988,7 +1101,12 @@ namespace ts { case SyntaxKind.RegularExpressionLiteral: return createRegularExpressionLiteral(text); case SyntaxKind.NoSubstitutionTemplateLiteral: - return createTemplateLiteralLikeNode(kind, text, /*rawText*/ undefined, /*templateFlags*/ 0) as NoSubstitutionTemplateLiteral; + return createTemplateLiteralLikeNode( + kind, + text, + /*rawText*/ undefined, + /*templateFlags*/ 0, + ) as NoSubstitutionTemplateLiteral; } } @@ -1009,7 +1127,12 @@ namespace ts { return node; } - function createBaseGeneratedIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags, prefix: string | GeneratedNamePart | undefined, suffix: string | undefined) { + function createBaseGeneratedIdentifier( + text: string, + autoGenerateFlags: GeneratedIdentifierFlags, + prefix: string | GeneratedNamePart | undefined, + suffix: string | undefined, + ) { const node = createBaseIdentifier(text, /*originalKeywordKind*/ undefined) as Mutable; node.autoGenerateFlags = autoGenerateFlags; node.autoGenerateId = nextAutoGenerateId; @@ -1020,7 +1143,12 @@ namespace ts { } // @api - function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier { + function createIdentifier( + text: string, + typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], + originalKeywordKind?: SyntaxKind, + hasExtendedUnicodeEscape?: boolean, + ): Identifier { const node = createBaseIdentifier(text, originalKeywordKind); if (typeArguments) { // NOTE: we do not use `setChildren` here because typeArguments in an identifier do not contribute to transformations @@ -1037,14 +1165,22 @@ namespace ts { } // @api - function updateIdentifier(node: Identifier, typeArguments?: NodeArray | undefined): Identifier { + function updateIdentifier( + node: Identifier, + typeArguments?: NodeArray | undefined, + ): Identifier { return node.typeArguments !== typeArguments ? update(createIdentifier(idText(node), typeArguments), node) : node; } // @api - function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean, prefix?: string | GeneratedNamePart, suffix?: string): GeneratedIdentifier { + function createTempVariable( + recordTempVariable: ((node: Identifier) => void) | undefined, + reservedInNestedScopes?: boolean, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): GeneratedIdentifier { let flags = GeneratedIdentifierFlags.Auto; if (reservedInNestedScopes) flags |= GeneratedIdentifierFlags.ReservedInNestedScopes; const name = createBaseGeneratedIdentifier("", flags, prefix, suffix); @@ -1064,19 +1200,33 @@ namespace ts { /** Create a unique name based on the supplied text. */ // @api - function createUniqueName(text: string, flags: GeneratedIdentifierFlags = GeneratedIdentifierFlags.None, prefix?: string | GeneratedNamePart, suffix?: string): Identifier { + function createUniqueName( + text: string, + flags: GeneratedIdentifierFlags = GeneratedIdentifierFlags.None, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier { Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags"); - Debug.assert((flags & (GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)) !== GeneratedIdentifierFlags.FileLevel, "GeneratedIdentifierFlags.FileLevel cannot be set without also setting GeneratedIdentifierFlags.Optimistic"); + Debug.assert( + (flags & (GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)) + !== GeneratedIdentifierFlags.FileLevel, + "GeneratedIdentifierFlags.FileLevel cannot be set without also setting GeneratedIdentifierFlags.Optimistic", + ); return createBaseGeneratedIdentifier(text, GeneratedIdentifierFlags.Unique | flags, prefix, suffix); } /** Create a unique name generated for a node. */ // @api - function getGeneratedNameForNode(node: Node | undefined, flags: GeneratedIdentifierFlags = 0, prefix?: string | GeneratedNamePart, suffix?: string): Identifier { + function getGeneratedNameForNode( + node: Node | undefined, + flags: GeneratedIdentifierFlags = 0, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier { Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags"); - const text = !node ? "" : - isMemberName(node) ? formatGeneratedName(/*privateName*/ false, prefix, node, suffix, idText) : - `generated@${getNodeId(node)}`; + const text = !node ? "" + : isMemberName(node) ? formatGeneratedName(/*privateName*/ false, prefix, node, suffix, idText) + : `generated@${getNodeId(node)}`; if (prefix || suffix) flags |= GeneratedIdentifierFlags.Optimistic; const name = createBaseGeneratedIdentifier(text, GeneratedIdentifierFlags.Node | flags, prefix, suffix); name.original = node; @@ -1084,7 +1234,9 @@ namespace ts { } function createBasePrivateIdentifier(text: string) { - const node = baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as Mutable; + const node = baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as Mutable< + PrivateIdentifier + >; node.escapedText = escapeLeadingUnderscores(text); node.transformFlags |= TransformFlags.ContainsClassFields; return node; @@ -1096,7 +1248,12 @@ namespace ts { return createBasePrivateIdentifier(text); } - function createBaseGeneratedPrivateIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags, prefix: string | GeneratedNamePart | undefined, suffix: string | undefined) { + function createBaseGeneratedPrivateIdentifier( + text: string, + autoGenerateFlags: GeneratedIdentifierFlags, + prefix: string | GeneratedNamePart | undefined, + suffix: string | undefined, + ) { const node = createBasePrivateIdentifier(text); node.autoGenerateFlags = autoGenerateFlags; node.autoGenerateId = nextAutoGenerateId; @@ -1108,19 +1265,32 @@ namespace ts { /** Create a unique name based on the supplied text. */ // @api - function createUniquePrivateName(text?: string, prefix?: string | GeneratedNamePart, suffix?: string): PrivateIdentifier { + function createUniquePrivateName( + text?: string, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): PrivateIdentifier { if (text && !startsWith(text, "#")) Debug.fail("First character of private identifier must be #: " + text); - const autoGenerateFlags = GeneratedIdentifierFlags.ReservedInNestedScopes | - (text ? GeneratedIdentifierFlags.Unique : GeneratedIdentifierFlags.Auto); + const autoGenerateFlags = GeneratedIdentifierFlags.ReservedInNestedScopes + | (text ? GeneratedIdentifierFlags.Unique : GeneratedIdentifierFlags.Auto); return createBaseGeneratedPrivateIdentifier(text ?? "", autoGenerateFlags, prefix, suffix); } // @api - function getGeneratedPrivateNameForNode(node: Node, prefix?: string | GeneratedNamePart, suffix?: string): PrivateIdentifier { - const text = isMemberName(node) ? formatGeneratedName(/*privateName*/ true, prefix, node, suffix, idText) : - `#generated@${getNodeId(node)}`; + function getGeneratedPrivateNameForNode( + node: Node, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): PrivateIdentifier { + const text = isMemberName(node) ? formatGeneratedName(/*privateName*/ true, prefix, node, suffix, idText) + : `#generated@${getNodeId(node)}`; const flags = prefix || suffix ? GeneratedIdentifierFlags.Optimistic : GeneratedIdentifierFlags.None; - const name = createBaseGeneratedPrivateIdentifier(text, GeneratedIdentifierFlags.Node | flags, prefix, suffix); + const name = createBaseGeneratedPrivateIdentifier( + text, + GeneratedIdentifierFlags.Node | flags, + prefix, + suffix, + ); name.original = node; return name; } @@ -1147,16 +1317,25 @@ namespace ts { function createToken(token: TKind): Token; function createToken(token: TKind) { Debug.assert(token >= SyntaxKind.FirstToken && token <= SyntaxKind.LastToken, "Invalid token"); - Debug.assert(token <= SyntaxKind.FirstTemplateToken || token >= SyntaxKind.LastTemplateToken, "Invalid token. Use 'createTemplateLiteralLikeNode' to create template literals."); - Debug.assert(token <= SyntaxKind.FirstLiteralToken || token >= SyntaxKind.LastLiteralToken, "Invalid token. Use 'createLiteralLikeNode' to create literals."); - Debug.assert(token !== SyntaxKind.Identifier, "Invalid token. Use 'createIdentifier' to create identifiers"); + Debug.assert( + token <= SyntaxKind.FirstTemplateToken || token >= SyntaxKind.LastTemplateToken, + "Invalid token. Use 'createTemplateLiteralLikeNode' to create template literals.", + ); + Debug.assert( + token <= SyntaxKind.FirstLiteralToken || token >= SyntaxKind.LastLiteralToken, + "Invalid token. Use 'createLiteralLikeNode' to create literals.", + ); + Debug.assert( + token !== SyntaxKind.Identifier, + "Invalid token. Use 'createIdentifier' to create identifiers", + ); const node = createBaseToken>(token); let transformFlags = TransformFlags.None; switch (token) { case SyntaxKind.AsyncKeyword: // 'async' modifier is ES2017 (async functions) or ES2018 (async generators) - transformFlags = TransformFlags.ContainsES2017 | - TransformFlags.ContainsES2018; + transformFlags = TransformFlags.ContainsES2017 + | TransformFlags.ContainsES2018; break; case SyntaxKind.PublicKeyword: @@ -1270,8 +1449,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.QualifiedName); node.left = left; node.right = asName(right); - node.transformFlags |= propagateChildFlags(node.left) | - propagateIdentifierNameFlags(node.right); + node.transformFlags |= propagateChildFlags(node.left) + | propagateIdentifierNameFlags(node.right); return node; } @@ -1287,9 +1466,9 @@ namespace ts { function createComputedPropertyName(expression: Expression) { const node = createBaseNode(SyntaxKind.ComputedPropertyName); node.expression = parenthesizerRules().parenthesizeExpressionOfComputedPropertyName(expression); - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsComputedPropertyName; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsComputedPropertyName; return node; } @@ -1305,7 +1484,12 @@ namespace ts { // // @api - function createTypeParameterDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration { + function createTypeParameterDeclaration( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + constraint?: TypeNode, + defaultType?: TypeNode, + ): TypeParameterDeclaration { const node = createBaseNamedDeclaration( SyntaxKind.TypeParameter, modifiers, @@ -1318,7 +1502,13 @@ namespace ts { } // @api - function updateTypeParameterDeclaration(node: TypeParameterDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration { + function updateTypeParameterDeclaration( + node: TypeParameterDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + constraint: TypeNode | undefined, + defaultType: TypeNode | undefined, + ): TypeParameterDeclaration { return node.modifiers !== modifiers || node.name !== name || node.constraint !== constraint @@ -1349,10 +1539,12 @@ namespace ts { node.transformFlags = TransformFlags.ContainsTypeScript; } else { - node.transformFlags |= propagateChildFlags(node.dotDotDotToken) | - propagateChildFlags(node.questionToken); + node.transformFlags |= propagateChildFlags(node.dotDotDotToken) + | propagateChildFlags(node.questionToken); if (questionToken) node.transformFlags |= TransformFlags.ContainsTypeScript; - if (modifiersToFlags(node.modifiers) & ModifierFlags.ParameterPropertyModifier) node.transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax; + if (modifiersToFlags(node.modifiers) & ModifierFlags.ParameterPropertyModifier) { + node.transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax; + } if (initializer || dotDotDotToken) node.transformFlags |= TransformFlags.ContainsES2015; } return node; @@ -1374,7 +1566,10 @@ namespace ts { || node.questionToken !== questionToken || node.type !== type || node.initializer !== initializer - ? update(createParameterDeclaration(modifiers, dotDotDotToken, name, questionToken, type, initializer), node) + ? update( + createParameterDeclaration(modifiers, dotDotDotToken, name, questionToken, type, initializer), + node, + ) : node; } @@ -1382,10 +1577,10 @@ namespace ts { function createDecorator(expression: Expression) { const node = createBaseNode(SyntaxKind.Decorator); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false); - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsTypeScript | - TransformFlags.ContainsTypeScriptClassSyntax | - TransformFlags.ContainsDecorators; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsTypeScript + | TransformFlags.ContainsTypeScriptClassSyntax + | TransformFlags.ContainsDecorators; return node; } @@ -1460,11 +1655,13 @@ namespace ts { type, initializer, ); - node.questionToken = questionOrExclamationToken && isQuestionToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined; - node.exclamationToken = questionOrExclamationToken && isExclamationToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined; - node.transformFlags |= propagateChildFlags(node.questionToken) | - propagateChildFlags(node.exclamationToken) | - TransformFlags.ContainsClassFields; + node.questionToken = questionOrExclamationToken && isQuestionToken(questionOrExclamationToken) + ? questionOrExclamationToken : undefined; + node.exclamationToken = questionOrExclamationToken && isExclamationToken(questionOrExclamationToken) + ? questionOrExclamationToken : undefined; + node.transformFlags |= propagateChildFlags(node.questionToken) + | propagateChildFlags(node.exclamationToken) + | TransformFlags.ContainsClassFields; if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) { node.transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax; } @@ -1485,11 +1682,18 @@ namespace ts { ) { return node.modifiers !== modifiers || node.name !== name - || node.questionToken !== (questionOrExclamationToken !== undefined && isQuestionToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined) - || node.exclamationToken !== (questionOrExclamationToken !== undefined && isExclamationToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined) + || node.questionToken + !== (questionOrExclamationToken !== undefined && isQuestionToken(questionOrExclamationToken) + ? questionOrExclamationToken : undefined) + || node.exclamationToken + !== (questionOrExclamationToken !== undefined && isExclamationToken(questionOrExclamationToken) + ? questionOrExclamationToken : undefined) || node.type !== type || node.initializer !== initializer - ? update(createPropertyDeclaration(modifiers, name, questionOrExclamationToken, type, initializer), node) + ? update( + createPropertyDeclaration(modifiers, name, questionOrExclamationToken, type, initializer), + node, + ) : node; } @@ -1531,7 +1735,10 @@ namespace ts { || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type - ? finishUpdateBaseSignatureDeclaration(createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type), node) + ? finishUpdateBaseSignatureDeclaration( + createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type), + node, + ) : node; } @@ -1557,9 +1764,9 @@ namespace ts { ); node.asteriskToken = asteriskToken; node.questionToken = questionToken; - node.transformFlags |= propagateChildFlags(node.asteriskToken) | - propagateChildFlags(node.questionToken) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.asteriskToken) + | propagateChildFlags(node.questionToken) + | TransformFlags.ContainsES2015; if (questionToken) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -1600,7 +1807,19 @@ namespace ts { || node.parameters !== parameters || node.type !== type || node.body !== body - ? finishUpdateMethodDeclaration(createMethodDeclaration(modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node) + ? finishUpdateMethodDeclaration( + createMethodDeclaration( + modifiers, + asteriskToken, + name, + questionToken, + typeParameters, + parameters, + type, + body, + ), + node, + ) : node; } @@ -1640,7 +1859,10 @@ namespace ts { : node; } - function finishUpdateClassStaticBlockDeclaration(updated: Mutable, original: ClassStaticBlockDeclaration) { + function finishUpdateClassStaticBlockDeclaration( + updated: Mutable, + original: ClassStaticBlockDeclaration, + ) { if (updated !== original) { updated.illegalDecorators = original.illegalDecorators; updated.modifiers = original.modifiers; @@ -1686,7 +1908,10 @@ namespace ts { : node; } - function finishUpdateConstructorDeclaration(updated: Mutable, original: ConstructorDeclaration) { + function finishUpdateConstructorDeclaration( + updated: Mutable, + original: ConstructorDeclaration, + ) { if (updated !== original) { updated.illegalDecorators = original.illegalDecorators; updated.typeParameters = original.typeParameters; @@ -1732,11 +1957,17 @@ namespace ts { || node.parameters !== parameters || node.type !== type || node.body !== body - ? finishUpdateGetAccessorDeclaration(createGetAccessorDeclaration(modifiers, name, parameters, type, body), node) + ? finishUpdateGetAccessorDeclaration( + createGetAccessorDeclaration(modifiers, name, parameters, type, body), + node, + ) : node; } - function finishUpdateGetAccessorDeclaration(updated: Mutable, original: GetAccessorDeclaration) { + function finishUpdateGetAccessorDeclaration( + updated: Mutable, + original: GetAccessorDeclaration, + ) { if (updated !== original) { updated.typeParameters = original.typeParameters; } @@ -1778,11 +2009,17 @@ namespace ts { || node.name !== name || node.parameters !== parameters || node.body !== body - ? finishUpdateSetAccessorDeclaration(createSetAccessorDeclaration(modifiers, name, parameters, body), node) + ? finishUpdateSetAccessorDeclaration( + createSetAccessorDeclaration(modifiers, name, parameters, body), + node, + ) : node; } - function finishUpdateSetAccessorDeclaration(updated: Mutable, original: SetAccessorDeclaration) { + function finishUpdateSetAccessorDeclaration( + updated: Mutable, + original: SetAccessorDeclaration, + ) { if (updated !== original) { updated.typeParameters = original.typeParameters; updated.type = original.type; @@ -1896,7 +2133,11 @@ namespace ts { } // @api - function updateTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail) { + function updateTemplateLiteralTypeSpan( + node: TemplateLiteralTypeSpan, + type: TypeNode, + literal: TemplateMiddle | TemplateTail, + ) { return node.type !== type || node.literal !== literal ? update(createTemplateLiteralTypeSpan(type, literal), node) @@ -1913,7 +2154,11 @@ namespace ts { } // @api - function createTypePredicateNode(assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined) { + function createTypePredicateNode( + assertsModifier: AssertsKeyword | undefined, + parameterName: Identifier | ThisTypeNode | string, + type: TypeNode | undefined, + ) { const node = createBaseNode(SyntaxKind.TypePredicate); node.assertsModifier = assertsModifier; node.parameterName = asName(parameterName); @@ -1923,7 +2168,12 @@ namespace ts { } // @api - function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined) { + function updateTypePredicateNode( + node: TypePredicateNode, + assertsModifier: AssertsKeyword | undefined, + parameterName: Identifier | ThisTypeNode, + type: TypeNode | undefined, + ) { return node.assertsModifier !== assertsModifier || node.parameterName !== parameterName || node.type !== type @@ -1932,16 +2182,24 @@ namespace ts { } // @api - function createTypeReferenceNode(typeName: string | EntityName, typeArguments: readonly TypeNode[] | undefined) { + function createTypeReferenceNode( + typeName: string | EntityName, + typeArguments: readonly TypeNode[] | undefined, + ) { const node = createBaseNode(SyntaxKind.TypeReference); node.typeName = asName(typeName); - node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(createNodeArray(typeArguments)); + node.typeArguments = typeArguments + && parenthesizerRules().parenthesizeTypeArguments(createNodeArray(typeArguments)); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api - function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined) { + function updateTypeReferenceNode( + node: TypeReferenceNode, + typeName: EntityName, + typeArguments: NodeArray | undefined, + ) { return node.typeName !== typeName || node.typeArguments !== typeArguments ? update(createTypeReferenceNode(typeName, typeArguments), node) @@ -1991,10 +2249,12 @@ namespace ts { } // @api - function createConstructorTypeNode(...args: Parameters) { - return args.length === 4 ? createConstructorTypeNode1(...args) : - args.length === 3 ? createConstructorTypeNode2(...args) : - Debug.fail("Incorrect number of arguments specified."); + function createConstructorTypeNode( + ...args: Parameters + ) { + return args.length === 4 ? createConstructorTypeNode1(...args) + : args.length === 3 ? createConstructorTypeNode2(...args) + : Debug.fail("Incorrect number of arguments specified."); } function createConstructorTypeNode1( @@ -2025,10 +2285,12 @@ namespace ts { } // @api - function updateConstructorTypeNode(...args: Parameters) { - return args.length === 5 ? updateConstructorTypeNode1(...args) : - args.length === 4 ? updateConstructorTypeNode2(...args) : - Debug.fail("Incorrect number of arguments specified."); + function updateConstructorTypeNode( + ...args: Parameters + ) { + return args.length === 5 ? updateConstructorTypeNode1(...args) + : args.length === 4 ? updateConstructorTypeNode2(...args) + : Debug.fail("Incorrect number of arguments specified."); } function updateConstructorTypeNode1( @@ -2042,7 +2304,10 @@ namespace ts { || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type - ? finishUpdateBaseSignatureDeclaration(createConstructorTypeNode(modifiers, typeParameters, parameters, type), node) + ? finishUpdateBaseSignatureDeclaration( + createConstructorTypeNode(modifiers, typeParameters, parameters, type), + node, + ) : node; } @@ -2119,7 +2384,12 @@ namespace ts { } // @api - function createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) { + function createNamedTupleMember( + dotDotDotToken: DotDotDotToken | undefined, + name: Identifier, + questionToken: QuestionToken | undefined, + type: TypeNode, + ) { const node = createBaseNode(SyntaxKind.NamedTupleMember); node.dotDotDotToken = dotDotDotToken; node.name = name; @@ -2130,7 +2400,13 @@ namespace ts { } // @api - function updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) { + function updateNamedTupleMember( + node: NamedTupleMember, + dotDotDotToken: DotDotDotToken | undefined, + name: Identifier, + questionToken: QuestionToken | undefined, + type: TypeNode, + ) { return node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.questionToken !== questionToken @@ -2169,14 +2445,22 @@ namespace ts { : node; } - function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: readonly TypeNode[], parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[]) { + function createUnionOrIntersectionTypeNode( + kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, + types: readonly TypeNode[], + parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[], + ) { const node = createBaseNode(kind); node.types = factory.createNodeArray(parenthesize(types)); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } - function updateUnionOrIntersectionTypeNode(node: T, types: NodeArray, parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[]): T { + function updateUnionOrIntersectionTypeNode( + node: T, + types: NodeArray, + parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[], + ): T { return node.types !== types ? update(createUnionOrIntersectionTypeNode(node.kind, types, parenthesize) as T, node) : node; @@ -2184,26 +2468,47 @@ namespace ts { // @api function createUnionTypeNode(types: readonly TypeNode[]): UnionTypeNode { - return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types, parenthesizerRules().parenthesizeConstituentTypesOfUnionType) as UnionTypeNode; + return createUnionOrIntersectionTypeNode( + SyntaxKind.UnionType, + types, + parenthesizerRules().parenthesizeConstituentTypesOfUnionType, + ) as UnionTypeNode; } // @api function updateUnionTypeNode(node: UnionTypeNode, types: NodeArray) { - return updateUnionOrIntersectionTypeNode(node, types, parenthesizerRules().parenthesizeConstituentTypesOfUnionType); + return updateUnionOrIntersectionTypeNode( + node, + types, + parenthesizerRules().parenthesizeConstituentTypesOfUnionType, + ); } // @api function createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode { - return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types, parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType) as IntersectionTypeNode; + return createUnionOrIntersectionTypeNode( + SyntaxKind.IntersectionType, + types, + parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType, + ) as IntersectionTypeNode; } // @api function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray) { - return updateUnionOrIntersectionTypeNode(node, types, parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType); + return updateUnionOrIntersectionTypeNode( + node, + types, + parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType, + ); } // @api - function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { + function createConditionalTypeNode( + checkType: TypeNode, + extendsType: TypeNode, + trueType: TypeNode, + falseType: TypeNode, + ) { const node = createBaseNode(SyntaxKind.ConditionalType); node.checkType = parenthesizerRules().parenthesizeCheckTypeOfConditionalType(checkType); node.extendsType = parenthesizerRules().parenthesizeExtendsTypeOfConditionalType(extendsType); @@ -2214,7 +2519,13 @@ namespace ts { } // @api - function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { + function updateConditionalTypeNode( + node: ConditionalTypeNode, + checkType: TypeNode, + extendsType: TypeNode, + trueType: TypeNode, + falseType: TypeNode, + ) { return node.checkType !== checkType || node.extendsType !== extendsType || node.trueType !== trueType @@ -2248,7 +2559,11 @@ namespace ts { } // @api - function updateTemplateLiteralType(node: TemplateLiteralTypeNode, head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]) { + function updateTemplateLiteralType( + node: TemplateLiteralTypeNode, + head: TemplateHead, + templateSpans: readonly TemplateLiteralTypeSpan[], + ) { return node.head !== head || node.templateSpans !== templateSpans ? update(createTemplateLiteralType(head, templateSpans), node) @@ -2314,12 +2629,15 @@ namespace ts { } // @api - function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode { + function createTypeOperatorNode( + operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, + type: TypeNode, + ): TypeOperatorNode { const node = createBaseNode(SyntaxKind.TypeOperator); node.operator = operator; - node.type = operator === SyntaxKind.ReadonlyKeyword ? - parenthesizerRules().parenthesizeOperandOfReadonlyTypeOperator(type) : - parenthesizerRules().parenthesizeOperandOfTypeOperator(type); + node.type = operator === SyntaxKind.ReadonlyKeyword + ? parenthesizerRules().parenthesizeOperandOfReadonlyTypeOperator(type) + : parenthesizerRules().parenthesizeOperandOfTypeOperator(type); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } @@ -2349,7 +2667,14 @@ namespace ts { } // @api - function createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: readonly TypeElement[] | undefined): MappedTypeNode { + function createMappedTypeNode( + readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, + typeParameter: TypeParameterDeclaration, + nameType: TypeNode | undefined, + questionToken: QuestionToken | PlusToken | MinusToken | undefined, + type: TypeNode | undefined, + members: readonly TypeElement[] | undefined, + ): MappedTypeNode { const node = createBaseNode(SyntaxKind.MappedType); node.readonlyToken = readonlyToken; node.typeParameter = typeParameter; @@ -2362,14 +2687,25 @@ namespace ts { } // @api - function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: readonly TypeElement[] | undefined): MappedTypeNode { + function updateMappedTypeNode( + node: MappedTypeNode, + readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, + typeParameter: TypeParameterDeclaration, + nameType: TypeNode | undefined, + questionToken: QuestionToken | PlusToken | MinusToken | undefined, + type: TypeNode | undefined, + members: readonly TypeElement[] | undefined, + ): MappedTypeNode { return node.readonlyToken !== readonlyToken || node.typeParameter !== typeParameter || node.nameType !== nameType || node.questionToken !== questionToken || node.type !== type || node.members !== members - ? update(createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), node) + ? update( + createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), + node, + ) : node; } @@ -2396,12 +2732,12 @@ namespace ts { function createObjectBindingPattern(elements: readonly BindingElement[]) { const node = createBaseNode(SyntaxKind.ObjectBindingPattern); node.elements = createNodeArray(elements); - node.transformFlags |= propagateChildrenFlags(node.elements) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsBindingPattern; + node.transformFlags |= propagateChildrenFlags(node.elements) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsBindingPattern; if (node.transformFlags & TransformFlags.ContainsRestOrSpread) { - node.transformFlags |= TransformFlags.ContainsES2018 | - TransformFlags.ContainsObjectRestOrSpread; + node.transformFlags |= TransformFlags.ContainsES2018 + | TransformFlags.ContainsObjectRestOrSpread; } return node; } @@ -2417,9 +2753,9 @@ namespace ts { function createArrayBindingPattern(elements: readonly ArrayBindingElement[]) { const node = createBaseNode(SyntaxKind.ArrayBindingPattern); node.elements = createNodeArray(elements); - node.transformFlags |= propagateChildrenFlags(node.elements) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsBindingPattern; + node.transformFlags |= propagateChildrenFlags(node.elements) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsBindingPattern; return node; } @@ -2431,7 +2767,12 @@ namespace ts { } // @api - function createBindingElement(dotDotDotToken: DotDotDotToken | undefined, propertyName: string | PropertyName | undefined, name: string | BindingName, initializer?: Expression) { + function createBindingElement( + dotDotDotToken: DotDotDotToken | undefined, + propertyName: string | PropertyName | undefined, + name: string | BindingName, + initializer?: Expression, + ) { const node = createBaseBindingLikeDeclaration( SyntaxKind.BindingElement, /*modifiers*/ undefined, @@ -2440,19 +2781,25 @@ namespace ts { ); node.propertyName = asName(propertyName); node.dotDotDotToken = dotDotDotToken; - node.transformFlags |= propagateChildFlags(node.dotDotDotToken) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.dotDotDotToken) + | TransformFlags.ContainsES2015; if (node.propertyName) { - node.transformFlags |= isIdentifier(node.propertyName) ? - propagateIdentifierNameFlags(node.propertyName) : - propagateChildFlags(node.propertyName); + node.transformFlags |= isIdentifier(node.propertyName) + ? propagateIdentifierNameFlags(node.propertyName) + : propagateChildFlags(node.propertyName); } if (dotDotDotToken) node.transformFlags |= TransformFlags.ContainsRestOrSpread; return node; } // @api - function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken | undefined, propertyName: PropertyName | undefined, name: BindingName, initializer: Expression | undefined) { + function updateBindingElement( + node: BindingElement, + dotDotDotToken: DotDotDotToken | undefined, + propertyName: PropertyName | undefined, + name: BindingName, + initializer: Expression | undefined, + ) { return node.propertyName !== propertyName || node.dotDotDotToken !== dotDotDotToken || node.name !== name @@ -2478,7 +2825,10 @@ namespace ts { // we end up with `[1, 2, ,]` instead of `[1, 2, ]` otherwise the `OmittedExpression` will just end up being treated like // a trailing comma. const lastElement = elements && lastOrUndefined(elements); - const elementsArray = createNodeArray(elements, lastElement && isOmittedExpression(lastElement) ? true : undefined); + const elementsArray = createNodeArray( + elements, + lastElement && isOmittedExpression(lastElement) ? true : undefined, + ); node.elements = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(elementsArray); node.multiLine = multiLine; node.transformFlags |= propagateChildrenFlags(node.elements); @@ -2502,7 +2852,10 @@ namespace ts { } // @api - function updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]) { + function updateObjectLiteralExpression( + node: ObjectLiteralExpression, + properties: readonly ObjectLiteralElementLike[], + ) { return node.properties !== properties ? update(createObjectLiteralExpression(properties, node.multiLine), node) : node; @@ -2513,21 +2866,25 @@ namespace ts { const node = createBaseExpression(SyntaxKind.PropertyAccessExpression); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false); node.name = asName(name); - node.transformFlags = propagateChildFlags(node.expression) | - (isIdentifier(node.name) ? - propagateIdentifierNameFlags(node.name) : - propagateChildFlags(node.name) | TransformFlags.ContainsPrivateIdentifierInExpression); + node.transformFlags = propagateChildFlags(node.expression) + | (isIdentifier(node.name) + ? propagateIdentifierNameFlags(node.name) + : propagateChildFlags(node.name) | TransformFlags.ContainsPrivateIdentifierInExpression); if (isSuperKeyword(expression)) { // super method calls require a lexical 'this' // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators - node.transformFlags |= TransformFlags.ContainsES2017 | - TransformFlags.ContainsES2018; + node.transformFlags |= TransformFlags.ContainsES2017 + | TransformFlags.ContainsES2018; } return node; } // @api - function updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) { + function updatePropertyAccessExpression( + node: PropertyAccessExpression, + expression: Expression, + name: Identifier | PrivateIdentifier, + ) { if (isPropertyAccessChain(node)) { return updatePropertyAccessChain(node, expression, node.questionDotToken, cast(name, isIdentifier)); } @@ -2538,24 +2895,36 @@ namespace ts { } // @api - function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) { + function createPropertyAccessChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + name: string | Identifier | PrivateIdentifier, + ) { const node = createBaseExpression(SyntaxKind.PropertyAccessExpression); node.flags |= NodeFlags.OptionalChain; node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true); node.questionDotToken = questionDotToken; node.name = asName(name); - node.transformFlags |= TransformFlags.ContainsES2020 | - propagateChildFlags(node.expression) | - propagateChildFlags(node.questionDotToken) | - (isIdentifier(node.name) ? - propagateIdentifierNameFlags(node.name) : - propagateChildFlags(node.name) | TransformFlags.ContainsPrivateIdentifierInExpression); + node.transformFlags |= TransformFlags.ContainsES2020 + | propagateChildFlags(node.expression) + | propagateChildFlags(node.questionDotToken) + | (isIdentifier(node.name) + ? propagateIdentifierNameFlags(node.name) + : propagateChildFlags(node.name) | TransformFlags.ContainsPrivateIdentifierInExpression); return node; } // @api - function updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier) { - Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a PropertyAccessExpression using updatePropertyAccessChain. Use updatePropertyAccess instead."); + function updatePropertyAccessChain( + node: PropertyAccessChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + name: Identifier | PrivateIdentifier, + ) { + Debug.assert( + !!(node.flags & NodeFlags.OptionalChain), + "Cannot update a PropertyAccessExpression using updatePropertyAccessChain. Use updatePropertyAccess instead.", + ); // Because we are updating an existing PropertyAccessChain we want to inherit its emitFlags // instead of using the default from createPropertyAccess return node.expression !== expression @@ -2570,19 +2939,23 @@ namespace ts { const node = createBaseExpression(SyntaxKind.ElementAccessExpression); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false); node.argumentExpression = asExpression(index); - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.argumentExpression); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.argumentExpression); if (isSuperKeyword(expression)) { // super method calls require a lexical 'this' // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators - node.transformFlags |= TransformFlags.ContainsES2017 | - TransformFlags.ContainsES2018; + node.transformFlags |= TransformFlags.ContainsES2017 + | TransformFlags.ContainsES2018; } return node; } // @api - function updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression) { + function updateElementAccessExpression( + node: ElementAccessExpression, + expression: Expression, + argumentExpression: Expression, + ) { if (isElementAccessChain(node)) { return updateElementAccessChain(node, expression, node.questionDotToken, argumentExpression); } @@ -2593,22 +2966,34 @@ namespace ts { } // @api - function createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression) { + function createElementAccessChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + index: number | Expression, + ) { const node = createBaseExpression(SyntaxKind.ElementAccessExpression); node.flags |= NodeFlags.OptionalChain; node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true); node.questionDotToken = questionDotToken; node.argumentExpression = asExpression(index); - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.questionDotToken) | - propagateChildFlags(node.argumentExpression) | - TransformFlags.ContainsES2020; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.questionDotToken) + | propagateChildFlags(node.argumentExpression) + | TransformFlags.ContainsES2020; return node; } // @api - function updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression) { - Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a ElementAccessExpression using updateElementAccessChain. Use updateElementAccess instead."); + function updateElementAccessChain( + node: ElementAccessChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + argumentExpression: Expression, + ) { + Debug.assert( + !!(node.flags & NodeFlags.OptionalChain), + "Cannot update a ElementAccessExpression using updateElementAccessChain. Use updateElementAccess instead.", + ); // Because we are updating an existing ElementAccessChain we want to inherit its emitFlags // instead of using the default from createElementAccess return node.expression !== expression @@ -2619,14 +3004,20 @@ namespace ts { } // @api - function createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + function createCallExpression( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ) { const node = createBaseExpression(SyntaxKind.CallExpression); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false); node.typeArguments = asNodeArray(typeArguments); - node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray)); - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildrenFlags(node.typeArguments) | - propagateChildrenFlags(node.arguments); + node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList( + createNodeArray(argumentsArray), + ); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildrenFlags(node.typeArguments) + | propagateChildrenFlags(node.arguments); if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -2640,7 +3031,12 @@ namespace ts { } // @api - function updateCallExpression(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) { + function updateCallExpression( + node: CallExpression, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[], + ) { if (isCallChain(node)) { return updateCallChain(node, expression, node.questionDotToken, typeArguments, argumentsArray); } @@ -2652,18 +3048,25 @@ namespace ts { } // @api - function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + function createCallChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ) { const node = createBaseExpression(SyntaxKind.CallExpression); node.flags |= NodeFlags.OptionalChain; node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true); node.questionDotToken = questionDotToken; node.typeArguments = asNodeArray(typeArguments); - node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray)); - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.questionDotToken) | - propagateChildrenFlags(node.typeArguments) | - propagateChildrenFlags(node.arguments) | - TransformFlags.ContainsES2020; + node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList( + createNodeArray(argumentsArray), + ); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.questionDotToken) + | propagateChildrenFlags(node.typeArguments) + | propagateChildrenFlags(node.arguments) + | TransformFlags.ContainsES2020; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -2674,8 +3077,17 @@ namespace ts { } // @api - function updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) { - Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a CallExpression using updateCallChain. Use updateCall instead."); + function updateCallChain( + node: CallChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[], + ) { + Debug.assert( + !!(node.flags & NodeFlags.OptionalChain), + "Cannot update a CallExpression using updateCallChain. Use updateCall instead.", + ); return node.expression !== expression || node.questionDotToken !== questionDotToken || node.typeArguments !== typeArguments @@ -2685,15 +3097,20 @@ namespace ts { } // @api - function createNewExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + function createNewExpression( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ) { const node = createBaseExpression(SyntaxKind.NewExpression); node.expression = parenthesizerRules().parenthesizeExpressionOfNew(expression); node.typeArguments = asNodeArray(typeArguments); - node.arguments = argumentsArray ? parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(argumentsArray) : undefined; - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildrenFlags(node.typeArguments) | - propagateChildrenFlags(node.arguments) | - TransformFlags.ContainsES2020; + node.arguments = argumentsArray + ? parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(argumentsArray) : undefined; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildrenFlags(node.typeArguments) + | propagateChildrenFlags(node.arguments) + | TransformFlags.ContainsES2020; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -2701,7 +3118,12 @@ namespace ts { } // @api - function updateNewExpression(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + function updateNewExpression( + node: NewExpression, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ) { return node.expression !== expression || node.typeArguments !== typeArguments || node.arguments !== argumentsArray @@ -2710,15 +3132,19 @@ namespace ts { } // @api - function createTaggedTemplateExpression(tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral) { + function createTaggedTemplateExpression( + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ) { const node = createBaseExpression(SyntaxKind.TaggedTemplateExpression); node.tag = parenthesizerRules().parenthesizeLeftSideOfAccess(tag, /*optionalChain*/ false); node.typeArguments = asNodeArray(typeArguments); node.template = template; - node.transformFlags |= propagateChildFlags(node.tag) | - propagateChildrenFlags(node.typeArguments) | - propagateChildFlags(node.template) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.tag) + | propagateChildrenFlags(node.typeArguments) + | propagateChildFlags(node.template) + | TransformFlags.ContainsES2015; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -2729,7 +3155,12 @@ namespace ts { } // @api - function updateTaggedTemplateExpression(node: TaggedTemplateExpression, tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral) { + function updateTaggedTemplateExpression( + node: TaggedTemplateExpression, + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ) { return node.tag !== tag || node.typeArguments !== typeArguments || node.template !== template @@ -2742,9 +3173,9 @@ namespace ts { const node = createBaseExpression(SyntaxKind.TypeAssertionExpression); node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression); node.type = type; - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.type) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.type) + | TransformFlags.ContainsTypeScript; return node; } @@ -2827,7 +3258,10 @@ namespace ts { || node.parameters !== parameters || node.type !== type || node.body !== body - ? finishUpdateBaseSignatureDeclaration(createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body), node) + ? finishUpdateBaseSignatureDeclaration( + createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body), + node, + ) : node; } @@ -2850,8 +3284,8 @@ namespace ts { parenthesizerRules().parenthesizeConciseBodyOfArrowFunction(body), ); node.equalsGreaterThanToken = equalsGreaterThanToken ?? createToken(SyntaxKind.EqualsGreaterThanToken); - node.transformFlags |= propagateChildFlags(node.equalsGreaterThanToken) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.equalsGreaterThanToken) + | TransformFlags.ContainsES2015; if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) { node.transformFlags |= TransformFlags.ContainsES2017 | TransformFlags.ContainsLexicalThis; } @@ -2874,7 +3308,10 @@ namespace ts { || node.type !== type || node.equalsGreaterThanToken !== equalsGreaterThanToken || node.body !== body - ? finishUpdateBaseSignatureDeclaration(createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body), node) + ? finishUpdateBaseSignatureDeclaration( + createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body), + node, + ) : node; } @@ -2927,10 +3364,10 @@ namespace ts { function createAwaitExpression(expression: Expression) { const node = createBaseExpression(SyntaxKind.AwaitExpression); node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression); - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsES2017 | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsAwait; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2017 + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsAwait; return node; } @@ -2950,10 +3387,10 @@ namespace ts { // Only set this flag for non-generated identifiers and non-"local" names. See the // comment in `visitPreOrPostfixUnaryExpression` in module.ts if ( - (operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken) && - isIdentifier(node.operand) && - !isGeneratedIdentifier(node.operand) && - !isLocalName(node.operand) + (operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken) + && isIdentifier(node.operand) + && !isGeneratedIdentifier(node.operand) + && !isLocalName(node.operand) ) { node.transformFlags |= TransformFlags.ContainsUpdateExpressionForIdentifier; } @@ -2976,9 +3413,9 @@ namespace ts { // Only set this flag for non-generated identifiers and non-"local" names. See the // comment in `visitPreOrPostfixUnaryExpression` in module.ts if ( - isIdentifier(node.operand) && - !isGeneratedIdentifier(node.operand) && - !isLocalName(node.operand) + isIdentifier(node.operand) + && !isGeneratedIdentifier(node.operand) + && !isLocalName(node.operand) ) { node.transformFlags |= TransformFlags.ContainsUpdateExpressionForIdentifier; } @@ -2993,33 +3430,40 @@ namespace ts { } // @api - function createBinaryExpression(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression) { + function createBinaryExpression( + left: Expression, + operator: BinaryOperator | BinaryOperatorToken, + right: Expression, + ) { const node = createBaseExpression(SyntaxKind.BinaryExpression); const operatorToken = asToken(operator); const operatorKind = operatorToken.kind; node.left = parenthesizerRules().parenthesizeLeftSideOfBinary(operatorKind, left); node.operatorToken = operatorToken; node.right = parenthesizerRules().parenthesizeRightSideOfBinary(operatorKind, node.left, right); - node.transformFlags |= propagateChildFlags(node.left) | - propagateChildFlags(node.operatorToken) | - propagateChildFlags(node.right); + node.transformFlags |= propagateChildFlags(node.left) + | propagateChildFlags(node.operatorToken) + | propagateChildFlags(node.right); if (operatorKind === SyntaxKind.QuestionQuestionToken) { node.transformFlags |= TransformFlags.ContainsES2020; } else if (operatorKind === SyntaxKind.EqualsToken) { if (isObjectLiteralExpression(node.left)) { - node.transformFlags |= TransformFlags.ContainsES2015 | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsDestructuringAssignment | - propagateAssignmentPatternFlags(node.left); + node.transformFlags |= TransformFlags.ContainsES2015 + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsDestructuringAssignment + | propagateAssignmentPatternFlags(node.left); } else if (isArrayLiteralExpression(node.left)) { - node.transformFlags |= TransformFlags.ContainsES2015 | - TransformFlags.ContainsDestructuringAssignment | - propagateAssignmentPatternFlags(node.left); + node.transformFlags |= TransformFlags.ContainsES2015 + | TransformFlags.ContainsDestructuringAssignment + | propagateAssignmentPatternFlags(node.left); } } - else if (operatorKind === SyntaxKind.AsteriskAsteriskToken || operatorKind === SyntaxKind.AsteriskAsteriskEqualsToken) { + else if ( + operatorKind === SyntaxKind.AsteriskAsteriskToken + || operatorKind === SyntaxKind.AsteriskAsteriskEqualsToken + ) { node.transformFlags |= TransformFlags.ContainsES2016; } else if (isLogicalOrCoalescingAssignmentOperator(operatorKind)) { @@ -3032,7 +3476,9 @@ namespace ts { } function propagateAssignmentPatternFlags(node: AssignmentPattern): TransformFlags { - if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) return TransformFlags.ContainsObjectRestOrSpread; + if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { + return TransformFlags.ContainsObjectRestOrSpread; + } if (node.transformFlags & TransformFlags.ContainsES2018) { // check for nested spread assignments, otherwise '{ x: { a, ...b } = foo } = c' // will not be correctly interpreted by the ES2018 transformer @@ -3053,7 +3499,12 @@ namespace ts { } // @api - function updateBinaryExpression(node: BinaryExpression, left: Expression, operator: BinaryOperatorToken, right: Expression) { + function updateBinaryExpression( + node: BinaryExpression, + left: Expression, + operator: BinaryOperatorToken, + right: Expression, + ) { return node.left !== left || node.operatorToken !== operator || node.right !== right @@ -3062,18 +3513,24 @@ namespace ts { } // @api - function createConditionalExpression(condition: Expression, questionToken: QuestionToken | undefined, whenTrue: Expression, colonToken: ColonToken | undefined, whenFalse: Expression) { + function createConditionalExpression( + condition: Expression, + questionToken: QuestionToken | undefined, + whenTrue: Expression, + colonToken: ColonToken | undefined, + whenFalse: Expression, + ) { const node = createBaseExpression(SyntaxKind.ConditionalExpression); node.condition = parenthesizerRules().parenthesizeConditionOfConditionalExpression(condition); node.questionToken = questionToken ?? createToken(SyntaxKind.QuestionToken); node.whenTrue = parenthesizerRules().parenthesizeBranchOfConditionalExpression(whenTrue); node.colonToken = colonToken ?? createToken(SyntaxKind.ColonToken); node.whenFalse = parenthesizerRules().parenthesizeBranchOfConditionalExpression(whenFalse); - node.transformFlags |= propagateChildFlags(node.condition) | - propagateChildFlags(node.questionToken) | - propagateChildFlags(node.whenTrue) | - propagateChildFlags(node.colonToken) | - propagateChildFlags(node.whenFalse); + node.transformFlags |= propagateChildFlags(node.condition) + | propagateChildFlags(node.questionToken) + | propagateChildFlags(node.whenTrue) + | propagateChildFlags(node.colonToken) + | propagateChildFlags(node.whenFalse); return node; } @@ -3100,21 +3557,30 @@ namespace ts { const node = createBaseExpression(SyntaxKind.TemplateExpression); node.head = head; node.templateSpans = createNodeArray(templateSpans); - node.transformFlags |= propagateChildFlags(node.head) | - propagateChildrenFlags(node.templateSpans) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.head) + | propagateChildrenFlags(node.templateSpans) + | TransformFlags.ContainsES2015; return node; } // @api - function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]) { + function updateTemplateExpression( + node: TemplateExpression, + head: TemplateHead, + templateSpans: readonly TemplateSpan[], + ) { return node.head !== head || node.templateSpans !== templateSpans ? update(createTemplateExpression(head, templateSpans), node) : node; } - function createTemplateLiteralLikeNodeChecked(kind: TemplateLiteralToken["kind"], text: string | undefined, rawText: string | undefined, templateFlags = TokenFlags.None) { + function createTemplateLiteralLikeNodeChecked( + kind: TemplateLiteralToken["kind"], + text: string | undefined, + rawText: string | undefined, + templateFlags = TokenFlags.None, + ) { Debug.assert(!(templateFlags & ~TokenFlags.TemplateLiteralLikeFlags), "Unsupported template flags."); // NOTE: without the assignment to `undefined`, we don't narrow the initial type of `cooked`. // eslint-disable-next-line no-undef-init @@ -3132,13 +3598,21 @@ namespace ts { text = cooked; } else if (cooked !== undefined) { - Debug.assert(text === cooked, "Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'."); + Debug.assert( + text === cooked, + "Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'.", + ); } return createTemplateLiteralLikeNode(kind, text, rawText, templateFlags); } // @api - function createTemplateLiteralLikeNode(kind: TemplateLiteralToken["kind"], text: string, rawText: string | undefined, templateFlags: TokenFlags | undefined) { + function createTemplateLiteralLikeNode( + kind: TemplateLiteralToken["kind"], + text: string, + rawText: string | undefined, + templateFlags: TokenFlags | undefined, + ) { const node = createBaseToken(kind); node.text = text; node.rawText = rawText; @@ -3152,40 +3626,74 @@ namespace ts { // @api function createTemplateHead(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) { - return createTemplateLiteralLikeNodeChecked(SyntaxKind.TemplateHead, text, rawText, templateFlags) as TemplateHead; + return createTemplateLiteralLikeNodeChecked( + SyntaxKind.TemplateHead, + text, + rawText, + templateFlags, + ) as TemplateHead; } // @api function createTemplateMiddle(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) { - return createTemplateLiteralLikeNodeChecked(SyntaxKind.TemplateMiddle, text, rawText, templateFlags) as TemplateMiddle; + return createTemplateLiteralLikeNodeChecked( + SyntaxKind.TemplateMiddle, + text, + rawText, + templateFlags, + ) as TemplateMiddle; } // @api function createTemplateTail(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) { - return createTemplateLiteralLikeNodeChecked(SyntaxKind.TemplateTail, text, rawText, templateFlags) as TemplateTail; + return createTemplateLiteralLikeNodeChecked( + SyntaxKind.TemplateTail, + text, + rawText, + templateFlags, + ) as TemplateTail; } // @api - function createNoSubstitutionTemplateLiteral(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) { - return createTemplateLiteralLikeNodeChecked(SyntaxKind.NoSubstitutionTemplateLiteral, text, rawText, templateFlags) as NoSubstitutionTemplateLiteral; + function createNoSubstitutionTemplateLiteral( + text: string | undefined, + rawText?: string, + templateFlags?: TokenFlags, + ) { + return createTemplateLiteralLikeNodeChecked( + SyntaxKind.NoSubstitutionTemplateLiteral, + text, + rawText, + templateFlags, + ) as NoSubstitutionTemplateLiteral; } // @api - function createYieldExpression(asteriskToken: AsteriskToken | undefined, expression: Expression | undefined): YieldExpression { - Debug.assert(!asteriskToken || !!expression, "A `YieldExpression` with an asteriskToken must have an expression."); + function createYieldExpression( + asteriskToken: AsteriskToken | undefined, + expression: Expression | undefined, + ): YieldExpression { + Debug.assert( + !asteriskToken || !!expression, + "A `YieldExpression` with an asteriskToken must have an expression.", + ); const node = createBaseExpression(SyntaxKind.YieldExpression); node.expression = expression && parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.asteriskToken = asteriskToken; - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.asteriskToken) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsYield; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.asteriskToken) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsYield; return node; } // @api - function updateYieldExpression(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression) { + function updateYieldExpression( + node: YieldExpression, + asteriskToken: AsteriskToken | undefined, + expression: Expression, + ) { return node.expression !== expression || node.asteriskToken !== asteriskToken ? update(createYieldExpression(asteriskToken, expression), node) @@ -3196,9 +3704,9 @@ namespace ts { function createSpreadElement(expression: Expression) { const node = createBaseExpression(SyntaxKind.SpreadElement); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsRestOrSpread; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsRestOrSpread; return node; } @@ -3253,18 +3761,25 @@ namespace ts { } // @api - function createExpressionWithTypeArguments(expression: Expression, typeArguments: readonly TypeNode[] | undefined) { + function createExpressionWithTypeArguments( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + ) { const node = createBaseNode(SyntaxKind.ExpressionWithTypeArguments); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false); node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(typeArguments); - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildrenFlags(node.typeArguments) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildrenFlags(node.typeArguments) + | TransformFlags.ContainsES2015; return node; } // @api - function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, expression: Expression, typeArguments: readonly TypeNode[] | undefined) { + function updateExpressionWithTypeArguments( + node: ExpressionWithTypeArguments, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + ) { return node.expression !== expression || node.typeArguments !== typeArguments ? update(createExpressionWithTypeArguments(expression, typeArguments), node) @@ -3276,9 +3791,9 @@ namespace ts { const node = createBaseExpression(SyntaxKind.AsExpression); node.expression = expression; node.type = type; - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.type) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.type) + | TransformFlags.ContainsTypeScript; return node; } @@ -3294,8 +3809,8 @@ namespace ts { function createNonNullExpression(expression: Expression) { const node = createBaseExpression(SyntaxKind.NonNullExpression); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false); - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsTypeScript; return node; } @@ -3314,9 +3829,9 @@ namespace ts { const node = createBaseExpression(SyntaxKind.SatisfiesExpression); node.expression = expression; node.type = type; - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.type) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.type) + | TransformFlags.ContainsTypeScript; return node; } @@ -3333,14 +3848,17 @@ namespace ts { const node = createBaseExpression(SyntaxKind.NonNullExpression); node.flags |= NodeFlags.OptionalChain; node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true); - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsTypeScript; return node; } // @api function updateNonNullChain(node: NonNullChain, expression: Expression) { - Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a NonNullExpression using updateNonNullChain. Use updateNonNullExpression instead."); + Debug.assert( + !!(node.flags & NodeFlags.OptionalChain), + "Cannot update a NonNullExpression using updateNonNullChain. Use updateNonNullExpression instead.", + ); return node.expression !== expression ? update(createNonNullChain(expression), node) : node; @@ -3381,14 +3899,18 @@ namespace ts { const node = createBaseNode(SyntaxKind.TemplateSpan); node.expression = expression; node.literal = literal; - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.literal) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.literal) + | TransformFlags.ContainsES2015; return node; } // @api - function updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail) { + function updateTemplateSpan( + node: TemplateSpan, + expression: Expression, + literal: TemplateMiddle | TemplateTail, + ) { return node.expression !== expression || node.literal !== literal ? update(createTemplateSpan(expression, literal), node) @@ -3423,12 +3945,16 @@ namespace ts { } // @api - function createVariableStatement(modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList | readonly VariableDeclaration[]) { + function createVariableStatement( + modifiers: readonly Modifier[] | undefined, + declarationList: VariableDeclarationList | readonly VariableDeclaration[], + ) { const node = createBaseDeclaration(SyntaxKind.VariableStatement); node.modifiers = asNodeArray(modifiers); - node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) : declarationList; - node.transformFlags |= propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.declarationList); + node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) + : declarationList; + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.declarationList); if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags = TransformFlags.ContainsTypeScript; } @@ -3436,7 +3962,11 @@ namespace ts { } // @api - function updateVariableStatement(node: VariableStatement, modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList) { + function updateVariableStatement( + node: VariableStatement, + modifiers: readonly Modifier[] | undefined, + declarationList: VariableDeclarationList, + ) { return node.modifiers !== modifiers || node.declarationList !== declarationList ? update(createVariableStatement(modifiers, declarationList), node) @@ -3469,14 +3999,19 @@ namespace ts { node.expression = expression; node.thenStatement = asEmbeddedStatement(thenStatement); node.elseStatement = asEmbeddedStatement(elseStatement); - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.thenStatement) | - propagateChildFlags(node.elseStatement); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.thenStatement) + | propagateChildFlags(node.elseStatement); return node; } // @api - function updateIfStatement(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement | undefined) { + function updateIfStatement( + node: IfStatement, + expression: Expression, + thenStatement: Statement, + elseStatement: Statement | undefined, + ) { return node.expression !== expression || node.thenStatement !== thenStatement || node.elseStatement !== elseStatement @@ -3489,8 +4024,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.DoStatement); node.statement = asEmbeddedStatement(statement); node.expression = expression; - node.transformFlags |= propagateChildFlags(node.statement) | - propagateChildFlags(node.expression); + node.transformFlags |= propagateChildFlags(node.statement) + | propagateChildFlags(node.expression); return node; } @@ -3507,8 +4042,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.WhileStatement); node.expression = expression; node.statement = asEmbeddedStatement(statement); - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.statement); return node; } @@ -3521,21 +4056,32 @@ namespace ts { } // @api - function createForStatement(initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) { + function createForStatement( + initializer: ForInitializer | undefined, + condition: Expression | undefined, + incrementor: Expression | undefined, + statement: Statement, + ) { const node = createBaseNode(SyntaxKind.ForStatement); node.initializer = initializer; node.condition = condition; node.incrementor = incrementor; node.statement = asEmbeddedStatement(statement); - node.transformFlags |= propagateChildFlags(node.initializer) | - propagateChildFlags(node.condition) | - propagateChildFlags(node.incrementor) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.initializer) + | propagateChildFlags(node.condition) + | propagateChildFlags(node.incrementor) + | propagateChildFlags(node.statement); return node; } // @api - function updateForStatement(node: ForStatement, initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) { + function updateForStatement( + node: ForStatement, + initializer: ForInitializer | undefined, + condition: Expression | undefined, + incrementor: Expression | undefined, + statement: Statement, + ) { return node.initializer !== initializer || node.condition !== condition || node.incrementor !== incrementor @@ -3550,14 +4096,19 @@ namespace ts { node.initializer = initializer; node.expression = expression; node.statement = asEmbeddedStatement(statement); - node.transformFlags |= propagateChildFlags(node.initializer) | - propagateChildFlags(node.expression) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.initializer) + | propagateChildFlags(node.expression) + | propagateChildFlags(node.statement); return node; } // @api - function updateForInStatement(node: ForInStatement, initializer: ForInitializer, expression: Expression, statement: Statement) { + function updateForInStatement( + node: ForInStatement, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ) { return node.initializer !== initializer || node.expression !== expression || node.statement !== statement @@ -3566,23 +4117,34 @@ namespace ts { } // @api - function createForOfStatement(awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) { + function createForOfStatement( + awaitModifier: AwaitKeyword | undefined, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ) { const node = createBaseNode(SyntaxKind.ForOfStatement); node.awaitModifier = awaitModifier; node.initializer = initializer; node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.statement = asEmbeddedStatement(statement); - node.transformFlags |= propagateChildFlags(node.awaitModifier) | - propagateChildFlags(node.initializer) | - propagateChildFlags(node.expression) | - propagateChildFlags(node.statement) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.awaitModifier) + | propagateChildFlags(node.initializer) + | propagateChildFlags(node.expression) + | propagateChildFlags(node.statement) + | TransformFlags.ContainsES2015; if (awaitModifier) node.transformFlags |= TransformFlags.ContainsES2018; return node; } // @api - function updateForOfStatement(node: ForOfStatement, awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) { + function updateForOfStatement( + node: ForOfStatement, + awaitModifier: AwaitKeyword | undefined, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ) { return node.awaitModifier !== awaitModifier || node.initializer !== initializer || node.expression !== expression @@ -3595,8 +4157,8 @@ namespace ts { function createContinueStatement(label?: string | Identifier): ContinueStatement { const node = createBaseNode(SyntaxKind.ContinueStatement); node.label = asName(label); - node.transformFlags |= propagateChildFlags(node.label) | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags |= propagateChildFlags(node.label) + | TransformFlags.ContainsHoistedDeclarationOrCompletion; return node; } @@ -3611,8 +4173,8 @@ namespace ts { function createBreakStatement(label?: string | Identifier): BreakStatement { const node = createBaseNode(SyntaxKind.BreakStatement); node.label = asName(label); - node.transformFlags |= propagateChildFlags(node.label) | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags |= propagateChildFlags(node.label) + | TransformFlags.ContainsHoistedDeclarationOrCompletion; return node; } @@ -3628,9 +4190,9 @@ namespace ts { const node = createBaseNode(SyntaxKind.ReturnStatement); node.expression = expression; // return in an ES2018 async generator must be awaited - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsHoistedDeclarationOrCompletion; return node; } @@ -3646,8 +4208,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.WithStatement); node.expression = expression; node.statement = asEmbeddedStatement(statement); - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.statement); return node; } @@ -3664,8 +4226,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.SwitchStatement); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.caseBlock = caseBlock; - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.caseBlock); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.caseBlock); return node; } @@ -3682,8 +4244,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.LabeledStatement); node.label = asName(label); node.statement = asEmbeddedStatement(statement); - node.transformFlags |= propagateChildFlags(node.label) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.label) + | propagateChildFlags(node.statement); return node; } @@ -3711,19 +4273,28 @@ namespace ts { } // @api - function createTryStatement(tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) { + function createTryStatement( + tryBlock: Block, + catchClause: CatchClause | undefined, + finallyBlock: Block | undefined, + ) { const node = createBaseNode(SyntaxKind.TryStatement); node.tryBlock = tryBlock; node.catchClause = catchClause; node.finallyBlock = finallyBlock; - node.transformFlags |= propagateChildFlags(node.tryBlock) | - propagateChildFlags(node.catchClause) | - propagateChildFlags(node.finallyBlock); + node.transformFlags |= propagateChildFlags(node.tryBlock) + | propagateChildFlags(node.catchClause) + | propagateChildFlags(node.finallyBlock); return node; } // @api - function updateTryStatement(node: TryStatement, tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) { + function updateTryStatement( + node: TryStatement, + tryBlock: Block, + catchClause: CatchClause | undefined, + finallyBlock: Block | undefined, + ) { return node.tryBlock !== tryBlock || node.catchClause !== catchClause || node.finallyBlock !== finallyBlock @@ -3737,7 +4308,12 @@ namespace ts { } // @api - function createVariableDeclaration(name: string | BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { + function createVariableDeclaration( + name: string | BindingName, + exclamationToken: ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ) { const node = createBaseVariableLikeDeclaration( SyntaxKind.VariableDeclaration, /*modifiers*/ undefined, @@ -3754,7 +4330,13 @@ namespace ts { } // @api - function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { + function updateVariableDeclaration( + node: VariableDeclaration, + name: BindingName, + exclamationToken: ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ) { return node.name !== name || node.type !== type || node.exclamationToken !== exclamationToken @@ -3768,17 +4350,20 @@ namespace ts { const node = createBaseNode(SyntaxKind.VariableDeclarationList); node.flags |= flags & NodeFlags.BlockScoped; node.declarations = createNodeArray(declarations); - node.transformFlags |= propagateChildrenFlags(node.declarations) | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags |= propagateChildrenFlags(node.declarations) + | TransformFlags.ContainsHoistedDeclarationOrCompletion; if (flags & NodeFlags.BlockScoped) { - node.transformFlags |= TransformFlags.ContainsES2015 | - TransformFlags.ContainsBlockScopedBinding; + node.transformFlags |= TransformFlags.ContainsES2015 + | TransformFlags.ContainsBlockScopedBinding; } return node; } // @api - function updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]) { + function updateVariableDeclarationList( + node: VariableDeclarationList, + declarations: readonly VariableDeclaration[], + ) { return node.declarations !== declarations ? update(createVariableDeclarationList(declarations, node.flags), node) : node; @@ -3808,8 +4393,8 @@ namespace ts { node.transformFlags = TransformFlags.ContainsTypeScript; } else { - node.transformFlags |= propagateChildFlags(node.asteriskToken) | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags |= propagateChildFlags(node.asteriskToken) + | TransformFlags.ContainsHoistedDeclarationOrCompletion; if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) { if (node.asteriskToken) { node.transformFlags |= TransformFlags.ContainsES2018; @@ -3846,7 +4431,10 @@ namespace ts { || node.parameters !== parameters || node.type !== type || node.body !== body - ? finishUpdateFunctionDeclaration(createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body), node) + ? finishUpdateFunctionDeclaration( + createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body), + node, + ) : node; } @@ -3941,11 +4529,17 @@ namespace ts { || node.typeParameters !== typeParameters || node.heritageClauses !== heritageClauses || node.members !== members - ? finishUpdateInterfaceDeclaration(createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members), node) + ? finishUpdateInterfaceDeclaration( + createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members), + node, + ) : node; } - function finishUpdateInterfaceDeclaration(updated: Mutable, original: InterfaceDeclaration) { + function finishUpdateInterfaceDeclaration( + updated: Mutable, + original: InterfaceDeclaration, + ) { if (updated !== original) { updated.illegalDecorators = original.illegalDecorators; } @@ -3985,11 +4579,17 @@ namespace ts { || node.name !== name || node.typeParameters !== typeParameters || node.type !== type - ? finishUpdateTypeAliasDeclaration(createTypeAliasDeclaration(modifiers, name, typeParameters, type), node) + ? finishUpdateTypeAliasDeclaration( + createTypeAliasDeclaration(modifiers, name, typeParameters, type), + node, + ) : node; } - function finishUpdateTypeAliasDeclaration(updated: Mutable, original: TypeAliasDeclaration) { + function finishUpdateTypeAliasDeclaration( + updated: Mutable, + original: TypeAliasDeclaration, + ) { if (updated !== original) { updated.illegalDecorators = original.illegalDecorators; } @@ -4008,8 +4608,8 @@ namespace ts { name, ); node.members = createNodeArray(members); - node.transformFlags |= propagateChildrenFlags(node.members) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildrenFlags(node.members) + | TransformFlags.ContainsTypeScript; node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Enum declarations cannot contain `await` // The following properties are used only to report grammar errors @@ -4054,10 +4654,10 @@ namespace ts { node.transformFlags = TransformFlags.ContainsTypeScript; } else { - node.transformFlags |= propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.name) | - propagateChildFlags(node.body) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.name) + | propagateChildFlags(node.body) + | TransformFlags.ContainsTypeScript; } node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Module declarations cannot contain `await`. @@ -4139,7 +4739,10 @@ namespace ts { : node; } - function finishUpdateNamespaceExportDeclaration(updated: Mutable, original: NamespaceExportDeclaration) { + function finishUpdateNamespaceExportDeclaration( + updated: Mutable, + original: NamespaceExportDeclaration, + ) { if (updated !== original) { updated.illegalDecorators = original.illegalDecorators; updated.modifiers = original.modifiers; @@ -4162,7 +4765,9 @@ namespace ts { node.isTypeOnly = isTypeOnly; node.moduleReference = moduleReference; node.transformFlags |= propagateChildFlags(node.moduleReference); - if (!isExternalModuleReference(node.moduleReference)) node.transformFlags |= TransformFlags.ContainsTypeScript; + if (!isExternalModuleReference(node.moduleReference)) { + node.transformFlags |= TransformFlags.ContainsTypeScript; + } node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Import= declaration is always parsed in an Await context // The following properties are used only to report grammar errors @@ -4182,11 +4787,17 @@ namespace ts { || node.isTypeOnly !== isTypeOnly || node.name !== name || node.moduleReference !== moduleReference - ? finishUpdateImportEqualsDeclaration(createImportEqualsDeclaration(modifiers, isTypeOnly, name, moduleReference), node) + ? finishUpdateImportEqualsDeclaration( + createImportEqualsDeclaration(modifiers, isTypeOnly, name, moduleReference), + node, + ) : node; } - function finishUpdateImportEqualsDeclaration(updated: Mutable, original: ImportEqualsDeclaration) { + function finishUpdateImportEqualsDeclaration( + updated: Mutable, + original: ImportEqualsDeclaration, + ) { if (updated !== original) { updated.illegalDecorators = original.illegalDecorators; } @@ -4205,8 +4816,8 @@ namespace ts { node.importClause = importClause; node.moduleSpecifier = moduleSpecifier; node.assertClause = assertClause; - node.transformFlags |= propagateChildFlags(node.importClause) | - propagateChildFlags(node.moduleSpecifier); + node.transformFlags |= propagateChildFlags(node.importClause) + | propagateChildFlags(node.moduleSpecifier); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context // The following properties are used only to report grammar errors @@ -4226,7 +4837,10 @@ namespace ts { || node.importClause !== importClause || node.moduleSpecifier !== moduleSpecifier || node.assertClause !== assertClause - ? finishUpdateImportDeclaration(createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause), node) + ? finishUpdateImportDeclaration( + createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause), + node, + ) : node; } @@ -4238,13 +4852,17 @@ namespace ts { } // @api - function createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause { + function createImportClause( + isTypeOnly: boolean, + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + ): ImportClause { const node = createBaseNode(SyntaxKind.ImportClause); node.isTypeOnly = isTypeOnly; node.name = name; node.namedBindings = namedBindings; - node.transformFlags |= propagateChildFlags(node.name) | - propagateChildFlags(node.namedBindings); + node.transformFlags |= propagateChildFlags(node.name) + | propagateChildFlags(node.namedBindings); if (isTypeOnly) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -4253,7 +4871,12 @@ namespace ts { } // @api - function updateImportClause(node: ImportClause, isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined) { + function updateImportClause( + node: ImportClause, + isTypeOnly: boolean, + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + ) { return node.isTypeOnly !== isTypeOnly || node.name !== name || node.namedBindings !== namedBindings @@ -4271,7 +4894,11 @@ namespace ts { } // @api - function updateAssertClause(node: AssertClause, elements: readonly AssertEntry[], multiLine?: boolean): AssertClause { + function updateAssertClause( + node: AssertClause, + elements: readonly AssertEntry[], + multiLine?: boolean, + ): AssertClause { return node.elements !== elements || node.multiLine !== multiLine ? update(createAssertClause(elements, multiLine), node) @@ -4296,7 +4923,10 @@ namespace ts { } // @api - function createImportTypeAssertionContainer(clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer { + function createImportTypeAssertionContainer( + clause: AssertClause, + multiLine?: boolean, + ): ImportTypeAssertionContainer { const node = createBaseNode(SyntaxKind.ImportTypeAssertionContainer); node.assertClause = clause; node.multiLine = multiLine; @@ -4304,7 +4934,11 @@ namespace ts { } // @api - function updateImportTypeAssertionContainer(node: ImportTypeAssertionContainer, clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer { + function updateImportTypeAssertionContainer( + node: ImportTypeAssertionContainer, + clause: AssertClause, + multiLine?: boolean, + ): ImportTypeAssertionContainer { return node.assertClause !== clause || node.multiLine !== multiLine ? update(createImportTypeAssertionContainer(clause, multiLine), node) @@ -4331,8 +4965,8 @@ namespace ts { function createNamespaceExport(name: Identifier): NamespaceExport { const node = createBaseNode(SyntaxKind.NamespaceExport); node.name = name; - node.transformFlags |= propagateChildFlags(node.name) | - TransformFlags.ContainsESNext; + node.transformFlags |= propagateChildFlags(node.name) + | TransformFlags.ContainsESNext; node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } @@ -4366,14 +5000,19 @@ namespace ts { node.isTypeOnly = isTypeOnly; node.propertyName = propertyName; node.name = name; - node.transformFlags |= propagateChildFlags(node.propertyName) | - propagateChildFlags(node.name); + node.transformFlags |= propagateChildFlags(node.propertyName) + | propagateChildFlags(node.name); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api - function updateImportSpecifier(node: ImportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier) { + function updateImportSpecifier( + node: ImportSpecifier, + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier, + ) { return node.isTypeOnly !== isTypeOnly || node.propertyName !== propertyName || node.name !== name @@ -4391,7 +5030,11 @@ namespace ts { node.modifiers = asNodeArray(modifiers); node.isExportEquals = isExportEquals; node.expression = isExportEquals - ? parenthesizerRules().parenthesizeRightSideOfBinary(SyntaxKind.EqualsToken, /*leftSide*/ undefined, expression) + ? parenthesizerRules().parenthesizeRightSideOfBinary( + SyntaxKind.EqualsToken, + /*leftSide*/ undefined, + expression, + ) : parenthesizerRules().parenthesizeExpressionOfExportDefault(expression); node.transformFlags |= propagateChildrenFlags(node.modifiers) | propagateChildFlags(node.expression); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context @@ -4434,9 +5077,9 @@ namespace ts { node.exportClause = exportClause; node.moduleSpecifier = moduleSpecifier; node.assertClause = assertClause; - node.transformFlags |= propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.exportClause) | - propagateChildFlags(node.moduleSpecifier); + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.exportClause) + | propagateChildFlags(node.moduleSpecifier); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context // The following properties are used only to report grammar errors @@ -4458,7 +5101,10 @@ namespace ts { || node.exportClause !== exportClause || node.moduleSpecifier !== moduleSpecifier || node.assertClause !== assertClause - ? finishUpdateExportDeclaration(createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause), node) + ? finishUpdateExportDeclaration( + createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause), + node, + ) : node; } @@ -4486,19 +5132,28 @@ namespace ts { } // @api - function createExportSpecifier(isTypeOnly: boolean, propertyName: string | Identifier | undefined, name: string | Identifier) { + function createExportSpecifier( + isTypeOnly: boolean, + propertyName: string | Identifier | undefined, + name: string | Identifier, + ) { const node = createBaseNode(SyntaxKind.ExportSpecifier); node.isTypeOnly = isTypeOnly; node.propertyName = asName(propertyName); node.name = asName(name); - node.transformFlags |= propagateChildFlags(node.propertyName) | - propagateChildFlags(node.name); + node.transformFlags |= propagateChildFlags(node.propertyName) + | propagateChildFlags(node.name); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api - function updateExportSpecifier(node: ExportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier) { + function updateExportSpecifier( + node: ExportSpecifier, + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier, + ) { return node.isTypeOnly !== isTypeOnly || node.propertyName !== propertyName || node.name !== name @@ -4546,7 +5201,9 @@ namespace ts { // @api // createJSDocNullableType // createJSDocNonNullableType - function createJSDocPrePostfixUnaryTypeWorker(kind: T["kind"], type: T["type"], postfix = false): T { + function createJSDocPrePostfixUnaryTypeWorker< + T extends JSDocType & { readonly type: TypeNode | undefined; readonly postfix: boolean; }, + >(kind: T["kind"], type: T["type"], postfix = false): T { const node = createJSDocUnaryTypeWorker( kind, postfix ? type && parenthesizerRules().parenthesizeNonArrayTypeOfPostfixType(type) : type, @@ -4559,7 +5216,10 @@ namespace ts { // createJSDocOptionalType // createJSDocVariadicType // createJSDocNamepathType - function createJSDocUnaryTypeWorker(kind: T["kind"], type: T["type"]): T { + function createJSDocUnaryTypeWorker( + kind: T["kind"], + type: T["type"], + ): T { const node = createBaseNode(kind); node.type = type; return node; @@ -4568,7 +5228,9 @@ namespace ts { // @api // updateJSDocNonNullableType // updateJSDocNullableType - function updateJSDocPrePostfixUnaryTypeWorker(kind: T["kind"], node: T, type: T["type"]): T { + function updateJSDocPrePostfixUnaryTypeWorker< + T extends JSDocType & { readonly type: TypeNode | undefined; readonly postfix: boolean; }, + >(kind: T["kind"], node: T, type: T["type"]): T { return node.type !== type ? update(createJSDocPrePostfixUnaryTypeWorker(kind, type, node.postfix), node) : node; @@ -4578,14 +5240,21 @@ namespace ts { // updateJSDocOptionalType // updateJSDocVariadicType // updateJSDocNamepathType - function updateJSDocUnaryTypeWorker(kind: T["kind"], node: T, type: T["type"]): T { + function updateJSDocUnaryTypeWorker( + kind: T["kind"], + node: T, + type: T["type"], + ): T { return node.type !== type ? update(createJSDocUnaryTypeWorker(kind, type), node) : node; } // @api - function createJSDocFunctionType(parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType { + function createJSDocFunctionType( + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): JSDocFunctionType { const node = createBaseSignatureDeclaration( SyntaxKind.JSDocFunctionType, /*modifiers*/ undefined, @@ -4598,7 +5267,11 @@ namespace ts { } // @api - function updateJSDocFunctionType(node: JSDocFunctionType, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType { + function updateJSDocFunctionType( + node: JSDocFunctionType, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): JSDocFunctionType { return node.parameters !== parameters || node.type !== type ? update(createJSDocFunctionType(parameters, type), node) @@ -4606,7 +5279,10 @@ namespace ts { } // @api - function createJSDocTypeLiteral(propertyTags?: readonly JSDocPropertyLikeTag[], isArrayType = false): JSDocTypeLiteral { + function createJSDocTypeLiteral( + propertyTags?: readonly JSDocPropertyLikeTag[], + isArrayType = false, + ): JSDocTypeLiteral { const node = createBaseNode(SyntaxKind.JSDocTypeLiteral); node.jsDocPropertyTags = asNodeArray(propertyTags); node.isArrayType = isArrayType; @@ -4614,7 +5290,11 @@ namespace ts { } // @api - function updateJSDocTypeLiteral(node: JSDocTypeLiteral, propertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean): JSDocTypeLiteral { + function updateJSDocTypeLiteral( + node: JSDocTypeLiteral, + propertyTags: readonly JSDocPropertyLikeTag[] | undefined, + isArrayType: boolean, + ): JSDocTypeLiteral { return node.jsDocPropertyTags !== propertyTags || node.isArrayType !== isArrayType ? update(createJSDocTypeLiteral(propertyTags, isArrayType), node) @@ -4636,7 +5316,11 @@ namespace ts { } // @api - function createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature { + function createJSDocSignature( + typeParameters: readonly JSDocTemplateTag[] | undefined, + parameters: readonly JSDocParameterTag[], + type?: JSDocReturnTag, + ): JSDocSignature { const node = createBaseNode(SyntaxKind.JSDocSignature); node.typeParameters = asNodeArray(typeParameters); node.parameters = createNodeArray(parameters); @@ -4645,7 +5329,12 @@ namespace ts { } // @api - function updateJSDocSignature(node: JSDocSignature, typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type: JSDocReturnTag | undefined): JSDocSignature { + function updateJSDocSignature( + node: JSDocSignature, + typeParameters: readonly JSDocTemplateTag[] | undefined, + parameters: readonly JSDocParameterTag[], + type: JSDocReturnTag | undefined, + ): JSDocSignature { return node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type @@ -4661,7 +5350,11 @@ namespace ts { } // @api - function createBaseJSDocTag(kind: T["kind"], tagName: Identifier, comment: string | NodeArray | undefined) { + function createBaseJSDocTag( + kind: T["kind"], + tagName: Identifier, + comment: string | NodeArray | undefined, + ) { const node = createBaseNode(kind); node.tagName = tagName; node.comment = comment; @@ -4669,15 +5362,30 @@ namespace ts { } // @api - function createJSDocTemplateTag(tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment?: string | NodeArray): JSDocTemplateTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocTemplateTag, tagName ?? createIdentifier("template"), comment); + function createJSDocTemplateTag( + tagName: Identifier | undefined, + constraint: JSDocTypeExpression | undefined, + typeParameters: readonly TypeParameterDeclaration[], + comment?: string | NodeArray, + ): JSDocTemplateTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocTemplateTag, + tagName ?? createIdentifier("template"), + comment, + ); node.constraint = constraint; node.typeParameters = createNodeArray(typeParameters); return node; } // @api - function updateJSDocTemplateTag(node: JSDocTemplateTag, tagName: Identifier = getDefaultTagName(node), constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment: string | NodeArray | undefined): JSDocTemplateTag { + function updateJSDocTemplateTag( + node: JSDocTemplateTag, + tagName: Identifier = getDefaultTagName(node), + constraint: JSDocTypeExpression | undefined, + typeParameters: readonly TypeParameterDeclaration[], + comment: string | NodeArray | undefined, + ): JSDocTemplateTag { return node.tagName !== tagName || node.constraint !== constraint || node.typeParameters !== typeParameters @@ -4687,8 +5395,17 @@ namespace ts { } // @api - function createJSDocTypedefTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray): JSDocTypedefTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocTypedefTag, tagName ?? createIdentifier("typedef"), comment); + function createJSDocTypedefTag( + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression, + fullName?: Identifier | JSDocNamespaceDeclaration, + comment?: string | NodeArray, + ): JSDocTypedefTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocTypedefTag, + tagName ?? createIdentifier("typedef"), + comment, + ); node.typeExpression = typeExpression; node.fullName = fullName; node.name = getJSDocTypeAliasName(fullName); @@ -4696,7 +5413,13 @@ namespace ts { } // @api - function updateJSDocTypedefTag(node: JSDocTypedefTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression | undefined, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocTypedefTag { + function updateJSDocTypedefTag( + node: JSDocTypedefTag, + tagName: Identifier = getDefaultTagName(node), + typeExpression: JSDocTypeExpression | undefined, + fullName: Identifier | JSDocNamespaceDeclaration | undefined, + comment: string | NodeArray | undefined, + ): JSDocTypedefTag { return node.tagName !== tagName || node.typeExpression !== typeExpression || node.fullName !== fullName @@ -4706,8 +5429,19 @@ namespace ts { } // @api - function createJSDocParameterTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray): JSDocParameterTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocParameterTag, tagName ?? createIdentifier("param"), comment); + function createJSDocParameterTag( + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression?: JSDocTypeExpression, + isNameFirst?: boolean, + comment?: string | NodeArray, + ): JSDocParameterTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocParameterTag, + tagName ?? createIdentifier("param"), + comment, + ); node.typeExpression = typeExpression; node.name = name; node.isNameFirst = !!isNameFirst; @@ -4716,20 +5450,42 @@ namespace ts { } // @api - function updateJSDocParameterTag(node: JSDocParameterTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray | undefined): JSDocParameterTag { + function updateJSDocParameterTag( + node: JSDocParameterTag, + tagName: Identifier = getDefaultTagName(node), + name: EntityName, + isBracketed: boolean, + typeExpression: JSDocTypeExpression | undefined, + isNameFirst: boolean, + comment: string | NodeArray | undefined, + ): JSDocParameterTag { return node.tagName !== tagName || node.name !== name || node.isBracketed !== isBracketed || node.typeExpression !== typeExpression || node.isNameFirst !== isNameFirst || node.comment !== comment - ? update(createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment), node) - : node; - } - - // @api - function createJSDocPropertyTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray): JSDocPropertyTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocPropertyTag, tagName ?? createIdentifier("prop"), comment); + ? update( + createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment), + node, + ) + : node; + } + + // @api + function createJSDocPropertyTag( + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression?: JSDocTypeExpression, + isNameFirst?: boolean, + comment?: string | NodeArray, + ): JSDocPropertyTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocPropertyTag, + tagName ?? createIdentifier("prop"), + comment, + ); node.typeExpression = typeExpression; node.name = name; node.isNameFirst = !!isNameFirst; @@ -4738,7 +5494,15 @@ namespace ts { } // @api - function updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray | undefined): JSDocPropertyTag { + function updateJSDocPropertyTag( + node: JSDocPropertyTag, + tagName: Identifier = getDefaultTagName(node), + name: EntityName, + isBracketed: boolean, + typeExpression: JSDocTypeExpression | undefined, + isNameFirst: boolean, + comment: string | NodeArray | undefined, + ): JSDocPropertyTag { return node.tagName !== tagName || node.name !== name || node.isBracketed !== isBracketed @@ -4750,8 +5514,17 @@ namespace ts { } // @api - function createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray): JSDocCallbackTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocCallbackTag, tagName ?? createIdentifier("callback"), comment); + function createJSDocCallbackTag( + tagName: Identifier | undefined, + typeExpression: JSDocSignature, + fullName?: Identifier | JSDocNamespaceDeclaration, + comment?: string | NodeArray, + ): JSDocCallbackTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocCallbackTag, + tagName ?? createIdentifier("callback"), + comment, + ); node.typeExpression = typeExpression; node.fullName = fullName; node.name = getJSDocTypeAliasName(fullName); @@ -4759,7 +5532,13 @@ namespace ts { } // @api - function updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocCallbackTag { + function updateJSDocCallbackTag( + node: JSDocCallbackTag, + tagName: Identifier = getDefaultTagName(node), + typeExpression: JSDocSignature, + fullName: Identifier | JSDocNamespaceDeclaration | undefined, + comment: string | NodeArray | undefined, + ): JSDocCallbackTag { return node.tagName !== tagName || node.typeExpression !== typeExpression || node.fullName !== fullName @@ -4769,14 +5548,27 @@ namespace ts { } // @api - function createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray): JSDocAugmentsTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocAugmentsTag, tagName ?? createIdentifier("augments"), comment); + function createJSDocAugmentsTag( + tagName: Identifier | undefined, + className: JSDocAugmentsTag["class"], + comment?: string | NodeArray, + ): JSDocAugmentsTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocAugmentsTag, + tagName ?? createIdentifier("augments"), + comment, + ); node.class = className; return node; } // @api - function updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier = getDefaultTagName(node), className: JSDocAugmentsTag["class"], comment: string | NodeArray | undefined): JSDocAugmentsTag { + function updateJSDocAugmentsTag( + node: JSDocAugmentsTag, + tagName: Identifier = getDefaultTagName(node), + className: JSDocAugmentsTag["class"], + comment: string | NodeArray | undefined, + ): JSDocAugmentsTag { return node.tagName !== tagName || node.class !== className || node.comment !== comment @@ -4785,21 +5577,42 @@ namespace ts { } // @api - function createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray): JSDocImplementsTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocImplementsTag, tagName ?? createIdentifier("implements"), comment); + function createJSDocImplementsTag( + tagName: Identifier | undefined, + className: JSDocImplementsTag["class"], + comment?: string | NodeArray, + ): JSDocImplementsTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocImplementsTag, + tagName ?? createIdentifier("implements"), + comment, + ); node.class = className; return node; } // @api - function createJSDocSeeTag(tagName: Identifier | undefined, name: JSDocNameReference | undefined, comment?: string | NodeArray): JSDocSeeTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocSeeTag, tagName ?? createIdentifier("see"), comment); + function createJSDocSeeTag( + tagName: Identifier | undefined, + name: JSDocNameReference | undefined, + comment?: string | NodeArray, + ): JSDocSeeTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocSeeTag, + tagName ?? createIdentifier("see"), + comment, + ); node.name = name; return node; } // @api - function updateJSDocSeeTag(node: JSDocSeeTag, tagName: Identifier | undefined, name: JSDocNameReference | undefined, comment?: string | NodeArray): JSDocSeeTag { + function updateJSDocSeeTag( + node: JSDocSeeTag, + tagName: Identifier | undefined, + name: JSDocNameReference | undefined, + comment?: string | NodeArray, + ): JSDocSeeTag { return node.tagName !== tagName || node.name !== name || node.comment !== comment @@ -4815,7 +5628,10 @@ namespace ts { } // @api - function updateJSDocNameReference(node: JSDocNameReference, name: EntityName | JSDocMemberName): JSDocNameReference { + function updateJSDocNameReference( + node: JSDocNameReference, + name: EntityName | JSDocMemberName, + ): JSDocNameReference { return node.name !== name ? update(createJSDocNameReference(name), node) : node; @@ -4826,8 +5642,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.JSDocMemberName); node.left = left; node.right = right; - node.transformFlags |= propagateChildFlags(node.left) | - propagateChildFlags(node.right); + node.transformFlags |= propagateChildFlags(node.left) + | propagateChildFlags(node.right); return node; } @@ -4848,7 +5664,11 @@ namespace ts { } // @api - function updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink { + function updateJSDocLink( + node: JSDocLink, + name: EntityName | JSDocMemberName | undefined, + text: string, + ): JSDocLink { return node.name !== name ? update(createJSDocLink(name, text), node) : node; @@ -4863,7 +5683,11 @@ namespace ts { } // @api - function updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode { + function updateJSDocLinkCode( + node: JSDocLinkCode, + name: EntityName | JSDocMemberName | undefined, + text: string, + ): JSDocLinkCode { return node.name !== name ? update(createJSDocLinkCode(name, text), node) : node; @@ -4878,14 +5702,23 @@ namespace ts { } // @api - function updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain { + function updateJSDocLinkPlain( + node: JSDocLinkPlain, + name: EntityName | JSDocMemberName | undefined, + text: string, + ): JSDocLinkPlain { return node.name !== name ? update(createJSDocLinkPlain(name, text), node) : node; } // @api - function updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier = getDefaultTagName(node), className: JSDocImplementsTag["class"], comment: string | NodeArray | undefined): JSDocImplementsTag { + function updateJSDocImplementsTag( + node: JSDocImplementsTag, + tagName: Identifier = getDefaultTagName(node), + className: JSDocImplementsTag["class"], + comment: string | NodeArray | undefined, + ): JSDocImplementsTag { return node.tagName !== tagName || node.class !== className || node.comment !== comment @@ -4901,8 +5734,16 @@ namespace ts { // createJSDocProtectedTag // createJSDocReadonlyTag // createJSDocDeprecatedTag - function createJSDocSimpleTagWorker(kind: T["kind"], tagName: Identifier | undefined, comment?: string | NodeArray) { - const node = createBaseJSDocTag(kind, tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), comment); + function createJSDocSimpleTagWorker( + kind: T["kind"], + tagName: Identifier | undefined, + comment?: string | NodeArray, + ) { + const node = createBaseJSDocTag( + kind, + tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), + comment, + ); return node; } @@ -4914,11 +5755,16 @@ namespace ts { // updateJSDocProtectedTag // updateJSDocReadonlyTag // updateJSDocDeprecatedTag - function updateJSDocSimpleTagWorker(kind: T["kind"], node: T, tagName: Identifier = getDefaultTagName(node), comment: string | NodeArray | undefined) { + function updateJSDocSimpleTagWorker( + kind: T["kind"], + node: T, + tagName: Identifier = getDefaultTagName(node), + comment: string | NodeArray | undefined, + ) { return node.tagName !== tagName || node.comment !== comment - ? update(createJSDocSimpleTagWorker(kind, tagName, comment), node) : - node; + ? update(createJSDocSimpleTagWorker(kind, tagName, comment), node) + : node; } // @api @@ -4926,8 +5772,17 @@ namespace ts { // createJSDocReturnTag // createJSDocThisTag // createJSDocEnumTag - function createJSDocTypeLikeTagWorker(kind: T["kind"], tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string | NodeArray) { - const node = createBaseJSDocTag(kind, tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), comment); + function createJSDocTypeLikeTagWorker( + kind: T["kind"], + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression, + comment?: string | NodeArray, + ) { + const node = createBaseJSDocTag( + kind, + tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), + comment, + ); node.typeExpression = typeExpression; return node; } @@ -4937,7 +5792,13 @@ namespace ts { // updateJSDocReturnTag // updateJSDocThisTag // updateJSDocEnumTag - function updateJSDocTypeLikeTagWorker(kind: T["kind"], node: T, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression | undefined, comment: string | NodeArray | undefined) { + function updateJSDocTypeLikeTagWorker( + kind: T["kind"], + node: T, + tagName: Identifier = getDefaultTagName(node), + typeExpression: JSDocTypeExpression | undefined, + comment: string | NodeArray | undefined, + ) { return node.tagName !== tagName || node.typeExpression !== typeExpression || node.comment !== comment @@ -4946,13 +5807,20 @@ namespace ts { } // @api - function createJSDocUnknownTag(tagName: Identifier, comment?: string | NodeArray): JSDocUnknownTag { + function createJSDocUnknownTag( + tagName: Identifier, + comment?: string | NodeArray, + ): JSDocUnknownTag { const node = createBaseJSDocTag(SyntaxKind.JSDocTag, tagName, comment); return node; } // @api - function updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag { + function updateJSDocUnknownTag( + node: JSDocUnknownTag, + tagName: Identifier, + comment: string | NodeArray | undefined, + ): JSDocUnknownTag { return node.tagName !== tagName || node.comment !== comment ? update(createJSDocUnknownTag(tagName, comment), node) @@ -4974,7 +5842,10 @@ namespace ts { } // @api - function createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined) { + function createJSDocComment( + comment?: string | NodeArray | undefined, + tags?: readonly JSDocTag[] | undefined, + ) { const node = createBaseNode(SyntaxKind.JSDoc); node.comment = comment; node.tags = asNodeArray(tags); @@ -4982,7 +5853,11 @@ namespace ts { } // @api - function updateJSDocComment(node: JSDoc, comment: string | NodeArray | undefined, tags: readonly JSDocTag[] | undefined) { + function updateJSDocComment( + node: JSDoc, + comment: string | NodeArray | undefined, + tags: readonly JSDocTag[] | undefined, + ) { return node.comment !== comment || node.tags !== tags ? update(createJSDocComment(comment, tags), node) @@ -4994,20 +5869,29 @@ namespace ts { // // @api - function createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) { + function createJsxElement( + openingElement: JsxOpeningElement, + children: readonly JsxChild[], + closingElement: JsxClosingElement, + ) { const node = createBaseNode(SyntaxKind.JsxElement); node.openingElement = openingElement; node.children = createNodeArray(children); node.closingElement = closingElement; - node.transformFlags |= propagateChildFlags(node.openingElement) | - propagateChildrenFlags(node.children) | - propagateChildFlags(node.closingElement) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.openingElement) + | propagateChildrenFlags(node.children) + | propagateChildFlags(node.closingElement) + | TransformFlags.ContainsJsx; return node; } // @api - function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) { + function updateJsxElement( + node: JsxElement, + openingElement: JsxOpeningElement, + children: readonly JsxChild[], + closingElement: JsxClosingElement, + ) { return node.openingElement !== openingElement || node.children !== children || node.closingElement !== closingElement @@ -5016,15 +5900,19 @@ namespace ts { } // @api - function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { + function createJsxSelfClosingElement( + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ) { const node = createBaseNode(SyntaxKind.JsxSelfClosingElement); node.tagName = tagName; node.typeArguments = asNodeArray(typeArguments); node.attributes = attributes; - node.transformFlags |= propagateChildFlags(node.tagName) | - propagateChildrenFlags(node.typeArguments) | - propagateChildFlags(node.attributes) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.tagName) + | propagateChildrenFlags(node.typeArguments) + | propagateChildFlags(node.attributes) + | TransformFlags.ContainsJsx; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -5032,7 +5920,12 @@ namespace ts { } // @api - function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { + function updateJsxSelfClosingElement( + node: JsxSelfClosingElement, + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ) { return node.tagName !== tagName || node.typeArguments !== typeArguments || node.attributes !== attributes @@ -5041,15 +5934,19 @@ namespace ts { } // @api - function createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { + function createJsxOpeningElement( + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ) { const node = createBaseNode(SyntaxKind.JsxOpeningElement); node.tagName = tagName; node.typeArguments = asNodeArray(typeArguments); node.attributes = attributes; - node.transformFlags |= propagateChildFlags(node.tagName) | - propagateChildrenFlags(node.typeArguments) | - propagateChildFlags(node.attributes) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.tagName) + | propagateChildrenFlags(node.typeArguments) + | propagateChildFlags(node.attributes) + | TransformFlags.ContainsJsx; if (typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -5057,7 +5954,12 @@ namespace ts { } // @api - function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { + function updateJsxOpeningElement( + node: JsxOpeningElement, + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ) { return node.tagName !== tagName || node.typeArguments !== typeArguments || node.attributes !== attributes @@ -5069,8 +5971,8 @@ namespace ts { function createJsxClosingElement(tagName: JsxTagNameExpression) { const node = createBaseNode(SyntaxKind.JsxClosingElement); node.tagName = tagName; - node.transformFlags |= propagateChildFlags(node.tagName) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.tagName) + | TransformFlags.ContainsJsx; return node; } @@ -5082,20 +5984,29 @@ namespace ts { } // @api - function createJsxFragment(openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) { + function createJsxFragment( + openingFragment: JsxOpeningFragment, + children: readonly JsxChild[], + closingFragment: JsxClosingFragment, + ) { const node = createBaseNode(SyntaxKind.JsxFragment); node.openingFragment = openingFragment; node.children = createNodeArray(children); node.closingFragment = closingFragment; - node.transformFlags |= propagateChildFlags(node.openingFragment) | - propagateChildrenFlags(node.children) | - propagateChildFlags(node.closingFragment) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.openingFragment) + | propagateChildrenFlags(node.children) + | propagateChildFlags(node.closingFragment) + | TransformFlags.ContainsJsx; return node; } // @api - function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) { + function updateJsxFragment( + node: JsxFragment, + openingFragment: JsxOpeningFragment, + children: readonly JsxChild[], + closingFragment: JsxClosingFragment, + ) { return node.openingFragment !== openingFragment || node.children !== children || node.closingFragment !== closingFragment @@ -5139,9 +6050,9 @@ namespace ts { const node = createBaseNode(SyntaxKind.JsxAttribute); node.name = name; node.initializer = initializer; - node.transformFlags |= propagateChildFlags(node.name) | - propagateChildFlags(node.initializer) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.name) + | propagateChildFlags(node.initializer) + | TransformFlags.ContainsJsx; return node; } @@ -5157,8 +6068,8 @@ namespace ts { function createJsxAttributes(properties: readonly JsxAttributeLike[]) { const node = createBaseNode(SyntaxKind.JsxAttributes); node.properties = createNodeArray(properties); - node.transformFlags |= propagateChildrenFlags(node.properties) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildrenFlags(node.properties) + | TransformFlags.ContainsJsx; return node; } @@ -5173,8 +6084,8 @@ namespace ts { function createJsxSpreadAttribute(expression: Expression) { const node = createBaseNode(SyntaxKind.JsxSpreadAttribute); node.expression = expression; - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsJsx; return node; } @@ -5190,9 +6101,9 @@ namespace ts { const node = createBaseNode(SyntaxKind.JsxExpression); node.dotDotDotToken = dotDotDotToken; node.expression = expression; - node.transformFlags |= propagateChildFlags(node.dotDotDotToken) | - propagateChildFlags(node.expression) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.dotDotDotToken) + | propagateChildFlags(node.expression) + | TransformFlags.ContainsJsx; return node; } @@ -5212,8 +6123,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.CaseClause); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.statements = createNodeArray(statements); - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildrenFlags(node.statements); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildrenFlags(node.statements); return node; } @@ -5267,9 +6178,15 @@ namespace ts { } // @api - function createCatchClause(variableDeclaration: string | BindingName | VariableDeclaration | undefined, block: Block) { + function createCatchClause( + variableDeclaration: string | BindingName | VariableDeclaration | undefined, + block: Block, + ) { const node = createBaseNode(SyntaxKind.CatchClause); - if (typeof variableDeclaration === "string" || variableDeclaration && !isVariableDeclaration(variableDeclaration)) { + if ( + typeof variableDeclaration === "string" + || variableDeclaration && !isVariableDeclaration(variableDeclaration) + ) { variableDeclaration = createVariableDeclaration( variableDeclaration, /*exclamationToken*/ undefined, @@ -5279,14 +6196,18 @@ namespace ts { } node.variableDeclaration = variableDeclaration; node.block = block; - node.transformFlags |= propagateChildFlags(node.variableDeclaration) | - propagateChildFlags(node.block); + node.transformFlags |= propagateChildFlags(node.variableDeclaration) + | propagateChildFlags(node.block); if (!variableDeclaration) node.transformFlags |= TransformFlags.ContainsES2019; return node; } // @api - function updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block) { + function updateCatchClause( + node: CatchClause, + variableDeclaration: VariableDeclaration | undefined, + block: Block, + ) { return node.variableDeclaration !== variableDeclaration || node.block !== block ? update(createCatchClause(variableDeclaration, block), node) @@ -5305,8 +6226,8 @@ namespace ts { name, ); node.initializer = parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer); - node.transformFlags |= propagateChildFlags(node.name) | - propagateChildFlags(node.initializer); + node.transformFlags |= propagateChildFlags(node.name) + | propagateChildFlags(node.initializer); // The following properties are used only to report grammar errors node.illegalDecorators = undefined; @@ -5336,15 +6257,19 @@ namespace ts { } // @api - function createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression) { + function createShorthandPropertyAssignment( + name: string | Identifier, + objectAssignmentInitializer?: Expression, + ) { const node = createBaseNamedDeclaration( SyntaxKind.ShorthandPropertyAssignment, /*modifiers*/ undefined, name, ); - node.objectAssignmentInitializer = objectAssignmentInitializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(objectAssignmentInitializer); - node.transformFlags |= propagateChildFlags(node.objectAssignmentInitializer) | - TransformFlags.ContainsES2015; + node.objectAssignmentInitializer = objectAssignmentInitializer + && parenthesizerRules().parenthesizeExpressionForDisallowedComma(objectAssignmentInitializer); + node.transformFlags |= propagateChildFlags(node.objectAssignmentInitializer) + | TransformFlags.ContainsES2015; // The following properties are used only to report grammar errors node.equalsToken = undefined; @@ -5356,14 +6281,24 @@ namespace ts { } // @api - function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression | undefined) { + function updateShorthandPropertyAssignment( + node: ShorthandPropertyAssignment, + name: Identifier, + objectAssignmentInitializer: Expression | undefined, + ) { return node.name !== name || node.objectAssignmentInitializer !== objectAssignmentInitializer - ? finishUpdateShorthandPropertyAssignment(createShorthandPropertyAssignment(name, objectAssignmentInitializer), node) + ? finishUpdateShorthandPropertyAssignment( + createShorthandPropertyAssignment(name, objectAssignmentInitializer), + node, + ) : node; } - function finishUpdateShorthandPropertyAssignment(updated: Mutable, original: ShorthandPropertyAssignment) { + function finishUpdateShorthandPropertyAssignment( + updated: Mutable, + original: ShorthandPropertyAssignment, + ) { if (updated !== original) { // copy children used only for error reporting updated.equalsToken = original.equalsToken; @@ -5379,9 +6314,9 @@ namespace ts { function createSpreadAssignment(expression: Expression) { const node = createBaseNode(SyntaxKind.SpreadAssignment); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsObjectRestOrSpread; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsObjectRestOrSpread; return node; } @@ -5400,10 +6335,11 @@ namespace ts { function createEnumMember(name: string | PropertyName, initializer?: Expression) { const node = createBaseNode(SyntaxKind.EnumMember); node.name = asName(name); - node.initializer = initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer); - node.transformFlags |= propagateChildFlags(node.name) | - propagateChildFlags(node.initializer) | - TransformFlags.ContainsTypeScript; + node.initializer = initializer + && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer); + node.transformFlags |= propagateChildFlags(node.name) + | propagateChildFlags(node.initializer) + | TransformFlags.ContainsTypeScript; return node; } @@ -5436,8 +6372,8 @@ namespace ts { node.scriptKind = 0; node.isDeclarationFile = false; node.hasNoDefaultLib = false; - node.transformFlags |= propagateChildrenFlags(node.statements) | - propagateChildFlags(node.endOfFileToken); + node.transformFlags |= propagateChildrenFlags(node.statements) + | propagateChildFlags(node.endOfFileToken); return node; } @@ -5450,7 +6386,8 @@ namespace ts { hasNoDefaultLib: boolean, libReferences: readonly FileReference[], ) { - const node = (source.redirectInfo ? Object.create(source.redirectInfo.redirectTarget) : baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile)) as Mutable; + const node = (source.redirectInfo ? Object.create(source.redirectInfo.redirectTarget) + : baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile)) as Mutable; for (const p in source) { if (p === "emitNode" || hasProperty(node, p) || !hasProperty(source, p)) continue; (node as any)[p] = (source as any)[p]; @@ -5463,8 +6400,8 @@ namespace ts { node.typeReferenceDirectives = typeReferences; node.hasNoDefaultLib = hasNoDefaultLib; node.libReferenceDirectives = libReferences; - node.transformFlags = propagateChildrenFlags(node.statements) | - propagateChildFlags(node.endOfFileToken); + node.transformFlags = propagateChildrenFlags(node.statements) + | propagateChildFlags(node.endOfFileToken); node.impliedNodeFormat = source.impliedNodeFormat; return node; } @@ -5485,12 +6422,26 @@ namespace ts { || node.typeReferenceDirectives !== typeReferenceDirectives || node.hasNoDefaultLib !== hasNoDefaultLib || node.libReferenceDirectives !== libReferenceDirectives - ? update(cloneSourceFileWithChanges(node, statements, isDeclarationFile, referencedFiles, typeReferenceDirectives, hasNoDefaultLib, libReferenceDirectives), node) + ? update( + cloneSourceFileWithChanges( + node, + statements, + isDeclarationFile, + referencedFiles, + typeReferenceDirectives, + hasNoDefaultLib, + libReferenceDirectives, + ), + node, + ) : node; } // @api - function createBundle(sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) { + function createBundle( + sourceFiles: readonly SourceFile[], + prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray, + ) { const node = createBaseNode(SyntaxKind.Bundle); node.prepends = prepends; node.sourceFiles = sourceFiles; @@ -5498,7 +6449,11 @@ namespace ts { } // @api - function updateBundle(node: Bundle, sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) { + function updateBundle( + node: Bundle, + sourceFiles: readonly SourceFile[], + prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray, + ) { return node.sourceFiles !== sourceFiles || node.prepends !== prepends ? update(createBundle(sourceFiles, prepends), node) @@ -5506,7 +6461,11 @@ namespace ts { } // @api - function createUnparsedSource(prologues: readonly UnparsedPrologue[], syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, texts: readonly UnparsedSourceText[]) { + function createUnparsedSource( + prologues: readonly UnparsedPrologue[], + syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, + texts: readonly UnparsedSourceText[], + ) { const node = createBaseNode(SyntaxKind.UnparsedSource); node.prologues = prologues; node.syntheticReferences = syntheticReferences; @@ -5543,7 +6502,9 @@ namespace ts { } // @api - function createUnparsedSyntheticReference(section: BundleFileHasNoDefaultLib | BundleFileReference): UnparsedSyntheticReference { + function createUnparsedSyntheticReference( + section: BundleFileHasNoDefaultLib | BundleFileReference, + ): UnparsedSyntheticReference { const node = createBaseNode(SyntaxKind.UnparsedSyntheticReference); node.data = section.data; node.section = section; @@ -5563,7 +6524,11 @@ namespace ts { // // @api - function createSyntheticExpression(type: Type, isSpread = false, tupleNameSource?: ParameterDeclaration | NamedTupleMember) { + function createSyntheticExpression( + type: Type, + isSpread = false, + tupleNameSource?: ParameterDeclaration | NamedTupleMember, + ) { const node = createBaseNode(SyntaxKind.SyntheticExpression); node.type = type; node.isSpread = isSpread; @@ -5608,8 +6573,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.PartiallyEmittedExpression); node.expression = expression; node.original = original; - node.transformFlags |= propagateChildFlags(node.expression) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsTypeScript; setTextRange(node, original); return node; } @@ -5677,13 +6642,17 @@ namespace ts { const node = createBaseNode(SyntaxKind.SyntheticReferenceExpression); node.expression = expression; node.thisArg = thisArg; - node.transformFlags |= propagateChildFlags(node.expression) | - propagateChildFlags(node.thisArg); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.thisArg); return node; } // @api - function updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression) { + function updateSyntheticReferenceExpression( + node: SyntheticReferenceExpression, + expression: Expression, + thisArg: Expression, + ) { return node.expression !== expression || node.thisArg !== thisArg ? update(createSyntheticReferenceExpression(expression, thisArg), node) @@ -5700,11 +6669,12 @@ namespace ts { return node; } - const clone = isSourceFile(node) ? baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as T : - isIdentifier(node) ? baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as T : - isPrivateIdentifier(node) ? baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as T : - !isNodeKind(node.kind) ? baseFactory.createBaseTokenNode(node.kind) as T : - baseFactory.createBaseNode(node.kind) as T; + const clone = isSourceFile(node) ? baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as T + : isIdentifier(node) ? baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as T + : isPrivateIdentifier(node) + ? baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as T + : !isNodeKind(node.kind) ? baseFactory.createBaseTokenNode(node.kind) as T + : baseFactory.createBaseNode(node.kind) as T; (clone as Mutable).flags |= node.flags & ~NodeFlags.Synthesized; (clone as Mutable).transformFlags = node.transformFlags; @@ -5723,8 +6693,16 @@ namespace ts { // compound nodes function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression; - function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; - function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) { + function createImmediatelyInvokedFunctionExpression( + statements: readonly Statement[], + param: ParameterDeclaration, + paramValue: Expression, + ): CallExpression; + function createImmediatelyInvokedFunctionExpression( + statements: readonly Statement[], + param?: ParameterDeclaration, + paramValue?: Expression, + ) { return createCallExpression( createFunctionExpression( /*modifiers*/ undefined, @@ -5741,8 +6719,16 @@ namespace ts { } function createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): CallExpression; - function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; - function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) { + function createImmediatelyInvokedArrowFunction( + statements: readonly Statement[], + param: ParameterDeclaration, + paramValue: Expression, + ): CallExpression; + function createImmediatelyInvokedArrowFunction( + statements: readonly Statement[], + param?: ParameterDeclaration, + paramValue?: Expression, + ) { return createCallExpression( createArrowFunction( /*modifiers*/ undefined, @@ -5789,7 +6775,11 @@ namespace ts { : factory.createStrictEquality(createTypeOfExpression(value), createStringLiteral(tag)); } - function createMethodCall(object: Expression, methodName: string | Identifier, argumentsList: readonly Expression[]) { + function createMethodCall( + object: Expression, + methodName: string | Identifier, + argumentsList: readonly Expression[], + ) { // Preserve the optionality of `object`. if (isCallChain(object)) { return createCallChain( @@ -5818,7 +6808,11 @@ namespace ts { return createMethodCall(target, "apply", [thisArg, argumentsExpression]); } - function createGlobalMethodCall(globalObjectName: string, methodName: string, argumentsList: readonly Expression[]) { + function createGlobalMethodCall( + globalObjectName: string, + methodName: string, + argumentsList: readonly Expression[], + ) { return createMethodCall(createIdentifier(globalObjectName), methodName, argumentsList); } @@ -5830,19 +6824,44 @@ namespace ts { return createMethodCall(array, "concat", argumentsList); } - function createObjectDefinePropertyCall(target: Expression, propertyName: string | Expression, attributes: Expression) { + function createObjectDefinePropertyCall( + target: Expression, + propertyName: string | Expression, + attributes: Expression, + ) { return createGlobalMethodCall("Object", "defineProperty", [target, asExpression(propertyName), attributes]); } - function createReflectGetCall(target: Expression, propertyKey: Expression, receiver?: Expression): CallExpression { - return createGlobalMethodCall("Reflect", "get", receiver ? [target, propertyKey, receiver] : [target, propertyKey]); + function createReflectGetCall( + target: Expression, + propertyKey: Expression, + receiver?: Expression, + ): CallExpression { + return createGlobalMethodCall( + "Reflect", + "get", + receiver ? [target, propertyKey, receiver] : [target, propertyKey], + ); } - function createReflectSetCall(target: Expression, propertyKey: Expression, value: Expression, receiver?: Expression): CallExpression { - return createGlobalMethodCall("Reflect", "set", receiver ? [target, propertyKey, value, receiver] : [target, propertyKey, value]); + function createReflectSetCall( + target: Expression, + propertyKey: Expression, + value: Expression, + receiver?: Expression, + ): CallExpression { + return createGlobalMethodCall( + "Reflect", + "set", + receiver ? [target, propertyKey, value, receiver] : [target, propertyKey, value], + ); } - function tryAddPropertyAssignment(properties: Push, propertyName: string, expression: Expression | undefined) { + function tryAddPropertyAssignment( + properties: Push, + propertyName: string, + expression: Expression | undefined, + ) { if (expression) { properties.push(createPropertyAssignment(propertyName, expression)); return true; @@ -5861,7 +6880,10 @@ namespace ts { let isAccessor = tryAddPropertyAssignment(properties, "get", attributes.get); isAccessor = tryAddPropertyAssignment(properties, "set", attributes.set) || isAccessor; - Debug.assert(!(isData && isAccessor), "A PropertyDescriptor may not be both an accessor descriptor and a data descriptor."); + Debug.assert( + !(isData && isAccessor), + "A PropertyDescriptor may not be both an accessor descriptor and a data descriptor.", + ); return createObjectLiteralExpression(properties, !singleLine); } @@ -5905,7 +6927,11 @@ namespace ts { && !some(getSyntheticTrailingComments(node)); } - function restoreOuterExpressions(outerExpression: Expression | undefined, innerExpression: Expression, kinds = OuterExpressionKinds.All): Expression { + function restoreOuterExpressions( + outerExpression: Expression | undefined, + innerExpression: Expression, + kinds = OuterExpressionKinds.All, + ): Expression { if (outerExpression && isOuterExpression(outerExpression, kinds) && !isIgnorableParen(outerExpression)) { return updateOuterExpression( outerExpression, @@ -5915,7 +6941,11 @@ namespace ts { return innerExpression; } - function restoreEnclosingLabel(node: Statement, outermostLabeledStatement: LabeledStatement | undefined, afterRestoreLabelCallback?: (node: LabeledStatement) => void): Statement { + function restoreEnclosingLabel( + node: Statement, + outermostLabeledStatement: LabeledStatement | undefined, + afterRestoreLabelCallback?: (node: LabeledStatement) => void, + ): Statement { if (!outermostLabeledStatement) { return node; } @@ -5955,7 +6985,12 @@ namespace ts { } } - function createCallBinding(expression: Expression, recordTempVariable: (temp: Identifier) => void, languageVersion?: ScriptTarget, cacheIdentifiers = false): CallBinding { + function createCallBinding( + expression: Expression, + recordTempVariable: (temp: Identifier) => void, + languageVersion?: ScriptTarget, + cacheIdentifiers = false, + ): CallBinding { const callee = skipOuterExpressions(expression, OuterExpressionKinds.All); let thisArg: Expression; let target: LeftHandSideExpression; @@ -6058,7 +7093,12 @@ namespace ts { : reduceLeft(expressions, factory.createComma)!; } - function getName(node: Declaration | undefined, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags: EmitFlags = 0) { + function getName( + node: Declaration | undefined, + allowComments?: boolean, + allowSourceMaps?: boolean, + emitFlags: EmitFlags = 0, + ) { const nodeName = getNameOfDeclaration(node); if (nodeName && isIdentifier(nodeName) && !isGeneratedIdentifier(nodeName)) { // TODO(rbuckton): Does this need to be parented? @@ -6134,7 +7174,12 @@ namespace ts { * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - function getNamespaceMemberName(ns: Identifier, name: Identifier, allowComments?: boolean, allowSourceMaps?: boolean): PropertyAccessExpression { + function getNamespaceMemberName( + ns: Identifier, + name: Identifier, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): PropertyAccessExpression { const qualifiedName = createPropertyAccessExpression(ns, nodeIsSynthesized(name) ? name : cloneNode(name)); setTextRange(qualifiedName, name); let emitFlags: EmitFlags = 0; @@ -6155,7 +7200,12 @@ namespace ts { * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - function getExternalModuleOrNamespaceExportName(ns: Identifier | undefined, node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier | PropertyAccessExpression { + function getExternalModuleOrNamespaceExportName( + ns: Identifier | undefined, + node: Declaration, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): Identifier | PropertyAccessExpression { if (ns && hasSyntacticModifier(node, ModifierFlags.Export)) { return getNamespaceMemberName(ns, getName(node), allowComments, allowSourceMaps); } @@ -6169,7 +7219,12 @@ namespace ts { * @param ensureUseStrict boolean determining whether the function need to add prologue-directives * @param visitor Optional callback used to visit any custom prologue directives. */ - function copyPrologue(source: readonly Statement[], target: Push, ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number { + function copyPrologue( + source: readonly Statement[], + target: Push, + ensureUseStrict?: boolean, + visitor?: (node: Node) => VisitResult, + ): number { const offset = copyStandardPrologue(source, target, 0, ensureUseStrict); return copyCustomPrologue(source, target, offset, visitor); } @@ -6190,8 +7245,16 @@ namespace ts { * @param ensureUseStrict boolean determining whether the function need to add prologue-directives * @returns Count of how many directive statements were copied. */ - function copyStandardPrologue(source: readonly Statement[], target: Push, statementOffset = 0, ensureUseStrict?: boolean): number { - Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array"); + function copyStandardPrologue( + source: readonly Statement[], + target: Push, + statementOffset = 0, + ensureUseStrict?: boolean, + ): number { + Debug.assert( + target.length === 0, + "Prologue directives should be at the first statement in the target statements array", + ); let foundUseStrict = false; const numStatements = source.length; while (statementOffset < numStatements) { @@ -6220,9 +7283,27 @@ namespace ts { * @param statementOffset The offset at which to begin the copy. * @param visitor Optional callback used to visit any custom prologue directives. */ - function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number; - function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number | undefined; - function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter: (node: Node) => boolean = returnTrue): number | undefined { + function copyCustomPrologue( + source: readonly Statement[], + target: Push, + statementOffset: number, + visitor?: (node: Node) => VisitResult, + filter?: (node: Node) => boolean, + ): number; + function copyCustomPrologue( + source: readonly Statement[], + target: Push, + statementOffset: number | undefined, + visitor?: (node: Node) => VisitResult, + filter?: (node: Node) => boolean, + ): number | undefined; + function copyCustomPrologue( + source: readonly Statement[], + target: Push, + statementOffset: number | undefined, + visitor?: (node: Node) => VisitResult, + filter: (node: Node) => boolean = returnTrue, + ): number | undefined { const numStatements = source.length; while (statementOffset !== undefined && statementOffset < numStatements) { const statement = source[statementOffset]; @@ -6270,9 +7351,18 @@ namespace ts { return i; } - function mergeLexicalEnvironment(statements: NodeArray, declarations: readonly Statement[] | undefined): NodeArray; - function mergeLexicalEnvironment(statements: Statement[], declarations: readonly Statement[] | undefined): Statement[]; - function mergeLexicalEnvironment(statements: Statement[] | NodeArray, declarations: readonly Statement[] | undefined) { + function mergeLexicalEnvironment( + statements: NodeArray, + declarations: readonly Statement[] | undefined, + ): NodeArray; + function mergeLexicalEnvironment( + statements: Statement[], + declarations: readonly Statement[] | undefined, + ): Statement[]; + function mergeLexicalEnvironment( + statements: Statement[] | NodeArray, + declarations: readonly Statement[] | undefined, + ) { if (!some(declarations)) { return statements; } @@ -6309,14 +7399,25 @@ namespace ts { // find standard prologues on left in the following order: standard directives, hoisted functions, hoisted variables, other custom const leftStandardPrologueEnd = findSpanEnd(statements, isPrologueDirective, 0); const leftHoistedFunctionsEnd = findSpanEnd(statements, isHoistedFunction, leftStandardPrologueEnd); - const leftHoistedVariablesEnd = findSpanEnd(statements, isHoistedVariableStatement, leftHoistedFunctionsEnd); + const leftHoistedVariablesEnd = findSpanEnd( + statements, + isHoistedVariableStatement, + leftHoistedFunctionsEnd, + ); // find standard prologues on right in the following order: standard directives, hoisted functions, hoisted variables, other custom const rightStandardPrologueEnd = findSpanEnd(declarations, isPrologueDirective, 0); const rightHoistedFunctionsEnd = findSpanEnd(declarations, isHoistedFunction, rightStandardPrologueEnd); - const rightHoistedVariablesEnd = findSpanEnd(declarations, isHoistedVariableStatement, rightHoistedFunctionsEnd); + const rightHoistedVariablesEnd = findSpanEnd( + declarations, + isHoistedVariableStatement, + rightHoistedFunctionsEnd, + ); const rightCustomPrologueEnd = findSpanEnd(declarations, isCustomPrologue, rightHoistedVariablesEnd); - Debug.assert(rightCustomPrologueEnd === declarations.length, "Expected declarations to be valid standard or custom prologues"); + Debug.assert( + rightCustomPrologueEnd === declarations.length, + "Expected declarations to be valid standard or custom prologues", + ); // splice prologues from the right into the left. We do this in reverse order // so that we don't need to recompute the index on the left when we insert items. @@ -6324,17 +7425,29 @@ namespace ts { // splice other custom prologues from right into left if (rightCustomPrologueEnd > rightHoistedVariablesEnd) { - left.splice(leftHoistedVariablesEnd, 0, ...declarations.slice(rightHoistedVariablesEnd, rightCustomPrologueEnd)); + left.splice( + leftHoistedVariablesEnd, + 0, + ...declarations.slice(rightHoistedVariablesEnd, rightCustomPrologueEnd), + ); } // splice hoisted variables from right into left if (rightHoistedVariablesEnd > rightHoistedFunctionsEnd) { - left.splice(leftHoistedFunctionsEnd, 0, ...declarations.slice(rightHoistedFunctionsEnd, rightHoistedVariablesEnd)); + left.splice( + leftHoistedFunctionsEnd, + 0, + ...declarations.slice(rightHoistedFunctionsEnd, rightHoistedVariablesEnd), + ); } // splice hoisted functions from right into left if (rightHoistedFunctionsEnd > rightStandardPrologueEnd) { - left.splice(leftStandardPrologueEnd, 0, ...declarations.slice(rightStandardPrologueEnd, rightHoistedFunctionsEnd)); + left.splice( + leftStandardPrologueEnd, + 0, + ...declarations.slice(rightStandardPrologueEnd, rightHoistedFunctionsEnd), + ); } // splice standard prologues from right into left (that are not already in left) @@ -6373,32 +7486,146 @@ namespace ts { else { modifierArray = modifiers; } - return isTypeParameterDeclaration(node) ? updateTypeParameterDeclaration(node, modifierArray, node.name, node.constraint, node.default) : - isParameter(node) ? updateParameterDeclaration(node, modifierArray, node.dotDotDotToken, node.name, node.questionToken, node.type, node.initializer) : - isConstructorTypeNode(node) ? updateConstructorTypeNode1(node, modifierArray, node.typeParameters, node.parameters, node.type) : - isPropertySignature(node) ? updatePropertySignature(node, modifierArray, node.name, node.questionToken, node.type) : - isPropertyDeclaration(node) ? updatePropertyDeclaration(node, modifierArray, node.name, node.questionToken ?? node.exclamationToken, node.type, node.initializer) : - isMethodSignature(node) ? updateMethodSignature(node, modifierArray, node.name, node.questionToken, node.typeParameters, node.parameters, node.type) : - isMethodDeclaration(node) ? updateMethodDeclaration(node, modifierArray, node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, node.type, node.body) : - isConstructorDeclaration(node) ? updateConstructorDeclaration(node, modifierArray, node.parameters, node.body) : - isGetAccessorDeclaration(node) ? updateGetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.type, node.body) : - isSetAccessorDeclaration(node) ? updateSetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.body) : - isIndexSignatureDeclaration(node) ? updateIndexSignature(node, modifierArray, node.parameters, node.type) : - isFunctionExpression(node) ? updateFunctionExpression(node, modifierArray, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body) : - isArrowFunction(node) ? updateArrowFunction(node, modifierArray, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, node.body) : - isClassExpression(node) ? updateClassExpression(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : - isVariableStatement(node) ? updateVariableStatement(node, modifierArray, node.declarationList) : - isFunctionDeclaration(node) ? updateFunctionDeclaration(node, modifierArray, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body) : - isClassDeclaration(node) ? updateClassDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : - isInterfaceDeclaration(node) ? updateInterfaceDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : - isTypeAliasDeclaration(node) ? updateTypeAliasDeclaration(node, modifierArray, node.name, node.typeParameters, node.type) : - isEnumDeclaration(node) ? updateEnumDeclaration(node, modifierArray, node.name, node.members) : - isModuleDeclaration(node) ? updateModuleDeclaration(node, modifierArray, node.name, node.body) : - isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, modifierArray, node.isTypeOnly, node.name, node.moduleReference) : - isImportDeclaration(node) ? updateImportDeclaration(node, modifierArray, node.importClause, node.moduleSpecifier, node.assertClause) : - isExportAssignment(node) ? updateExportAssignment(node, modifierArray, node.expression) : - isExportDeclaration(node) ? updateExportDeclaration(node, modifierArray, node.isTypeOnly, node.exportClause, node.moduleSpecifier, node.assertClause) : - Debug.assertNever(node); + return isTypeParameterDeclaration(node) + ? updateTypeParameterDeclaration(node, modifierArray, node.name, node.constraint, node.default) + : isParameter(node) + ? updateParameterDeclaration( + node, + modifierArray, + node.dotDotDotToken, + node.name, + node.questionToken, + node.type, + node.initializer, + ) + : isConstructorTypeNode(node) + ? updateConstructorTypeNode1(node, modifierArray, node.typeParameters, node.parameters, node.type) + : isPropertySignature(node) + ? updatePropertySignature(node, modifierArray, node.name, node.questionToken, node.type) + : isPropertyDeclaration(node) + ? updatePropertyDeclaration( + node, + modifierArray, + node.name, + node.questionToken ?? node.exclamationToken, + node.type, + node.initializer, + ) + : isMethodSignature(node) + ? updateMethodSignature( + node, + modifierArray, + node.name, + node.questionToken, + node.typeParameters, + node.parameters, + node.type, + ) + : isMethodDeclaration(node) + ? updateMethodDeclaration( + node, + modifierArray, + node.asteriskToken, + node.name, + node.questionToken, + node.typeParameters, + node.parameters, + node.type, + node.body, + ) + : isConstructorDeclaration(node) + ? updateConstructorDeclaration(node, modifierArray, node.parameters, node.body) + : isGetAccessorDeclaration(node) + ? updateGetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.type, node.body) + : isSetAccessorDeclaration(node) + ? updateSetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.body) + : isIndexSignatureDeclaration(node) + ? updateIndexSignature(node, modifierArray, node.parameters, node.type) + : isFunctionExpression(node) + ? updateFunctionExpression( + node, + modifierArray, + node.asteriskToken, + node.name, + node.typeParameters, + node.parameters, + node.type, + node.body, + ) + : isArrowFunction(node) + ? updateArrowFunction( + node, + modifierArray, + node.typeParameters, + node.parameters, + node.type, + node.equalsGreaterThanToken, + node.body, + ) + : isClassExpression(node) + ? updateClassExpression( + node, + modifierArray, + node.name, + node.typeParameters, + node.heritageClauses, + node.members, + ) + : isVariableStatement(node) ? updateVariableStatement(node, modifierArray, node.declarationList) + : isFunctionDeclaration(node) + ? updateFunctionDeclaration( + node, + modifierArray, + node.asteriskToken, + node.name, + node.typeParameters, + node.parameters, + node.type, + node.body, + ) + : isClassDeclaration(node) + ? updateClassDeclaration( + node, + modifierArray, + node.name, + node.typeParameters, + node.heritageClauses, + node.members, + ) + : isInterfaceDeclaration(node) + ? updateInterfaceDeclaration( + node, + modifierArray, + node.name, + node.typeParameters, + node.heritageClauses, + node.members, + ) + : isTypeAliasDeclaration(node) + ? updateTypeAliasDeclaration(node, modifierArray, node.name, node.typeParameters, node.type) + : isEnumDeclaration(node) ? updateEnumDeclaration(node, modifierArray, node.name, node.members) + : isModuleDeclaration(node) ? updateModuleDeclaration(node, modifierArray, node.name, node.body) + : isImportEqualsDeclaration(node) + ? updateImportEqualsDeclaration(node, modifierArray, node.isTypeOnly, node.name, node.moduleReference) + : isImportDeclaration(node) + ? updateImportDeclaration( + node, + modifierArray, + node.importClause, + node.moduleSpecifier, + node.assertClause, + ) + : isExportAssignment(node) ? updateExportAssignment(node, modifierArray, node.expression) + : isExportDeclaration(node) + ? updateExportDeclaration( + node, + modifierArray, + node.isTypeOnly, + node.exportClause, + node.moduleSpecifier, + node.assertClause, + ) + : Debug.assertNever(node); } function asNodeArray(array: readonly T[]): NodeArray; @@ -6407,16 +7634,28 @@ namespace ts { return array ? createNodeArray(array) : undefined; } - function asName(name: string | T): T | Identifier { - return typeof name === "string" ? createIdentifier(name) : - name; + function asName< + T extends + | DeclarationName + | Identifier + | BindingName + | PropertyName + | NoSubstitutionTemplateLiteral + | EntityName + | ThisTypeNode + | undefined, + >(name: string | T): T | Identifier { + return typeof name === "string" ? createIdentifier(name) + : name; } - function asExpression(value: string | number | boolean | T): T | StringLiteral | NumericLiteral | BooleanLiteral { - return typeof value === "string" ? createStringLiteral(value) : - typeof value === "number" ? createNumericLiteral(value) : - typeof value === "boolean" ? value ? createTrue() : createFalse() : - value; + function asExpression( + value: string | number | boolean | T, + ): T | StringLiteral | NumericLiteral | BooleanLiteral { + return typeof value === "string" ? createStringLiteral(value) + : typeof value === "number" ? createNumericLiteral(value) + : typeof value === "boolean" ? value ? createTrue() : createFalse() + : value; } function asToken(value: TKind | Token): Token { @@ -6426,7 +7665,8 @@ namespace ts { function asEmbeddedStatement(statement: T): T | EmptyStatement; function asEmbeddedStatement(statement: T | undefined): T | EmptyStatement | undefined; function asEmbeddedStatement(statement: T | undefined): T | EmptyStatement | undefined { - return statement && isNotEmittedStatement(statement) ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement; + return statement && isNotEmittedStatement(statement) + ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement; } } @@ -6553,7 +7793,8 @@ namespace ts { function propagateChildFlags(child: Node | undefined): TransformFlags { if (!child) return TransformFlags.None; const childFlags = child.transformFlags & ~getTransformFlagsSubtreeExclusions(child.kind); - return isNamedDeclaration(child) && isPropertyName(child.name) ? propagatePropertyNameFlagsOfChild(child.name, childFlags) : childFlags; + return isNamedDeclaration(child) && isPropertyName(child.name) + ? propagatePropertyNameFlagsOfChild(child.name, childFlags) : childFlags; } function propagateChildrenFlags(children: NodeArray | undefined): TransformFlags { @@ -6662,9 +7903,21 @@ namespace ts { export const factory = createNodeFactory(NodeFactoryFlags.NoIndentationOnFreshPropertyAccess, syntheticFactory); export function createUnparsedSourceFile(text: string): UnparsedSource; - export function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts", stripInternal?: boolean): UnparsedSource; - export function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource; - export function createUnparsedSourceFile(textOrInputFiles: string | InputFiles, mapPathOrType?: string, mapTextOrStripInternal?: string | boolean): UnparsedSource { + export function createUnparsedSourceFile( + inputFile: InputFiles, + type: "js" | "dts", + stripInternal?: boolean, + ): UnparsedSource; + export function createUnparsedSourceFile( + text: string, + mapPath: string | undefined, + map: string | undefined, + ): UnparsedSource; + export function createUnparsedSourceFile( + textOrInputFiles: string | InputFiles, + mapPathOrType?: string, + mapTextOrStripInternal?: string | boolean, + ): UnparsedSource { let stripInternal: boolean | undefined; let bundleFileInfo: BundleFileInfo | undefined; let fileName: string; @@ -6678,15 +7931,19 @@ namespace ts { if (!isString(textOrInputFiles)) { Debug.assert(mapPathOrType === "js" || mapPathOrType === "dts"); - fileName = (mapPathOrType === "js" ? textOrInputFiles.javascriptPath : textOrInputFiles.declarationPath) || ""; - sourceMapPath = mapPathOrType === "js" ? textOrInputFiles.javascriptMapPath : textOrInputFiles.declarationMapPath; + fileName = (mapPathOrType === "js" ? textOrInputFiles.javascriptPath : textOrInputFiles.declarationPath) + || ""; + sourceMapPath = mapPathOrType === "js" ? textOrInputFiles.javascriptMapPath + : textOrInputFiles.declarationMapPath; getText = () => mapPathOrType === "js" ? textOrInputFiles.javascriptText : textOrInputFiles.declarationText; - getSourceMapText = () => mapPathOrType === "js" ? textOrInputFiles.javascriptMapText : textOrInputFiles.declarationMapText; + getSourceMapText = () => + mapPathOrType === "js" ? textOrInputFiles.javascriptMapText : textOrInputFiles.declarationMapText; length = () => getText!().length; if (textOrInputFiles.buildInfo && textOrInputFiles.buildInfo.bundle) { Debug.assert(mapTextOrStripInternal === undefined || typeof mapTextOrStripInternal === "boolean"); stripInternal = mapTextOrStripInternal; - bundleFileInfo = mapPathOrType === "js" ? textOrInputFiles.buildInfo.bundle.js : textOrInputFiles.buildInfo.bundle.dts; + bundleFileInfo = mapPathOrType === "js" ? textOrInputFiles.buildInfo.bundle.js + : textOrInputFiles.buildInfo.bundle.dts; oldFileOfCurrentEmit = textOrInputFiles.oldFileOfCurrentEmit; } } @@ -6697,9 +7954,9 @@ namespace ts { sourceMapPath = mapPathOrType; sourceMapText = mapTextOrStripInternal as string; } - const node = oldFileOfCurrentEmit ? - parseOldFileOfCurrentEmit(Debug.checkDefined(bundleFileInfo)) : - parseUnparsedSourceFile(bundleFileInfo, stripInternal, length); + const node = oldFileOfCurrentEmit + ? parseOldFileOfCurrentEmit(Debug.checkDefined(bundleFileInfo)) + : parseUnparsedSourceFile(bundleFileInfo, stripInternal, length); node.fileName = fileName; node.sourceMapPath = sourceMapPath; node.oldFileOfCurrentEmit = oldFileOfCurrentEmit; @@ -6716,7 +7973,11 @@ namespace ts { return node; } - function parseUnparsedSourceFile(bundleFileInfo: BundleFileInfo | undefined, stripInternal: boolean | undefined, length: number | (() => number)) { + function parseUnparsedSourceFile( + bundleFileInfo: BundleFileInfo | undefined, + stripInternal: boolean | undefined, + length: number | (() => number), + ) { let prologues: UnparsedPrologue[] | undefined; let helpers: UnscopedEmitHelper[] | undefined; let referencedFiles: FileReference[] | undefined; @@ -6741,22 +8002,49 @@ namespace ts { referencedFiles = append(referencedFiles, { pos: -1, end: -1, fileName: section.data }); break; case BundleFileSectionKind.Type: - typeReferenceDirectives = append(typeReferenceDirectives, { pos: -1, end: -1, fileName: section.data }); + typeReferenceDirectives = append(typeReferenceDirectives, { + pos: -1, + end: -1, + fileName: section.data, + }); break; case BundleFileSectionKind.TypeResolutionModeImport: - typeReferenceDirectives = append(typeReferenceDirectives, { pos: -1, end: -1, fileName: section.data, resolutionMode: ModuleKind.ESNext }); + typeReferenceDirectives = append(typeReferenceDirectives, { + pos: -1, + end: -1, + fileName: section.data, + resolutionMode: ModuleKind.ESNext, + }); break; case BundleFileSectionKind.TypeResolutionModeRequire: - typeReferenceDirectives = append(typeReferenceDirectives, { pos: -1, end: -1, fileName: section.data, resolutionMode: ModuleKind.CommonJS }); + typeReferenceDirectives = append(typeReferenceDirectives, { + pos: -1, + end: -1, + fileName: section.data, + resolutionMode: ModuleKind.CommonJS, + }); break; case BundleFileSectionKind.Lib: - libReferenceDirectives = append(libReferenceDirectives, { pos: -1, end: -1, fileName: section.data }); + libReferenceDirectives = append(libReferenceDirectives, { + pos: -1, + end: -1, + fileName: section.data, + }); break; case BundleFileSectionKind.Prepend: let prependTexts: UnparsedTextLike[] | undefined; for (const text of section.texts) { if (!stripInternal || text.kind !== BundleFileSectionKind.Internal) { - prependTexts = append(prependTexts, setTextRange(factory.createUnparsedTextLike(text.data, text.kind === BundleFileSectionKind.Internal), text)); + prependTexts = append( + prependTexts, + setTextRange( + factory.createUnparsedTextLike( + text.data, + text.kind === BundleFileSectionKind.Internal, + ), + text, + ), + ); } } prependChildren = addRange(prependChildren, prependTexts); @@ -6770,7 +8058,16 @@ namespace ts { // falls through case BundleFileSectionKind.Text: - texts = append(texts, setTextRange(factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), section)); + texts = append( + texts, + setTextRange( + factory.createUnparsedTextLike( + section.data, + section.kind === BundleFileSectionKind.Internal, + ), + section, + ), + ); break; default: Debug.assertNever(section); @@ -6783,7 +8080,11 @@ namespace ts { texts = [textNode]; } - const node = parseNodeFactory.createUnparsedSource(prologues ?? emptyArray, /*syntheticReferences*/ undefined, texts); + const node = parseNodeFactory.createUnparsedSource( + prologues ?? emptyArray, + /*syntheticReferences*/ undefined, + texts, + ); setEachParent(prologues, node); setEachParent(texts, node); setEachParent(prependChildren, node); @@ -6802,7 +8103,16 @@ namespace ts { switch (section.kind) { case BundleFileSectionKind.Internal: case BundleFileSectionKind.Text: - texts = append(texts, setTextRange(factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), section)); + texts = append( + texts, + setTextRange( + factory.createUnparsedTextLike( + section.data, + section.kind === BundleFileSectionKind.Internal, + ), + section, + ), + ); break; case BundleFileSectionKind.NoDefaultLib: @@ -6811,7 +8121,10 @@ namespace ts { case BundleFileSectionKind.TypeResolutionModeImport: case BundleFileSectionKind.TypeResolutionModeRequire: case BundleFileSectionKind.Lib: - syntheticReferences = append(syntheticReferences, setTextRange(factory.createUnparsedSyntheticReference(section), section)); + syntheticReferences = append( + syntheticReferences, + setTextRange(factory.createUnparsedSyntheticReference(section), section), + ); break; // Ignore @@ -6828,7 +8141,10 @@ namespace ts { const node = factory.createUnparsedSource(emptyArray, syntheticReferences, texts ?? emptyArray); setEachParent(syntheticReferences, node); setEachParent(texts, node); - node.helpers = map(bundleFileInfo.sources && bundleFileInfo.sources.helpers, name => getAllUnscopedEmitHelpers().get(name)!); + node.helpers = map( + bundleFileInfo.sources && bundleFileInfo.sources.helpers, + name => getAllUnscopedEmitHelpers().get(name)!, + ); return node; } @@ -6959,8 +8275,16 @@ namespace ts { /** * Create an external source map source file reference */ - export function createSourceMapSource(fileName: string, text: string, skipTrivia?: (pos: number) => number): SourceMapSource { - return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))(fileName, text, skipTrivia); + export function createSourceMapSource( + fileName: string, + text: string, + skipTrivia?: (pos: number) => number, + ): SourceMapSource { + return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))( + fileName, + text, + skipTrivia, + ); } // Utilities @@ -6989,12 +8313,21 @@ namespace ts { } = sourceEmitNode; if (!destEmitNode) destEmitNode = {} as EmitNode; // We are using `.slice()` here in case `destEmitNode.leadingComments` is pushed to later. - if (leadingComments) destEmitNode.leadingComments = addRange(leadingComments.slice(), destEmitNode.leadingComments); - if (trailingComments) destEmitNode.trailingComments = addRange(trailingComments.slice(), destEmitNode.trailingComments); + if (leadingComments) { + destEmitNode.leadingComments = addRange(leadingComments.slice(), destEmitNode.leadingComments); + } + if (trailingComments) { + destEmitNode.trailingComments = addRange(trailingComments.slice(), destEmitNode.trailingComments); + } if (flags) destEmitNode.flags = flags & ~EmitFlags.Immutable; if (commentRange) destEmitNode.commentRange = commentRange; if (sourceMapRange) destEmitNode.sourceMapRange = sourceMapRange; - if (tokenSourceMapRanges) destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges(tokenSourceMapRanges, destEmitNode.tokenSourceMapRanges!); + if (tokenSourceMapRanges) { + destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges( + tokenSourceMapRanges, + destEmitNode.tokenSourceMapRanges!, + ); + } if (constantValue !== undefined) destEmitNode.constantValue = constantValue; if (helpers) { for (const helper of helpers) { diff --git a/src/compiler/factory/parenthesizerRules.ts b/src/compiler/factory/parenthesizerRules.ts index d07142f97c81a..8453ca9a78a3a 100644 --- a/src/compiler/factory/parenthesizerRules.ts +++ b/src/compiler/factory/parenthesizerRules.ts @@ -69,7 +69,12 @@ namespace ts { * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the * BinaryExpression. */ - function binaryOperandNeedsParentheses(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand: Expression | undefined) { + function binaryOperandNeedsParentheses( + binaryOperator: SyntaxKind, + operand: Expression, + isLeftSideOfBinary: boolean, + leftOperand: Expression | undefined, + ) { // If the operand has lower precedence, then it needs to be parenthesized to preserve the // intent of the expression. For example, if the operand is `a + b` and the operator is // `*`, then we need to parenthesize the operand to preserve the intended order of @@ -90,7 +95,10 @@ namespace ts { const binaryOperatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, binaryOperator); const binaryOperatorAssociativity = getOperatorAssociativity(SyntaxKind.BinaryExpression, binaryOperator); const emittedOperand = skipPartiallyEmittedExpressions(operand); - if (!isLeftSideOfBinary && operand.kind === SyntaxKind.ArrowFunction && binaryOperatorPrecedence > OperatorPrecedence.Assignment) { + if ( + !isLeftSideOfBinary && operand.kind === SyntaxKind.ArrowFunction + && binaryOperatorPrecedence > OperatorPrecedence.Assignment + ) { // We need to parenthesize arrow functions on the right side to avoid it being // parsed as parenthesized expression: `a && (() => {})` return true; @@ -148,8 +156,12 @@ namespace ts { // "a"+(1+2) => "a"+(1+2) // "a"+("b"+"c") => "a"+"b"+"c" if (binaryOperator === SyntaxKind.PlusToken) { - const leftKind = leftOperand ? getLiteralKindOfBinaryPlusOperand(leftOperand) : SyntaxKind.Unknown; - if (isLiteralKind(leftKind) && leftKind === getLiteralKindOfBinaryPlusOperand(emittedOperand)) { + const leftKind = leftOperand ? getLiteralKindOfBinaryPlusOperand(leftOperand) + : SyntaxKind.Unknown; + if ( + isLiteralKind(leftKind) + && leftKind === getLiteralKindOfBinaryPlusOperand(emittedOperand) + ) { return false; } } @@ -205,7 +217,10 @@ namespace ts { return node.kind; } - if (node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken) { + if ( + node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken + ) { if ((node as BinaryPlusExpression).cachedLiteralKind !== undefined) { return (node as BinaryPlusExpression).cachedLiteralKind; } @@ -232,7 +247,12 @@ namespace ts { * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the * BinaryExpression. */ - function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand?: Expression) { + function parenthesizeBinaryOperand( + binaryOperator: SyntaxKind, + operand: Expression, + isLeftSideOfBinary: boolean, + leftOperand?: Expression, + ) { const skipped = skipPartiallyEmittedExpressions(operand); // If the resulting expression is already parenthesized, we do not need to do any further processing. @@ -249,7 +269,11 @@ namespace ts { return parenthesizeBinaryOperand(binaryOperator, leftSide, /*isLeftSideOfBinary*/ true); } - function parenthesizeRightSideOfBinary(binaryOperator: SyntaxKind, leftSide: Expression | undefined, rightSide: Expression): Expression { + function parenthesizeRightSideOfBinary( + binaryOperator: SyntaxKind, + leftSide: Expression | undefined, + rightSide: Expression, + ): Expression { return parenthesizeBinaryOperand(binaryOperator, rightSide, /*isLeftSideOfBinary*/ false, leftSide); } @@ -258,7 +282,10 @@ namespace ts { } function parenthesizeConditionOfConditionalExpression(condition: Expression): Expression { - const conditionalPrecedence = getOperatorPrecedence(SyntaxKind.ConditionalExpression, SyntaxKind.QuestionToken); + const conditionalPrecedence = getOperatorPrecedence( + SyntaxKind.ConditionalExpression, + SyntaxKind.QuestionToken, + ); const emittedCondition = skipPartiallyEmittedExpressions(condition); const conditionPrecedence = getExpressionPrecedence(emittedCondition); if (compareValues(conditionPrecedence, conditionalPrecedence) !== Comparison.GreaterThan) { @@ -334,7 +361,8 @@ namespace ts { const emittedExpression = skipPartiallyEmittedExpressions(expression); if ( isLeftHandSideExpression(emittedExpression) - && (emittedExpression.kind !== SyntaxKind.NewExpression || (emittedExpression as NewExpression).arguments) + && (emittedExpression.kind !== SyntaxKind.NewExpression + || (emittedExpression as NewExpression).arguments) && (optionalChain || !isOptionalChain(emittedExpression)) ) { // TODO(rbuckton): Verify whether this assertion holds. @@ -347,12 +375,14 @@ namespace ts { function parenthesizeOperandOfPostfixUnary(operand: Expression): LeftHandSideExpression { // TODO(rbuckton): Verifiy whether `setTextRange` is needed. - return isLeftHandSideExpression(operand) ? operand : setTextRange(factory.createParenthesizedExpression(operand), operand); + return isLeftHandSideExpression(operand) ? operand + : setTextRange(factory.createParenthesizedExpression(operand), operand); } function parenthesizeOperandOfPrefixUnary(operand: Expression): UnaryExpression { // TODO(rbuckton): Verifiy whether `setTextRange` is needed. - return isUnaryExpression(operand) ? operand : setTextRange(factory.createParenthesizedExpression(operand), operand); + return isUnaryExpression(operand) ? operand + : setTextRange(factory.createParenthesizedExpression(operand), operand); } function parenthesizeExpressionsOfCommaDelimitedList(elements: NodeArray): NodeArray { @@ -365,7 +395,8 @@ namespace ts { const expressionPrecedence = getExpressionPrecedence(emittedExpression); const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken); // TODO(rbuckton): Verifiy whether `setTextRange` is needed. - return expressionPrecedence > commaPrecedence ? expression : setTextRange(factory.createParenthesizedExpression(expression), expression); + return expressionPrecedence > commaPrecedence ? expression + : setTextRange(factory.createParenthesizedExpression(expression), expression); } function parenthesizeExpressionOfExpressionStatement(expression: Expression): Expression { @@ -381,12 +412,20 @@ namespace ts { emittedExpression.typeArguments, emittedExpression.arguments, ); - return factory.restoreOuterExpressions(expression, updated, OuterExpressionKinds.PartiallyEmittedExpressions); + return factory.restoreOuterExpressions( + expression, + updated, + OuterExpressionKinds.PartiallyEmittedExpressions, + ); } } - const leftmostExpressionKind = getLeftmostExpression(emittedExpression, /*stopAtCallExpressions*/ false).kind; - if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) { + const leftmostExpressionKind = + getLeftmostExpression(emittedExpression, /*stopAtCallExpressions*/ false).kind; + if ( + leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression + || leftmostExpressionKind === SyntaxKind.FunctionExpression + ) { // TODO(rbuckton): Verifiy whether `setTextRange` is needed. return setTextRange(factory.createParenthesizedExpression(expression), expression); } @@ -397,7 +436,12 @@ namespace ts { function parenthesizeConciseBodyOfArrowFunction(body: Expression): Expression; function parenthesizeConciseBodyOfArrowFunction(body: ConciseBody): ConciseBody; function parenthesizeConciseBodyOfArrowFunction(body: ConciseBody): ConciseBody { - if (!isBlock(body) && (isCommaSequence(body) || getLeftmostExpression(body, /*stopAtCallExpressions*/ false).kind === SyntaxKind.ObjectLiteralExpression)) { + if ( + !isBlock(body) + && (isCommaSequence(body) + || getLeftmostExpression(body, /*stopAtCallExpressions*/ false).kind + === SyntaxKind.ObjectLiteralExpression) + ) { // TODO(rbuckton): Verifiy whether `setTextRange` is needed. return setTextRange(factory.createParenthesizedExpression(body), body); } @@ -546,7 +590,9 @@ namespace ts { // RestType : // `...` Type[~Extends] // - function parenthesizeElementTypesOfTupleType(types: readonly (TypeNode | NamedTupleMember)[]): NodeArray { + function parenthesizeElementTypesOfTupleType( + types: readonly (TypeNode | NamedTupleMember)[], + ): NodeArray { return factory.createNodeArray(sameMap(types, parenthesizeElementTypeOfTupleType)); } @@ -558,11 +604,15 @@ namespace ts { function hasJSDocPostfixQuestion(type: TypeNode | NamedTupleMember): boolean { if (isJSDocNullableType(type)) return type.postfix; if (isNamedTupleMember(type)) return hasJSDocPostfixQuestion(type.type); - if (isFunctionTypeNode(type) || isConstructorTypeNode(type) || isTypeOperatorNode(type)) return hasJSDocPostfixQuestion(type.type); + if (isFunctionTypeNode(type) || isConstructorTypeNode(type) || isTypeOperatorNode(type)) { + return hasJSDocPostfixQuestion(type.type); + } if (isConditionalTypeNode(type)) return hasJSDocPostfixQuestion(type.falseType); if (isUnionTypeNode(type)) return hasJSDocPostfixQuestion(last(type.types)); if (isIntersectionTypeNode(type)) return hasJSDocPostfixQuestion(last(type.types)); - if (isInferTypeNode(type)) return !!type.typeParameter.constraint && hasJSDocPostfixQuestion(type.typeParameter.constraint); + if (isInferTypeNode(type)) { + return !!type.typeParameter.constraint && hasJSDocPostfixQuestion(type.typeParameter.constraint); + } return false; } @@ -593,14 +643,17 @@ namespace ts { // } function parenthesizeLeadingTypeArgument(node: TypeNode) { - return isFunctionOrConstructorTypeNode(node) && node.typeParameters ? factory.createParenthesizedType(node) : node; + return isFunctionOrConstructorTypeNode(node) && node.typeParameters ? factory.createParenthesizedType(node) + : node; } function parenthesizeOrdinalTypeArgument(node: TypeNode, i: number) { return i === 0 ? parenthesizeLeadingTypeArgument(node) : node; } - function parenthesizeTypeArguments(typeArguments: NodeArray | undefined): NodeArray | undefined { + function parenthesizeTypeArguments( + typeArguments: NodeArray | undefined, + ): NodeArray | undefined { if (some(typeArguments)) { return factory.createNodeArray(sameMap(typeArguments, parenthesizeOrdinalTypeArgument)); } diff --git a/src/compiler/factory/utilities.ts b/src/compiler/factory/utilities.ts index 87da38f2f1611..0d2f6a9429657 100644 --- a/src/compiler/factory/utilities.ts +++ b/src/compiler/factory/utilities.ts @@ -3,10 +3,20 @@ namespace ts { // Compound nodes export function createEmptyExports(factory: NodeFactory) { - return factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createNamedExports([]), /*moduleSpecifier*/ undefined); + return factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([]), + /*moduleSpecifier*/ undefined, + ); } - export function createMemberAccessForPropertyName(factory: NodeFactory, target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression { + export function createMemberAccessForPropertyName( + factory: NodeFactory, + target: Expression, + memberName: PropertyName, + location?: TextRange, + ): MemberExpression { if (isComputedPropertyName(memberName)) { return setTextRange(factory.createElementAccessExpression(target, memberName.expression), location); } @@ -33,7 +43,11 @@ namespace ts { return react; } - function createJsxFactoryExpressionFromEntityName(factory: NodeFactory, jsxFactory: EntityName, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { + function createJsxFactoryExpressionFromEntityName( + factory: NodeFactory, + jsxFactory: EntityName, + parent: JsxOpeningLikeElement | JsxOpeningFragment, + ): Expression { if (isQualifiedName(jsxFactory)) { const left = createJsxFactoryExpressionFromEntityName(factory, jsxFactory.left, parent); const right = factory.createIdentifier(idText(jsxFactory.right)) as Mutable; @@ -45,25 +59,42 @@ namespace ts { } } - export function createJsxFactoryExpression(factory: NodeFactory, jsxFactoryEntity: EntityName | undefined, reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { - return jsxFactoryEntity ? - createJsxFactoryExpressionFromEntityName(factory, jsxFactoryEntity, parent) : - factory.createPropertyAccessExpression( + export function createJsxFactoryExpression( + factory: NodeFactory, + jsxFactoryEntity: EntityName | undefined, + reactNamespace: string, + parent: JsxOpeningLikeElement | JsxOpeningFragment, + ): Expression { + return jsxFactoryEntity + ? createJsxFactoryExpressionFromEntityName(factory, jsxFactoryEntity, parent) + : factory.createPropertyAccessExpression( createReactNamespace(reactNamespace, parent), "createElement", ); } - function createJsxFragmentFactoryExpression(factory: NodeFactory, jsxFragmentFactoryEntity: EntityName | undefined, reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { - return jsxFragmentFactoryEntity ? - createJsxFactoryExpressionFromEntityName(factory, jsxFragmentFactoryEntity, parent) : - factory.createPropertyAccessExpression( + function createJsxFragmentFactoryExpression( + factory: NodeFactory, + jsxFragmentFactoryEntity: EntityName | undefined, + reactNamespace: string, + parent: JsxOpeningLikeElement | JsxOpeningFragment, + ): Expression { + return jsxFragmentFactoryEntity + ? createJsxFactoryExpressionFromEntityName(factory, jsxFragmentFactoryEntity, parent) + : factory.createPropertyAccessExpression( createReactNamespace(reactNamespace, parent), "Fragment", ); } - export function createExpressionForJsxElement(factory: NodeFactory, callee: Expression, tagName: Expression, props: Expression | undefined, children: readonly Expression[] | undefined, location: TextRange): LeftHandSideExpression { + export function createExpressionForJsxElement( + factory: NodeFactory, + callee: Expression, + tagName: Expression, + props: Expression | undefined, + children: readonly Expression[] | undefined, + location: TextRange, + ): LeftHandSideExpression { const argumentsList = [tagName]; if (props) { argumentsList.push(props); @@ -95,8 +126,21 @@ namespace ts { ); } - export function createExpressionForJsxFragment(factory: NodeFactory, jsxFactoryEntity: EntityName | undefined, jsxFragmentFactoryEntity: EntityName | undefined, reactNamespace: string, children: readonly Expression[], parentElement: JsxOpeningFragment, location: TextRange): LeftHandSideExpression { - const tagName = createJsxFragmentFactoryExpression(factory, jsxFragmentFactoryEntity, reactNamespace, parentElement); + export function createExpressionForJsxFragment( + factory: NodeFactory, + jsxFactoryEntity: EntityName | undefined, + jsxFragmentFactoryEntity: EntityName | undefined, + reactNamespace: string, + children: readonly Expression[], + parentElement: JsxOpeningFragment, + location: TextRange, + ): LeftHandSideExpression { + const tagName = createJsxFragmentFactoryExpression( + factory, + jsxFragmentFactoryEntity, + reactNamespace, + parentElement, + ); const argumentsList = [tagName, factory.createNull()]; if (children && children.length > 0) { @@ -123,7 +167,11 @@ namespace ts { // Utilities - export function createForOfBindingStatement(factory: NodeFactory, node: ForInitializer, boundValue: Expression): Statement { + export function createForOfBindingStatement( + factory: NodeFactory, + node: ForInitializer, + boundValue: Expression, + ): Statement { if (isVariableDeclarationList(node)) { const firstDeclaration = first(node.declarations); const updatedDeclaration = factory.updateVariableDeclaration( @@ -149,7 +197,10 @@ namespace ts { export function insertLeadingStatement(factory: NodeFactory, dest: Statement, source: Statement) { if (isBlock(dest)) { - return factory.updateBlock(dest, setTextRange(factory.createNodeArray([source, ...dest.statements]), dest.statements)); + return factory.updateBlock( + dest, + setTextRange(factory.createNodeArray([source, ...dest.statements]), dest.statements), + ); } else { return factory.createBlock(factory.createNodeArray([dest, source]), /*multiLine*/ true); @@ -169,13 +220,19 @@ namespace ts { } } - export function createExpressionForPropertyName(factory: NodeFactory, memberName: Exclude): Expression { + export function createExpressionForPropertyName( + factory: NodeFactory, + memberName: Exclude, + ): Expression { if (isIdentifier(memberName)) { return factory.createStringLiteralFromNode(memberName); } else if (isComputedPropertyName(memberName)) { // TODO(rbuckton): Does this need to be parented? - return setParent(setTextRange(factory.cloneNode(memberName.expression), memberName.expression), memberName.expression.parent); + return setParent( + setTextRange(factory.cloneNode(memberName.expression), memberName.expression), + memberName.expression.parent, + ); } else { // TODO(rbuckton): Does this need to be parented? @@ -183,7 +240,13 @@ namespace ts { } } - function createExpressionForAccessorDeclaration(factory: NodeFactory, properties: NodeArray, property: AccessorDeclaration & { readonly name: Exclude; }, receiver: Expression, multiLine: boolean) { + function createExpressionForAccessorDeclaration( + factory: NodeFactory, + properties: NodeArray, + property: AccessorDeclaration & { readonly name: Exclude; }, + receiver: Expression, + multiLine: boolean, + ) { const { firstAccessor, getAccessor, setAccessor } = getAllAccessorDeclarations(properties, property); if (property === firstAccessor) { return setTextRange( @@ -232,7 +295,11 @@ namespace ts { return undefined; } - function createExpressionForPropertyAssignment(factory: NodeFactory, property: PropertyAssignment, receiver: Expression) { + function createExpressionForPropertyAssignment( + factory: NodeFactory, + property: PropertyAssignment, + receiver: Expression, + ) { return setOriginalNode( setTextRange( factory.createAssignment( @@ -245,7 +312,11 @@ namespace ts { ); } - function createExpressionForShorthandPropertyAssignment(factory: NodeFactory, property: ShorthandPropertyAssignment, receiver: Expression) { + function createExpressionForShorthandPropertyAssignment( + factory: NodeFactory, + property: ShorthandPropertyAssignment, + receiver: Expression, + ) { return setOriginalNode( setTextRange( factory.createAssignment( @@ -258,7 +329,11 @@ namespace ts { ); } - function createExpressionForMethodDeclaration(factory: NodeFactory, method: MethodDeclaration, receiver: Expression) { + function createExpressionForMethodDeclaration( + factory: NodeFactory, + method: MethodDeclaration, + receiver: Expression, + ) { return setOriginalNode( setTextRange( factory.createAssignment( @@ -285,14 +360,25 @@ namespace ts { ); } - export function createExpressionForObjectLiteralElementLike(factory: NodeFactory, node: ObjectLiteralExpression, property: ObjectLiteralElementLike, receiver: Expression): Expression | undefined { + export function createExpressionForObjectLiteralElementLike( + factory: NodeFactory, + node: ObjectLiteralExpression, + property: ObjectLiteralElementLike, + receiver: Expression, + ): Expression | undefined { if (property.name && isPrivateIdentifier(property.name)) { Debug.failBadSyntaxKind(property.name, "Private identifiers are not allowed in object literals."); } switch (property.kind) { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return createExpressionForAccessorDeclaration(factory, node.properties, property as typeof property & { readonly name: Exclude; }, receiver, !!node.multiLine); + return createExpressionForAccessorDeclaration( + factory, + node.properties, + property as typeof property & { readonly name: Exclude; }, + receiver, + !!node.multiLine, + ); case SyntaxKind.PropertyAssignment: return createExpressionForPropertyAssignment(factory, property, receiver); case SyntaxKind.ShorthandPropertyAssignment: @@ -334,17 +420,26 @@ namespace ts { * @param expression The expression to use as the value to increment or decrement * @param resultVariable A temporary variable in which to store the result. Pass `undefined` if the result is discarded, or if the value of `` is the expected result. */ - export function expandPreOrPostfixIncrementOrDecrementExpression(factory: NodeFactory, node: PrefixUnaryExpression | PostfixUnaryExpression, expression: Expression, recordTempVariable: (node: Identifier) => void, resultVariable: Identifier | undefined) { + export function expandPreOrPostfixIncrementOrDecrementExpression( + factory: NodeFactory, + node: PrefixUnaryExpression | PostfixUnaryExpression, + expression: Expression, + recordTempVariable: (node: Identifier) => void, + resultVariable: Identifier | undefined, + ) { const operator = node.operator; - Debug.assert(operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken, "Expected 'node' to be a pre- or post-increment or pre- or post-decrement expression"); + Debug.assert( + operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken, + "Expected 'node' to be a pre- or post-increment or pre- or post-decrement expression", + ); const temp = factory.createTempVariable(recordTempVariable); expression = factory.createAssignment(temp, expression); setTextRange(expression, node.operand); - let operation: Expression = isPrefixUnaryExpression(node) ? - factory.createPrefixUnaryExpression(operator, temp) : - factory.createPostfixUnaryExpression(temp, operator); + let operation: Expression = isPrefixUnaryExpression(node) + ? factory.createPrefixUnaryExpression(operator, temp) + : factory.createPostfixUnaryExpression(temp, operator); setTextRange(operation, node); if (resultVariable) { @@ -410,9 +505,12 @@ namespace ts { && isUseStrictPrologue(firstStatement); } - export function isCommaSequence(node: Expression): node is BinaryExpression & { operatorToken: Token; } | CommaListExpression { - return node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken || - node.kind === SyntaxKind.CommaListExpression; + export function isCommaSequence( + node: Expression, + ): node is BinaryExpression & { operatorToken: Token; } | CommaListExpression { + return node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken + || node.kind === SyntaxKind.CommaListExpression; } export function isJSDocTypeAssertion(node: Node): node is JSDocTypeAssertion { @@ -477,11 +575,22 @@ namespace ts { return !!emitNode && (!!emitNode.externalHelpersModuleName || !!emitNode.externalHelpers); } - export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: NodeFactory, helperFactory: EmitHelperFactory, sourceFile: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean, hasImportStar?: boolean, hasImportDefault?: boolean) { + export function createExternalHelpersImportDeclarationIfNeeded( + nodeFactory: NodeFactory, + helperFactory: EmitHelperFactory, + sourceFile: SourceFile, + compilerOptions: CompilerOptions, + hasExportStarsToExportValues?: boolean, + hasImportStar?: boolean, + hasImportDefault?: boolean, + ) { if (compilerOptions.importHelpers && isEffectiveExternalModule(sourceFile, compilerOptions)) { let namedBindings: NamedImportBindings | undefined; const moduleKind = getEmitModuleKind(compilerOptions); - if ((moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext) || sourceFile.impliedNodeFormat === ModuleKind.ESNext) { + if ( + (moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext) + || sourceFile.impliedNodeFormat === ModuleKind.ESNext + ) { // use named imports const helpers = getEmitHelpers(sourceFile); if (helpers) { @@ -501,8 +610,16 @@ namespace ts { namedBindings = nodeFactory.createNamedImports( map(helperNames, name => isFileLevelUniqueName(sourceFile, name) - ? nodeFactory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, nodeFactory.createIdentifier(name)) - : nodeFactory.createImportSpecifier(/*isTypeOnly*/ false, nodeFactory.createIdentifier(name), helperFactory.getUnscopedHelperName(name))), + ? nodeFactory.createImportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + nodeFactory.createIdentifier(name), + ) + : nodeFactory.createImportSpecifier( + /*isTypeOnly*/ false, + nodeFactory.createIdentifier(name), + helperFactory.getUnscopedHelperName(name), + )), ); const parseNode = getOriginalNode(sourceFile, isSourceFile); const emitNode = getOrCreateEmitNode(parseNode); @@ -512,7 +629,13 @@ namespace ts { } else { // use a namespace import - const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(nodeFactory, sourceFile, compilerOptions, hasExportStarsToExportValues, hasImportStar || hasImportDefault); + const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded( + nodeFactory, + sourceFile, + compilerOptions, + hasExportStarsToExportValues, + hasImportStar || hasImportDefault, + ); if (externalHelpersModuleName) { namedBindings = nodeFactory.createNamespaceImport(externalHelpersModuleName); } @@ -530,7 +653,13 @@ namespace ts { } } - export function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactory, node: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean, hasImportStarOrImportDefault?: boolean) { + export function getOrCreateExternalHelpersModuleNameIfNeeded( + factory: NodeFactory, + node: SourceFile, + compilerOptions: CompilerOptions, + hasExportStarsToExportValues?: boolean, + hasImportStarOrImportDefault?: boolean, + ) { if (compilerOptions.importHelpers && isEffectiveExternalModule(node, compilerOptions)) { const externalHelpersModuleName = getExternalHelpersModuleName(node); if (externalHelpersModuleName) { @@ -538,7 +667,8 @@ namespace ts { } const moduleKind = getEmitModuleKind(compilerOptions); - let create = (hasExportStarsToExportValues || (getESModuleInterop(compilerOptions) && hasImportStarOrImportDefault)) + let create = + (hasExportStarsToExportValues || (getESModuleInterop(compilerOptions) && hasImportStarOrImportDefault)) && moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || node.impliedNodeFormat === ModuleKind.CommonJS); if (!create) { @@ -556,7 +686,8 @@ namespace ts { if (create) { const parseNode = getOriginalNode(node, isSourceFile); const emitNode = getOrCreateEmitNode(parseNode); - return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = factory.createUniqueName(externalHelpersModuleNameText)); + return emitNode.externalHelpersModuleName + || (emitNode.externalHelpersModuleName = factory.createUniqueName(externalHelpersModuleNameText)); } } } @@ -564,11 +695,16 @@ namespace ts { /** * Get the name of that target module from an import or export declaration */ - export function getLocalNameForExternalImport(factory: NodeFactory, node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration, sourceFile: SourceFile): Identifier | undefined { + export function getLocalNameForExternalImport( + factory: NodeFactory, + node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration, + sourceFile: SourceFile, + ): Identifier | undefined { const namespaceDeclaration = getNamespaceDeclarationNode(node); if (namespaceDeclaration && !isDefaultImport(node) && !isExportNamespaceAsDefaultDeclaration(node)) { const name = namespaceDeclaration.name; - return isGeneratedIdentifier(name) ? name : factory.createIdentifier(getSourceTextOfNodeFromSourceFile(sourceFile, name) || idText(name)); + return isGeneratedIdentifier(name) ? name + : factory.createIdentifier(getSourceTextOfNodeFromSourceFile(sourceFile, name) || idText(name)); } if (node.kind === SyntaxKind.ImportDeclaration && node.importClause) { return factory.getGeneratedNameForNode(node); @@ -587,7 +723,14 @@ namespace ts { * 3- The containing SourceFile has an entry in renamedDependencies for the import as requested by some module loaders (e.g. System). * Otherwise, a new StringLiteral node representing the module name will be returned. */ - export function getExternalModuleNameLiteral(factory: NodeFactory, importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration | ImportCall, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, compilerOptions: CompilerOptions) { + export function getExternalModuleNameLiteral( + factory: NodeFactory, + importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration | ImportCall, + sourceFile: SourceFile, + host: EmitHost, + resolver: EmitResolver, + compilerOptions: CompilerOptions, + ) { const moduleName = getExternalModuleName(importNode); if (moduleName && isStringLiteral(moduleName)) { return tryGetModuleNameFromDeclaration(importNode, host, factory, resolver, compilerOptions) @@ -614,7 +757,12 @@ namespace ts { * 2. --out or --outFile is used, making the name relative to the rootDir * Otherwise, a new StringLiteral node representing the module name will be returned. */ - export function tryGetModuleNameFromFile(factory: NodeFactory, file: SourceFile | undefined, host: EmitHost, options: CompilerOptions): StringLiteral | undefined { + export function tryGetModuleNameFromFile( + factory: NodeFactory, + file: SourceFile | undefined, + host: EmitHost, + options: CompilerOptions, + ): StringLiteral | undefined { if (!file) { return undefined; } @@ -627,14 +775,27 @@ namespace ts { return undefined; } - function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ImportCall, host: EmitHost, factory: NodeFactory, resolver: EmitResolver, compilerOptions: CompilerOptions) { - return tryGetModuleNameFromFile(factory, resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions); + function tryGetModuleNameFromDeclaration( + declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ImportCall, + host: EmitHost, + factory: NodeFactory, + resolver: EmitResolver, + compilerOptions: CompilerOptions, + ) { + return tryGetModuleNameFromFile( + factory, + resolver.getExternalModuleFileFromDeclaration(declaration), + host, + compilerOptions, + ); } /** * Gets the initializer of an BindingOrAssignmentElement. */ - export function getInitializerOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): Expression | undefined { + export function getInitializerOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, + ): Expression | undefined { if (isDeclarationBindingElement(bindingElement)) { // `1` in `let { a = 1 } = ...` // `1` in `let { a: b = 1 } = ...` @@ -677,7 +838,9 @@ namespace ts { /** * Gets the name of an BindingOrAssignmentElement. */ - export function getTargetOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): BindingOrAssignmentElementTarget | undefined { + export function getTargetOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, + ): BindingOrAssignmentElementTarget | undefined { if (isDeclarationBindingElement(bindingElement)) { // `a` in `let { a } = ...` // `a` in `let { a = 1 } = ...` @@ -711,7 +874,9 @@ namespace ts { // `b.c` in `({ a: b.c = 1 } = ...)` // `b[0]` in `({ a: b[0] } = ...)` // `b[0]` in `({ a: b[0] = 1 } = ...)` - return getTargetOfBindingOrAssignmentElement(bindingElement.initializer as BindingOrAssignmentElement); + return getTargetOfBindingOrAssignmentElement( + bindingElement.initializer as BindingOrAssignmentElement, + ); case SyntaxKind.ShorthandPropertyAssignment: // `a` in `({ a } = ...)` @@ -720,7 +885,9 @@ namespace ts { case SyntaxKind.SpreadAssignment: // `a` in `({ ...a } = ...)` - return getTargetOfBindingOrAssignmentElement(bindingElement.expression as BindingOrAssignmentElement); + return getTargetOfBindingOrAssignmentElement( + bindingElement.expression as BindingOrAssignmentElement, + ); } // no target @@ -752,7 +919,9 @@ namespace ts { /** * Determines whether an BindingOrAssignmentElement is a rest element. */ - export function getRestIndicatorOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): BindingOrAssignmentElementRestIndicator | undefined { + export function getRestIndicatorOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, + ): BindingOrAssignmentElementRestIndicator | undefined { switch (bindingElement.kind) { case SyntaxKind.Parameter: case SyntaxKind.BindingElement: @@ -771,13 +940,20 @@ namespace ts { /** * Gets the property name of a BindingOrAssignmentElement */ - export function getPropertyNameOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): Exclude | undefined { + export function getPropertyNameOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, + ): Exclude | undefined { const propertyName = tryGetPropertyNameOfBindingOrAssignmentElement(bindingElement); - Debug.assert(!!propertyName || isSpreadAssignment(bindingElement), "Invalid property name for binding element."); + Debug.assert( + !!propertyName || isSpreadAssignment(bindingElement), + "Invalid property name for binding element.", + ); return propertyName; } - export function tryGetPropertyNameOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): Exclude | undefined { + export function tryGetPropertyNameOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, + ): Exclude | undefined { switch (bindingElement.kind) { case SyntaxKind.BindingElement: // `a` in `let { a: b } = ...` @@ -836,7 +1012,9 @@ namespace ts { /** * Gets the elements of a BindingOrAssignmentPattern */ - export function getElementsOfBindingOrAssignmentPattern(name: BindingOrAssignmentPattern): readonly BindingOrAssignmentElement[] { + export function getElementsOfBindingOrAssignmentPattern( + name: BindingOrAssignmentPattern, + ): readonly BindingOrAssignmentElement[] { switch (name.kind) { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: @@ -908,14 +1086,26 @@ namespace ts { || kind === SyntaxKind.NamespaceExportDeclaration; } - export const isTypeNodeOrTypeParameterDeclaration = or(isTypeNode, isTypeParameterDeclaration) as (node: Node) => node is TypeNode | TypeParameterDeclaration; - export const isQuestionOrExclamationToken = or(isQuestionToken, isExclamationToken) as (node: Node) => node is QuestionToken | ExclamationToken; - export const isIdentifierOrThisTypeNode = or(isIdentifier, isThisTypeNode) as (node: Node) => node is Identifier | ThisTypeNode; - export const isReadonlyKeywordOrPlusOrMinusToken = or(isReadonlyKeyword, isPlusToken, isMinusToken) as (node: Node) => node is ReadonlyKeyword | PlusToken | MinusToken; - export const isQuestionOrPlusOrMinusToken = or(isQuestionToken, isPlusToken, isMinusToken) as (node: Node) => node is QuestionToken | PlusToken | MinusToken; + export const isTypeNodeOrTypeParameterDeclaration = or(isTypeNode, isTypeParameterDeclaration) as ( + node: Node, + ) => node is TypeNode | TypeParameterDeclaration; + export const isQuestionOrExclamationToken = or(isQuestionToken, isExclamationToken) as ( + node: Node, + ) => node is QuestionToken | ExclamationToken; + export const isIdentifierOrThisTypeNode = or(isIdentifier, isThisTypeNode) as ( + node: Node, + ) => node is Identifier | ThisTypeNode; + export const isReadonlyKeywordOrPlusOrMinusToken = or(isReadonlyKeyword, isPlusToken, isMinusToken) as ( + node: Node, + ) => node is ReadonlyKeyword | PlusToken | MinusToken; + export const isQuestionOrPlusOrMinusToken = or(isQuestionToken, isPlusToken, isMinusToken) as ( + node: Node, + ) => node is QuestionToken | PlusToken | MinusToken; export const isModuleName = or(isIdentifier, isStringLiteral) as (node: Node) => node is ModuleName; - export function isLiteralTypeLikeExpression(node: Node): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression { + export function isLiteralTypeLikeExpression( + node: Node, + ): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression { const kind = node.kind; return kind === SyntaxKind.NullKeyword || kind === SyntaxKind.TrueKeyword @@ -1023,7 +1213,15 @@ namespace ts { return isBinaryOperator(node.kind); } - type BinaryExpressionState = (machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], resultHolder: { value: TResult; }, outerState: TOuterState) => number; + type BinaryExpressionState = ( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + resultHolder: { value: TResult; }, + outerState: TOuterState, + ) => number; namespace BinaryExpressionState { /** @@ -1032,7 +1230,15 @@ namespace ts { * @param frame The current frame * @returns The new frame */ - export function enter(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult; }, outerState: TOuterState): number { + export function enter( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + _resultHolder: { value: TResult; }, + outerState: TOuterState, + ): number { const prevUserState = stackIndex > 0 ? userStateStack[stackIndex - 1] : undefined; Debug.assertEqual(stateStack[stackIndex], enter); userStateStack[stackIndex] = machine.onEnter(nodeStack[stackIndex], prevUserState, outerState); @@ -1046,11 +1252,23 @@ namespace ts { * @param frame The current frame * @returns The new frame */ - export function left(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult; }, _outerState: TOuterState): number { + export function left( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + _resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], left); Debug.assertIsDefined(machine.onLeft); stateStack[stackIndex] = nextState(machine, left); - const nextNode = machine.onLeft(nodeStack[stackIndex].left, userStateStack[stackIndex], nodeStack[stackIndex]); + const nextNode = machine.onLeft( + nodeStack[stackIndex].left, + userStateStack[stackIndex], + nodeStack[stackIndex], + ); if (nextNode) { checkCircularity(stackIndex, nodeStack, nextNode); return pushStack(stackIndex, stateStack, nodeStack, userStateStack, nextNode); @@ -1064,7 +1282,15 @@ namespace ts { * @param frame The current frame * @returns The new frame */ - export function operator(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult; }, _outerState: TOuterState): number { + export function operator( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + _resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], operator); Debug.assertIsDefined(machine.onOperator); stateStack[stackIndex] = nextState(machine, operator); @@ -1078,11 +1304,23 @@ namespace ts { * @param frame The current frame * @returns The new frame */ - export function right(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult; }, _outerState: TOuterState): number { + export function right( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + _resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], right); Debug.assertIsDefined(machine.onRight); stateStack[stackIndex] = nextState(machine, right); - const nextNode = machine.onRight(nodeStack[stackIndex].right, userStateStack[stackIndex], nodeStack[stackIndex]); + const nextNode = machine.onRight( + nodeStack[stackIndex].right, + userStateStack[stackIndex], + nodeStack[stackIndex], + ); if (nextNode) { checkCircularity(stackIndex, nodeStack, nextNode); return pushStack(stackIndex, stateStack, nodeStack, userStateStack, nextNode); @@ -1096,7 +1334,15 @@ namespace ts { * @param frame The current frame * @returns The new frame */ - export function exit(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], resultHolder: { value: TResult; }, _outerState: TOuterState): number { + export function exit( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], exit); stateStack[stackIndex] = nextState(machine, exit); const result = machine.onExit(nodeStack[stackIndex], userStateStack[stackIndex]); @@ -1117,12 +1363,23 @@ namespace ts { * Handles a frame that is already done. * @returns The `done` state. */ - export function done(_machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], _nodeStack: BinaryExpression[], _userStateStack: TState[], _resultHolder: { value: TResult; }, _outerState: TOuterState): number { + export function done( + _machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + _nodeStack: BinaryExpression[], + _userStateStack: TState[], + _resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], done); return stackIndex; } - export function nextState(machine: BinaryExpressionStateMachine, currentState: BinaryExpressionState) { + export function nextState( + machine: BinaryExpressionStateMachine, + currentState: BinaryExpressionState, + ) { switch (currentState) { case enter: if (machine.onLeft) return left; @@ -1144,7 +1401,13 @@ namespace ts { } } - function pushStack(stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], node: BinaryExpression) { + function pushStack( + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + node: BinaryExpression, + ) { stackIndex++; stateStack[stackIndex] = enter; nodeStack[stackIndex] = node; @@ -1168,9 +1431,15 @@ namespace ts { class BinaryExpressionStateMachine { constructor( readonly onEnter: (node: BinaryExpression, prev: TState | undefined, outerState: TOuterState) => TState, - readonly onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, - readonly onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined, - readonly onRight: ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, + readonly onLeft: + | ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) + | undefined, + readonly onOperator: + | ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) + | undefined, + readonly onRight: + | ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) + | undefined, readonly onExit: (node: BinaryExpression, userState: TState) => TResult, readonly foldState: ((userState: TState, result: TResult, side: "left" | "right") => TState) | undefined, ) { @@ -1189,8 +1458,12 @@ namespace ts { export function createBinaryExpressionTrampoline( onEnter: (node: BinaryExpression, prev: TState | undefined) => TState, onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, - onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined, - onRight: ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, + onOperator: + | ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) + | undefined, + onRight: + | ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) + | undefined, onExit: (node: BinaryExpression, userState: TState) => TResult, foldState: ((userState: TState, result: TResult, side: "left" | "right") => TState) | undefined, ): (node: BinaryExpression) => TResult; @@ -1206,16 +1479,24 @@ namespace ts { export function createBinaryExpressionTrampoline( onEnter: (node: BinaryExpression, prev: TState | undefined, outerState: TOuterState) => TState, onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, - onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined, - onRight: ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, + onOperator: + | ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) + | undefined, + onRight: + | ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) + | undefined, onExit: (node: BinaryExpression, userState: TState) => TResult, foldState: ((userState: TState, result: TResult, side: "left" | "right") => TState) | undefined, ): (node: BinaryExpression, outerState: TOuterState) => TResult; export function createBinaryExpressionTrampoline( onEnter: (node: BinaryExpression, prev: TState | undefined, outerState: TOuterState) => TState, onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, - onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined, - onRight: ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, + onOperator: + | ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) + | undefined, + onRight: + | ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) + | undefined, onExit: (node: BinaryExpression, userState: TState) => TResult, foldState: ((userState: TState, result: TResult, side: "left" | "right") => TState) | undefined, ) { @@ -1229,7 +1510,15 @@ namespace ts { const userStateStack: TState[] = [undefined!]; let stackIndex = 0; while (stateStack[stackIndex] !== BinaryExpressionState.done) { - stackIndex = stateStack[stackIndex](machine, stackIndex, stateStack, nodeStack, userStateStack, resultHolder, outerState); + stackIndex = stateStack[stackIndex]( + machine, + stackIndex, + stateStack, + nodeStack, + userStateStack, + resultHolder, + outerState, + ); } Debug.assertEqual(stackIndex, 0); return resultHolder.value; @@ -1241,8 +1530,14 @@ namespace ts { * @internal */ export function elideNodes(factory: NodeFactory, nodes: NodeArray): NodeArray; - export function elideNodes(factory: NodeFactory, nodes: NodeArray | undefined): NodeArray | undefined; - export function elideNodes(factory: NodeFactory, nodes: NodeArray | undefined): NodeArray | undefined { + export function elideNodes( + factory: NodeFactory, + nodes: NodeArray | undefined, + ): NodeArray | undefined; + export function elideNodes( + factory: NodeFactory, + nodes: NodeArray | undefined, + ): NodeArray | undefined { if (nodes === undefined) return undefined; if (nodes.length === 0) return nodes; return setTextRange(factory.createNodeArray([], nodes.hasTrailingComma), nodes); @@ -1283,23 +1578,37 @@ namespace ts { /** * Formats a prefix or suffix of a generated name. If the part is a {@link GeneratedNamePart}, calls {@link generateName} to format the source node. */ - export function formatGeneratedNamePart(part: string | GeneratedNamePart | undefined, generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string): string; - export function formatGeneratedNamePart(part: string | GeneratedNamePart | undefined, generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string): string { - return typeof part === "object" ? formatGeneratedName(/*privateName*/ false, part.prefix, part.node, part.suffix, generateName!) : - typeof part === "string" ? part.length > 0 && part.charCodeAt(0) === CharacterCodes.hash ? part.slice(1) : part : - ""; - } - - function formatIdentifier(name: string | Identifier | PrivateIdentifier, generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string) { - return typeof name === "string" ? name : - formatIdentifierWorker(name, Debug.checkDefined(generateName)); + export function formatGeneratedNamePart( + part: string | GeneratedNamePart | undefined, + generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, + ): string; + export function formatGeneratedNamePart( + part: string | GeneratedNamePart | undefined, + generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, + ): string { + return typeof part === "object" + ? formatGeneratedName(/*privateName*/ false, part.prefix, part.node, part.suffix, generateName!) + : typeof part === "string" + ? part.length > 0 && part.charCodeAt(0) === CharacterCodes.hash ? part.slice(1) : part + : ""; + } + + function formatIdentifier( + name: string | Identifier | PrivateIdentifier, + generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, + ) { + return typeof name === "string" ? name + : formatIdentifierWorker(name, Debug.checkDefined(generateName)); } - function formatIdentifierWorker(node: Identifier | PrivateIdentifier, generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string) { - return isGeneratedPrivateIdentifier(node) ? generateName(node).slice(1) : - isGeneratedIdentifier(node) ? generateName(node) : - isPrivateIdentifier(node) ? (node.escapedText as string).slice(1) : - idText(node); + function formatIdentifierWorker( + node: Identifier | PrivateIdentifier, + generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, + ) { + return isGeneratedPrivateIdentifier(node) ? generateName(node).slice(1) + : isGeneratedIdentifier(node) ? generateName(node) + : isPrivateIdentifier(node) ? (node.escapedText as string).slice(1) + : idText(node); } /** @@ -1309,7 +1618,12 @@ namespace ts { * @param baseName The base name for the generated name. * @param suffix The suffix (if any) to include after the base name. */ - export function formatGeneratedName(privateName: boolean, prefix: string | undefined, baseName: string, suffix: string | undefined): string; + export function formatGeneratedName( + privateName: boolean, + prefix: string | undefined, + baseName: string, + suffix: string | undefined, + ): string; /** * Formats a generated name. * @param privateName When `true`, inserts a `#` character at the start of the result. @@ -1318,8 +1632,20 @@ namespace ts { * @param suffix The suffix (if any) to include after the base name. * @param generateName Called to format the source node of {@link prefix} when it is a {@link GeneratedNamePart}. */ - export function formatGeneratedName(privateName: boolean, prefix: string | GeneratedNamePart | undefined, baseName: string | Identifier | PrivateIdentifier, suffix: string | GeneratedNamePart | undefined, generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string): string; - export function formatGeneratedName(privateName: boolean, prefix: string | GeneratedNamePart | undefined, baseName: string | Identifier | PrivateIdentifier, suffix: string | GeneratedNamePart | undefined, generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string) { + export function formatGeneratedName( + privateName: boolean, + prefix: string | GeneratedNamePart | undefined, + baseName: string | Identifier | PrivateIdentifier, + suffix: string | GeneratedNamePart | undefined, + generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, + ): string; + export function formatGeneratedName( + privateName: boolean, + prefix: string | GeneratedNamePart | undefined, + baseName: string | Identifier | PrivateIdentifier, + suffix: string | GeneratedNamePart | undefined, + generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, + ) { prefix = formatGeneratedNamePart(prefix, generateName!); suffix = formatGeneratedNamePart(suffix, generateName!); baseName = formatIdentifier(baseName, generateName); @@ -1329,7 +1655,12 @@ namespace ts { /** * Creates a private backing field for an `accessor` {@link PropertyDeclaration}. */ - export function createAccessorPropertyBackingField(factory: NodeFactory, node: PropertyDeclaration, modifiers: ModifiersArray | undefined, initializer: Expression | undefined) { + export function createAccessorPropertyBackingField( + factory: NodeFactory, + node: PropertyDeclaration, + modifiers: ModifiersArray | undefined, + initializer: Expression | undefined, + ) { return factory.updatePropertyDeclaration( node, modifiers, @@ -1343,7 +1674,12 @@ namespace ts { /** * Creates a {@link GetAccessorDeclaration} that reads from a private backing field. */ - export function createAccessorPropertyGetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: ModifiersArray | undefined, name: PropertyName) { + export function createAccessorPropertyGetRedirector( + factory: NodeFactory, + node: PropertyDeclaration, + modifiers: ModifiersArray | undefined, + name: PropertyName, + ) { return factory.createGetAccessorDeclaration( modifiers, name, @@ -1363,7 +1699,12 @@ namespace ts { /** * Creates a {@link SetAccessorDeclaration} that writes to a private backing field. */ - export function createAccessorPropertySetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: ModifiersArray | undefined, name: PropertyName) { + export function createAccessorPropertySetRedirector( + factory: NodeFactory, + node: PropertyDeclaration, + modifiers: ModifiersArray | undefined, + name: PropertyName, + ) { return factory.createSetAccessorDeclaration( modifiers, name, @@ -1377,7 +1718,11 @@ namespace ts { factory.createAssignment( factory.createPropertyAccessExpression( factory.createThis(), - factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage"), + factory.getGeneratedPrivateNameForNode( + node.name, + /*prefix*/ undefined, + "_accessor_storage", + ), ), factory.createIdentifier("value"), ), diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 0dc61f3e3a576..f2c1088a848a1 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -10,7 +10,10 @@ namespace ts { return !!compilerOptions.traceResolution && host.trace !== undefined; } - function withPackageId(packageInfo: PackageJsonInfo | undefined, r: PathAndExtension | undefined): Resolved | undefined { + function withPackageId( + packageInfo: PackageJsonInfo | undefined, + r: PathAndExtension | undefined, + ): Resolved | undefined { let packageId: PackageId | undefined; if (r && packageInfo) { const packageJsonContent = packageInfo.contents.packageJsonContent as PackageJson; @@ -100,7 +103,14 @@ namespace ts { return resultFromCache; } return { - resolvedModule: resolved && { resolvedFileName: resolved.path, originalPath: resolved.originalPath === true ? undefined : resolved.originalPath, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId }, + resolvedModule: resolved + && { + resolvedFileName: resolved.path, + originalPath: resolved.originalPath === true ? undefined : resolved.originalPath, + extension: resolved.extension, + isExternalLibraryImport, + packageId: resolved.packageId, + }, failedLookupLocations, affectingLocations, resolutionDiagnostics: diagnostics, @@ -141,9 +151,24 @@ namespace ts { version?: string; } - function readPackageJsonField>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined; - function readPackageJsonField>(jsonContent: PackageJson, fieldName: K, typeOfTag: "object", state: ModuleResolutionState): PackageJson[K] | undefined; - function readPackageJsonField(jsonContent: PackageJson, fieldName: K, typeOfTag: "string" | "object", state: ModuleResolutionState): PackageJson[K] | undefined { + function readPackageJsonField>( + jsonContent: PackageJson, + fieldName: K, + typeOfTag: "string", + state: ModuleResolutionState, + ): PackageJson[K] | undefined; + function readPackageJsonField>( + jsonContent: PackageJson, + fieldName: K, + typeOfTag: "object", + state: ModuleResolutionState, + ): PackageJson[K] | undefined; + function readPackageJsonField( + jsonContent: PackageJson, + fieldName: K, + typeOfTag: "string" | "object", + state: ModuleResolutionState, + ): PackageJson[K] | undefined { if (!hasProperty(jsonContent, fieldName)) { if (state.traceEnabled) { trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, fieldName); @@ -154,14 +179,25 @@ namespace ts { if (typeof value !== typeOfTag || value === null) { // eslint-disable-line no-null/no-null if (state.traceEnabled) { // eslint-disable-next-line no-null/no-null - trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, fieldName, typeOfTag, value === null ? "null" : typeof value); + trace( + state.host, + Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, + fieldName, + typeOfTag, + value === null ? "null" : typeof value, + ); } return; } return value; } - function readPackageJsonPathField(jsonContent: PackageJson, fieldName: K, baseDirectory: string, state: ModuleResolutionState): PackageJson[K] | undefined { + function readPackageJsonPathField( + jsonContent: PackageJson, + fieldName: K, + baseDirectory: string, + state: ModuleResolutionState, + ): PackageJson[K] | undefined { const fileName = readPackageJsonField(jsonContent, fieldName, "string", state); if (fileName === undefined) { return; @@ -184,7 +220,11 @@ namespace ts { || readPackageJsonPathField(jsonContent, "types", baseDirectory, state); } - function readPackageJsonTSConfigField(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) { + function readPackageJsonTSConfigField( + jsonContent: PackageJson, + baseDirectory: string, + state: ModuleResolutionState, + ) { return readPackageJsonPathField(jsonContent, "tsconfig", baseDirectory, state); } @@ -209,14 +249,21 @@ namespace ts { paths: MapLike; } - function readPackageJsonTypesVersionPaths(jsonContent: PackageJson, state: ModuleResolutionState): VersionPaths | undefined { + function readPackageJsonTypesVersionPaths( + jsonContent: PackageJson, + state: ModuleResolutionState, + ): VersionPaths | undefined { const typesVersions = readPackageJsonTypesVersionsField(jsonContent, state); if (typesVersions === undefined) return; if (state.traceEnabled) { for (const key in typesVersions) { if (hasProperty(typesVersions, key) && !VersionRange.tryParse(key)) { - trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_is_not_a_valid_semver_range, key); + trace( + state.host, + Diagnostics.package_json_has_a_typesVersions_entry_0_that_is_not_a_valid_semver_range, + key, + ); } } } @@ -224,7 +271,11 @@ namespace ts { const result = getPackageJsonTypesVersionsPaths(typesVersions); if (!result) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_does_not_have_a_typesVersions_entry_that_matches_version_0, versionMajorMinor); + trace( + state.host, + Diagnostics.package_json_does_not_have_a_typesVersions_entry_that_matches_version_0, + versionMajorMinor, + ); } return; } @@ -232,7 +283,13 @@ namespace ts { const { version: bestVersionKey, paths: bestVersionPaths } = result; if (typeof bestVersionPaths !== "object") { if (state.traceEnabled) { - trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, `typesVersions['${bestVersionKey}']`, "object", typeof bestVersionPaths); + trace( + state.host, + Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, + `typesVersions['${bestVersionKey}']`, + "object", + typeof bestVersionPaths, + ); } return; } @@ -261,7 +318,10 @@ namespace ts { } } - export function getEffectiveTypeRoots(options: CompilerOptions, host: GetEffectiveTypeRootsHost): string[] | undefined { + export function getEffectiveTypeRoots( + options: CompilerOptions, + host: GetEffectiveTypeRootsHost, + ): string[] | undefined { if (options.typeRoots) { return options.typeRoots; } @@ -283,7 +343,10 @@ namespace ts { * Returns the path to every node_modules/@types directory from some ancestor directory. * Returns undefined if there are none. */ - function getDefaultTypeRoots(currentDirectory: string, host: { directoryExists?: (directoryName: string) => boolean; }): string[] | undefined { + function getDefaultTypeRoots( + currentDirectory: string, + host: { directoryExists?: (directoryName: string) => boolean; }, + ): string[] | undefined { if (!host.directoryExists) { return [combinePaths(currentDirectory, nodeModulesAtTypes)]; // And if it doesn't exist, tough. @@ -302,7 +365,8 @@ namespace ts { const nodeModulesAtTypes = combinePaths("node_modules", "@types"); function arePathsEqual(path1: string, path2: string, host: ModuleResolutionHost): boolean { - const useCaseSensitiveFileNames = typeof host.useCaseSensitiveFileNames === "function" ? host.useCaseSensitiveFileNames() : host.useCaseSensitiveFileNames; + const useCaseSensitiveFileNames = typeof host.useCaseSensitiveFileNames === "function" + ? host.useCaseSensitiveFileNames() : host.useCaseSensitiveFileNames; return comparePaths(path1, path2, !useCaseSensitiveFileNames) === Comparison.EqualTo; } @@ -311,21 +375,49 @@ namespace ts { * This is possible in case if resolution is performed for directives specified via 'types' parameter. In this case initial path for secondary lookups * is assumed to be the same as root directory of the project. */ - export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string | undefined, options: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference, cache?: TypeReferenceDirectiveResolutionCache, resolutionMode?: SourceFile["impliedNodeFormat"]): ResolvedTypeReferenceDirectiveWithFailedLookupLocations { - Debug.assert(typeof typeReferenceDirectiveName === "string", "Non-string value passed to `ts.resolveTypeReferenceDirective`, likely by a wrapping package working with an outdated `resolveTypeReferenceDirectives` signature. This is probably not a problem in TS itself."); + export function resolveTypeReferenceDirective( + typeReferenceDirectiveName: string, + containingFile: string | undefined, + options: CompilerOptions, + host: ModuleResolutionHost, + redirectedReference?: ResolvedProjectReference, + cache?: TypeReferenceDirectiveResolutionCache, + resolutionMode?: SourceFile["impliedNodeFormat"], + ): ResolvedTypeReferenceDirectiveWithFailedLookupLocations { + Debug.assert( + typeof typeReferenceDirectiveName === "string", + "Non-string value passed to `ts.resolveTypeReferenceDirective`, likely by a wrapping package working with an outdated `resolveTypeReferenceDirectives` signature. This is probably not a problem in TS itself.", + ); const traceEnabled = isTraceEnabled(options, host); if (redirectedReference) { options = redirectedReference.commandLine.options; } const containingDirectory = containingFile ? getDirectoryPath(containingFile) : undefined; - const perFolderCache = containingDirectory ? cache && cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference) : undefined; + const perFolderCache = containingDirectory + ? cache && cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference) : undefined; let result = perFolderCache && perFolderCache.get(typeReferenceDirectiveName, /*mode*/ resolutionMode); if (result) { if (traceEnabled) { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1, typeReferenceDirectiveName, containingFile); - if (redirectedReference) trace(host, Diagnostics.Using_compiler_options_of_project_reference_redirect_0, redirectedReference.sourceFile.fileName); - trace(host, Diagnostics.Resolution_for_type_reference_directive_0_was_found_in_cache_from_location_1, typeReferenceDirectiveName, containingDirectory); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_1, + typeReferenceDirectiveName, + containingFile, + ); + if (redirectedReference) { + trace( + host, + Diagnostics.Using_compiler_options_of_project_reference_redirect_0, + redirectedReference.sourceFile.fileName, + ); + } + trace( + host, + Diagnostics.Resolution_for_type_reference_directive_0_was_found_in_cache_from_location_1, + typeReferenceDirectiveName, + containingDirectory, + ); traceResult(result); } return result; @@ -335,22 +427,46 @@ namespace ts { if (traceEnabled) { if (containingFile === undefined) { if (typeRoots === undefined) { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_not_set, typeReferenceDirectiveName); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_not_set, + typeReferenceDirectiveName, + ); } else { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, typeReferenceDirectiveName, typeRoots); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, + typeReferenceDirectiveName, + typeRoots, + ); } } else { if (typeRoots === undefined) { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_not_set, typeReferenceDirectiveName, containingFile); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_not_set, + typeReferenceDirectiveName, + containingFile, + ); } else { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, typeReferenceDirectiveName, containingFile, typeRoots); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, + typeReferenceDirectiveName, + containingFile, + typeRoots, + ); } } if (redirectedReference) { - trace(host, Diagnostics.Using_compiler_options_of_project_reference_redirect_0, redirectedReference.sourceFile.fileName); + trace( + host, + Diagnostics.Using_compiler_options_of_project_reference_redirect_0, + redirectedReference.sourceFile.fileName, + ); } } @@ -364,10 +480,16 @@ namespace ts { // in practice, not every cache has the options available to intelligently make the choice to ignore the mode request, and it's unclear how modern "faithful modern // resolution" should be (`node16`? `nodenext`?). As such, witnessing a mode-overriding triple-slash reference in a non-modal module resolution // context should _probably_ be an error - and that should likely be handled by the `Program` (which is what we do). - if (resolutionMode === ModuleKind.ESNext && (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext)) { + if ( + resolutionMode === ModuleKind.ESNext + && (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext) + ) { features |= NodeResolutionFeatures.EsmMode; } - const conditions = features & NodeResolutionFeatures.Exports ? features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"] : []; + const conditions = features & NodeResolutionFeatures.Exports + ? features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"] + : []; const diagnostics: Diagnostic[] = []; const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, @@ -402,7 +524,12 @@ namespace ts { isExternalLibraryImport: pathContainsNodeModules(fileName), }; } - result = { resolvedTypeReferenceDirective, failedLookupLocations, affectingLocations, resolutionDiagnostics: diagnostics }; + result = { + resolvedTypeReferenceDirective, + failedLookupLocations, + affectingLocations, + resolutionDiagnostics: diagnostics, + }; perFolderCache?.set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result); if (traceEnabled) traceResult(result); return result; @@ -412,10 +539,24 @@ namespace ts { trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName); } else if (result.resolvedTypeReferenceDirective.packageId) { - trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_with_Package_ID_2_primary_Colon_3, typeReferenceDirectiveName, result.resolvedTypeReferenceDirective.resolvedFileName, packageIdToString(result.resolvedTypeReferenceDirective.packageId), result.resolvedTypeReferenceDirective.primary); + trace( + host, + Diagnostics + .Type_reference_directive_0_was_successfully_resolved_to_1_with_Package_ID_2_primary_Colon_3, + typeReferenceDirectiveName, + result.resolvedTypeReferenceDirective.resolvedFileName, + packageIdToString(result.resolvedTypeReferenceDirective.packageId), + result.resolvedTypeReferenceDirective.primary, + ); } else { - trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, result.resolvedTypeReferenceDirective.resolvedFileName, result.resolvedTypeReferenceDirective.primary); + trace( + host, + Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, + typeReferenceDirectiveName, + result.resolvedTypeReferenceDirective.resolvedFileName, + result.resolvedTypeReferenceDirective.primary, + ); } } @@ -430,10 +571,19 @@ namespace ts { const candidateDirectory = getDirectoryPath(candidate); const directoryExists = directoryProbablyExists(candidateDirectory, host); if (!directoryExists && traceEnabled) { - trace(host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, candidateDirectory); + trace( + host, + Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, + candidateDirectory, + ); } return resolvedTypeScriptOnly( - loadNodeModuleFromDirectory(Extensions.DtsOnly, candidate, !directoryExists, moduleResolutionState), + loadNodeModuleFromDirectory( + Extensions.DtsOnly, + candidate, + !directoryExists, + moduleResolutionState, + ), ); }); } @@ -450,31 +600,57 @@ namespace ts { if (initialLocationForSecondaryLookup !== undefined) { // check secondary locations if (traceEnabled) { - trace(host, Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, initialLocationForSecondaryLookup); + trace( + host, + Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, + initialLocationForSecondaryLookup, + ); } let result: Resolved | undefined; if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) { - const searchResult = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined, /*redirectedReference*/ undefined); + const searchResult = loadModuleFromNearestNodeModulesDirectory( + Extensions.DtsOnly, + typeReferenceDirectiveName, + initialLocationForSecondaryLookup, + moduleResolutionState, + /*cache*/ undefined, + /*redirectedReference*/ undefined, + ); result = searchResult && searchResult.value; } else { - const { path: candidate } = normalizePathForCJSResolution(initialLocationForSecondaryLookup, typeReferenceDirectiveName); - result = nodeLoadModuleByRelativeName(Extensions.DtsOnly, candidate, /*onlyRecordFailures*/ false, moduleResolutionState, /*considerPackageJson*/ true); + const { path: candidate } = normalizePathForCJSResolution( + initialLocationForSecondaryLookup, + typeReferenceDirectiveName, + ); + result = nodeLoadModuleByRelativeName( + Extensions.DtsOnly, + candidate, + /*onlyRecordFailures*/ false, + moduleResolutionState, + /*considerPackageJson*/ true, + ); } return resolvedTypeScriptOnly(result); } else { if (traceEnabled) { - trace(host, Diagnostics.Containing_file_is_not_specified_and_root_directory_cannot_be_determined_skipping_lookup_in_node_modules_folder); + trace( + host, + Diagnostics + .Containing_file_is_not_specified_and_root_directory_cannot_be_determined_skipping_lookup_in_node_modules_folder, + ); } } } } function getDefaultNodeResolutionFeatures(options: CompilerOptions) { - return getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 ? NodeResolutionFeatures.Node16Default : - getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext ? NodeResolutionFeatures.NodeNextDefault : - NodeResolutionFeatures.None; + return getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 + ? NodeResolutionFeatures.Node16Default + : getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext + ? NodeResolutionFeatures.NodeNextDefault + : NodeResolutionFeatures.None; } /** @@ -488,7 +664,11 @@ namespace ts { host: ModuleResolutionHost, cache: ModuleResolutionCache | undefined, ): PackageJsonInfo | undefined { - const moduleResolutionState = getTemporaryModuleResolutionState(cache?.getPackageJsonInfoCache(), host, options); + const moduleResolutionState = getTemporaryModuleResolutionState( + cache?.getPackageJsonInfoCache(), + host, + options, + ); return forEachAncestorDirectory(containingDirectory, ancestorDirectory => { if (getBaseFileName(ancestorDirectory) !== "node_modules") { @@ -526,7 +706,8 @@ namespace ts { // `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types. // See `createNotNeededPackageJSON` in the types-publisher` repo. // eslint-disable-next-line no-null/no-null - const isNotNeededPackage = host.fileExists(packageJsonPath) && (readJson(packageJsonPath, host) as PackageJson).typings === null; + const isNotNeededPackage = host.fileExists(packageJsonPath) + && (readJson(packageJsonPath, host) as PackageJson).typings === null; if (!isNotNeededPackage) { const baseFileName = getBaseFileName(normalized); @@ -544,7 +725,11 @@ namespace ts { return result; } - export interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache, PackageJsonInfoCache { + export interface TypeReferenceDirectiveResolutionCache + extends + PerDirectoryResolutionCache, + PackageJsonInfoCache + { /*@internal*/ clearAllExceptPackageJsonInfoCache(): void; } @@ -562,7 +747,10 @@ namespace ts { * This assumes that any module id will have the same resolution for sibling files located in the same folder. */ export interface PerDirectoryResolutionCache { - getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): ModeAwareCache; + getOrCreateCacheForDirectory( + directoryName: string, + redirectedReference?: ResolvedProjectReference, + ): ModeAwareCache; clear(): void; /** * Updates with the current compilerOptions the cache will operate with. @@ -571,7 +759,12 @@ namespace ts { update(options: CompilerOptions): void; } - export interface ModuleResolutionCache extends PerDirectoryResolutionCache, NonRelativeModuleNameResolutionCache, PackageJsonInfoCache { + export interface ModuleResolutionCache + extends + PerDirectoryResolutionCache, + NonRelativeModuleNameResolutionCache, + PackageJsonInfoCache + { getPackageJsonInfoCache(): PackageJsonInfoCache; /*@internal*/ clearAllExceptPackageJsonInfoCache(): void; } @@ -581,7 +774,11 @@ namespace ts { * We support only non-relative module names because resolution of relative module names is usually more deterministic and thus less expensive. */ export interface NonRelativeModuleNameResolutionCache extends PackageJsonInfoCache { - getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, redirectedReference?: ResolvedProjectReference): PerModuleNameCache; + getOrCreateCacheForModuleName( + nonRelativeModuleName: string, + mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, + redirectedReference?: ResolvedProjectReference, + ): PerModuleNameCache; } export interface PackageJsonInfoCache { @@ -640,7 +837,9 @@ namespace ts { let redirects = redirectsMap.get(path); if (!redirects) { // Reuse map if redirected reference map uses same resolution - redirects = !options || optionsHaveModuleResolutionChanges(options, redirectedReference.commandLine.options) ? new Map() : ownMap; + redirects = + !options || optionsHaveModuleResolutionChanges(options, redirectedReference.commandLine.options) + ? new Map() : ownMap; redirectsMap.set(path, redirects); } return redirects; @@ -652,7 +851,10 @@ namespace ts { } } - function createPackageJsonInfoCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): PackageJsonInfoCache { + function createPackageJsonInfoCache( + currentDirectory: string, + getCanonicalFileName: (s: string) => string, + ): PackageJsonInfoCache { let cache: ESMap | undefined; return { getPackageJsonInfo, setPackageJsonInfo, clear, entries, getInternalMap }; function getPackageJsonInfo(packageJsonPath: string) { @@ -673,7 +875,12 @@ namespace ts { } } - function getOrCreateCache(cacheWithRedirects: CacheWithRedirects, redirectedReference: ResolvedProjectReference | undefined, key: string, create: () => T): T { + function getOrCreateCache( + cacheWithRedirects: CacheWithRedirects, + redirectedReference: ResolvedProjectReference | undefined, + key: string, + create: () => T, + ): T { const cache = cacheWithRedirects.getOrCreateMapOfCacheRedirects(redirectedReference); let result = cache.get(key); if (!result) { @@ -711,7 +918,11 @@ namespace ts { moduleNameToDirectoryMap?.setOwnOptions(options); } - function createPerDirectoryResolutionCache(currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, directoryToModuleNameMap: CacheWithRedirects>): PerDirectoryResolutionCache { + function createPerDirectoryResolutionCache( + currentDirectory: string, + getCanonicalFileName: GetCanonicalFileName, + directoryToModuleNameMap: CacheWithRedirects>, + ): PerDirectoryResolutionCache { return { getOrCreateCacheForDirectory, clear, @@ -728,14 +939,22 @@ namespace ts { function getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference) { const path = toPath(directoryName, currentDirectory, getCanonicalFileName); - return getOrCreateCache>(directoryToModuleNameMap, redirectedReference, path, () => createModeAwareCache()); + return getOrCreateCache>( + directoryToModuleNameMap, + redirectedReference, + path, + () => createModeAwareCache(), + ); } } /* @internal */ export function createModeAwareCache(): ModeAwareCache { const underlying = new Map(); - const memoizedReverseKeys = new Map(); + const memoizedReverseKeys = new Map< + string, + [specifier: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined] + >(); const cache: ModeAwareCache = { get(specifier, mode) { @@ -772,14 +991,19 @@ namespace ts { } /* @internal */ - export function zipToModeAwareCache(file: SourceFile, keys: readonly string[] | readonly FileReference[], values: readonly V[]): ModeAwareCache { + export function zipToModeAwareCache( + file: SourceFile, + keys: readonly string[] | readonly FileReference[], + values: readonly V[], + ): ModeAwareCache { Debug.assert(keys.length === values.length); const map = createModeAwareCache(); for (let i = 0; i < keys.length; ++i) { const entry = keys[i]; // We lower-case all type references because npm automatically lowercases all packages. See GH#9824. const name = !isString(entry) ? entry.fileName.toLowerCase() : entry; - const mode = !isString(entry) ? entry.resolutionMode || file.impliedNodeFormat : getModeForResolutionAtIndex(file, i); + const mode = !isString(entry) ? entry.resolutionMode || file.impliedNodeFormat + : getModeForResolutionAtIndex(file, i); map.set(name, mode, values[i]); } return map; @@ -805,7 +1029,11 @@ namespace ts { directoryToModuleNameMap?: CacheWithRedirects>, moduleNameToDirectoryMap?: CacheWithRedirects, ): ModuleResolutionCache { - const perDirectoryResolutionCache = createPerDirectoryResolutionCache(currentDirectory, getCanonicalFileName, directoryToModuleNameMap ||= createCacheWithRedirects(options)); + const perDirectoryResolutionCache = createPerDirectoryResolutionCache( + currentDirectory, + getCanonicalFileName, + directoryToModuleNameMap ||= createCacheWithRedirects(options), + ); moduleNameToDirectoryMap ||= createCacheWithRedirects(options); const packageJsonInfoCache = createPackageJsonInfoCache(currentDirectory, getCanonicalFileName); @@ -833,9 +1061,18 @@ namespace ts { updateRedirectsMap(options, directoryToModuleNameMap!, moduleNameToDirectoryMap); } - function getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, redirectedReference?: ResolvedProjectReference): PerModuleNameCache { + function getOrCreateCacheForModuleName( + nonRelativeModuleName: string, + mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, + redirectedReference?: ResolvedProjectReference, + ): PerModuleNameCache { Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName)); - return getOrCreateCache(moduleNameToDirectoryMap!, redirectedReference, mode === undefined ? nonRelativeModuleName : `${mode}|${nonRelativeModuleName}`, createPerModuleNameCache); + return getOrCreateCache( + moduleNameToDirectoryMap!, + redirectedReference, + mode === undefined ? nonRelativeModuleName : `${mode}|${nonRelativeModuleName}`, + createPerModuleNameCache, + ); } function createPerModuleNameCache(): PerModuleNameCache { @@ -866,8 +1103,8 @@ namespace ts { } directoryPathMap.set(path, result); - const resolvedFileName = result.resolvedModule && - (result.resolvedModule.originalPath || result.resolvedModule.resolvedFileName); + const resolvedFileName = result.resolvedModule + && (result.resolvedModule.originalPath || result.resolvedModule.resolvedFileName); // find common prefix between directory and resolved file name // this common prefix should be the shortest path that has the same resolution // directory: /a/b/c/d/e @@ -887,7 +1124,11 @@ namespace ts { } function getCommonPrefix(directory: Path, resolution: string) { - const resolutionDirectory = toPath(getDirectoryPath(resolution), currentDirectory, getCanonicalFileName); + const resolutionDirectory = toPath( + getDirectoryPath(resolution), + currentDirectory, + getCanonicalFileName, + ); // find first position where directory and resolution differs let i = 0; @@ -895,7 +1136,10 @@ namespace ts { while (i < limit && directory.charCodeAt(i) === resolutionDirectory.charCodeAt(i)) { i++; } - if (i === directory.length && (resolutionDirectory.length === i || resolutionDirectory[i] === directorySeparator)) { + if ( + i === directory.length + && (resolutionDirectory.length === i || resolutionDirectory[i] === directorySeparator) + ) { return directory; } const rootLength = getRootLength(directory); @@ -923,16 +1167,24 @@ namespace ts { getCanonicalFileName: GetCanonicalFileName, options: undefined, packageJsonInfoCache: PackageJsonInfoCache | undefined, - directoryToModuleNameMap: CacheWithRedirects>, + directoryToModuleNameMap: CacheWithRedirects< + ModeAwareCache + >, ): TypeReferenceDirectiveResolutionCache; export function createTypeReferenceDirectiveResolutionCache( currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, options?: CompilerOptions, packageJsonInfoCache?: PackageJsonInfoCache | undefined, - directoryToModuleNameMap?: CacheWithRedirects>, + directoryToModuleNameMap?: CacheWithRedirects< + ModeAwareCache + >, ): TypeReferenceDirectiveResolutionCache { - const perDirectoryResolutionCache = createPerDirectoryResolutionCache(currentDirectory, getCanonicalFileName, directoryToModuleNameMap ||= createCacheWithRedirects(options)); + const perDirectoryResolutionCache = createPerDirectoryResolutionCache( + currentDirectory, + getCanonicalFileName, + directoryToModuleNameMap ||= createCacheWithRedirects(options), + ); packageJsonInfoCache ||= createPackageJsonInfoCache(currentDirectory, getCanonicalFileName); return { @@ -952,14 +1204,27 @@ namespace ts { } } - export function resolveModuleNameFromCache(moduleName: string, containingFile: string, cache: ModuleResolutionCache, mode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined { + export function resolveModuleNameFromCache( + moduleName: string, + containingFile: string, + cache: ModuleResolutionCache, + mode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): ResolvedModuleWithFailedLookupLocations | undefined { const containingDirectory = getDirectoryPath(containingFile); const perFolderCache = cache && cache.getOrCreateCacheForDirectory(containingDirectory); if (!perFolderCache) return undefined; return perFolderCache.get(moduleName, mode); } - export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations { + export function resolveModuleName( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); if (redirectedReference) { compilerOptions = redirectedReference.commandLine.options; @@ -967,7 +1232,11 @@ namespace ts { if (traceEnabled) { trace(host, Diagnostics.Resolving_module_0_from_1, moduleName, containingFile); if (redirectedReference) { - trace(host, Diagnostics.Using_compiler_options_of_project_reference_redirect_0, redirectedReference.sourceFile.fileName); + trace( + host, + Diagnostics.Using_compiler_options_of_project_reference_redirect_0, + redirectedReference.sourceFile.fileName, + ); } } const containingDirectory = getDirectoryPath(containingFile); @@ -976,7 +1245,12 @@ namespace ts { if (result) { if (traceEnabled) { - trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory); + trace( + host, + Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, + moduleName, + containingDirectory, + ); } } else { @@ -997,40 +1271,87 @@ namespace ts { break; } if (traceEnabled) { - trace(host, Diagnostics.Module_resolution_kind_is_not_specified_using_0, ModuleResolutionKind[moduleResolution]); + trace( + host, + Diagnostics.Module_resolution_kind_is_not_specified_using_0, + ModuleResolutionKind[moduleResolution], + ); } } else { if (traceEnabled) { - trace(host, Diagnostics.Explicitly_specified_module_resolution_kind_Colon_0, ModuleResolutionKind[moduleResolution]); + trace( + host, + Diagnostics.Explicitly_specified_module_resolution_kind_Colon_0, + ModuleResolutionKind[moduleResolution], + ); } } perfLogger.logStartResolveModule(moduleName /* , containingFile, ModuleResolutionKind[moduleResolution]*/); switch (moduleResolution) { case ModuleResolutionKind.Node16: - result = node16ModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode); + result = node16ModuleNameResolver( + moduleName, + containingFile, + compilerOptions, + host, + cache, + redirectedReference, + resolutionMode, + ); break; case ModuleResolutionKind.NodeNext: - result = nodeNextModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode); + result = nodeNextModuleNameResolver( + moduleName, + containingFile, + compilerOptions, + host, + cache, + redirectedReference, + resolutionMode, + ); break; case ModuleResolutionKind.NodeJs: - result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference); + result = nodeModuleNameResolver( + moduleName, + containingFile, + compilerOptions, + host, + cache, + redirectedReference, + ); break; case ModuleResolutionKind.Classic: - result = classicNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference); + result = classicNameResolver( + moduleName, + containingFile, + compilerOptions, + host, + cache, + redirectedReference, + ); break; default: return Debug.fail(`Unexpected moduleResolution: ${moduleResolution}`); } - if (result && result.resolvedModule) perfLogger.logInfoEvent(`Module "${moduleName}" resolved to "${result.resolvedModule.resolvedFileName}"`); - perfLogger.logStopResolveModule((result && result.resolvedModule) ? "" + result.resolvedModule.resolvedFileName : "null"); + if (result && result.resolvedModule) { + perfLogger.logInfoEvent( + `Module "${moduleName}" resolved to "${result.resolvedModule.resolvedFileName}"`, + ); + } + perfLogger.logStopResolveModule( + (result && result.resolvedModule) ? "" + result.resolvedModule.resolvedFileName : "null", + ); if (perFolderCache) { perFolderCache.set(moduleName, resolutionMode, result); if (!isExternalModuleNameRelative(moduleName)) { // put result in per-module name cache - cache.getOrCreateCacheForModuleName(moduleName, resolutionMode, redirectedReference).set(containingDirectory, result); + cache.getOrCreateCacheForModuleName(moduleName, resolutionMode, redirectedReference).set( + containingDirectory, + result, + ); } } } @@ -1038,10 +1359,21 @@ namespace ts { if (traceEnabled) { if (result.resolvedModule) { if (result.resolvedModule.packageId) { - trace(host, Diagnostics.Module_name_0_was_successfully_resolved_to_1_with_Package_ID_2, moduleName, result.resolvedModule.resolvedFileName, packageIdToString(result.resolvedModule.packageId)); + trace( + host, + Diagnostics.Module_name_0_was_successfully_resolved_to_1_with_Package_ID_2, + moduleName, + result.resolvedModule.resolvedFileName, + packageIdToString(result.resolvedModule.packageId), + ); } else { - trace(host, Diagnostics.Module_name_0_was_successfully_resolved_to_1, moduleName, result.resolvedModule.resolvedFileName); + trace( + host, + Diagnostics.Module_name_0_was_successfully_resolved_to_1, + moduleName, + result.resolvedModule.resolvedFileName, + ); } } else { @@ -1060,7 +1392,12 @@ namespace ts { * 'typings' entry or file 'index' with some supported extension * - Classic loader will only try to interpret '/a/b/c' as file. */ - type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined; + type ResolutionKindSpecificLoader = ( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + ) => Resolved | undefined; /** * Any module resolution kind can be augmented with optional settings: 'baseUrl', 'paths' and 'rootDirs' - they are used to @@ -1122,7 +1459,13 @@ namespace ts { * be converted to a path relative to found rootDir entry './content/protocols/file2' (*). As a last step compiler will check all remaining * entries in 'rootDirs', use them to build absolute path out of (*) and try to resolve module from this location. */ - function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined { + function tryLoadModuleUsingOptionalResolutionSettings( + extensions: Extensions, + moduleName: string, + containingDirectory: string, + loader: ResolutionKindSpecificLoader, + state: ModuleResolutionState, + ): Resolved | undefined { const resolved = tryLoadModuleUsingPathsIfEligible(extensions, moduleName, loader, state); if (resolved) return resolved.value; @@ -1134,28 +1477,62 @@ namespace ts { } } - function tryLoadModuleUsingPathsIfEligible(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState) { + function tryLoadModuleUsingPathsIfEligible( + extensions: Extensions, + moduleName: string, + loader: ResolutionKindSpecificLoader, + state: ModuleResolutionState, + ) { const { baseUrl, paths, configFile } = state.compilerOptions; if (paths && !pathIsRelative(moduleName)) { if (state.traceEnabled) { if (baseUrl) { - trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName); + trace( + state.host, + Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, + baseUrl, + moduleName, + ); } - trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName); + trace( + state.host, + Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, + moduleName, + ); } const baseDirectory = getPathsBasePath(state.compilerOptions, state.host)!; // Always defined when 'paths' is defined - const pathPatterns = configFile?.configFileSpecs ? configFile.configFileSpecs.pathPatterns ||= tryParsePatterns(paths) : undefined; - return tryLoadModuleUsingPaths(extensions, moduleName, baseDirectory, paths, pathPatterns, loader, /*onlyRecordFailures*/ false, state); - } - } - - function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined { + const pathPatterns = configFile?.configFileSpecs + ? configFile.configFileSpecs.pathPatterns ||= tryParsePatterns(paths) : undefined; + return tryLoadModuleUsingPaths( + extensions, + moduleName, + baseDirectory, + paths, + pathPatterns, + loader, + /*onlyRecordFailures*/ false, + state, + ); + } + } + + function tryLoadModuleUsingRootDirs( + extensions: Extensions, + moduleName: string, + containingDirectory: string, + loader: ResolutionKindSpecificLoader, + state: ModuleResolutionState, + ): Resolved | undefined { if (!state.compilerOptions.rootDirs) { return undefined; } if (state.traceEnabled) { - trace(state.host, Diagnostics.rootDirs_option_is_set_using_it_to_resolve_relative_module_name_0, moduleName); + trace( + state.host, + Diagnostics.rootDirs_option_is_set_using_it_to_resolve_relative_module_name_0, + moduleName, + ); } const candidate = normalizePath(combinePaths(containingDirectory, moduleName)); @@ -1170,11 +1547,17 @@ namespace ts { if (!endsWith(normalizedRoot, directorySeparator)) { normalizedRoot += directorySeparator; } - const isLongestMatchingPrefix = startsWith(candidate, normalizedRoot) && - (matchedNormalizedPrefix === undefined || matchedNormalizedPrefix.length < normalizedRoot.length); + const isLongestMatchingPrefix = startsWith(candidate, normalizedRoot) + && (matchedNormalizedPrefix === undefined || matchedNormalizedPrefix.length < normalizedRoot.length); if (state.traceEnabled) { - trace(state.host, Diagnostics.Checking_if_0_is_the_longest_matching_prefix_for_1_2, normalizedRoot, candidate, isLongestMatchingPrefix); + trace( + state.host, + Diagnostics.Checking_if_0_is_the_longest_matching_prefix_for_1_2, + normalizedRoot, + candidate, + isLongestMatchingPrefix, + ); } if (isLongestMatchingPrefix) { @@ -1190,9 +1573,20 @@ namespace ts { // first - try to load from a initial location if (state.traceEnabled) { - trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, matchedNormalizedPrefix, candidate); + trace( + state.host, + Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, + suffix, + matchedNormalizedPrefix, + candidate, + ); } - const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(containingDirectory, state.host), state); + const resolvedFileName = loader( + extensions, + candidate, + !directoryProbablyExists(containingDirectory, state.host), + state, + ); if (resolvedFileName) { return resolvedFileName; } @@ -1208,10 +1602,21 @@ namespace ts { } const candidate = combinePaths(normalizePath(rootDir), suffix); if (state.traceEnabled) { - trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, rootDir, candidate); + trace( + state.host, + Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, + suffix, + rootDir, + candidate, + ); } const baseDirectory = getDirectoryPath(candidate); - const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(baseDirectory, state.host), state); + const resolvedFileName = loader( + extensions, + candidate, + !directoryProbablyExists(baseDirectory, state.host), + state, + ); if (resolvedFileName) { return resolvedFileName; } @@ -1223,17 +1628,33 @@ namespace ts { return undefined; } - function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined { + function tryLoadModuleUsingBaseUrl( + extensions: Extensions, + moduleName: string, + loader: ResolutionKindSpecificLoader, + state: ModuleResolutionState, + ): Resolved | undefined { const { baseUrl } = state.compilerOptions; if (!baseUrl) { return undefined; } if (state.traceEnabled) { - trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName); + trace( + state.host, + Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, + baseUrl, + moduleName, + ); } const candidate = normalizePath(combinePaths(baseUrl, moduleName)); if (state.traceEnabled) { - trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, baseUrl, candidate); + trace( + state.host, + Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, + moduleName, + baseUrl, + candidate, + ); } return loader(extensions, candidate, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state); } @@ -1247,7 +1668,11 @@ namespace ts { export function resolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string { const { resolvedModule, failedLookupLocations } = tryResolveJSModuleWorker(moduleName, initialDir, host); if (!resolvedModule) { - throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`); + throw new Error( + `Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${ + failedLookupLocations.join(", ") + }`, + ); } return resolvedModule.resolvedFileName; } @@ -1273,7 +1698,15 @@ namespace ts { EsmMode = 1 << 5, } - function node16ModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations { + function node16ModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): ResolvedModuleWithFailedLookupLocations { return nodeNextModuleNameResolverWorker( NodeResolutionFeatures.Node16Default, moduleName, @@ -1286,7 +1719,15 @@ namespace ts { ); } - function nodeNextModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations { + function nodeNextModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): ResolvedModuleWithFailedLookupLocations { return nodeNextModuleNameResolverWorker( NodeResolutionFeatures.NodeNextDefault, moduleName, @@ -1303,7 +1744,16 @@ namespace ts { const tsExtensions = [Extensions.TypeScript, Extensions.JavaScript]; const tsPlusJsonExtensions = [...tsExtensions, Extensions.Json]; const tsconfigExtensions = [Extensions.TSConfig]; - function nodeNextModuleNameResolverWorker(features: NodeResolutionFeatures, moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations { + function nodeNextModuleNameResolverWorker( + features: NodeResolutionFeatures, + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): ResolvedModuleWithFailedLookupLocations { const containingDirectory = getDirectoryPath(containingFile); // es module file or cjs-like input file, use a variant of the legacy cjs resolver that supports the selected modern features @@ -1312,16 +1762,61 @@ namespace ts { if (compilerOptions.resolveJsonModule) { extensions = [...extensions, Extensions.Json]; } - return nodeModuleNameResolverWorker(features | esmMode, moduleName, containingDirectory, compilerOptions, host, cache, extensions, redirectedReference); + return nodeModuleNameResolverWorker( + features | esmMode, + moduleName, + containingDirectory, + compilerOptions, + host, + cache, + extensions, + redirectedReference, + ); } - function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations { - return nodeModuleNameResolverWorker(NodeResolutionFeatures.None, moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, jsOnlyExtensions, /*redirectedReferences*/ undefined); + function tryResolveJSModuleWorker( + moduleName: string, + initialDir: string, + host: ModuleResolutionHost, + ): ResolvedModuleWithFailedLookupLocations { + return nodeModuleNameResolverWorker( + NodeResolutionFeatures.None, + moduleName, + initialDir, + { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, + host, + /*cache*/ undefined, + jsOnlyExtensions, + /*redirectedReferences*/ undefined, + ); } - export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; - /* @internal */ export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, lookupConfig?: boolean): ResolvedModuleWithFailedLookupLocations; // eslint-disable-line @typescript-eslint/unified-signatures - export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, lookupConfig?: boolean): ResolvedModuleWithFailedLookupLocations { + export function nodeModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + ): ResolvedModuleWithFailedLookupLocations; + /* @internal */ export function nodeModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + lookupConfig?: boolean, + ): ResolvedModuleWithFailedLookupLocations; // eslint-disable-line @typescript-eslint/unified-signatures + export function nodeModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + lookupConfig?: boolean, + ): ResolvedModuleWithFailedLookupLocations { let extensions; if (lookupConfig) { extensions = tsconfigExtensions; @@ -1334,17 +1829,36 @@ namespace ts { else { extensions = compilerOptions.resolveJsonModule ? tsPlusJsonExtensions : tsExtensions; } - return nodeModuleNameResolverWorker(NodeResolutionFeatures.None, moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, extensions, redirectedReference); + return nodeModuleNameResolverWorker( + NodeResolutionFeatures.None, + moduleName, + getDirectoryPath(containingFile), + compilerOptions, + host, + cache, + extensions, + redirectedReference, + ); } - function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleName: string, containingDirectory: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache: ModuleResolutionCache | undefined, extensions: Extensions[], redirectedReference: ResolvedProjectReference | undefined): ResolvedModuleWithFailedLookupLocations { + function nodeModuleNameResolverWorker( + features: NodeResolutionFeatures, + moduleName: string, + containingDirectory: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache: ModuleResolutionCache | undefined, + extensions: Extensions[], + redirectedReference: ResolvedProjectReference | undefined, + ): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); const failedLookupLocations: string[] = []; const affectingLocations: string[] = []; // conditions are only used by the node16/nodenext resolver - there's no priority order in the list, // it's essentially a set (priority is determined by object insertion order in the object we look at). - const conditions = features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"]; + const conditions = features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] + : ["node", "require", "types"]; if (compilerOptions.noDtsResolution) { conditions.pop(); } @@ -1363,8 +1877,16 @@ namespace ts { reportDiagnostic: diag => void diagnostics.push(diag), }; - if (traceEnabled && getEmitModuleResolutionKind(compilerOptions) >= ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) <= ModuleResolutionKind.NodeNext) { - trace(host, Diagnostics.Resolving_in_0_mode_with_conditions_1, features & NodeResolutionFeatures.EsmMode ? "ESM" : "CJS", conditions.map(c => `'${c}'`).join(", ")); + if ( + traceEnabled && getEmitModuleResolutionKind(compilerOptions) >= ModuleResolutionKind.Node16 + && getEmitModuleResolutionKind(compilerOptions) <= ModuleResolutionKind.NodeNext + ) { + trace( + host, + Diagnostics.Resolving_in_0_mode_with_conditions_1, + features & NodeResolutionFeatures.EsmMode ? "ESM" : "CJS", + conditions.map(c => `'${c}'`).join(", "), + ); } const result = forEach(extensions, ext => tryResolve(ext)); @@ -1377,9 +1899,24 @@ namespace ts { state.resultFromCache, ); - function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved; isExternalLibraryImport: boolean; }> { - const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true); - const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, state); + function tryResolve( + extensions: Extensions, + ): SearchResult<{ resolved: Resolved; isExternalLibraryImport: boolean; }> { + const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => + nodeLoadModuleByRelativeName( + extensions, + candidate, + onlyRecordFailures, + state, + /*considerPackageJson*/ true, + ); + const resolved = tryLoadModuleUsingOptionalResolutionSettings( + extensions, + moduleName, + containingDirectory, + loader, + state, + ); if (resolved) { return toSearchResult({ resolved, isExternalLibraryImport: pathContainsNodeModules(resolved.path) }); } @@ -1387,16 +1924,42 @@ namespace ts { if (!isExternalModuleNameRelative(moduleName)) { let resolved: SearchResult | undefined; if (features & NodeResolutionFeatures.Imports && startsWith(moduleName, "#")) { - resolved = loadModuleFromImports(extensions, moduleName, containingDirectory, state, cache, redirectedReference); + resolved = loadModuleFromImports( + extensions, + moduleName, + containingDirectory, + state, + cache, + redirectedReference, + ); } if (!resolved && features & NodeResolutionFeatures.SelfName) { - resolved = loadModuleFromSelfNameReference(extensions, moduleName, containingDirectory, state, cache, redirectedReference); + resolved = loadModuleFromSelfNameReference( + extensions, + moduleName, + containingDirectory, + state, + cache, + redirectedReference, + ); } if (!resolved) { if (traceEnabled) { - trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, moduleName, Extensions[extensions]); + trace( + host, + Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, + moduleName, + Extensions[extensions], + ); } - resolved = loadModuleFromNearestNodeModulesDirectory(extensions, moduleName, containingDirectory, state, cache, redirectedReference); + resolved = loadModuleFromNearestNodeModulesDirectory( + extensions, + moduleName, + containingDirectory, + state, + cache, + redirectedReference, + ); } if (!resolved) return undefined; @@ -1413,9 +1976,16 @@ namespace ts { } else { const { path: candidate, parts } = normalizePathForCJSResolution(containingDirectory, moduleName); - const resolved = nodeLoadModuleByRelativeName(extensions, candidate, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true); + const resolved = nodeLoadModuleByRelativeName( + extensions, + candidate, + /*onlyRecordFailures*/ false, + state, + /*considerPackageJson*/ true, + ); // Treat explicit "node_modules" import as an external library import. - return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") }); + return resolved + && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") }); } } } @@ -1429,7 +1999,8 @@ namespace ts { const combined = combinePaths(containingDirectory, moduleName); const parts = getPathComponents(combined); const lastPart = lastOrUndefined(parts); - const path = lastPart === "." || lastPart === ".." ? ensureTrailingDirectorySeparator(normalizePath(combined)) : normalizePath(combined); + const path = lastPart === "." || lastPart === ".." ? ensureTrailingDirectorySeparator(normalizePath(combined)) + : normalizePath(combined); return { path, parts }; } @@ -1446,24 +2017,41 @@ namespace ts { return real; } - function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined { + function nodeLoadModuleByRelativeName( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + considerPackageJson: boolean, + ): Resolved | undefined { if (state.traceEnabled) { - trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_type_1, candidate, Extensions[extensions]); + trace( + state.host, + Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_type_1, + candidate, + Extensions[extensions], + ); } if (!hasTrailingDirectorySeparator(candidate)) { if (!onlyRecordFailures) { const parentOfCandidate = getDirectoryPath(candidate); if (!directoryProbablyExists(parentOfCandidate, state.host)) { if (state.traceEnabled) { - trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, parentOfCandidate); + trace( + state.host, + Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, + parentOfCandidate, + ); } onlyRecordFailures = true; } } const resolvedFromFile = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state); if (resolvedFromFile) { - const packageDirectory = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile.path) : undefined; - const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined; + const packageDirectory = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile.path) + : undefined; + const packageInfo = packageDirectory + ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined; return withPackageId(packageInfo, resolvedFromFile); } } @@ -1523,7 +2111,12 @@ namespace ts { return nextSeparatorIndex === -1 ? prevSeparatorIndex : nextSeparatorIndex; } - function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined { + function loadModuleFromFileNoPackageId( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + ): Resolved | undefined { return noPackageId(loadModuleFromFile(extensions, candidate, onlyRecordFailures, state)); } @@ -1531,11 +2124,17 @@ namespace ts { * @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary * in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations. */ - function loadModuleFromFile(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { + function loadModuleFromFile( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + ): PathAndExtension | undefined { if (extensions === Extensions.Json || extensions === Extensions.TSConfig) { const extensionLess = tryRemoveExtension(candidate, Extension.Json); const extension = extensionLess ? candidate.substring(extensionLess.length) : ""; - return (extensionLess === undefined && extensions === Extensions.Json) ? undefined : tryAddingExtensions(extensionLess || candidate, extensions, extension, onlyRecordFailures, state); + return (extensionLess === undefined && extensions === Extensions.Json) ? undefined + : tryAddingExtensions(extensionLess || candidate, extensions, extension, onlyRecordFailures, state); } // esm mode resolutions don't include automatic extension lookup (without additional flags, at least) @@ -1550,10 +2149,18 @@ namespace ts { return loadModuleFromFileNoImplicitExtensions(extensions, candidate, onlyRecordFailures, state); } - function loadModuleFromFileNoImplicitExtensions(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { + function loadModuleFromFileNoImplicitExtensions( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + ): PathAndExtension | undefined { // If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one; // e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" - if (hasJSFileExtension(candidate) || (fileExtensionIs(candidate, Extension.Json) && state.compilerOptions.resolveJsonModule)) { + if ( + hasJSFileExtension(candidate) + || (fileExtensionIs(candidate, Extension.Json) && state.compilerOptions.resolveJsonModule) + ) { const extensionless = removeFileExtension(candidate); const extension = candidate.substring(extensionless.length); if (state.traceEnabled) { @@ -1563,17 +2170,32 @@ namespace ts { } } - function loadJSOrExactTSFileName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { - if ((extensions === Extensions.TypeScript || extensions === Extensions.DtsOnly) && fileExtensionIsOneOf(candidate, supportedTSExtensionsFlat)) { + function loadJSOrExactTSFileName( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + ): PathAndExtension | undefined { + if ( + (extensions === Extensions.TypeScript || extensions === Extensions.DtsOnly) + && fileExtensionIsOneOf(candidate, supportedTSExtensionsFlat) + ) { const result = tryFile(candidate, onlyRecordFailures, state); - return result !== undefined ? { path: candidate, ext: tryExtractTSExtension(candidate) as Extension } : undefined; + return result !== undefined ? { path: candidate, ext: tryExtractTSExtension(candidate) as Extension } + : undefined; } return loadModuleFromFileNoImplicitExtensions(extensions, candidate, onlyRecordFailures, state); } /** Try to return an existing file that adds one of the `extensions` to `candidate`. */ - function tryAddingExtensions(candidate: string, extensions: Extensions, originalExtension: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { + function tryAddingExtensions( + candidate: string, + extensions: Extensions, + originalExtension: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + ): PathAndExtension | undefined { if (!onlyRecordFailures) { // check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing const directory = getDirectoryPath(candidate); @@ -1615,7 +2237,8 @@ namespace ts { candidate += Extension.Json; return useDts ? tryExtension(Extension.Dts) : undefined; default: - return tryExtension(Extension.Ts) || tryExtension(Extension.Tsx) || (useDts ? tryExtension(Extension.Dts) : undefined); + return tryExtension(Extension.Ts) || tryExtension(Extension.Tsx) + || (useDts ? tryExtension(Extension.Dts) : undefined); } case Extensions.JavaScript: switch (originalExtension) { @@ -1651,10 +2274,17 @@ namespace ts { const ext = tryGetExtensionFromPath(fileName) ?? ""; const fileNameNoExtension = ext ? removeExtension(fileName, ext) : fileName; - return forEach(state.compilerOptions.moduleSuffixes, suffix => tryFileLookup(fileNameNoExtension + suffix + ext, onlyRecordFailures, state)); + return forEach( + state.compilerOptions.moduleSuffixes, + suffix => tryFileLookup(fileNameNoExtension + suffix + ext, onlyRecordFailures, state), + ); } - function tryFileLookup(fileName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { + function tryFileLookup( + fileName: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + ): string | undefined { if (!onlyRecordFailures) { if (state.host.fileExists(fileName)) { if (state.traceEnabled) { @@ -1672,11 +2302,27 @@ namespace ts { return undefined; } - function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) { + function loadNodeModuleFromDirectory( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + considerPackageJson = true, + ) { const packageInfo = considerPackageJson ? getPackageJsonInfo(candidate, onlyRecordFailures, state) : undefined; const packageJsonContent = packageInfo && packageInfo.contents.packageJsonContent; const versionPaths = packageInfo && packageInfo.contents.versionPaths; - return withPackageId(packageInfo, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths)); + return withPackageId( + packageInfo, + loadNodeModuleFromDirectoryWorker( + extensions, + candidate, + onlyRecordFailures, + state, + packageJsonContent, + versionPaths, + ), + ); } /* @internal */ @@ -1755,7 +2401,10 @@ namespace ts { function loadEntrypointsFromTargetExports(target: unknown): boolean | undefined { if (typeof target === "string" && startsWith(target, "./") && target.indexOf("*") === -1) { const partsAfterFirst = getPathComponents(target).slice(2); - if (partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 || partsAfterFirst.indexOf("node_modules") >= 0) { + if ( + partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 + || partsAfterFirst.indexOf("node_modules") >= 0 + ) { return false; } const resolvedTarget = combinePaths(scope.packageDirectory, target); @@ -1777,7 +2426,10 @@ namespace ts { // eslint-disable-next-line no-null/no-null else if (typeof target === "object" && target !== null) { return forEach(getOwnKeys(target as MapLike), key => { - if (key === "default" || contains(state.conditions, key) || isApplicableVersionedTypesKey(state.conditions, key)) { + if ( + key === "default" || contains(state.conditions, key) + || isApplicableVersionedTypesKey(state.conditions, key) + ) { loadEntrypointsFromTargetExports((target as MapLike)[key]); return true; } @@ -1787,7 +2439,11 @@ namespace ts { } /*@internal*/ - export function getTemporaryModuleResolutionState(packageJsonInfoCache: PackageJsonInfoCache | undefined, host: ModuleResolutionHost, options: CompilerOptions): ModuleResolutionState { + export function getTemporaryModuleResolutionState( + packageJsonInfoCache: PackageJsonInfoCache | undefined, + host: ModuleResolutionHost, + options: CompilerOptions, + ): ModuleResolutionState { return { host, compilerOptions: options, @@ -1819,7 +2475,10 @@ namespace ts { * A function for locating the package.json scope for a given path */ /*@internal*/ - export function getPackageScopeForPath(fileName: string, state: ModuleResolutionState): PackageJsonInfo | undefined { + export function getPackageScopeForPath( + fileName: string, + state: ModuleResolutionState, + ): PackageJsonInfo | undefined { const parts = getPathComponents(fileName); parts.pop(); while (parts.length > 0) { @@ -1833,7 +2492,11 @@ namespace ts { } /*@internal*/ - export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined { + export function getPackageJsonInfo( + packageDirectory: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + ): PackageJsonInfo | undefined { const { host, traceEnabled } = state; const packageJsonPath = combinePaths(packageDirectory, "package.json"); if (onlyRecordFailures) { @@ -1844,14 +2507,18 @@ namespace ts { const existing = state.packageJsonInfoCache?.getPackageJsonInfo(packageJsonPath); if (existing !== undefined) { if (typeof existing !== "boolean") { - if (traceEnabled) trace(host, Diagnostics.File_0_exists_according_to_earlier_cached_lookups, packageJsonPath); + if (traceEnabled) { + trace(host, Diagnostics.File_0_exists_according_to_earlier_cached_lookups, packageJsonPath); + } state.affectingLocations.push(packageJsonPath); - return existing.packageDirectory === packageDirectory ? - existing : - { packageDirectory, contents: existing.contents }; + return existing.packageDirectory === packageDirectory + ? existing + : { packageDirectory, contents: existing.contents }; } else { - if (existing && traceEnabled) trace(host, Diagnostics.File_0_does_not_exist_according_to_earlier_cached_lookups, packageJsonPath); + if (existing && traceEnabled) { + trace(host, Diagnostics.File_0_does_not_exist_according_to_earlier_cached_lookups, packageJsonPath); + } state.failedLookupLocations.push(packageJsonPath); return undefined; } @@ -1863,7 +2530,10 @@ namespace ts { trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath); } const versionPaths = readPackageJsonTypesVersionPaths(packageJsonContent, state); - const result: PackageJsonInfo = { packageDirectory, contents: { packageJsonContent, versionPaths, resolvedEntrypoints: undefined } }; + const result: PackageJsonInfo = { + packageDirectory, + contents: { packageJsonContent, versionPaths, resolvedEntrypoints: undefined }, + }; state.packageJsonInfoCache?.setPackageJsonInfo(packageJsonPath, result); state.affectingLocations.push(packageJsonPath); return result; @@ -1878,7 +2548,14 @@ namespace ts { } } - function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, jsonContent: PackageJsonPathFields | undefined, versionPaths: VersionPaths | undefined): PathAndExtension | undefined { + function loadNodeModuleFromDirectoryWorker( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + jsonContent: PackageJsonPathFields | undefined, + versionPaths: VersionPaths | undefined, + ): PathAndExtension | undefined { let packageFile: string | undefined; if (jsonContent) { switch (extensions) { @@ -1889,7 +2566,8 @@ namespace ts { break; case Extensions.TypeScript: // When resolving typescript modules, try resolving using main field as well - packageFile = readPackageJsonTypesFields(jsonContent, candidate, state) || readPackageJsonMainField(jsonContent, candidate, state); + packageFile = readPackageJsonTypesFields(jsonContent, candidate, state) + || readPackageJsonMainField(jsonContent, candidate, state); break; case Extensions.DtsOnly: packageFile = readPackageJsonTypesFields(jsonContent, candidate, state); @@ -1925,28 +2603,52 @@ namespace ts { if (jsonContent?.type !== "module") { state.features &= ~NodeResolutionFeatures.EsmMode; } - const result = nodeLoadModuleByRelativeName(nextExtensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ false); + const result = nodeLoadModuleByRelativeName( + nextExtensions, + candidate, + onlyRecordFailures, + state, + /*considerPackageJson*/ false, + ); state.features = features; return result; }; - const onlyRecordFailuresForPackageFile = packageFile ? !directoryProbablyExists(getDirectoryPath(packageFile), state.host) : undefined; + const onlyRecordFailuresForPackageFile = packageFile + ? !directoryProbablyExists(getDirectoryPath(packageFile), state.host) : undefined; const onlyRecordFailuresForIndex = onlyRecordFailures || !directoryProbablyExists(candidate, state.host); const indexPath = combinePaths(candidate, extensions === Extensions.TSConfig ? "tsconfig" : "index"); if (versionPaths && (!packageFile || containsPath(candidate, packageFile))) { const moduleName = getRelativePathFromDirectory(candidate, packageFile || indexPath, /*ignoreCase*/ false); if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, moduleName); + trace( + state.host, + Diagnostics + .package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, + versionPaths.version, + version, + moduleName, + ); } - const result = tryLoadModuleUsingPaths(extensions, moduleName, candidate, versionPaths.paths, /*pathPatterns*/ undefined, loader, onlyRecordFailuresForPackageFile || onlyRecordFailuresForIndex, state); + const result = tryLoadModuleUsingPaths( + extensions, + moduleName, + candidate, + versionPaths.paths, + /*pathPatterns*/ undefined, + loader, + onlyRecordFailuresForPackageFile || onlyRecordFailuresForIndex, + state, + ); if (result) { return removeIgnoredPackageId(result.value); } } // It won't have a `packageId` set, because we disabled `considerPackageJson`. - const packageFileResult = packageFile && removeIgnoredPackageId(loader(extensions, packageFile, onlyRecordFailuresForPackageFile!, state)); + const packageFileResult = packageFile + && removeIgnoredPackageId(loader(extensions, packageFile, onlyRecordFailuresForPackageFile!, state)); if (packageFileResult) return packageFileResult; // esm mode resolutions don't do package `index` lookups @@ -1965,14 +2667,18 @@ namespace ts { function extensionIsOk(extensions: Extensions, extension: Extension): boolean { switch (extensions) { case Extensions.JavaScript: - return extension === Extension.Js || extension === Extension.Jsx || extension === Extension.Mjs || extension === Extension.Cjs; + return extension === Extension.Js || extension === Extension.Jsx || extension === Extension.Mjs + || extension === Extension.Cjs; case Extensions.TSConfig: case Extensions.Json: return extension === Extension.Json; case Extensions.TypeScript: - return extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Mts || extension === Extension.Cts || extension === Extension.Dts || extension === Extension.Dmts || extension === Extension.Dcts; + return extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Mts + || extension === Extension.Cts || extension === Extension.Dts || extension === Extension.Dmts + || extension === Extension.Dcts; case Extensions.TsOnly: - return extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Mts || extension === Extension.Cts; + return extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Mts + || extension === Extension.Cts; case Extensions.DtsOnly: return extension === Extension.Dts || extension === Extension.Dmts || extension === Extension.Dcts; } @@ -1984,7 +2690,8 @@ namespace ts { if (moduleName[0] === "@") { idx = moduleName.indexOf(directorySeparator, idx + 1); } - return idx === -1 ? { packageName: moduleName, rest: "" } : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) }; + return idx === -1 ? { packageName: moduleName, rest: "" } + : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) }; } /* @internal */ @@ -1996,8 +2703,18 @@ namespace ts { return !some(getOwnKeys(obj), k => startsWith(k, ".")); } - function loadModuleFromSelfNameReference(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { - const directoryPath = getNormalizedAbsolutePath(combinePaths(directory, "dummy"), state.host.getCurrentDirectory?.()); + function loadModuleFromSelfNameReference( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + ): SearchResult { + const directoryPath = getNormalizedAbsolutePath( + combinePaths(directory, "dummy"), + state.host.getCurrentDirectory?.(), + ); const scope = getPackageScopeForPath(directoryPath, state); if (!scope || !scope.contents.packageJsonContent.exports) { return undefined; @@ -2011,58 +2728,118 @@ namespace ts { return undefined; } const trailingParts = parts.slice(nameParts.length); - return loadModuleFromExports(scope, extensions, !length(trailingParts) ? "." : `.${directorySeparator}${trailingParts.join(directorySeparator)}`, state, cache, redirectedReference); + return loadModuleFromExports( + scope, + extensions, + !length(trailingParts) ? "." : `.${directorySeparator}${trailingParts.join(directorySeparator)}`, + state, + cache, + redirectedReference, + ); } - function loadModuleFromExports(scope: PackageJsonInfo, extensions: Extensions, subpath: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { + function loadModuleFromExports( + scope: PackageJsonInfo, + extensions: Extensions, + subpath: string, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + ): SearchResult { if (!scope.contents.packageJsonContent.exports) { return undefined; } if (subpath === ".") { let mainExport; - if (typeof scope.contents.packageJsonContent.exports === "string" || Array.isArray(scope.contents.packageJsonContent.exports) || (typeof scope.contents.packageJsonContent.exports === "object" && noKeyStartsWithDot(scope.contents.packageJsonContent.exports as MapLike))) { + if ( + typeof scope.contents.packageJsonContent.exports === "string" + || Array.isArray(scope.contents.packageJsonContent.exports) + || (typeof scope.contents.packageJsonContent.exports === "object" + && noKeyStartsWithDot(scope.contents.packageJsonContent.exports as MapLike)) + ) { mainExport = scope.contents.packageJsonContent.exports; } else if (hasProperty(scope.contents.packageJsonContent.exports as MapLike, ".")) { mainExport = (scope.contents.packageJsonContent.exports as MapLike)["."]; } if (mainExport) { - const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport(extensions, state, cache, redirectedReference, subpath, scope, /*isImports*/ false); + const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport( + extensions, + state, + cache, + redirectedReference, + subpath, + scope, + /*isImports*/ false, + ); return loadModuleFromTargetImportOrExport(mainExport, "", /*pattern*/ false, "."); } } else if (allKeysStartWithDot(scope.contents.packageJsonContent.exports as MapLike)) { if (typeof scope.contents.packageJsonContent.exports !== "object") { if (state.traceEnabled) { - trace(state.host, Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, subpath, scope.packageDirectory); + trace( + state.host, + Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, + subpath, + scope.packageDirectory, + ); } return toSearchResult(/*value*/ undefined); } - const result = loadModuleFromImportsOrExports(extensions, state, cache, redirectedReference, subpath, scope.contents.packageJsonContent.exports, scope, /*isImports*/ false); + const result = loadModuleFromImportsOrExports( + extensions, + state, + cache, + redirectedReference, + subpath, + scope.contents.packageJsonContent.exports, + scope, + /*isImports*/ false, + ); if (result) { return result; } } if (state.traceEnabled) { - trace(state.host, Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, subpath, scope.packageDirectory); + trace( + state.host, + Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, + subpath, + scope.packageDirectory, + ); } return toSearchResult(/*value*/ undefined); } - function loadModuleFromImports(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { + function loadModuleFromImports( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + ): SearchResult { if (moduleName === "#" || startsWith(moduleName, "#/")) { if (state.traceEnabled) { trace(state.host, Diagnostics.Invalid_import_specifier_0_has_no_possible_resolutions, moduleName); } return toSearchResult(/*value*/ undefined); } - const directoryPath = getNormalizedAbsolutePath(combinePaths(directory, "dummy"), state.host.getCurrentDirectory?.()); + const directoryPath = getNormalizedAbsolutePath( + combinePaths(directory, "dummy"), + state.host.getCurrentDirectory?.(), + ); const scope = getPackageScopeForPath(directoryPath, state); if (!scope) { if (state.traceEnabled) { - trace(state.host, Diagnostics.Directory_0_has_no_containing_package_json_scope_Imports_will_not_resolve, directoryPath); + trace( + state.host, + Diagnostics.Directory_0_has_no_containing_package_json_scope_Imports_will_not_resolve, + directoryPath, + ); } return toSearchResult(/*value*/ undefined); } @@ -2073,13 +2850,27 @@ namespace ts { return toSearchResult(/*value*/ undefined); } - const result = loadModuleFromImportsOrExports(extensions, state, cache, redirectedReference, moduleName, scope.contents.packageJsonContent.imports, scope, /*isImports*/ true); + const result = loadModuleFromImportsOrExports( + extensions, + state, + cache, + redirectedReference, + moduleName, + scope.contents.packageJsonContent.imports, + scope, + /*isImports*/ true, + ); if (result) { return result; } if (state.traceEnabled) { - trace(state.host, Diagnostics.Import_specifier_0_does_not_exist_in_package_json_scope_at_path_1, moduleName, scope.packageDirectory); + trace( + state.host, + Diagnostics.Import_specifier_0_does_not_exist_in_package_json_scope_at_path_1, + moduleName, + scope.packageDirectory, + ); } return toSearchResult(/*value*/ undefined); } @@ -2103,22 +2894,54 @@ namespace ts { return 0; } - function loadModuleFromImportsOrExports(extensions: Extensions, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined, moduleName: string, lookupTable: object, scope: PackageJsonInfo, isImports: boolean): SearchResult | undefined { - const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport(extensions, state, cache, redirectedReference, moduleName, scope, isImports); + function loadModuleFromImportsOrExports( + extensions: Extensions, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + moduleName: string, + lookupTable: object, + scope: PackageJsonInfo, + isImports: boolean, + ): SearchResult | undefined { + const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport( + extensions, + state, + cache, + redirectedReference, + moduleName, + scope, + isImports, + ); - if (!endsWith(moduleName, directorySeparator) && moduleName.indexOf("*") === -1 && hasProperty(lookupTable, moduleName)) { + if ( + !endsWith(moduleName, directorySeparator) && moduleName.indexOf("*") === -1 + && hasProperty(lookupTable, moduleName) + ) { const target = (lookupTable as { [idx: string]: unknown; })[moduleName]; return loadModuleFromTargetImportOrExport(target, /*subpath*/ "", /*pattern*/ false, moduleName); } - const expandingKeys = sort(filter(getOwnKeys(lookupTable as MapLike), k => k.indexOf("*") !== -1 || endsWith(k, "/")), comparePatternKeys); + const expandingKeys = sort( + filter(getOwnKeys(lookupTable as MapLike), k => k.indexOf("*") !== -1 || endsWith(k, "/")), + comparePatternKeys, + ); for (const potentialTarget of expandingKeys) { - if (state.features & NodeResolutionFeatures.ExportsPatternTrailers && matchesPatternWithTrailer(potentialTarget, moduleName)) { + if ( + state.features & NodeResolutionFeatures.ExportsPatternTrailers + && matchesPatternWithTrailer(potentialTarget, moduleName) + ) { const target = (lookupTable as { [idx: string]: unknown; })[potentialTarget]; const starPos = potentialTarget.indexOf("*"); - const subpath = moduleName.substring(potentialTarget.substring(0, starPos).length, moduleName.length - (potentialTarget.length - 1 - starPos)); + const subpath = moduleName.substring( + potentialTarget.substring(0, starPos).length, + moduleName.length - (potentialTarget.length - 1 - starPos), + ); return loadModuleFromTargetImportOrExport(target, subpath, /*pattern*/ true, potentialTarget); } - else if (endsWith(potentialTarget, "*") && startsWith(moduleName, potentialTarget.substring(0, potentialTarget.length - 1))) { + else if ( + endsWith(potentialTarget, "*") + && startsWith(moduleName, potentialTarget.substring(0, potentialTarget.length - 1)) + ) { const target = (lookupTable as { [idx: string]: unknown; })[potentialTarget]; const subpath = moduleName.substring(potentialTarget.length - 1); return loadModuleFromTargetImportOrExport(target, subpath, /*pattern*/ true, potentialTarget); @@ -2141,34 +2964,95 @@ namespace ts { /** * Gets the self-recursive function specialized to retrieving the targeted import/export element for the given resolution configuration */ - function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined, moduleName: string, scope: PackageJsonInfo, isImports: boolean) { + function getLoadModuleFromTargetImportOrExport( + extensions: Extensions, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + moduleName: string, + scope: PackageJsonInfo, + isImports: boolean, + ) { return loadModuleFromTargetImportOrExport; - function loadModuleFromTargetImportOrExport(target: unknown, subpath: string, pattern: boolean, key: string): SearchResult | undefined { + function loadModuleFromTargetImportOrExport( + target: unknown, + subpath: string, + pattern: boolean, + key: string, + ): SearchResult | undefined { if (typeof target === "string") { if (!pattern && subpath.length > 0 && !endsWith(target, "/")) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } if (!startsWith(target, "./")) { - if (isImports && !startsWith(target, "../") && !startsWith(target, "/") && !isRootedDiskPath(target)) { + if ( + isImports && !startsWith(target, "../") && !startsWith(target, "/") && !isRootedDiskPath(target) + ) { const combinedLookup = pattern ? target.replace(/\*/g, subpath) : target + subpath; - traceIfEnabled(state, Diagnostics.Using_0_subpath_1_with_target_2, "imports", key, combinedLookup); - traceIfEnabled(state, Diagnostics.Resolving_module_0_from_1, combinedLookup, scope.packageDirectory + "/"); - const result = nodeModuleNameResolverWorker(state.features, combinedLookup, scope.packageDirectory + "/", state.compilerOptions, state.host, cache, [extensions], redirectedReference); - return toSearchResult(result.resolvedModule ? { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId, originalPath: result.resolvedModule.originalPath } : undefined); + traceIfEnabled( + state, + Diagnostics.Using_0_subpath_1_with_target_2, + "imports", + key, + combinedLookup, + ); + traceIfEnabled( + state, + Diagnostics.Resolving_module_0_from_1, + combinedLookup, + scope.packageDirectory + "/", + ); + const result = nodeModuleNameResolverWorker( + state.features, + combinedLookup, + scope.packageDirectory + "/", + state.compilerOptions, + state.host, + cache, + [extensions], + redirectedReference, + ); + return toSearchResult( + result.resolvedModule + ? { + path: result.resolvedModule.resolvedFileName, + extension: result.resolvedModule.extension, + packageId: result.resolvedModule.packageId, + originalPath: result.resolvedModule.originalPath, + } : undefined, + ); } if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } const parts = pathIsRelative(target) ? getPathComponents(target).slice(1) : getPathComponents(target); const partsAfterFirst = parts.slice(1); - if (partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 || partsAfterFirst.indexOf("node_modules") >= 0) { + if ( + partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 + || partsAfterFirst.indexOf("node_modules") >= 0 + ) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } @@ -2176,26 +3060,60 @@ namespace ts { // TODO: Assert that `resolvedTarget` is actually within the package directory? That's what the spec says.... but I'm not sure we need // to be in the business of validating everyone's import and export map correctness. const subpathParts = getPathComponents(subpath); - if (subpathParts.indexOf("..") >= 0 || subpathParts.indexOf(".") >= 0 || subpathParts.indexOf("node_modules") >= 0) { + if ( + subpathParts.indexOf("..") >= 0 || subpathParts.indexOf(".") >= 0 + || subpathParts.indexOf("node_modules") >= 0 + ) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } if (state.traceEnabled) { - trace(state.host, Diagnostics.Using_0_subpath_1_with_target_2, isImports ? "imports" : "exports", key, pattern ? target.replace(/\*/g, subpath) : target + subpath); + trace( + state.host, + Diagnostics.Using_0_subpath_1_with_target_2, + isImports ? "imports" : "exports", + key, + pattern ? target.replace(/\*/g, subpath) : target + subpath, + ); } - const finalPath = toAbsolutePath(pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath); - const inputLink = tryLoadInputFileForPath(finalPath, subpath, combinePaths(scope.packageDirectory, "package.json"), isImports); + const finalPath = toAbsolutePath( + pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath, + ); + const inputLink = tryLoadInputFileForPath( + finalPath, + subpath, + combinePaths(scope.packageDirectory, "package.json"), + isImports, + ); if (inputLink) return inputLink; - return toSearchResult(withPackageId(scope, loadJSOrExactTSFileName(extensions, finalPath, /*onlyRecordFailures*/ false, state))); + return toSearchResult( + withPackageId( + scope, + loadJSOrExactTSFileName(extensions, finalPath, /*onlyRecordFailures*/ false, state), + ), + ); } else if (typeof target === "object" && target !== null) { // eslint-disable-line no-null/no-null if (!Array.isArray(target)) { for (const condition of getOwnKeys(target as MapLike)) { - if (condition === "default" || state.conditions.indexOf(condition) >= 0 || isApplicableVersionedTypesKey(state.conditions, condition)) { - traceIfEnabled(state, Diagnostics.Matched_0_condition_1, isImports ? "imports" : "exports", condition); + if ( + condition === "default" || state.conditions.indexOf(condition) >= 0 + || isApplicableVersionedTypesKey(state.conditions, condition) + ) { + traceIfEnabled( + state, + Diagnostics.Matched_0_condition_1, + isImports ? "imports" : "exports", + condition, + ); const subTarget = (target as MapLike)[condition]; const result = loadModuleFromTargetImportOrExport(subTarget, subpath, pattern, key); if (result) { @@ -2211,7 +3129,12 @@ namespace ts { else { if (!length(target)) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } @@ -2225,12 +3148,22 @@ namespace ts { } else if (target === null) { // eslint-disable-line no-null/no-null if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_explicitly_maps_specifier_1_to_null, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_explicitly_maps_specifier_1_to_null, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); @@ -2246,22 +3179,33 @@ namespace ts { } function useCaseSensitiveFileNames() { - return !state.host.useCaseSensitiveFileNames ? true : - typeof state.host.useCaseSensitiveFileNames === "boolean" ? state.host.useCaseSensitiveFileNames : - state.host.useCaseSensitiveFileNames(); + return !state.host.useCaseSensitiveFileNames ? true + : typeof state.host.useCaseSensitiveFileNames === "boolean" ? state.host.useCaseSensitiveFileNames + : state.host.useCaseSensitiveFileNames(); } - function tryLoadInputFileForPath(finalPath: string, entry: string, packagePath: string, isImports: boolean) { + function tryLoadInputFileForPath( + finalPath: string, + entry: string, + packagePath: string, + isImports: boolean, + ) { // Replace any references to outputs for files in the program with the input files to support package self-names used with outDir // PROBLEM: We don't know how to calculate the output paths yet, because the "common source directory" we use as the base of the file structure // we reproduce into the output directory is based on the set of input files, which we're still in the process of traversing and resolving! // _Given that_, we have to guess what the base of the output directory is (obviously the user wrote the export map, so has some idea what it is!). // We are going to probe _so many_ possible paths. We limit where we'll do this to try to reduce the possibilities of false positive lookups. if ( - (extensions === Extensions.TypeScript || extensions === Extensions.JavaScript || extensions === Extensions.Json) + (extensions === Extensions.TypeScript || extensions === Extensions.JavaScript + || extensions === Extensions.Json) && (state.compilerOptions.declarationDir || state.compilerOptions.outDir) && finalPath.indexOf("/node_modules/") === -1 - && (state.compilerOptions.configFile ? containsPath(scope.packageDirectory, toAbsolutePath(state.compilerOptions.configFile.fileName), !useCaseSensitiveFileNames()) : true) + && (state.compilerOptions.configFile + ? containsPath( + scope.packageDirectory, + toAbsolutePath(state.compilerOptions.configFile.fileName), + !useCaseSensitiveFileNames(), + ) : true) ) { // So that all means we'll only try these guesses for files outside `node_modules` in a directory where the `package.json` and `tsconfig.json` are siblings. // Even with all that, we still don't know if the root of the output file structure will be (relative to the package file) @@ -2271,8 +3215,18 @@ namespace ts { const commonSourceDirGuesses: string[] = []; // A `rootDir` compiler option strongly indicates the root location // A `composite` project is using project references and has it's common src dir set to `.`, so it shouldn't need to check any other locations - if (state.compilerOptions.rootDir || (state.compilerOptions.composite && state.compilerOptions.configFilePath)) { - const commonDir = toAbsolutePath(getCommonSourceDirectory(state.compilerOptions, () => [], state.host.getCurrentDirectory?.() || "", getCanonicalFileName)); + if ( + state.compilerOptions.rootDir + || (state.compilerOptions.composite && state.compilerOptions.configFilePath) + ) { + const commonDir = toAbsolutePath( + getCommonSourceDirectory( + state.compilerOptions, + () => [], + state.host.getCurrentDirectory?.() || "", + getCanonicalFileName, + ), + ); commonSourceDirGuesses.push(commonDir); } else if (state.requestContainingDirectory) { @@ -2290,7 +3244,9 @@ namespace ts { // But we do have more context! Just a tiny bit more! We're resolving an import _for some other input file_! And that input file, too // must be inside the common source directory! So we propagate that tidbit of info all the way to here via state.requestContainingDirectory - const requestingFile = toAbsolutePath(combinePaths(state.requestContainingDirectory, "index.ts")); + const requestingFile = toAbsolutePath( + combinePaths(state.requestContainingDirectory, "index.ts"), + ); // And we can try every folder above the common folder for the request folder and the config/package base directory // This technically can be wrong - we may load ./src/index.ts when ./src/sub/index.ts was right because we don't // know if only `./src/sub` files were loaded by the program; but this has the best chance to be right of just about anything @@ -2298,7 +3254,14 @@ namespace ts { // be a file outside of `./src/sub` in the program (the file we resolved to), making us de-facto right. So this fallback lookup // logic may influence what files are pulled in by self-names, which in turn influences the output path shape, but it's all // internally consistent so the paths should be stable so long as we prefer the "most general" (meaning: top-most-level directory) possible results first. - const commonDir = toAbsolutePath(getCommonSourceDirectory(state.compilerOptions, () => [requestingFile, toAbsolutePath(packagePath)], state.host.getCurrentDirectory?.() || "", getCanonicalFileName)); + const commonDir = toAbsolutePath( + getCommonSourceDirectory( + state.compilerOptions, + () => [requestingFile, toAbsolutePath(packagePath)], + state.host.getCurrentDirectory?.() || "", + getCanonicalFileName, + ), + ); commonSourceDirGuesses.push(commonDir); let fragment = ensureTrailingDirectorySeparator(commonDir); @@ -2313,8 +3276,10 @@ namespace ts { if (commonSourceDirGuesses.length > 1) { state.reportDiagnostic(createCompilerDiagnostic( isImports - ? Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_import_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate - : Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_export_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate, + ? Diagnostics + .The_project_root_is_ambiguous_but_is_required_to_resolve_import_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate + : Diagnostics + .The_project_root_is_ambiguous_but_is_required_to_resolve_export_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate, entry === "" ? "." : entry, // replace empty string with `.` - the reverse of the operation done when entries are built - so main entrypoint errors don't look weird packagePath, )); @@ -2326,20 +3291,47 @@ namespace ts { // The matched export is looking up something in either the out declaration or js dir, now map the written path back into the source dir and source extension const pathFragment = finalPath.slice(candidateDir.length + 1); // +1 to also remove directory seperator const possibleInputBase = combinePaths(commonSourceDirGuess, pathFragment); - const jsAndDtsExtensions = [Extension.Mjs, Extension.Cjs, Extension.Js, Extension.Json, Extension.Dmts, Extension.Dcts, Extension.Dts]; + const jsAndDtsExtensions = [ + Extension.Mjs, + Extension.Cjs, + Extension.Js, + Extension.Json, + Extension.Dmts, + Extension.Dcts, + Extension.Dts, + ]; for (const ext of jsAndDtsExtensions) { if (fileExtensionIs(possibleInputBase, ext)) { - const inputExts = getPossibleOriginalInputExtensionForExtension(possibleInputBase); + const inputExts = getPossibleOriginalInputExtensionForExtension( + possibleInputBase, + ); for (const possibleExt of inputExts) { - const possibleInputWithInputExtension = changeAnyExtension(possibleInputBase, possibleExt, ext, !useCaseSensitiveFileNames()); + const possibleInputWithInputExtension = changeAnyExtension( + possibleInputBase, + possibleExt, + ext, + !useCaseSensitiveFileNames(), + ); if ( - (extensions === Extensions.TypeScript && hasJSFileExtension(possibleInputWithInputExtension)) || - (extensions === Extensions.JavaScript && hasTSFileExtension(possibleInputWithInputExtension)) + (extensions === Extensions.TypeScript + && hasJSFileExtension(possibleInputWithInputExtension)) + || (extensions === Extensions.JavaScript + && hasTSFileExtension(possibleInputWithInputExtension)) ) { continue; } if (state.host.fileExists(possibleInputWithInputExtension)) { - return toSearchResult(withPackageId(scope, loadJSOrExactTSFileName(extensions, possibleInputWithInputExtension, /*onlyRecordFailures*/ false, state))); + return toSearchResult( + withPackageId( + scope, + loadJSOrExactTSFileName( + extensions, + possibleInputWithInputExtension, + /*onlyRecordFailures*/ false, + state, + ), + ), + ); } } } @@ -2353,13 +3345,21 @@ namespace ts { function getOutputDirectoriesForBaseDirectory(commonSourceDirGuess: string) { // Config file ouput paths are processed to be relative to the host's current directory, while // otherwise the paths are resolved relative to the common source dir the compiler puts together - const currentDir = state.compilerOptions.configFile ? state.host.getCurrentDirectory?.() || "" : commonSourceDirGuess; + const currentDir = state.compilerOptions.configFile ? state.host.getCurrentDirectory?.() || "" + : commonSourceDirGuess; const candidateDirectories = []; if (state.compilerOptions.declarationDir) { - candidateDirectories.push(toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.declarationDir))); + candidateDirectories.push( + toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.declarationDir)), + ); } - if (state.compilerOptions.outDir && state.compilerOptions.outDir !== state.compilerOptions.declarationDir) { - candidateDirectories.push(toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.outDir))); + if ( + state.compilerOptions.outDir + && state.compilerOptions.outDir !== state.compilerOptions.declarationDir + ) { + candidateDirectories.push( + toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.outDir)), + ); } return candidateDirectories; } @@ -2376,36 +3376,109 @@ namespace ts { return range.test(version); } - function loadModuleFromNearestNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { - return loadModuleFromNearestNodeModulesDirectoryWorker(extensions, moduleName, directory, state, /*typesScopeOnly*/ false, cache, redirectedReference); + function loadModuleFromNearestNodeModulesDirectory( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + ): SearchResult { + return loadModuleFromNearestNodeModulesDirectoryWorker( + extensions, + moduleName, + directory, + state, + /*typesScopeOnly*/ false, + cache, + redirectedReference, + ); } - function loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName: string, directory: string, state: ModuleResolutionState): SearchResult { + function loadModuleFromNearestNodeModulesDirectoryTypesScope( + moduleName: string, + directory: string, + state: ModuleResolutionState, + ): SearchResult { // Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly. - return loadModuleFromNearestNodeModulesDirectoryWorker(Extensions.DtsOnly, moduleName, directory, state, /*typesScopeOnly*/ true, /*cache*/ undefined, /*redirectedReference*/ undefined); + return loadModuleFromNearestNodeModulesDirectoryWorker( + Extensions.DtsOnly, + moduleName, + directory, + state, + /*typesScopeOnly*/ true, + /*cache*/ undefined, + /*redirectedReference*/ undefined, + ); } - function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { - const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName, state.features === 0 ? undefined : state.features & NodeResolutionFeatures.EsmMode ? ModuleKind.ESNext : ModuleKind.CommonJS, redirectedReference); + function loadModuleFromNearestNodeModulesDirectoryWorker( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + typesScopeOnly: boolean, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + ): SearchResult { + const perModuleNameCache = cache + && cache.getOrCreateCacheForModuleName( + moduleName, + state.features === 0 ? undefined + : state.features & NodeResolutionFeatures.EsmMode ? ModuleKind.ESNext : ModuleKind.CommonJS, + redirectedReference, + ); return forEachAncestorDirectory(normalizeSlashes(directory), ancestorDirectory => { if (getBaseFileName(ancestorDirectory) !== "node_modules") { - const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state); + const resolutionFromCache = tryFindNonRelativeModuleNameInCache( + perModuleNameCache, + moduleName, + ancestorDirectory, + state, + ); if (resolutionFromCache) { return resolutionFromCache; } - return toSearchResult(loadModuleFromImmediateNodeModulesDirectory(extensions, moduleName, ancestorDirectory, state, typesScopeOnly, cache, redirectedReference)); + return toSearchResult( + loadModuleFromImmediateNodeModulesDirectory( + extensions, + moduleName, + ancestorDirectory, + state, + typesScopeOnly, + cache, + redirectedReference, + ), + ); } }); } - function loadModuleFromImmediateNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): Resolved | undefined { + function loadModuleFromImmediateNodeModulesDirectory( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + typesScopeOnly: boolean, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + ): Resolved | undefined { const nodeModulesFolder = combinePaths(directory, "node_modules"); const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host); if (!nodeModulesFolderExists && state.traceEnabled) { trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, nodeModulesFolder); } - const packageResult = typesScopeOnly ? undefined : loadModuleFromSpecificNodeModulesDirectory(extensions, moduleName, nodeModulesFolder, nodeModulesFolderExists, state, cache, redirectedReference); + const packageResult = typesScopeOnly ? undefined + : loadModuleFromSpecificNodeModulesDirectory( + extensions, + moduleName, + nodeModulesFolder, + nodeModulesFolderExists, + state, + cache, + redirectedReference, + ); if (packageResult) { return packageResult; } @@ -2414,15 +3487,35 @@ namespace ts { let nodeModulesAtTypesExists = nodeModulesFolderExists; if (nodeModulesFolderExists && !directoryProbablyExists(nodeModulesAtTypes, state.host)) { if (state.traceEnabled) { - trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, nodeModulesAtTypes); + trace( + state.host, + Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, + nodeModulesAtTypes, + ); } nodeModulesAtTypesExists = false; } - return loadModuleFromSpecificNodeModulesDirectory(Extensions.DtsOnly, mangleScopedPackageNameWithTrace(moduleName, state), nodeModulesAtTypes, nodeModulesAtTypesExists, state, cache, redirectedReference); + return loadModuleFromSpecificNodeModulesDirectory( + Extensions.DtsOnly, + mangleScopedPackageNameWithTrace(moduleName, state), + nodeModulesAtTypes, + nodeModulesAtTypesExists, + state, + cache, + redirectedReference, + ); } } - function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, moduleName: string, nodeModulesDirectory: string, nodeModulesDirectoryExists: boolean, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): Resolved | undefined { + function loadModuleFromSpecificNodeModulesDirectory( + extensions: Extensions, + moduleName: string, + nodeModulesDirectory: string, + nodeModulesDirectoryExists: boolean, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + ): Resolved | undefined { const candidate = normalizePath(combinePaths(nodeModulesDirectory, moduleName)); // First look for a nested package.json, as in `node_modules/foo/bar/package.json`. @@ -2448,8 +3541,8 @@ namespace ts { } const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => { - let pathAndExtension = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) || - loadNodeModuleFromDirectoryWorker( + let pathAndExtension = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) + || loadNodeModuleFromDirectoryWorker( extensions, candidate, onlyRecordFailures, @@ -2460,12 +3553,18 @@ namespace ts { if ( !pathAndExtension && packageInfo // eslint-disable-next-line no-null/no-null - && (packageInfo.contents.packageJsonContent.exports === undefined || packageInfo.contents.packageJsonContent.exports === null) + && (packageInfo.contents.packageJsonContent.exports === undefined + || packageInfo.contents.packageJsonContent.exports === null) && state.features & NodeResolutionFeatures.EsmMode ) { // EsmMode disables index lookup in `loadNodeModuleFromDirectoryWorker` generally, however non-relative package resolutions still assume // a default `index.js` entrypoint if no `main` or `exports` are present - pathAndExtension = loadModuleFromFile(extensions, combinePaths(candidate, "index.js"), onlyRecordFailures, state); + pathAndExtension = loadModuleFromFile( + extensions, + combinePaths(candidate, "index.js"), + onlyRecordFailures, + state, + ); } return withPackageId(packageInfo, pathAndExtension); }; @@ -2477,15 +3576,42 @@ namespace ts { packageInfo = getPackageJsonInfo(packageDirectory, !nodeModulesDirectoryExists, state); } // package exports are higher priority than file/directory/typesVersions lookups and (and, if there's exports present, blocks them) - if (packageInfo && packageInfo.contents.packageJsonContent.exports && state.features & NodeResolutionFeatures.Exports) { - return loadModuleFromExports(packageInfo, extensions, combinePaths(".", rest), state, cache, redirectedReference)?.value; + if ( + packageInfo && packageInfo.contents.packageJsonContent.exports + && state.features & NodeResolutionFeatures.Exports + ) { + return loadModuleFromExports( + packageInfo, + extensions, + combinePaths(".", rest), + state, + cache, + redirectedReference, + )?.value; } if (rest !== "" && packageInfo && packageInfo.contents.versionPaths) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, packageInfo.contents.versionPaths.version, version, rest); + trace( + state.host, + Diagnostics + .package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, + packageInfo.contents.versionPaths.version, + version, + rest, + ); } - const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host); - const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, packageInfo.contents.versionPaths.paths, /*pathPatterns*/ undefined, loader, !packageDirectoryExists, state); + const packageDirectoryExists = nodeModulesDirectoryExists + && directoryProbablyExists(packageDirectory, state.host); + const fromPaths = tryLoadModuleUsingPaths( + extensions, + rest, + packageDirectory, + packageInfo.contents.versionPaths.paths, + /*pathPatterns*/ undefined, + loader, + !packageDirectoryExists, + state, + ); if (fromPaths) { return fromPaths.value; } @@ -2494,7 +3620,16 @@ namespace ts { return loader(extensions, candidate, !nodeModulesDirectoryExists, state); } - function tryLoadModuleUsingPaths(extensions: Extensions, moduleName: string, baseDirectory: string, paths: MapLike, pathPatterns: readonly (string | Pattern)[] | undefined, loader: ResolutionKindSpecificLoader, onlyRecordFailures: boolean, state: ModuleResolutionState): SearchResult { + function tryLoadModuleUsingPaths( + extensions: Extensions, + moduleName: string, + baseDirectory: string, + paths: MapLike, + pathPatterns: readonly (string | Pattern)[] | undefined, + loader: ResolutionKindSpecificLoader, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + ): SearchResult { pathPatterns ||= tryParsePatterns(paths); const matchedPattern = matchPatternOrExact(pathPatterns, moduleName); if (matchedPattern) { @@ -2518,7 +3653,12 @@ namespace ts { return noPackageId({ path, ext: extension }); } } - return loader(extensions, candidate, onlyRecordFailures || !directoryProbablyExists(getDirectoryPath(candidate), state.host), state); + return loader( + extensions, + candidate, + onlyRecordFailures || !directoryProbablyExists(getDirectoryPath(candidate), state.host), + state, + ); }); return { value: resolved }; } @@ -2563,23 +3703,48 @@ namespace ts { /* @internal */ export function unmangleScopedPackageName(typesPackageName: string): string { - return stringContains(typesPackageName, mangledScopedPackageSeparator) ? - "@" + typesPackageName.replace(mangledScopedPackageSeparator, directorySeparator) : - typesPackageName; + return stringContains(typesPackageName, mangledScopedPackageSeparator) + ? "@" + typesPackageName.replace(mangledScopedPackageSeparator, directorySeparator) + : typesPackageName; } - function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, state: ModuleResolutionState): SearchResult { + function tryFindNonRelativeModuleNameInCache( + cache: PerModuleNameCache | undefined, + moduleName: string, + containingDirectory: string, + state: ModuleResolutionState, + ): SearchResult { const result = cache && cache.get(containingDirectory); if (result) { if (state.traceEnabled) { - trace(state.host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory); + trace( + state.host, + Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, + moduleName, + containingDirectory, + ); } state.resultFromCache = result; - return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, originalPath: result.resolvedModule.originalPath || true, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } }; + return { + value: result.resolvedModule + && { + path: result.resolvedModule.resolvedFileName, + originalPath: result.resolvedModule.originalPath || true, + extension: result.resolvedModule.extension, + packageId: result.resolvedModule.packageId, + }, + }; } } - export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations { + export function classicNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: NonRelativeModuleNameResolutionCache, + redirectedReference?: ResolvedProjectReference, + ): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); const failedLookupLocations: string[] = []; const affectingLocations: string[] = []; @@ -2610,21 +3775,35 @@ namespace ts { ); function tryResolve(extensions: Extensions): SearchResult { - const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, state); + const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings( + extensions, + moduleName, + containingDirectory, + loadModuleFromFileNoPackageId, + state, + ); if (resolvedUsingSettings) { return { value: resolvedUsingSettings }; } if (!isExternalModuleNameRelative(moduleName)) { - const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName, /*mode*/ undefined, redirectedReference); + const perModuleNameCache = cache + && cache.getOrCreateCacheForModuleName(moduleName, /*mode*/ undefined, redirectedReference); // Climb up parent directories looking for a module. const resolved = forEachAncestorDirectory(containingDirectory, directory => { - const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, state); + const resolutionFromCache = tryFindNonRelativeModuleNameInCache( + perModuleNameCache, + moduleName, + directory, + state, + ); if (resolutionFromCache) { return resolutionFromCache; } const searchName = normalizePath(combinePaths(directory, moduleName)); - return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, /*onlyRecordFailures*/ false, state)); + return toSearchResult( + loadModuleFromFileNoPackageId(extensions, searchName, /*onlyRecordFailures*/ false, state), + ); }); if (resolved) { return resolved; @@ -2636,7 +3815,9 @@ namespace ts { } else { const candidate = normalizePath(combinePaths(containingDirectory, moduleName)); - return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, /*onlyRecordFailures*/ false, state)); + return toSearchResult( + loadModuleFromFileNoPackageId(extensions, candidate, /*onlyRecordFailures*/ false, state), + ); } } } @@ -2646,10 +3827,24 @@ namespace ts { * This is the minumum code needed to expose that functionality; the rest is in the host. */ /* @internal */ - export function loadModuleFromGlobalCache(moduleName: string, projectName: string | undefined, compilerOptions: CompilerOptions, host: ModuleResolutionHost, globalCache: string, packageJsonInfoCache: PackageJsonInfoCache): ResolvedModuleWithFailedLookupLocations { + export function loadModuleFromGlobalCache( + moduleName: string, + projectName: string | undefined, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + globalCache: string, + packageJsonInfoCache: PackageJsonInfoCache, + ): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); if (traceEnabled) { - trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, projectName, moduleName, globalCache); + trace( + host, + Diagnostics + .Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, + projectName, + moduleName, + globalCache, + ); } const failedLookupLocations: string[] = []; const affectingLocations: string[] = []; @@ -2666,7 +3861,15 @@ namespace ts { requestContainingDirectory: undefined, reportDiagnostic: diag => void diagnostics.push(diag), }; - const resolved = loadModuleFromImmediateNodeModulesDirectory(Extensions.DtsOnly, moduleName, globalCache, state, /*typesScopeOnly*/ false, /*cache*/ undefined, /*redirectedReference*/ undefined); + const resolved = loadModuleFromImmediateNodeModulesDirectory( + Extensions.DtsOnly, + moduleName, + globalCache, + state, + /*typesScopeOnly*/ false, + /*cache*/ undefined, + /*redirectedReference*/ undefined, + ); return createResolvedModuleWithFailedLookupLocations( resolved, /*isExternalLibraryImport*/ true, diff --git a/src/compiler/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts index 5d30911766d47..445d647ebe80e 100644 --- a/src/compiler/moduleSpecifiers.ts +++ b/src/compiler/moduleSpecifiers.ts @@ -20,12 +20,17 @@ namespace ts.moduleSpecifiers { readonly ending: Ending; } - function getPreferences(host: ModuleSpecifierResolutionHost, { importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences, compilerOptions: CompilerOptions, importingSourceFile: SourceFile): Preferences { + function getPreferences( + host: ModuleSpecifierResolutionHost, + { importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences, + compilerOptions: CompilerOptions, + importingSourceFile: SourceFile, + ): Preferences { return { - relativePreference: importModuleSpecifierPreference === "relative" ? RelativePreference.Relative : - importModuleSpecifierPreference === "non-relative" ? RelativePreference.NonRelative : - importModuleSpecifierPreference === "project-relative" ? RelativePreference.ExternalNonRelative : - RelativePreference.Shortest, + relativePreference: importModuleSpecifierPreference === "relative" ? RelativePreference.Relative + : importModuleSpecifierPreference === "non-relative" ? RelativePreference.NonRelative + : importModuleSpecifierPreference === "project-relative" ? RelativePreference.ExternalNonRelative + : RelativePreference.Shortest, ending: getEnding(), }; function getEnding(): Ending { @@ -37,29 +42,49 @@ namespace ts.moduleSpecifiers { case "js": return Ending.JsExtension; default: - return usesJsExtensionOnImports(importingSourceFile) || isFormatRequiringExtensions(compilerOptions, importingSourceFile.path, host) ? Ending.JsExtension - : getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs ? Ending.Index : Ending.Minimal; + return usesJsExtensionOnImports(importingSourceFile) + || isFormatRequiringExtensions(compilerOptions, importingSourceFile.path, host) + ? Ending.JsExtension + : getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs ? Ending.Index + : Ending.Minimal; } } } - function getPreferencesForUpdate(compilerOptions: CompilerOptions, oldImportSpecifier: string, importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Preferences { + function getPreferencesForUpdate( + compilerOptions: CompilerOptions, + oldImportSpecifier: string, + importingSourceFileName: Path, + host: ModuleSpecifierResolutionHost, + ): Preferences { return { - relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative : RelativePreference.NonRelative, - ending: hasJSFileExtension(oldImportSpecifier) || isFormatRequiringExtensions(compilerOptions, importingSourceFileName, host) ? - Ending.JsExtension : - getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal, + relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative + : RelativePreference.NonRelative, + ending: hasJSFileExtension(oldImportSpecifier) + || isFormatRequiringExtensions(compilerOptions, importingSourceFileName, host) + ? Ending.JsExtension + : getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs + || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal, }; } - function isFormatRequiringExtensions(compilerOptions: CompilerOptions, importingSourceFileName: Path, host: ModuleSpecifierResolutionHost) { + function isFormatRequiringExtensions( + compilerOptions: CompilerOptions, + importingSourceFileName: Path, + host: ModuleSpecifierResolutionHost, + ) { if ( getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext ) { return false; } - return getImpliedNodeFormatForFile(importingSourceFileName, host.getPackageJsonInfoCache?.(), getModuleResolutionHost(host), compilerOptions) !== ModuleKind.CommonJS; + return getImpliedNodeFormatForFile( + importingSourceFileName, + host.getPackageJsonInfoCache?.(), + getModuleResolutionHost(host), + compilerOptions, + ) !== ModuleKind.CommonJS; } function getModuleResolutionHost(host: ModuleSpecifierResolutionHost): ModuleResolutionHost { @@ -86,7 +111,16 @@ namespace ts.moduleSpecifiers { oldImportSpecifier: string, options: ModuleSpecifierOptions = {}, ): string | undefined { - const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getPreferencesForUpdate(compilerOptions, oldImportSpecifier, importingSourceFileName, host), {}, options); + const res = getModuleSpecifierWorker( + compilerOptions, + importingSourceFile, + importingSourceFileName, + toFileName, + host, + getPreferencesForUpdate(compilerOptions, oldImportSpecifier, importingSourceFileName, host), + {}, + options, + ); if (res === oldImportSpecifier) return undefined; return res; } @@ -105,7 +139,16 @@ namespace ts.moduleSpecifiers { host: ModuleSpecifierResolutionHost, options: ModuleSpecifierOptions = {}, ): string { - return getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getPreferences(host, {}, compilerOptions, importingSourceFile), {}, options); + return getModuleSpecifierWorker( + compilerOptions, + importingSourceFile, + importingSourceFileName, + toFileName, + host, + getPreferences(host, {}, compilerOptions, importingSourceFile), + {}, + options, + ); } export function getNodeModulesPackageName( @@ -117,8 +160,27 @@ namespace ts.moduleSpecifiers { options: ModuleSpecifierOptions = {}, ): string | undefined { const info = getInfo(importingSourceFile.path, host); - const modulePaths = getAllModulePaths(importingSourceFile.path, nodeModulesFileName, host, preferences, options); - return firstDefined(modulePaths, modulePath => tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, preferences, /*packageNameOnly*/ true, options.overrideImportMode)); + const modulePaths = getAllModulePaths( + importingSourceFile.path, + nodeModulesFileName, + host, + preferences, + options, + ); + return firstDefined( + modulePaths, + modulePath => + tryGetModuleNameAsNodeModule( + modulePath, + info, + importingSourceFile, + host, + compilerOptions, + preferences, + /*packageNameOnly*/ true, + options.overrideImportMode, + ), + ); } function getModuleSpecifierWorker( @@ -133,8 +195,28 @@ namespace ts.moduleSpecifiers { ): string { const info = getInfo(importingSourceFileName, host); const modulePaths = getAllModulePaths(importingSourceFileName, toFileName, host, userPreferences, options); - return firstDefined(modulePaths, modulePath => tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, userPreferences, /*packageNameOnly*/ undefined, options.overrideImportMode)) || - getLocalModuleSpecifier(toFileName, info, compilerOptions, host, options.overrideImportMode || importingSourceFile.impliedNodeFormat, preferences); + return firstDefined( + modulePaths, + modulePath => + tryGetModuleNameAsNodeModule( + modulePath, + info, + importingSourceFile, + host, + compilerOptions, + userPreferences, + /*packageNameOnly*/ undefined, + options.overrideImportMode, + ), + ) + || getLocalModuleSpecifier( + toFileName, + info, + compilerOptions, + host, + options.overrideImportMode || importingSourceFile.impliedNodeFormat, + preferences, + ); } export function tryGetModuleSpecifiersFromCache( @@ -159,7 +241,12 @@ namespace ts.moduleSpecifiers { host: ModuleSpecifierResolutionHost, userPreferences: UserPreferences, options: ModuleSpecifierOptions = {}, - ): readonly [specifiers?: readonly string[], moduleFile?: SourceFile, modulePaths?: readonly ModulePath[], cache?: ModuleSpecifierCache] { + ): readonly [ + specifiers?: readonly string[], + moduleFile?: SourceFile, + modulePaths?: readonly ModulePath[], + cache?: ModuleSpecifierCache, + ] { const moduleSourceFile = getSourceFileOfModule(moduleSymbol); if (!moduleSourceFile) { return emptyArray as []; @@ -217,7 +304,14 @@ namespace ts.moduleSpecifiers { computedWithoutCache = true; modulePaths ||= getAllModulePathsWorker(importingSourceFile.path, moduleSourceFile.originalFileName, host); - const result = computeModuleSpecifiers(modulePaths, compilerOptions, importingSourceFile, host, userPreferences, options); + const result = computeModuleSpecifiers( + modulePaths, + compilerOptions, + importingSourceFile, + host, + userPreferences, + options, + ); cache?.set(importingSourceFile.path, moduleSourceFile.path, userPreferences, options, modulePaths, result); return { moduleSpecifiers: result, computedWithoutCache }; } @@ -234,17 +328,26 @@ namespace ts.moduleSpecifiers { const preferences = getPreferences(host, userPreferences, compilerOptions, importingSourceFile); const existingSpecifier = forEach(modulePaths, modulePath => forEach( - host.getFileIncludeReasons().get(toPath(modulePath.path, host.getCurrentDirectory(), info.getCanonicalFileName)), + host.getFileIncludeReasons().get( + toPath(modulePath.path, host.getCurrentDirectory(), info.getCanonicalFileName), + ), reason => { - if (reason.kind !== FileIncludeKind.Import || reason.file !== importingSourceFile.path) return undefined; + if ( + reason.kind !== FileIncludeKind.Import || reason.file !== importingSourceFile.path + ) return undefined; // If the candidate import mode doesn't match the mode we're generating for, don't consider it // TODO: maybe useful to keep around as an alternative option for certain contexts where the mode is overridable - if (importingSourceFile.impliedNodeFormat && importingSourceFile.impliedNodeFormat !== getModeForResolutionAtIndex(importingSourceFile, reason.index)) return undefined; + if ( + importingSourceFile.impliedNodeFormat + && importingSourceFile.impliedNodeFormat + !== getModeForResolutionAtIndex(importingSourceFile, reason.index) + ) return undefined; const specifier = getModuleNameStringLiteralAt(importingSourceFile, reason.index).text; // If the preference is for non relative and the module specifier is relative, ignore it - return preferences.relativePreference !== RelativePreference.NonRelative || !pathIsRelative(specifier) ? - specifier : - undefined; + return preferences.relativePreference !== RelativePreference.NonRelative + || !pathIsRelative(specifier) + ? specifier + : undefined; }, )); if (existingSpecifier) { @@ -263,7 +366,16 @@ namespace ts.moduleSpecifiers { let pathsSpecifiers: string[] | undefined; let relativeSpecifiers: string[] | undefined; for (const modulePath of modulePaths) { - const specifier = tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, userPreferences, /*packageNameOnly*/ undefined, options.overrideImportMode); + const specifier = tryGetModuleNameAsNodeModule( + modulePath, + info, + importingSourceFile, + host, + compilerOptions, + userPreferences, + /*packageNameOnly*/ undefined, + options.overrideImportMode, + ); nodeModulesSpecifiers = append(nodeModulesSpecifiers, specifier); if (specifier && modulePath.isRedirect) { // If we got a specifier for a redirect, it was a bare package specifier (e.g. "@foo/bar", @@ -272,7 +384,14 @@ namespace ts.moduleSpecifiers { } if (!specifier && !modulePath.isRedirect) { - const local = getLocalModuleSpecifier(modulePath.path, info, compilerOptions, host, options.overrideImportMode || importingSourceFile.impliedNodeFormat, preferences); + const local = getLocalModuleSpecifier( + modulePath.path, + info, + compilerOptions, + host, + options.overrideImportMode || importingSourceFile.impliedNodeFormat, + preferences, + ); if (pathIsBareSpecifier(local)) { pathsSpecifiers = append(pathsSpecifiers, local); } @@ -291,9 +410,9 @@ namespace ts.moduleSpecifiers { } } - return pathsSpecifiers?.length ? pathsSpecifiers : - nodeModulesSpecifiers?.length ? nodeModulesSpecifiers : - Debug.checkDefined(relativeSpecifiers); + return pathsSpecifiers?.length ? pathsSpecifiers + : nodeModulesSpecifiers?.length ? nodeModulesSpecifiers + : Debug.checkDefined(relativeSpecifiers); } interface Info { @@ -303,28 +422,62 @@ namespace ts.moduleSpecifiers { } // importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path function getInfo(importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info { - const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true); + const getCanonicalFileName = createGetCanonicalFileName( + host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true, + ); const sourceDirectory = getDirectoryPath(importingSourceFileName); return { getCanonicalFileName, importingSourceFileName, sourceDirectory }; } - function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOptions: CompilerOptions, host: ModuleSpecifierResolutionHost, importMode: SourceFile["impliedNodeFormat"], { ending, relativePreference }: Preferences): string { + function getLocalModuleSpecifier( + moduleFileName: string, + info: Info, + compilerOptions: CompilerOptions, + host: ModuleSpecifierResolutionHost, + importMode: SourceFile["impliedNodeFormat"], + { ending, relativePreference }: Preferences, + ): string { const { baseUrl, paths, rootDirs } = compilerOptions; const { sourceDirectory, getCanonicalFileName } = info; - const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName, ending, compilerOptions) || - removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), ending, compilerOptions); + const relativePath = rootDirs + && tryGetModuleNameFromRootDirs( + rootDirs, + moduleFileName, + sourceDirectory, + getCanonicalFileName, + ending, + compilerOptions, + ) + || removeExtensionAndIndexPostFix( + ensurePathIsNonModuleName( + getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName), + ), + ending, + compilerOptions, + ); if (!baseUrl && !paths || relativePreference === RelativePreference.Relative) { return relativePath; } - const baseDirectory = getNormalizedAbsolutePath(getPathsBasePath(compilerOptions, host) || baseUrl!, host.getCurrentDirectory()); + const baseDirectory = getNormalizedAbsolutePath( + getPathsBasePath(compilerOptions, host) || baseUrl!, + host.getCurrentDirectory(), + ); const relativeToBaseUrl = getRelativePathIfInDirectory(moduleFileName, baseDirectory, getCanonicalFileName); if (!relativeToBaseUrl) { return relativePath; } - const fromPaths = paths && tryGetModuleNameFromPaths(relativeToBaseUrl, paths, getAllowedEndings(ending, compilerOptions, importMode), host, compilerOptions); - const nonRelative = fromPaths === undefined && baseUrl !== undefined ? removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions) : fromPaths; + const fromPaths = paths + && tryGetModuleNameFromPaths( + relativeToBaseUrl, + paths, + getAllowedEndings(ending, compilerOptions, importMode), + host, + compilerOptions, + ); + const nonRelative = fromPaths === undefined && baseUrl !== undefined + ? removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions) : fromPaths; if (!nonRelative) { return relativePath; } @@ -334,9 +487,13 @@ namespace ts.moduleSpecifiers { } if (relativePreference === RelativePreference.ExternalNonRelative) { - const projectDirectory = compilerOptions.configFilePath ? - toPath(getDirectoryPath(compilerOptions.configFilePath), host.getCurrentDirectory(), info.getCanonicalFileName) : - info.getCanonicalFileName(host.getCurrentDirectory()); + const projectDirectory = compilerOptions.configFilePath + ? toPath( + getDirectoryPath(compilerOptions.configFilePath), + host.getCurrentDirectory(), + info.getCanonicalFileName, + ) + : info.getCanonicalFileName(host.getCurrentDirectory()); const modulePath = toPath(moduleFileName, projectDirectory, getCanonicalFileName); const sourceIsInternal = startsWith(sourceDirectory, projectDirectory); const targetIsInternal = startsWith(modulePath, projectDirectory); @@ -352,7 +509,10 @@ namespace ts.moduleSpecifiers { return nonRelative; } - const nearestTargetPackageJson = getNearestAncestorDirectoryWithPackageJson(host, getDirectoryPath(modulePath)); + const nearestTargetPackageJson = getNearestAncestorDirectoryWithPackageJson( + host, + getDirectoryPath(modulePath), + ); const nearestSourcePackageJson = getNearestAncestorDirectoryWithPackageJson(host, sourceDirectory); if (nearestSourcePackageJson !== nearestTargetPackageJson) { // 2. The importing and imported files are part of different packages. @@ -373,7 +533,8 @@ namespace ts.moduleSpecifiers { if (relativePreference !== RelativePreference.Shortest) Debug.assertNever(relativePreference); // Prefer a relative import over a baseUrl import if it has fewer components. - return isPathRelativeToParent(nonRelative) || countPathComponents(relativePath) < countPathComponents(nonRelative) ? relativePath : nonRelative; + return isPathRelativeToParent(nonRelative) + || countPathComponents(relativePath) < countPathComponents(nonRelative) ? relativePath : nonRelative; } export function countPathComponents(path: string): number { @@ -385,7 +546,8 @@ namespace ts.moduleSpecifiers { } function usesJsExtensionOnImports({ imports }: SourceFile): boolean { - return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJSFileExtension(text) : undefined) || false; + return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJSFileExtension(text) : undefined) + || false; } function comparePathsByRedirectAndNumberOfDirectorySeparators(a: ModulePath, b: ModulePath) { @@ -410,47 +572,61 @@ namespace ts.moduleSpecifiers { ): T | undefined { const getCanonicalFileName = hostGetCanonicalFileName(host); const cwd = host.getCurrentDirectory(); - const referenceRedirect = host.isSourceOfProjectReferenceRedirect(importedFileName) ? host.getProjectReferenceRedirect(importedFileName) : undefined; + const referenceRedirect = host.isSourceOfProjectReferenceRedirect(importedFileName) + ? host.getProjectReferenceRedirect(importedFileName) : undefined; const importedPath = toPath(importedFileName, cwd, getCanonicalFileName); const redirects = host.redirectTargetsMap.get(importedPath) || emptyArray; - const importedFileNames = [...(referenceRedirect ? [referenceRedirect] : emptyArray), importedFileName, ...redirects]; + const importedFileNames = [ + ...(referenceRedirect ? [referenceRedirect] : emptyArray), + importedFileName, + ...redirects, + ]; const targets = importedFileNames.map(f => getNormalizedAbsolutePath(f, cwd)); let shouldFilterIgnoredPaths = !every(targets, containsIgnoredPath); if (!preferSymlinks) { // Symlinks inside ignored paths are already filtered out of the symlink cache, // so we only need to remove them from the realpath filenames. - const result = forEach(targets, p => !(shouldFilterIgnoredPaths && containsIgnoredPath(p)) && cb(p, referenceRedirect === p)); + const result = forEach( + targets, + p => !(shouldFilterIgnoredPaths && containsIgnoredPath(p)) && cb(p, referenceRedirect === p), + ); if (result) return result; } const symlinkedDirectories = host.getSymlinkCache?.().getSymlinkedDirectoriesByRealpath(); const fullImportedFileName = getNormalizedAbsolutePath(importedFileName, cwd); - const result = symlinkedDirectories && forEachAncestorDirectory(getDirectoryPath(fullImportedFileName), realPathDirectory => { - const symlinkDirectories = symlinkedDirectories.get(ensureTrailingDirectorySeparator(toPath(realPathDirectory, cwd, getCanonicalFileName))); - if (!symlinkDirectories) return undefined; // Continue to ancestor directory - - // Don't want to a package to globally import from itself (importNameCodeFix_symlink_own_package.ts) - if (startsWithDirectory(importingFileName, realPathDirectory, getCanonicalFileName)) { - return false; // Stop search, each ancestor directory will also hit this condition - } - - return forEach(targets, target => { - if (!startsWithDirectory(target, realPathDirectory, getCanonicalFileName)) { - return; + const result = symlinkedDirectories + && forEachAncestorDirectory(getDirectoryPath(fullImportedFileName), realPathDirectory => { + const symlinkDirectories = symlinkedDirectories.get( + ensureTrailingDirectorySeparator(toPath(realPathDirectory, cwd, getCanonicalFileName)), + ); + if (!symlinkDirectories) return undefined; // Continue to ancestor directory + + // Don't want to a package to globally import from itself (importNameCodeFix_symlink_own_package.ts) + if (startsWithDirectory(importingFileName, realPathDirectory, getCanonicalFileName)) { + return false; // Stop search, each ancestor directory will also hit this condition } - const relative = getRelativePathFromDirectory(realPathDirectory, target, getCanonicalFileName); - for (const symlinkDirectory of symlinkDirectories) { - const option = resolvePath(symlinkDirectory, relative); - const result = cb(option, target === referenceRedirect); - shouldFilterIgnoredPaths = true; // We found a non-ignored path in symlinks, so we can reject ignored-path realpaths - if (result) return result; - } + return forEach(targets, target => { + if (!startsWithDirectory(target, realPathDirectory, getCanonicalFileName)) { + return; + } + + const relative = getRelativePathFromDirectory(realPathDirectory, target, getCanonicalFileName); + for (const symlinkDirectory of symlinkDirectories) { + const option = resolvePath(symlinkDirectory, relative); + const result = cb(option, target === referenceRedirect); + shouldFilterIgnoredPaths = true; // We found a non-ignored path in symlinks, so we can reject ignored-path realpaths + if (result) return result; + } + }); }); - }); return result || (preferSymlinks - ? forEach(targets, p => shouldFilterIgnoredPaths && containsIgnoredPath(p) ? undefined : cb(p, p === referenceRedirect)) + ? forEach( + targets, + p => shouldFilterIgnoredPaths && containsIgnoredPath(p) ? undefined : cb(p, p === referenceRedirect), + ) : undefined); } @@ -478,7 +654,11 @@ namespace ts.moduleSpecifiers { return modulePaths; } - function getAllModulePathsWorker(importingFileName: Path, importedFileName: string, host: ModuleSpecifierResolutionHost): readonly ModulePath[] { + function getAllModulePathsWorker( + importingFileName: Path, + importedFileName: string, + host: ModuleSpecifierResolutionHost, + ): readonly ModulePath[] { const getCanonicalFileName = hostGetCanonicalFileName(host); const allFileNames = new Map(); let importedFileFromNodeModules = false; @@ -530,7 +710,9 @@ namespace ts.moduleSpecifiers { function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol, checker: TypeChecker): string | undefined { const decl = moduleSymbol.declarations?.find( - d => isNonGlobalAmbientModule(d) && (!isExternalModuleAugmentation(d) || !isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(d.name))), + d => isNonGlobalAmbientModule(d) + && (!isExternalModuleAugmentation(d) + || !isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(d.name))), ) as (ModuleDeclaration & { name: StringLiteral; }) | undefined; if (decl) { return decl.name.text; @@ -551,13 +733,16 @@ namespace ts.moduleSpecifiers { const topNamespace = getTopNamespace(d); if ( !(topNamespace?.parent?.parent - && isModuleBlock(topNamespace.parent) && isAmbientModule(topNamespace.parent.parent) && isSourceFile(topNamespace.parent.parent.parent)) + && isModuleBlock(topNamespace.parent) && isAmbientModule(topNamespace.parent.parent) + && isSourceFile(topNamespace.parent.parent.parent)) ) return; - const exportAssignment = ((topNamespace.parent.parent.symbol.exports?.get("export=" as __String)?.valueDeclaration as ExportAssignment)?.expression as PropertyAccessExpression | Identifier); + const exportAssignment = ((topNamespace.parent.parent.symbol.exports?.get("export=" as __String) + ?.valueDeclaration as ExportAssignment)?.expression as PropertyAccessExpression | Identifier); if (!exportAssignment) return; const exportSymbol = checker.getSymbolAtLocation(exportAssignment); if (!exportSymbol) return; - const originalExportSymbol = exportSymbol?.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(exportSymbol) : exportSymbol; + const originalExportSymbol = exportSymbol?.flags & SymbolFlags.Alias + ? checker.getAliasedSymbol(exportSymbol) : exportSymbol; if (originalExportSymbol === d.symbol) return topNamespace.parent.parent; function getTopNamespace(namespaceDeclaration: ModuleDeclaration) { @@ -567,14 +752,23 @@ namespace ts.moduleSpecifiers { return namespaceDeclaration; } }); - const ambientModuleDeclare = ambientModuleDeclareCandidates[0] as (AmbientModuleDeclaration & { name: StringLiteral; }) | undefined; + const ambientModuleDeclare = ambientModuleDeclareCandidates[0] as + | (AmbientModuleDeclaration & { name: StringLiteral; }) + | undefined; if (ambientModuleDeclare) { return ambientModuleDeclare.name.text; } } - function getAllowedEndings(preferredEnding: Ending, compilerOptions: CompilerOptions, importMode: SourceFile["impliedNodeFormat"]) { - if (getEmitModuleResolutionKind(compilerOptions) >= ModuleResolutionKind.Node16 && importMode === ModuleKind.ESNext) { + function getAllowedEndings( + preferredEnding: Ending, + compilerOptions: CompilerOptions, + importMode: SourceFile["impliedNodeFormat"], + ) { + if ( + getEmitModuleResolutionKind(compilerOptions) >= ModuleResolutionKind.Node16 + && importMode === ModuleKind.ESNext + ) { return [Ending.JsExtension]; } switch (preferredEnding) { @@ -589,7 +783,13 @@ namespace ts.moduleSpecifiers { } } - function tryGetModuleNameFromPaths(relativeToBaseUrl: string, paths: MapLike, allowedEndings: Ending[], host: ModuleSpecifierResolutionHost, compilerOptions: CompilerOptions): string | undefined { + function tryGetModuleNameFromPaths( + relativeToBaseUrl: string, + paths: MapLike, + allowedEndings: Ending[], + host: ModuleSpecifierResolutionHost, + compilerOptions: CompilerOptions, + ): string | undefined { for (const key in paths) { for (const patternText of paths[key]) { const pattern = normalizePath(patternText); @@ -643,10 +843,10 @@ namespace ts.moduleSpecifiers { const suffix = pattern.substring(indexOfStar + 1); for (const { ending, value } of candidates) { if ( - value.length >= prefix.length + suffix.length && - startsWith(value, prefix) && - endsWith(value, suffix) && - validateEnding({ ending, value }) + value.length >= prefix.length + suffix.length + && startsWith(value, prefix) + && endsWith(value, suffix) + && validateEnding({ ending, value }) ) { const matchedStar = value.substring(prefix.length, value.length - suffix.length); return key.replace("*", matchedStar); @@ -654,8 +854,8 @@ namespace ts.moduleSpecifiers { } } else if ( - some(candidates, c => c.ending !== Ending.Minimal && pattern === c.value) || - some(candidates, c => c.ending === Ending.Minimal && pattern === c.value && validateEnding(c)) + some(candidates, c => c.ending !== Ending.Minimal && pattern === c.value) + || some(candidates, c => c.ending === Ending.Minimal && pattern === c.value && validateEnding(c)) ) { return key; } @@ -670,7 +870,8 @@ namespace ts.moduleSpecifiers { // `Ending.Index` result, which should already be in the list of candidates if `Minimal` was. (Note: the assumption here is // that every module resolution mode that supports dropping extensions also supports dropping `/index`. Like literally // everything else in this file, this logic needs to be updated if that's not true in some future module resolution mode.) - return ending !== Ending.Minimal || value === removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions, host); + return ending !== Ending.Minimal + || value === removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions, host); } } @@ -680,20 +881,45 @@ namespace ts.moduleSpecifiers { Pattern, } - function tryGetModuleNameFromExports(options: CompilerOptions, targetFilePath: string, packageDirectory: string, packageName: string, exports: unknown, conditions: string[], mode = MatchingMode.Exact): { moduleFileToTry: string; } | undefined { + function tryGetModuleNameFromExports( + options: CompilerOptions, + targetFilePath: string, + packageDirectory: string, + packageName: string, + exports: unknown, + conditions: string[], + mode = MatchingMode.Exact, + ): { moduleFileToTry: string; } | undefined { if (typeof exports === "string") { - const pathOrPattern = getNormalizedAbsolutePath(combinePaths(packageDirectory, exports), /*currentDirectory*/ undefined); - const extensionSwappedTarget = hasTSFileExtension(targetFilePath) ? removeFileExtension(targetFilePath) + tryGetJSExtensionForFile(targetFilePath, options) : undefined; + const pathOrPattern = getNormalizedAbsolutePath( + combinePaths(packageDirectory, exports), + /*currentDirectory*/ undefined, + ); + const extensionSwappedTarget = hasTSFileExtension(targetFilePath) + ? removeFileExtension(targetFilePath) + tryGetJSExtensionForFile(targetFilePath, options) : undefined; switch (mode) { case MatchingMode.Exact: - if (comparePaths(targetFilePath, pathOrPattern) === Comparison.EqualTo || (extensionSwappedTarget && comparePaths(extensionSwappedTarget, pathOrPattern) === Comparison.EqualTo)) { + if ( + comparePaths(targetFilePath, pathOrPattern) === Comparison.EqualTo + || (extensionSwappedTarget + && comparePaths(extensionSwappedTarget, pathOrPattern) === Comparison.EqualTo) + ) { return { moduleFileToTry: packageName }; } break; case MatchingMode.Directory: if (containsPath(pathOrPattern, targetFilePath)) { - const fragment = getRelativePathFromDirectory(pathOrPattern, targetFilePath, /*ignoreCase*/ false); - return { moduleFileToTry: getNormalizedAbsolutePath(combinePaths(combinePaths(packageName, exports), fragment), /*currentDirectory*/ undefined) }; + const fragment = getRelativePathFromDirectory( + pathOrPattern, + targetFilePath, + /*ignoreCase*/ false, + ); + return { + moduleFileToTry: getNormalizedAbsolutePath( + combinePaths(combinePaths(packageName, exports), fragment), + /*currentDirectory*/ undefined, + ), + }; } break; case MatchingMode.Pattern: @@ -701,18 +927,30 @@ namespace ts.moduleSpecifiers { const leadingSlice = pathOrPattern.slice(0, starPos); const trailingSlice = pathOrPattern.slice(starPos + 1); if (startsWith(targetFilePath, leadingSlice) && endsWith(targetFilePath, trailingSlice)) { - const starReplacement = targetFilePath.slice(leadingSlice.length, targetFilePath.length - trailingSlice.length); + const starReplacement = targetFilePath.slice( + leadingSlice.length, + targetFilePath.length - trailingSlice.length, + ); return { moduleFileToTry: packageName.replace("*", starReplacement) }; } - if (extensionSwappedTarget && startsWith(extensionSwappedTarget, leadingSlice) && endsWith(extensionSwappedTarget, trailingSlice)) { - const starReplacement = extensionSwappedTarget.slice(leadingSlice.length, extensionSwappedTarget.length - trailingSlice.length); + if ( + extensionSwappedTarget && startsWith(extensionSwappedTarget, leadingSlice) + && endsWith(extensionSwappedTarget, trailingSlice) + ) { + const starReplacement = extensionSwappedTarget.slice( + leadingSlice.length, + extensionSwappedTarget.length - trailingSlice.length, + ); return { moduleFileToTry: packageName.replace("*", starReplacement) }; } break; } } else if (Array.isArray(exports)) { - return forEach(exports, e => tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, packageName, e, conditions)); + return forEach( + exports, + e => tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, packageName, e, conditions), + ); } else if (typeof exports === "object" && exports !== null) { // eslint-disable-line no-null/no-null if (allKeysStartWithDot(exports as MapLike)) { @@ -722,19 +960,40 @@ namespace ts.moduleSpecifiers { // * pattern mappings (contains a *) // * exact mappings (no *, does not end with /) return forEach(getOwnKeys(exports as MapLike), k => { - const subPackageName = getNormalizedAbsolutePath(combinePaths(packageName, k), /*currentDirectory*/ undefined); + const subPackageName = getNormalizedAbsolutePath( + combinePaths(packageName, k), + /*currentDirectory*/ undefined, + ); const mode = endsWith(k, "/") ? MatchingMode.Directory : stringContains(k, "*") ? MatchingMode.Pattern : MatchingMode.Exact; - return tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, subPackageName, (exports as MapLike)[k], conditions, mode); + return tryGetModuleNameFromExports( + options, + targetFilePath, + packageDirectory, + subPackageName, + (exports as MapLike)[k], + conditions, + mode, + ); }); } else { // conditional mapping for (const key of getOwnKeys(exports as MapLike)) { - if (key === "default" || conditions.indexOf(key) >= 0 || isApplicableVersionedTypesKey(conditions, key)) { + if ( + key === "default" || conditions.indexOf(key) >= 0 + || isApplicableVersionedTypesKey(conditions, key) + ) { const subTarget = (exports as MapLike)[key]; - const result = tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, packageName, subTarget, conditions); + const result = tryGetModuleNameFromExports( + options, + targetFilePath, + packageDirectory, + packageName, + subTarget, + conditions, + ); if (result) { return result; } @@ -745,20 +1004,39 @@ namespace ts.moduleSpecifiers { return undefined; } - function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string, ending: Ending, compilerOptions: CompilerOptions): string | undefined { + function tryGetModuleNameFromRootDirs( + rootDirs: readonly string[], + moduleFileName: string, + sourceDirectory: string, + getCanonicalFileName: (file: string) => string, + ending: Ending, + compilerOptions: CompilerOptions, + ): string | undefined { const normalizedTargetPath = getPathRelativeToRootDirs(moduleFileName, rootDirs, getCanonicalFileName); if (normalizedTargetPath === undefined) { return undefined; } const normalizedSourcePath = getPathRelativeToRootDirs(sourceDirectory, rootDirs, getCanonicalFileName); - const relativePath = normalizedSourcePath !== undefined ? ensurePathIsNonModuleName(getRelativePathFromDirectory(normalizedSourcePath, normalizedTargetPath, getCanonicalFileName)) : normalizedTargetPath; + const relativePath = normalizedSourcePath !== undefined + ? ensurePathIsNonModuleName( + getRelativePathFromDirectory(normalizedSourcePath, normalizedTargetPath, getCanonicalFileName), + ) : normalizedTargetPath; return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs ? removeExtensionAndIndexPostFix(relativePath, ending, compilerOptions) : removeFileExtension(relativePath); } - function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCanonicalFileName, sourceDirectory }: Info, importingSourceFile: SourceFile, host: ModuleSpecifierResolutionHost, options: CompilerOptions, userPreferences: UserPreferences, packageNameOnly?: boolean, overrideMode?: ModuleKind.ESNext | ModuleKind.CommonJS): string | undefined { + function tryGetModuleNameAsNodeModule( + { path, isRedirect }: ModulePath, + { getCanonicalFileName, sourceDirectory }: Info, + importingSourceFile: SourceFile, + host: ModuleSpecifierResolutionHost, + options: CompilerOptions, + userPreferences: UserPreferences, + packageNameOnly?: boolean, + overrideMode?: ModuleKind.ESNext | ModuleKind.CommonJS, + ): string | undefined { if (!host.fileExists || !host.readFile) { return undefined; } @@ -777,7 +1055,8 @@ namespace ts.moduleSpecifiers { let moduleFileName: string | undefined; while (true) { // If the module could be imported by a directory name, use that directory's name - const { moduleFileToTry, packageRootPath, blockedByExports, verbatimFromExports } = tryDirectoryWithPackageJson(packageRootIndex); + const { moduleFileToTry, packageRootPath, blockedByExports, verbatimFromExports } = + tryDirectoryWithPackageJson(packageRootIndex); if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Classic) { if (blockedByExports) { return undefined; // File is under this package.json, but is not publicly exported - there's no way to name it via `node_modules` resolution @@ -809,8 +1088,14 @@ namespace ts.moduleSpecifiers { const globalTypingsCacheLocation = host.getGlobalTypingsCacheLocation && host.getGlobalTypingsCacheLocation(); // Get a path that's relative to node_modules or the importing file's path // if node_modules folder is in this folder or any of its parent folders, no need to keep it. - const pathToTopLevelNodeModules = getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex)); - if (!(startsWith(sourceDirectory, pathToTopLevelNodeModules) || globalTypingsCacheLocation && startsWith(getCanonicalFileName(globalTypingsCacheLocation), pathToTopLevelNodeModules))) { + const pathToTopLevelNodeModules = getCanonicalFileName( + moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex), + ); + if ( + !(startsWith(sourceDirectory, pathToTopLevelNodeModules) + || globalTypingsCacheLocation + && startsWith(getCanonicalFileName(globalTypingsCacheLocation), pathToTopLevelNodeModules)) + ) { return undefined; } @@ -818,26 +1103,46 @@ namespace ts.moduleSpecifiers { const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1); const packageName = getPackageNameFromTypesPackageName(nodeModulesDirectoryName); // For classic resolution, only allow importing from node_modules/@types, not other node_modules - return getEmitModuleResolutionKind(options) === ModuleResolutionKind.Classic && packageName === nodeModulesDirectoryName ? undefined : packageName; + return getEmitModuleResolutionKind(options) === ModuleResolutionKind.Classic + && packageName === nodeModulesDirectoryName ? undefined : packageName; - function tryDirectoryWithPackageJson(packageRootIndex: number): { moduleFileToTry: string; packageRootPath?: string; blockedByExports?: true; verbatimFromExports?: true; } { + function tryDirectoryWithPackageJson( + packageRootIndex: number, + ): { moduleFileToTry: string; packageRootPath?: string; blockedByExports?: true; verbatimFromExports?: true; } { const packageRootPath = path.substring(0, packageRootIndex); const packageJsonPath = combinePaths(packageRootPath, "package.json"); let moduleFileToTry = path; let maybeBlockedByTypesVersions = false; const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath); - if (typeof cachedPackageJson === "object" || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) { - const packageJsonContent = cachedPackageJson?.contents.packageJsonContent || JSON.parse(host.readFile!(packageJsonPath)!); + if ( + typeof cachedPackageJson === "object" + || cachedPackageJson === undefined && host.fileExists(packageJsonPath) + ) { + const packageJsonContent = cachedPackageJson?.contents.packageJsonContent + || JSON.parse(host.readFile!(packageJsonPath)!); const importMode = overrideMode || importingSourceFile.impliedNodeFormat; - if (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext) { + if ( + getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext + ) { const conditions = ["node", importMode === ModuleKind.ESNext ? "import" : "require", "types"]; const fromExports = packageJsonContent.exports && typeof packageJsonContent.name === "string" - ? tryGetModuleNameFromExports(options, path, packageRootPath, getPackageNameFromTypesPackageName(packageJsonContent.name), packageJsonContent.exports, conditions) + ? tryGetModuleNameFromExports( + options, + path, + packageRootPath, + getPackageNameFromTypesPackageName(packageJsonContent.name), + packageJsonContent.exports, + conditions, + ) : undefined; if (fromExports) { const withJsExtension = !hasTSFileExtension(fromExports.moduleFileToTry) ? fromExports - : { moduleFileToTry: removeFileExtension(fromExports.moduleFileToTry) + tryGetJSExtensionForFile(fromExports.moduleFileToTry, options) }; + : { + moduleFileToTry: removeFileExtension(fromExports.moduleFileToTry) + + tryGetJSExtensionForFile(fromExports.moduleFileToTry, options), + }; return { ...withJsExtension, verbatimFromExports: true }; } if (packageJsonContent.exports) { @@ -864,8 +1169,13 @@ namespace ts.moduleSpecifiers { } } // If the file is the main module, it can be imported by the package name - const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main || "index.js"; - if (isString(mainFileRelative) && !(maybeBlockedByTypesVersions && matchPatternOrExact(tryParsePatterns(versionPaths!.paths), mainFileRelative))) { + const mainFileRelative = packageJsonContent.typings || packageJsonContent.types + || packageJsonContent.main || "index.js"; + if ( + isString(mainFileRelative) + && !(maybeBlockedByTypesVersions + && matchPatternOrExact(tryParsePatterns(versionPaths!.paths), mainFileRelative)) + ) { // The 'main' file is also subject to mapping through typesVersions, and we couldn't come up with a path // explicitly through typesVersions, so if it matches a key in typesVersions now, it's not reachable. // (The only way this can happen is if some file in a package that's not resolvable from outside the @@ -873,7 +1183,10 @@ namespace ts.moduleSpecifiers { // happens very easily in fourslash tests though, since every test file listed gets included. See // importNameCodeFix_typesVersions.ts for an example.) const mainExportFile = toPath(mainFileRelative, packageRootPath, getCanonicalFileName); - if (removeFileExtension(mainExportFile) === removeFileExtension(getCanonicalFileName(moduleFileToTry))) { + if ( + removeFileExtension(mainExportFile) + === removeFileExtension(getCanonicalFileName(moduleFileToTry)) + ) { // ^ An arbitrary removal of file extension for this comparison is almost certainly wrong return { packageRootPath, moduleFileToTry }; } @@ -882,7 +1195,10 @@ namespace ts.moduleSpecifiers { else { // No package.json exists; an index.js will still resolve as the package name const fileName = getCanonicalFileName(moduleFileToTry.substring(parts.packageRootIndex + 1)); - if (fileName === "index.d.ts" || fileName === "index.js" || fileName === "index.ts" || fileName === "index.tsx") { + if ( + fileName === "index.d.ts" || fileName === "index.js" || fileName === "index.ts" + || fileName === "index.tsx" + ) { return { moduleFileToTry, packageRootPath }; } } @@ -893,7 +1209,13 @@ namespace ts.moduleSpecifiers { function tryGetAnyFileFromPath(host: ModuleSpecifierResolutionHost, path: string) { if (!host.fileExists) return; // We check all js, `node` and `json` extensions in addition to TS, since node module resolution would also choose those over the directory - const extensions = flatten(getSupportedExtensions({ allowJs: true }, [{ extension: "node", isMixedContent: false }, { extension: "json", isMixedContent: false, scriptKind: ScriptKind.JSON }])); + const extensions = flatten( + getSupportedExtensions({ allowJs: true }, [{ extension: "node", isMixedContent: false }, { + extension: "json", + isMixedContent: false, + scriptKind: ScriptKind.JSON, + }]), + ); for (const e of extensions) { const fullPath = path + e; if (host.fileExists(fullPath)) { @@ -902,18 +1224,29 @@ namespace ts.moduleSpecifiers { } } - function getPathRelativeToRootDirs(path: string, rootDirs: readonly string[], getCanonicalFileName: GetCanonicalFileName): string | undefined { + function getPathRelativeToRootDirs( + path: string, + rootDirs: readonly string[], + getCanonicalFileName: GetCanonicalFileName, + ): string | undefined { return firstDefined(rootDirs, rootDir => { const relativePath = getRelativePathIfInDirectory(path, rootDir, getCanonicalFileName); return relativePath !== undefined && isPathRelativeToParent(relativePath) ? undefined : relativePath; }); } - function removeExtensionAndIndexPostFix(fileName: string, ending: Ending, options: CompilerOptions, host?: ModuleSpecifierResolutionHost): string { + function removeExtensionAndIndexPostFix( + fileName: string, + ending: Ending, + options: CompilerOptions, + host?: ModuleSpecifierResolutionHost, + ): string { if (fileExtensionIsOneOf(fileName, [Extension.Json, Extension.Mjs, Extension.Cjs])) return fileName; const noExtension = removeFileExtension(fileName); if (fileName === noExtension) return fileName; - if (fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Dcts, Extension.Cts])) return noExtension + getJSExtensionForFile(fileName, options); + if (fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Dcts, Extension.Cts])) { + return noExtension + getJSExtensionForFile(fileName, options); + } switch (ending) { case Ending.Minimal: const withoutIndex = removeSuffix(noExtension, "/index"); @@ -933,7 +1266,8 @@ namespace ts.moduleSpecifiers { } function getJSExtensionForFile(fileName: string, options: CompilerOptions): Extension { - return tryGetJSExtensionForFile(fileName, options) ?? Debug.fail(`Extension ${extensionFromPath(fileName)} is unsupported:: FileName:: ${fileName}`); + return tryGetJSExtensionForFile(fileName, options) + ?? Debug.fail(`Extension ${extensionFromPath(fileName)} is unsupported:: FileName:: ${fileName}`); } export function tryGetJSExtensionForFile(fileName: string, options: CompilerOptions): Extension | undefined { @@ -961,8 +1295,18 @@ namespace ts.moduleSpecifiers { } } - function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined { - const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); + function getRelativePathIfInDirectory( + path: string, + directoryPath: string, + getCanonicalFileName: GetCanonicalFileName, + ): string | undefined { + const relativePath = getRelativePathToDirectoryOrUrl( + directoryPath, + path, + directoryPath, + getCanonicalFileName, + /*isAbsolutePathAnUrl*/ false, + ); return isRootedDiskPath(relativePath) ? undefined : relativePath; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f620a5b1c6c35..a28499b7bac98 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -25,11 +25,25 @@ namespace ts { */ /* @internal */ export const parseBaseNodeFactory: BaseNodeFactory = { - createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1), - createBaseIdentifierNode: kind => new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, -1, -1), - createBasePrivateIdentifierNode: kind => new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1), - createBaseTokenNode: kind => new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1), - createBaseNode: kind => new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1), + createBaseSourceFileNode: kind => + new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))( + kind, + -1, + -1, + ), + createBaseIdentifierNode: kind => + new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))( + kind, + -1, + -1, + ), + createBasePrivateIdentifierNode: kind => + new (PrivateIdentifierConstructor + || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1), + createBaseTokenNode: kind => + new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1), + createBaseNode: kind => + new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1), }; /* @internal */ @@ -39,7 +53,11 @@ namespace ts { return node && cbNode(node); } - function visitNodes(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray) => T | undefined) | undefined, nodes: NodeArray | undefined): T | undefined { + function visitNodes( + cbNode: (node: Node) => T, + cbNodes: ((node: NodeArray) => T | undefined) | undefined, + nodes: NodeArray | undefined, + ): T | undefined { if (nodes) { if (cbNodes) { return cbNodes(nodes); @@ -55,17 +73,17 @@ namespace ts { /*@internal*/ export function isJSDocLikeText(text: string, start: number) { - return text.charCodeAt(start + 1) === CharacterCodes.asterisk && - text.charCodeAt(start + 2) === CharacterCodes.asterisk && - text.charCodeAt(start + 3) !== CharacterCodes.slash; + return text.charCodeAt(start + 1) === CharacterCodes.asterisk + && text.charCodeAt(start + 2) === CharacterCodes.asterisk + && text.charCodeAt(start + 3) !== CharacterCodes.slash; } /*@internal*/ export function isFileProbablyExternalModule(sourceFile: SourceFile) { // Try to use the first top-level import/export when available, then // fall back to looking for an 'import.meta' somewhere in the tree if necessary. - return forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) || - getImportMetaIfNecessary(sourceFile); + return forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) + || getImportMetaIfNecessary(sourceFile); } function isAnExternalModuleIndicatorNode(node: Node) { @@ -77,9 +95,9 @@ namespace ts { } function getImportMetaIfNecessary(sourceFile: SourceFile) { - return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta ? - walkTreeForImportMeta(sourceFile) : - undefined; + return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta + ? walkTreeForImportMeta(sourceFile) + : undefined; } function walkTreeForImportMeta(node: Node): Node | undefined { @@ -92,558 +110,1003 @@ namespace ts { } function isImportMeta(node: Node): boolean { - return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta"; + return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword + && node.name.escapedText === "meta"; } - type ForEachChildFunction = (node: TNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined) => T | undefined; + type ForEachChildFunction = ( + node: TNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ) => T | undefined; type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction; }; const forEachChildTable: ForEachChildTable = { - [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName(node: QualifiedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.left) || - visitNode(cbNode, node.right); + [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName( + node: QualifiedName, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.left) + || visitNode(cbNode, node.right); }, - [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter(node: TypeParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.constraint) || - visitNode(cbNode, node.default) || - visitNode(cbNode, node.expression); + [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter( + node: TypeParameterDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.constraint) + || visitNode(cbNode, node.default) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment(node: ShorthandPropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.exclamationToken) || - visitNode(cbNode, node.equalsToken) || - visitNode(cbNode, node.objectAssignmentInitializer); + [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment( + node: ShorthandPropertyAssignment, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.exclamationToken) + || visitNode(cbNode, node.equalsToken) + || visitNode(cbNode, node.objectAssignmentInitializer); }, - [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment(node: SpreadAssignment, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment( + node: SpreadAssignment, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.Parameter]: function forEachChildInParameter(node: ParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.dotDotDotToken) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.initializer); + [SyntaxKind.Parameter]: function forEachChildInParameter( + node: ParameterDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.dotDotDotToken) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration(node: PropertyDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.exclamationToken) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.initializer); + [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration( + node: PropertyDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.exclamationToken) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature(node: PropertySignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.initializer); + [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature( + node: PropertySignature, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment(node: PropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.exclamationToken) || - visitNode(cbNode, node.initializer); + [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment( + node: PropertyAssignment, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.exclamationToken) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration(node: VariableDeclaration, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.exclamationToken) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.initializer); + [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration( + node: VariableDeclaration, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.exclamationToken) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.BindingElement]: function forEachChildInBindingElement(node: BindingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.dotDotDotToken) || - visitNode(cbNode, node.propertyName) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.initializer); + [SyntaxKind.BindingElement]: function forEachChildInBindingElement( + node: BindingElement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.dotDotDotToken) + || visitNode(cbNode, node.propertyName) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature(node: IndexSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature( + node: IndexSignatureDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.ConstructorType]: function forEachChildInConstructorType(node: ConstructorTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.ConstructorType]: function forEachChildInConstructorType( + node: ConstructorTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.FunctionType]: function forEachChildInFunctionType(node: FunctionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.FunctionType]: function forEachChildInFunctionType( + node: FunctionTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, [SyntaxKind.CallSignature]: forEachChildInCallOrConstructSignature, [SyntaxKind.ConstructSignature]: forEachChildInCallOrConstructSignature, - [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration(node: MethodDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.asteriskToken) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.exclamationToken) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration( + node: MethodDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.asteriskToken) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.exclamationToken) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature(node: MethodSignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature( + node: MethodSignature, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.Constructor]: function forEachChildInConstructor(node: ConstructorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.Constructor]: function forEachChildInConstructor( + node: ConstructorDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor(node: GetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor( + node: GetAccessorDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor(node: SetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor( + node: SetAccessorDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration(node: FunctionDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.asteriskToken) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration( + node: FunctionDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.asteriskToken) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression(node: FunctionExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.asteriskToken) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression( + node: FunctionExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.asteriskToken) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction(node: ArrowFunction, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.equalsGreaterThanToken) || - visitNode(cbNode, node.body); + [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction( + node: ArrowFunction, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.equalsGreaterThanToken) + || visitNode(cbNode, node.body); }, - [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.body); + [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration( + node: ClassStaticBlockDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.body); }, - [SyntaxKind.TypeReference]: function forEachChildInTypeReference(node: TypeReferenceNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.typeName) || - visitNodes(cbNode, cbNodes, node.typeArguments); + [SyntaxKind.TypeReference]: function forEachChildInTypeReference( + node: TypeReferenceNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.typeName) + || visitNodes(cbNode, cbNodes, node.typeArguments); }, - [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate(node: TypePredicateNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.assertsModifier) || - visitNode(cbNode, node.parameterName) || - visitNode(cbNode, node.type); + [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate( + node: TypePredicateNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.assertsModifier) + || visitNode(cbNode, node.parameterName) + || visitNode(cbNode, node.type); }, - [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery(node: TypeQueryNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.exprName) || - visitNodes(cbNode, cbNodes, node.typeArguments); + [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery( + node: TypeQueryNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.exprName) + || visitNodes(cbNode, cbNodes, node.typeArguments); }, - [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral(node: TypeLiteralNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral( + node: TypeLiteralNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.members); }, - [SyntaxKind.ArrayType]: function forEachChildInArrayType(node: ArrayTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ArrayType]: function forEachChildInArrayType( + node: ArrayTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.elementType); }, - [SyntaxKind.TupleType]: function forEachChildInTupleType(node: TupleTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.TupleType]: function forEachChildInTupleType( + node: TupleTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); }, [SyntaxKind.UnionType]: forEachChildInUnionOrIntersectionType, [SyntaxKind.IntersectionType]: forEachChildInUnionOrIntersectionType, - [SyntaxKind.ConditionalType]: function forEachChildInConditionalType(node: ConditionalTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.checkType) || - visitNode(cbNode, node.extendsType) || - visitNode(cbNode, node.trueType) || - visitNode(cbNode, node.falseType); + [SyntaxKind.ConditionalType]: function forEachChildInConditionalType( + node: ConditionalTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.checkType) + || visitNode(cbNode, node.extendsType) + || visitNode(cbNode, node.trueType) + || visitNode(cbNode, node.falseType); }, - [SyntaxKind.InferType]: function forEachChildInInferType(node: InferTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.InferType]: function forEachChildInInferType( + node: InferTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.typeParameter); }, - [SyntaxKind.ImportType]: function forEachChildInImportType(node: ImportTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.argument) || - visitNode(cbNode, node.assertions) || - visitNode(cbNode, node.qualifier) || - visitNodes(cbNode, cbNodes, node.typeArguments); + [SyntaxKind.ImportType]: function forEachChildInImportType( + node: ImportTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.argument) + || visitNode(cbNode, node.assertions) + || visitNode(cbNode, node.qualifier) + || visitNodes(cbNode, cbNodes, node.typeArguments); }, - [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer(node: ImportTypeAssertionContainer, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer( + node: ImportTypeAssertionContainer, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.assertClause); }, [SyntaxKind.ParenthesizedType]: forEachChildInParenthesizedTypeOrTypeOperator, [SyntaxKind.TypeOperator]: forEachChildInParenthesizedTypeOrTypeOperator, - [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType(node: IndexedAccessTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.objectType) || - visitNode(cbNode, node.indexType); + [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType( + node: IndexedAccessTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.objectType) + || visitNode(cbNode, node.indexType); }, - [SyntaxKind.MappedType]: function forEachChildInMappedType(node: MappedTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.readonlyToken) || - visitNode(cbNode, node.typeParameter) || - visitNode(cbNode, node.nameType) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.type) || - visitNodes(cbNode, cbNodes, node.members); + [SyntaxKind.MappedType]: function forEachChildInMappedType( + node: MappedTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.readonlyToken) + || visitNode(cbNode, node.typeParameter) + || visitNode(cbNode, node.nameType) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.type) + || visitNodes(cbNode, cbNodes, node.members); }, - [SyntaxKind.LiteralType]: function forEachChildInLiteralType(node: LiteralTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.LiteralType]: function forEachChildInLiteralType( + node: LiteralTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.literal); }, - [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember(node: NamedTupleMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.dotDotDotToken) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.type); + [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember( + node: NamedTupleMember, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.dotDotDotToken) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.type); }, [SyntaxKind.ObjectBindingPattern]: forEachChildInObjectOrArrayBindingPattern, [SyntaxKind.ArrayBindingPattern]: forEachChildInObjectOrArrayBindingPattern, - [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression(node: ArrayLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression( + node: ArrayLiteralExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); }, - [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression(node: ObjectLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression( + node: ObjectLiteralExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.properties); }, - [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression(node: PropertyAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.questionDotToken) || - visitNode(cbNode, node.name); + [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression( + node: PropertyAccessExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.questionDotToken) + || visitNode(cbNode, node.name); }, - [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression(node: ElementAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.questionDotToken) || - visitNode(cbNode, node.argumentExpression); + [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression( + node: ElementAccessExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.questionDotToken) + || visitNode(cbNode, node.argumentExpression); }, [SyntaxKind.CallExpression]: forEachChildInCallOrNewExpression, [SyntaxKind.NewExpression]: forEachChildInCallOrNewExpression, - [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression(node: TaggedTemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tag) || - visitNode(cbNode, node.questionDotToken) || - visitNodes(cbNode, cbNodes, node.typeArguments) || - visitNode(cbNode, node.template); + [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression( + node: TaggedTemplateExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tag) + || visitNode(cbNode, node.questionDotToken) + || visitNodes(cbNode, cbNodes, node.typeArguments) + || visitNode(cbNode, node.template); }, - [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression(node: TypeAssertion, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.type) || - visitNode(cbNode, node.expression); + [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression( + node: TypeAssertion, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.type) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression(node: ParenthesizedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression( + node: ParenthesizedExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression(node: DeleteExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression( + node: DeleteExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression(node: TypeOfExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression( + node: TypeOfExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression(node: VoidExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression( + node: VoidExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression(node: PrefixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression( + node: PrefixUnaryExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.operand); }, - [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression(node: YieldExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.asteriskToken) || - visitNode(cbNode, node.expression); + [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression( + node: YieldExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.asteriskToken) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression(node: AwaitExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression( + node: AwaitExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression(node: PostfixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression( + node: PostfixUnaryExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.operand); }, - [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression(node: BinaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.left) || - visitNode(cbNode, node.operatorToken) || - visitNode(cbNode, node.right); + [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression( + node: BinaryExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.left) + || visitNode(cbNode, node.operatorToken) + || visitNode(cbNode, node.right); }, - [SyntaxKind.AsExpression]: function forEachChildInAsExpression(node: AsExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.type); + [SyntaxKind.AsExpression]: function forEachChildInAsExpression( + node: AsExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.type); }, - [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression(node: NonNullExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression( + node: NonNullExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression(node: SatisfiesExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression( + node: SatisfiesExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression) || visitNode(cbNode, node.type); }, - [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty(node: MetaProperty, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty( + node: MetaProperty, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.name); }, - [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression(node: ConditionalExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.condition) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.whenTrue) || - visitNode(cbNode, node.colonToken) || - visitNode(cbNode, node.whenFalse); + [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression( + node: ConditionalExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.condition) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.whenTrue) + || visitNode(cbNode, node.colonToken) + || visitNode(cbNode, node.whenFalse); }, - [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement(node: SpreadElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement( + node: SpreadElement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, [SyntaxKind.Block]: forEachChildInBlock, [SyntaxKind.ModuleBlock]: forEachChildInBlock, - [SyntaxKind.SourceFile]: function forEachChildInSourceFile(node: SourceFile, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.statements) || - visitNode(cbNode, node.endOfFileToken); + [SyntaxKind.SourceFile]: function forEachChildInSourceFile( + node: SourceFile, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.statements) + || visitNode(cbNode, node.endOfFileToken); }, - [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement(node: VariableStatement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.declarationList); + [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement( + node: VariableStatement, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.declarationList); }, - [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList(node: VariableDeclarationList, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList( + node: VariableDeclarationList, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.declarations); }, - [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement(node: ExpressionStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement( + node: ExpressionStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.IfStatement]: function forEachChildInIfStatement(node: IfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.thenStatement) || - visitNode(cbNode, node.elseStatement); + [SyntaxKind.IfStatement]: function forEachChildInIfStatement( + node: IfStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.thenStatement) + || visitNode(cbNode, node.elseStatement); }, - [SyntaxKind.DoStatement]: function forEachChildInDoStatement(node: DoStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.statement) || - visitNode(cbNode, node.expression); + [SyntaxKind.DoStatement]: function forEachChildInDoStatement( + node: DoStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.statement) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement(node: WhileStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.statement); + [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement( + node: WhileStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.ForStatement]: function forEachChildInForStatement(node: ForStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.initializer) || - visitNode(cbNode, node.condition) || - visitNode(cbNode, node.incrementor) || - visitNode(cbNode, node.statement); + [SyntaxKind.ForStatement]: function forEachChildInForStatement( + node: ForStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.initializer) + || visitNode(cbNode, node.condition) + || visitNode(cbNode, node.incrementor) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.ForInStatement]: function forEachChildInForInStatement(node: ForInStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.initializer) || - visitNode(cbNode, node.expression) || - visitNode(cbNode, node.statement); + [SyntaxKind.ForInStatement]: function forEachChildInForInStatement( + node: ForInStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.initializer) + || visitNode(cbNode, node.expression) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement(node: ForOfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.awaitModifier) || - visitNode(cbNode, node.initializer) || - visitNode(cbNode, node.expression) || - visitNode(cbNode, node.statement); + [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement( + node: ForOfStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.awaitModifier) + || visitNode(cbNode, node.initializer) + || visitNode(cbNode, node.expression) + || visitNode(cbNode, node.statement); }, [SyntaxKind.ContinueStatement]: forEachChildInContinueOrBreakStatement, [SyntaxKind.BreakStatement]: forEachChildInContinueOrBreakStatement, - [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement(node: ReturnStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement( + node: ReturnStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.WithStatement]: function forEachChildInWithStatement(node: WithStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.statement); + [SyntaxKind.WithStatement]: function forEachChildInWithStatement( + node: WithStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement(node: SwitchStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.caseBlock); + [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement( + node: SwitchStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.caseBlock); }, - [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock(node: CaseBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock( + node: CaseBlock, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.clauses); }, - [SyntaxKind.CaseClause]: function forEachChildInCaseClause(node: CaseClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNodes(cbNode, cbNodes, node.statements); + [SyntaxKind.CaseClause]: function forEachChildInCaseClause( + node: CaseClause, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNodes(cbNode, cbNodes, node.statements); }, - [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause(node: DefaultClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause( + node: DefaultClause, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.statements); }, - [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement(node: LabeledStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.label) || - visitNode(cbNode, node.statement); + [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement( + node: LabeledStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.label) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement(node: ThrowStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement( + node: ThrowStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.TryStatement]: function forEachChildInTryStatement(node: TryStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tryBlock) || - visitNode(cbNode, node.catchClause) || - visitNode(cbNode, node.finallyBlock); + [SyntaxKind.TryStatement]: function forEachChildInTryStatement( + node: TryStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tryBlock) + || visitNode(cbNode, node.catchClause) + || visitNode(cbNode, node.finallyBlock); }, - [SyntaxKind.CatchClause]: function forEachChildInCatchClause(node: CatchClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.variableDeclaration) || - visitNode(cbNode, node.block); + [SyntaxKind.CatchClause]: function forEachChildInCatchClause( + node: CatchClause, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.variableDeclaration) + || visitNode(cbNode, node.block); }, - [SyntaxKind.Decorator]: function forEachChildInDecorator(node: Decorator, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.Decorator]: function forEachChildInDecorator( + node: Decorator, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, [SyntaxKind.ClassDeclaration]: forEachChildInClassDeclarationOrExpression, [SyntaxKind.ClassExpression]: forEachChildInClassDeclarationOrExpression, - [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration(node: InterfaceDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.heritageClauses) || - visitNodes(cbNode, cbNodes, node.members); + [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration( + node: InterfaceDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.heritageClauses) + || visitNodes(cbNode, cbNodes, node.members); }, - [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration(node: TypeAliasDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNode(cbNode, node.type); + [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration( + node: TypeAliasDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration(node: EnumDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.members); + [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration( + node: EnumDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.members); }, - [SyntaxKind.EnumMember]: function forEachChildInEnumMember(node: EnumMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.initializer); + [SyntaxKind.EnumMember]: function forEachChildInEnumMember( + node: EnumMember, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.body); + [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration( + node: ModuleDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.body); }, - [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration(node: ImportEqualsDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.moduleReference); + [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration( + node: ImportEqualsDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.moduleReference); }, - [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration(node: ImportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.importClause) || - visitNode(cbNode, node.moduleSpecifier) || - visitNode(cbNode, node.assertClause); + [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration( + node: ImportDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.importClause) + || visitNode(cbNode, node.moduleSpecifier) + || visitNode(cbNode, node.assertClause); }, - [SyntaxKind.ImportClause]: function forEachChildInImportClause(node: ImportClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.namedBindings); + [SyntaxKind.ImportClause]: function forEachChildInImportClause( + node: ImportClause, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.namedBindings); }, - [SyntaxKind.AssertClause]: function forEachChildInAssertClause(node: AssertClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.AssertClause]: function forEachChildInAssertClause( + node: AssertClause, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); }, - [SyntaxKind.AssertEntry]: function forEachChildInAssertEntry(node: AssertEntry, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.value); + [SyntaxKind.AssertEntry]: function forEachChildInAssertEntry( + node: AssertEntry, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.value); }, - [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration(node: NamespaceExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNode(cbNode, node.name); + [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration( + node: NamespaceExportDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNode(cbNode, node.name); }, - [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport(node: NamespaceImport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport( + node: NamespaceImport, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.name); }, - [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport(node: NamespaceExport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport( + node: NamespaceExport, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.name); }, [SyntaxKind.NamedImports]: forEachChildInNamedImportsOrExports, [SyntaxKind.NamedExports]: forEachChildInNamedImportsOrExports, - [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration(node: ExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.exportClause) || - visitNode(cbNode, node.moduleSpecifier) || - visitNode(cbNode, node.assertClause); + [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration( + node: ExportDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.exportClause) + || visitNode(cbNode, node.moduleSpecifier) + || visitNode(cbNode, node.assertClause); }, [SyntaxKind.ImportSpecifier]: forEachChildInImportOrExportSpecifier, [SyntaxKind.ExportSpecifier]: forEachChildInImportOrExportSpecifier, - [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment(node: ExportAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.expression); + [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment( + node: ExportAssignment, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression(node: TemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.head) || - visitNodes(cbNode, cbNodes, node.templateSpans); + [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression( + node: TemplateExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.head) + || visitNodes(cbNode, cbNodes, node.templateSpans); }, - [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan(node: TemplateSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.literal); + [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan( + node: TemplateSpan, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.literal); }, - [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType(node: TemplateLiteralTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.head) || - visitNodes(cbNode, cbNodes, node.templateSpans); + [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType( + node: TemplateLiteralTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.head) + || visitNodes(cbNode, cbNodes, node.templateSpans); }, - [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.type) || - visitNode(cbNode, node.literal); + [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan( + node: TemplateLiteralTypeSpan, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.type) + || visitNode(cbNode, node.literal); }, - [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName(node: ComputedPropertyName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName( + node: ComputedPropertyName, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause(node: HeritageClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause( + node: HeritageClause, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.types); }, - [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments(node: ExpressionWithTypeArguments, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNodes(cbNode, cbNodes, node.typeArguments); + [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments( + node: ExpressionWithTypeArguments, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNodes(cbNode, cbNodes, node.typeArguments); }, - [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference(node: ExternalModuleReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference( + node: ExternalModuleReference, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration(node: MissingDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.illegalDecorators) || - visitNodes(cbNode, cbNodes, node.modifiers); + [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration( + node: MissingDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.illegalDecorators) + || visitNodes(cbNode, cbNodes, node.modifiers); }, - [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression(node: CommaListExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression( + node: CommaListExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); }, - [SyntaxKind.JsxElement]: function forEachChildInJsxElement(node: JsxElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.openingElement) || - visitNodes(cbNode, cbNodes, node.children) || - visitNode(cbNode, node.closingElement); + [SyntaxKind.JsxElement]: function forEachChildInJsxElement( + node: JsxElement, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.openingElement) + || visitNodes(cbNode, cbNodes, node.children) + || visitNode(cbNode, node.closingElement); }, - [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment(node: JsxFragment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.openingFragment) || - visitNodes(cbNode, cbNodes, node.children) || - visitNode(cbNode, node.closingFragment); + [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment( + node: JsxFragment, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.openingFragment) + || visitNodes(cbNode, cbNodes, node.children) + || visitNode(cbNode, node.closingFragment); }, [SyntaxKind.JsxSelfClosingElement]: forEachChildInJsxOpeningOrSelfClosingElement, [SyntaxKind.JsxOpeningElement]: forEachChildInJsxOpeningOrSelfClosingElement, - [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes(node: JsxAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes( + node: JsxAttributes, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.properties); }, - [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute(node: JsxAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.initializer); + [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute( + node: JsxAttribute, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute(node: JsxSpreadAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute( + node: JsxSpreadAttribute, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression(node: JsxExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.dotDotDotToken) || - visitNode(cbNode, node.expression); + [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression( + node: JsxExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.dotDotDotToken) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement(node: JsxClosingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement( + node: JsxClosingElement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.tagName); }, [SyntaxKind.OptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, @@ -653,78 +1116,130 @@ namespace ts { [SyntaxKind.JSDocNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier, [SyntaxKind.JSDocOptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, [SyntaxKind.JSDocVariadicType]: forEachChildInOptionalRestOrJSDocParameterModifier, - [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType(node: JSDocFunctionType, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType( + node: JSDocFunctionType, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.JSDoc]: function forEachChildInJSDoc(node: JSDoc, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JSDoc]: function forEachChildInJSDoc( + node: JSDoc, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) || visitNodes(cbNode, cbNodes, node.tags); }, - [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag(node: JSDocSeeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.name) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag( + node: JSDocSeeTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.name) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference(node: JSDocNameReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference( + node: JSDocNameReference, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.name); }, - [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName(node: JSDocMemberName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.left) || - visitNode(cbNode, node.right); + [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName( + node: JSDocMemberName, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.left) + || visitNode(cbNode, node.right); }, [SyntaxKind.JSDocParameterTag]: forEachChildInJSDocParameterOrPropertyTag, [SyntaxKind.JSDocPropertyTag]: forEachChildInJSDocParameterOrPropertyTag, - [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag(node: JSDocAuthorTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag( + node: JSDocAuthorTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag(node: JSDocImplementsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.class) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag( + node: JSDocImplementsTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.class) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag(node: JSDocAugmentsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.class) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag( + node: JSDocAugmentsTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.class) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag(node: JSDocTemplateTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.constraint) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag( + node: JSDocTemplateTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.constraint) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag(node: JSDocTypedefTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - (node.typeExpression && - node.typeExpression.kind === SyntaxKind.JSDocTypeExpression - ? visitNode(cbNode, node.typeExpression) || - visitNode(cbNode, node.fullName) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) - : visitNode(cbNode, node.fullName) || - visitNode(cbNode, node.typeExpression) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))); + [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag( + node: JSDocTypedefTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || (node.typeExpression + && node.typeExpression.kind === SyntaxKind.JSDocTypeExpression + ? visitNode(cbNode, node.typeExpression) + || visitNode(cbNode, node.fullName) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) + : visitNode(cbNode, node.fullName) + || visitNode(cbNode, node.typeExpression) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))); }, - [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag(node: JSDocCallbackTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.fullName) || - visitNode(cbNode, node.typeExpression) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag( + node: JSDocCallbackTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.fullName) + || visitNode(cbNode, node.typeExpression) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, [SyntaxKind.JSDocReturnTag]: forEachChildInJSDocReturnTag, [SyntaxKind.JSDocTypeTag]: forEachChildInJSDocReturnTag, [SyntaxKind.JSDocThisTag]: forEachChildInJSDocReturnTag, [SyntaxKind.JSDocEnumTag]: forEachChildInJSDocReturnTag, - [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature(node: JSDocSignature, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return forEach(node.typeParameters, cbNode) || - forEach(node.parameters, cbNode) || - visitNode(cbNode, node.type); + [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature( + node: JSDocSignature, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return forEach(node.typeParameters, cbNode) + || forEach(node.parameters, cbNode) + || visitNode(cbNode, node.type); }, [SyntaxKind.JSDocLink]: forEachChildInJSDocLinkCodeOrPlain, [SyntaxKind.JSDocLinkCode]: forEachChildInJSDocLinkCodeOrPlain, [SyntaxKind.JSDocLinkPlain]: forEachChildInJSDocLinkCodeOrPlain, - [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral(node: JSDocTypeLiteral, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral( + node: JSDocTypeLiteral, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return forEach(node.jsDocPropertyTags, cbNode); }, [SyntaxKind.JSDocTag]: forEachChildInJSDocTag, @@ -740,91 +1255,174 @@ namespace ts { // shared - function forEachChildInCallOrConstructSignature(node: CallSignatureDeclaration | ConstructSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + function forEachChildInCallOrConstructSignature( + node: CallSignatureDeclaration | ConstructSignatureDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); } - function forEachChildInUnionOrIntersectionType(node: UnionTypeNode | IntersectionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInUnionOrIntersectionType( + node: UnionTypeNode | IntersectionTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.types); } - function forEachChildInParenthesizedTypeOrTypeOperator(node: ParenthesizedTypeNode | TypeOperatorNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInParenthesizedTypeOrTypeOperator( + node: ParenthesizedTypeNode | TypeOperatorNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.type); } - function forEachChildInObjectOrArrayBindingPattern(node: BindingPattern, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInObjectOrArrayBindingPattern( + node: BindingPattern, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); } - function forEachChildInCallOrNewExpression(node: CallExpression | NewExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || + function forEachChildInCallOrNewExpression( + node: CallExpression | NewExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) // TODO: should we separate these branches out? - visitNode(cbNode, (node as CallExpression).questionDotToken) || - visitNodes(cbNode, cbNodes, node.typeArguments) || - visitNodes(cbNode, cbNodes, node.arguments); + || visitNode(cbNode, (node as CallExpression).questionDotToken) + || visitNodes(cbNode, cbNodes, node.typeArguments) + || visitNodes(cbNode, cbNodes, node.arguments); } - function forEachChildInBlock(node: Block | ModuleBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInBlock( + node: Block | ModuleBlock, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.statements); } - function forEachChildInContinueOrBreakStatement(node: ContinueStatement | BreakStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInContinueOrBreakStatement( + node: ContinueStatement | BreakStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.label); } - function forEachChildInClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.heritageClauses) || - visitNodes(cbNode, cbNodes, node.members); + function forEachChildInClassDeclarationOrExpression( + node: ClassDeclaration | ClassExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.heritageClauses) + || visitNodes(cbNode, cbNodes, node.members); } - function forEachChildInNamedImportsOrExports(node: NamedImports | NamedExports, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInNamedImportsOrExports( + node: NamedImports | NamedExports, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); } - function forEachChildInImportOrExportSpecifier(node: ImportSpecifier | ExportSpecifier, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.propertyName) || - visitNode(cbNode, node.name); + function forEachChildInImportOrExportSpecifier( + node: ImportSpecifier | ExportSpecifier, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.propertyName) + || visitNode(cbNode, node.name); } - function forEachChildInJsxOpeningOrSelfClosingElement(node: JsxOpeningLikeElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNodes(cbNode, cbNodes, node.typeArguments) || - visitNode(cbNode, node.attributes); + function forEachChildInJsxOpeningOrSelfClosingElement( + node: JsxOpeningLikeElement, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNodes(cbNode, cbNodes, node.typeArguments) + || visitNode(cbNode, node.attributes); } - function forEachChildInOptionalRestOrJSDocParameterModifier(node: OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocNullableType | JSDocNonNullableType | JSDocOptionalType | JSDocVariadicType, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInOptionalRestOrJSDocParameterModifier( + node: + | OptionalTypeNode + | RestTypeNode + | JSDocTypeExpression + | JSDocNullableType + | JSDocNonNullableType + | JSDocOptionalType + | JSDocVariadicType, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.type); } - function forEachChildInJSDocParameterOrPropertyTag(node: JSDocParameterTag | JSDocPropertyTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - (node.isNameFirst + function forEachChildInJSDocParameterOrPropertyTag( + node: JSDocParameterTag | JSDocPropertyTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || (node.isNameFirst ? visitNode(cbNode, node.name) || visitNode(cbNode, node.typeExpression) - : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } - function forEachChildInJSDocReturnTag(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.typeExpression) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + function forEachChildInJSDocReturnTag( + node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.typeExpression) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } - function forEachChildInJSDocLinkCodeOrPlain(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInJSDocLinkCodeOrPlain( + node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.name); } - function forEachChildInJSDocTag(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInJSDocTag( + node: + | JSDocUnknownTag + | JSDocClassTag + | JSDocPublicTag + | JSDocPrivateTag + | JSDocProtectedTag + | JSDocReadonlyTag + | JSDocDeprecatedTag + | JSDocOverrideTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.tagName) || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } - function forEachChildInPartiallyEmittedExpression(node: PartiallyEmittedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + function forEachChildInPartiallyEmittedExpression( + node: PartiallyEmittedExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); } @@ -841,7 +1439,11 @@ namespace ts { * @remarks `forEachChild` must visit the children of a node in the order * that they appear in the source code. The language service depends on this property to locate nodes by position. */ - export function forEachChild(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + export function forEachChild( + node: Node, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { if (node === undefined || node.kind <= SyntaxKind.LastToken) { return; } @@ -863,7 +1465,11 @@ namespace ts { * @remarks Unlike `forEachChild`, `forEachChildRecursively` handles recursively invoking the traversal on each child node found, * and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure. */ - export function forEachChildRecursively(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray, parent: Node) => T | "skip" | undefined): T | undefined { + export function forEachChildRecursively( + rootNode: Node, + cbNode: (node: Node, parent: Node) => T | "skip" | undefined, + cbNodes?: (nodes: NodeArray, parent: Node) => T | "skip" | undefined, + ): T | undefined { const queue: (Node | NodeArray)[] = gatherPossibleChildren(rootNode); const parents: Node[] = []; // tracks parent references for elements in queue while (parents.length < queue.length) { @@ -934,7 +1540,13 @@ namespace ts { sourceFile.externalModuleIndicator = isFileProbablyExternalModule(sourceFile); } - export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind): SourceFile { + export function createSourceFile( + fileName: string, + sourceText: string, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + setParentNodes = false, + scriptKind?: ScriptKind, + ): SourceFile { tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true); performance.mark("beforeParse"); let result: SourceFile; @@ -944,16 +1556,33 @@ namespace ts { languageVersion, setExternalModuleIndicator: overrideSetExternalModuleIndicator, impliedNodeFormat: format, - } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions); + } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions + : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions); if (languageVersion === ScriptTarget.JSON) { - result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop); + result = Parser.parseSourceFile( + fileName, + sourceText, + languageVersion, + /*syntaxCursor*/ undefined, + setParentNodes, + ScriptKind.JSON, + noop, + ); } else { const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => { file.impliedNodeFormat = format; return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file); }; - result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator); + result = Parser.parseSourceFile( + fileName, + sourceText, + languageVersion, + /*syntaxCursor*/ undefined, + setParentNodes, + scriptKind, + setIndicator, + ); } perfLogger.logStopParseSourceFile(); @@ -990,8 +1619,18 @@ namespace ts { // from this SourceFile that are being held onto may change as a result (including // becoming detached from any SourceFile). It is recommended that this SourceFile not // be used once 'update' is called on it. - export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false): SourceFile { - const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); + export function updateSourceFile( + sourceFile: SourceFile, + newText: string, + textChangeRange: TextChangeRange, + aggressiveChecks = false, + ): SourceFile { + const newSourceFile = IncrementalParser.updateSourceFile( + sourceFile, + newText, + textChangeRange, + aggressiveChecks, + ); // Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import. // We will manually port the flag to the new source file. (newSourceFile as Mutable).flags |= sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags; @@ -1045,12 +1684,16 @@ namespace ts { const baseNodeFactory: BaseNodeFactory = { createBaseSourceFileNode: kind => countNode(new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0)), createBaseIdentifierNode: kind => countNode(new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), - createBasePrivateIdentifierNode: kind => countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), + createBasePrivateIdentifierNode: kind => + countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), createBaseTokenNode: kind => countNode(new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0)), createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0)), }; - const factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, baseNodeFactory); + const factory = createNodeFactory( + NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, + baseNodeFactory, + ); let fileName: string; let sourceFlags: NodeFlags; @@ -1152,11 +1795,26 @@ namespace ts { // attached to the EOF token. let parseErrorBeforeNextFinishedNode = false; - export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void): SourceFile { + export function parseSourceFile( + fileName: string, + sourceText: string, + languageVersion: ScriptTarget, + syntaxCursor: IncrementalParser.SyntaxCursor | undefined, + setParentNodes = false, + scriptKind?: ScriptKind, + setExternalModuleIndicatorOverride?: (file: SourceFile) => void, + ): SourceFile { scriptKind = ensureScriptKind(fileName, scriptKind); if (scriptKind === ScriptKind.JSON) { const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes); - convertToObjectWorker(result, result.statements[0]?.expression, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined); + convertToObjectWorker( + result, + result.statements[0]?.expression, + result.parseDiagnostics, + /*returnValue*/ false, + /*knownRootOptions*/ undefined, + /*jsonConversionNotifier*/ undefined, + ); result.referencedFiles = emptyArray; result.typeReferenceDirectives = emptyArray; result.libReferenceDirectives = emptyArray; @@ -1168,14 +1826,22 @@ namespace ts { initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind); - const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator); + const result = parseSourceFileWorker( + languageVersion, + setParentNodes, + scriptKind, + setExternalModuleIndicatorOverride || setExternalModuleIndicator, + ); clearState(); return result; } - export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined { + export function parseIsolatedEntityName( + content: string, + languageVersion: ScriptTarget, + ): EntityName | undefined { // Choice of `isDeclarationFile` should be arbitrary initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS); // Prime the scanner. @@ -1186,7 +1852,13 @@ namespace ts { return isInvalid ? entityName : undefined; } - export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile { + export function parseJsonText( + fileName: string, + sourceText: string, + languageVersion: ScriptTarget = ScriptTarget.ES2015, + syntaxCursor?: IncrementalParser.SyntaxCursor, + setParentNodes = false, + ): JsonSourceFile { initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON); sourceFlags = contextFlags; @@ -1214,7 +1886,11 @@ namespace ts { expression = parseTokenNode(); break; case SyntaxKind.MinusToken: - if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) { + if ( + lookAhead(() => + nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken + ) + ) { expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral; } else { @@ -1248,7 +1924,9 @@ namespace ts { } } - const expression = isArray(expressions) ? finishNode(factory.createArrayLiteralExpression(expressions), pos) : Debug.checkDefined(expressions); + const expression = isArray(expressions) + ? finishNode(factory.createArrayLiteralExpression(expressions), pos) + : Debug.checkDefined(expressions); const statement = factory.createExpressionStatement(expression) as JsonObjectExpressionStatement; finishNode(statement, pos); statements = createNodeArray([statement], pos); @@ -1256,7 +1934,16 @@ namespace ts { } // Set source file so that errors will be reported with this file name - const sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false, statements, endOfFileToken, sourceFlags, noop); + const sourceFile = createSourceFile( + fileName, + ScriptTarget.ES2015, + ScriptKind.JSON, + /*isDeclaration*/ false, + statements, + endOfFileToken, + sourceFlags, + noop, + ); if (setParentNodes) { fixupParentReferences(sourceFile); @@ -1275,7 +1962,13 @@ namespace ts { return result; } - function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind) { + function initializeState( + _fileName: string, + _sourceText: string, + _languageVersion: ScriptTarget, + _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, + _scriptKind: ScriptKind, + ) { NodeConstructor = objectAllocator.getNodeConstructor(); TokenConstructor = objectAllocator.getTokenConstructor(); IdentifierConstructor = objectAllocator.getIdentifierConstructor(); @@ -1340,7 +2033,12 @@ namespace ts { topLevel = true; } - function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile { + function parseSourceFileWorker( + languageVersion: ScriptTarget, + setParentNodes: boolean, + scriptKind: ScriptKind, + setExternalModuleIndicator: (file: SourceFile) => void, + ): SourceFile { const isDeclarationFile = isDeclarationFileName(fileName); if (isDeclarationFile) { contextFlags |= NodeFlags.Ambient; @@ -1355,7 +2053,16 @@ namespace ts { Debug.assert(token() === SyntaxKind.EndOfFileToken); const endOfFileToken = addJSDocComment(parseTokenNode()); - const sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile, statements, endOfFileToken, sourceFlags, setExternalModuleIndicator); + const sourceFile = createSourceFile( + fileName, + languageVersion, + scriptKind, + isDeclarationFile, + statements, + endOfFileToken, + sourceFlags, + setExternalModuleIndicator, + ); // A member of ReadonlyArray isn't assignable to a member of T[] (and prevents a direct cast) - but this is where we set up those members so they can be readonly in the future processCommentPragmas(sourceFile as {} as PragmaContext, sourceText); @@ -1388,7 +2095,10 @@ namespace ts { let hasDeprecatedTag = false; function addJSDocComment(node: T): T { Debug.assert(!node.jsDoc); // Should only be called once per node - const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos)); + const jsDoc = mapDefined( + getJSDocCommentRanges(node, sourceText), + comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos), + ); if (jsDoc.length) node.jsDoc = jsDoc; if (hasDeprecatedTag) { hasDeprecatedTag = false; @@ -1417,10 +2127,19 @@ namespace ts { pos = findNextStatementWithoutAwait(sourceFile.statements, start); // append all diagnostics associated with the copied range - const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); - const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= nextStatement.pos, diagnosticStart) : -1; + const diagnosticStart = findIndex( + savedParseDiagnostics, + diagnostic => diagnostic.start >= prevStatement.pos, + ); + const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => + diagnostic.start >= nextStatement.pos, diagnosticStart) : -1; if (diagnosticStart >= 0) { - addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart, diagnosticEnd >= 0 ? diagnosticEnd : undefined); + addRange( + parseDiagnostics, + savedParseDiagnostics, + diagnosticStart, + diagnosticEnd >= 0 ? diagnosticEnd : undefined, + ); } // reparse all statements between start and pos. We skip existing diagnostics for the same range and allow the parser to generate new ones. @@ -1464,14 +2183,20 @@ namespace ts { addRange(statements, sourceFile.statements, pos); // append all diagnostics associated with the copied range - const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); + const diagnosticStart = findIndex( + savedParseDiagnostics, + diagnostic => diagnostic.start >= prevStatement.pos, + ); if (diagnosticStart >= 0) { addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart); } } syntaxCursor = savedSyntaxCursor; - return factory.updateSourceFile(sourceFile, setTextRange(factory.createNodeArray(statements), sourceFile.statements)); + return factory.updateSourceFile( + sourceFile, + setTextRange(factory.createNodeArray(statements), sourceFile.statements), + ); function containsPossibleTopLevelAwait(node: Node) { return !(node.flags & NodeFlags.AwaitContext) @@ -1530,7 +2255,10 @@ namespace ts { setFields(sourceFile); // If we parsed this as an external module, it may contain top-level await - if (!isDeclarationFile && isExternalModule(sourceFile) && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait) { + if ( + !isDeclarationFile && isExternalModule(sourceFile) + && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait + ) { sourceFile = reparseTopLevelAwait(sourceFile); setFields(sourceFile); } @@ -1683,11 +2411,19 @@ namespace ts { return inContext(NodeFlags.AwaitContext); } - function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { + function parseErrorAtCurrentToken( + message: DiagnosticMessage, + arg0?: any, + ): DiagnosticWithDetachedLocation | undefined { return parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0); } - function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { + function parseErrorAtPosition( + start: number, + length: number, + message: DiagnosticMessage, + arg0?: any, + ): DiagnosticWithDetachedLocation | undefined { // Don't report another error if it would just be at the same position as the last error. const lastError = lastOrUndefined(parseDiagnostics); let result: DiagnosticWithDetachedLocation | undefined; @@ -1702,7 +2438,12 @@ namespace ts { return result; } - function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { + function parseErrorAt( + start: number, + end: number, + message: DiagnosticMessage, + arg0?: any, + ): DiagnosticWithDetachedLocation | undefined { return parseErrorAtPosition(start, end - start, message, arg0); } @@ -1745,7 +2486,11 @@ namespace ts { // if the keyword had an escape if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) { // issue a parse error for the escape - parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), Diagnostics.Keywords_cannot_contain_escape_characters); + parseErrorAt( + scanner.getTokenPos(), + scanner.getTextPos(), + Diagnostics.Keywords_cannot_contain_escape_characters, + ); } return nextTokenWithoutCheck(); } @@ -1903,7 +2648,11 @@ namespace ts { // module `M1` { // ^^^^^^^^^^^ This block is parsed as a template literal like module`M1`. if (isTaggedTemplateExpression(node)) { - parseErrorAt(skipTrivia(sourceText, node.template.pos), node.template.end, Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings); + parseErrorAt( + skipTrivia(sourceText, node.template.pos), + node.template.end, + Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings, + ); return; } @@ -1929,25 +2678,42 @@ namespace ts { return; case "interface": - parseErrorForInvalidName(Diagnostics.Interface_name_cannot_be_0, Diagnostics.Interface_must_be_given_a_name, SyntaxKind.OpenBraceToken); + parseErrorForInvalidName( + Diagnostics.Interface_name_cannot_be_0, + Diagnostics.Interface_must_be_given_a_name, + SyntaxKind.OpenBraceToken, + ); return; case "is": - parseErrorAt(pos, scanner.getTextPos(), Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); + parseErrorAt( + pos, + scanner.getTextPos(), + Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods, + ); return; case "module": case "namespace": - parseErrorForInvalidName(Diagnostics.Namespace_name_cannot_be_0, Diagnostics.Namespace_must_be_given_a_name, SyntaxKind.OpenBraceToken); + parseErrorForInvalidName( + Diagnostics.Namespace_name_cannot_be_0, + Diagnostics.Namespace_must_be_given_a_name, + SyntaxKind.OpenBraceToken, + ); return; case "type": - parseErrorForInvalidName(Diagnostics.Type_alias_name_cannot_be_0, Diagnostics.Type_alias_must_be_given_a_name, SyntaxKind.EqualsToken); + parseErrorForInvalidName( + Diagnostics.Type_alias_name_cannot_be_0, + Diagnostics.Type_alias_must_be_given_a_name, + SyntaxKind.EqualsToken, + ); return; } // The user alternatively might have misspelled or forgotten to add a space after a common keyword. - const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) ?? getSpaceSuggestion(expressionText); + const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) + ?? getSpaceSuggestion(expressionText); if (suggestion) { parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion); return; @@ -1969,7 +2735,11 @@ namespace ts { * @param nameDiagnostic Diagnostic to report for all other cases. * @param tokenIfBlankName Current token if the name was invalid for being blank (not provided / skipped). */ - function parseErrorForInvalidName(nameDiagnostic: DiagnosticMessage, blankDiagnostic: DiagnosticMessage, tokenIfBlankName: SyntaxKind) { + function parseErrorForInvalidName( + nameDiagnostic: DiagnosticMessage, + blankDiagnostic: DiagnosticMessage, + tokenIfBlankName: SyntaxKind, + ) { if (token() === tokenIfBlankName) { parseErrorAtCurrentToken(blankDiagnostic); } @@ -1988,9 +2758,15 @@ namespace ts { return undefined; } - function parseSemicolonAfterPropertyName(name: PropertyName, type: TypeNode | undefined, initializer: Expression | undefined) { + function parseSemicolonAfterPropertyName( + name: PropertyName, + type: TypeNode | undefined, + initializer: Expression | undefined, + ) { if (token() === SyntaxKind.AtToken && !scanner.hasPrecedingLineBreak()) { - parseErrorAtCurrentToken(Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations); + parseErrorAtCurrentToken( + Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations, + ); return; } @@ -2031,7 +2807,12 @@ namespace ts { return false; } - function parseExpectedMatchingBrackets(openKind: SyntaxKind, closeKind: SyntaxKind, openParsed: boolean, openPosition: number) { + function parseExpectedMatchingBrackets( + openKind: SyntaxKind, + closeKind: SyntaxKind, + openParsed: boolean, + openPosition: number, + ) { if (token() === closeKind) { nextToken(); return; @@ -2043,7 +2824,14 @@ namespace ts { if (lastError) { addRelatedInfo( lastError, - createDetachedDiagnostic(fileName, openPosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, tokenToString(openKind), tokenToString(closeKind)), + createDetachedDiagnostic( + fileName, + openPosition, + 1, + Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, + tokenToString(openKind), + tokenToString(closeKind), + ), ); } } @@ -2072,16 +2860,25 @@ namespace ts { return undefined; } - function parseExpectedToken(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token; + function parseExpectedToken( + t: TKind, + diagnosticMessage?: DiagnosticMessage, + arg0?: any, + ): Token; function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node { - return parseOptionalToken(t) || - createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)); + return parseOptionalToken(t) + || createMissingNode( + t, + /*reportAtCurrentPosition*/ false, + diagnosticMessage || Diagnostics._0_expected, + arg0 || tokenToString(t), + ); } function parseExpectedTokenJSDoc(t: TKind): Token; function parseExpectedTokenJSDoc(t: JSDocSyntaxKind): Node { - return parseOptionalTokenJSDoc(t) || - createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t)); + return parseOptionalTokenJSDoc(t) + || createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t)); } function parseTokenNode(): T { @@ -2105,7 +2902,8 @@ namespace ts { } // We can parse out an optional semicolon in ASI cases in the following cases. - return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); + return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken + || scanner.hasPrecedingLineBreak(); } function tryParseSemicolon() { @@ -2125,7 +2923,12 @@ namespace ts { return tryParseSemicolon() || parseExpected(SyntaxKind.SemicolonToken); } - function createNodeArray(elements: T[], pos: number, end?: number, hasTrailingComma?: boolean): NodeArray { + function createNodeArray( + elements: T[], + pos: number, + end?: number, + hasTrailingComma?: boolean, + ): NodeArray { const array = factory.createNodeArray(elements, hasTrailingComma); setTextRangePosEnd(array, pos, end ?? scanner.getStartPos()); return array; @@ -2148,9 +2951,24 @@ namespace ts { return node; } - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, arg0?: any): T; - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T; - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T { + function createMissingNode( + kind: T["kind"], + reportAtCurrentPosition: false, + diagnosticMessage?: DiagnosticMessage, + arg0?: any, + ): T; + function createMissingNode( + kind: T["kind"], + reportAtCurrentPosition: boolean, + diagnosticMessage: DiagnosticMessage, + arg0?: any, + ): T; + function createMissingNode( + kind: T["kind"], + reportAtCurrentPosition: boolean, + diagnosticMessage: DiagnosticMessage, + arg0?: any, + ): T { if (reportAtCurrentPosition) { parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0); } @@ -2159,12 +2977,15 @@ namespace ts { } const pos = getNodePos(); - const result = kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*typeArguments*/ undefined, /*originalKeywordKind*/ undefined) : - isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) : - kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral("", /*numericLiteralFlags*/ undefined) : - kind === SyntaxKind.StringLiteral ? factory.createStringLiteral("", /*isSingleQuote*/ undefined) : - kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() : - factory.createToken(kind); + const result = kind === SyntaxKind.Identifier + ? factory.createIdentifier("", /*typeArguments*/ undefined, /*originalKeywordKind*/ undefined) + : isTemplateLiteralKind(kind) + ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) + : kind === SyntaxKind.NumericLiteral + ? factory.createNumericLiteral("", /*numericLiteralFlags*/ undefined) + : kind === SyntaxKind.StringLiteral ? factory.createStringLiteral("", /*isSingleQuote*/ undefined) + : kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() + : factory.createToken(kind); return finishNode(result, pos) as T; } @@ -2179,7 +3000,11 @@ namespace ts { // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for // each identifier in order to reduce memory consumption. - function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { + function createIdentifier( + isIdentifier: boolean, + diagnosticMessage?: DiagnosticMessage, + privateIdentifierDiagnosticMessage?: DiagnosticMessage, + ): Identifier { if (isIdentifier) { identifierCount++; const pos = getNodePos(); @@ -2188,15 +3013,29 @@ namespace ts { const text = internIdentifier(scanner.getTokenValue()); const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape(); nextTokenWithoutCheck(); - return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind, hasExtendedUnicodeEscape), pos); + return finishNode( + factory.createIdentifier( + text, + /*typeArguments*/ undefined, + originalKeywordKind, + hasExtendedUnicodeEscape, + ), + pos, + ); } if (token() === SyntaxKind.PrivateIdentifier) { - parseErrorAtCurrentToken(privateIdentifierDiagnosticMessage || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); + parseErrorAtCurrentToken( + privateIdentifierDiagnosticMessage + || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies, + ); return createIdentifier(/*isIdentifier*/ true); } - if (token() === SyntaxKind.Unknown && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier)) { + if ( + token() === SyntaxKind.Unknown + && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier) + ) { // Scanner has already recorded an 'Invalid character' error, so no need to add another from the parser. return createIdentifier(/*isIdentifier*/ true); } @@ -2208,18 +3047,30 @@ namespace ts { const isReservedWord = scanner.isReservedWord(); const msgArg = scanner.getTokenText(); - const defaultMessage = isReservedWord ? - Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here : - Diagnostics.Identifier_expected; + const defaultMessage = isReservedWord + ? Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here + : Diagnostics.Identifier_expected; - return createMissingNode(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || defaultMessage, msgArg); + return createMissingNode( + SyntaxKind.Identifier, + reportAtCurrentPosition, + diagnosticMessage || defaultMessage, + msgArg, + ); } function parseBindingIdentifier(privateIdentifierDiagnosticMessage?: DiagnosticMessage) { - return createIdentifier(isBindingIdentifier(), /*diagnosticMessage*/ undefined, privateIdentifierDiagnosticMessage); + return createIdentifier( + isBindingIdentifier(), + /*diagnosticMessage*/ undefined, + privateIdentifierDiagnosticMessage, + ); } - function parseIdentifier(diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { + function parseIdentifier( + diagnosticMessage?: DiagnosticMessage, + privateIdentifierDiagnosticMessage?: DiagnosticMessage, + ): Identifier { return createIdentifier(isIdentifier(), diagnosticMessage, privateIdentifierDiagnosticMessage); } @@ -2228,14 +3079,14 @@ namespace ts { } function isLiteralPropertyName(): boolean { - return tokenIsIdentifierOrKeyword(token()) || - token() === SyntaxKind.StringLiteral || - token() === SyntaxKind.NumericLiteral; + return tokenIsIdentifierOrKeyword(token()) + || token() === SyntaxKind.StringLiteral + || token() === SyntaxKind.NumericLiteral; } function isAssertionKey(): boolean { - return tokenIsIdentifierOrKeyword(token()) || - token() === SyntaxKind.StringLiteral; + return tokenIsIdentifierOrKeyword(token()) + || token() === SyntaxKind.StringLiteral; } function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName { @@ -2351,10 +3202,10 @@ namespace ts { function nextTokenCanFollowDefaultKeyword(): boolean { nextToken(); - return token() === SyntaxKind.ClassKeyword || token() === SyntaxKind.FunctionKeyword || - token() === SyntaxKind.InterfaceKeyword || - (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) || - (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine)); + return token() === SyntaxKind.ClassKeyword || token() === SyntaxKind.FunctionKeyword + || token() === SyntaxKind.InterfaceKeyword + || (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) + || (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine)); } // True if positioned at the start of a list element @@ -2402,7 +3253,8 @@ namespace ts { case ParsingContext.RestProperties: return isLiteralPropertyName(); case ParsingContext.ObjectBindingElements: - return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); + return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken + || isLiteralPropertyName(); case ParsingContext.AssertEntries: return isAssertionKey(); case ParsingContext.HeritageClauseElement: @@ -2424,7 +3276,8 @@ namespace ts { case ParsingContext.VariableDeclarations: return isBindingIdentifierOrPrivateIdentifierOrPattern(); case ParsingContext.ArrayBindingElements: - return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern(); + return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken + || isBindingIdentifierOrPrivateIdentifierOrPattern(); case ParsingContext.TypeParameters: return token() === SyntaxKind.InKeyword || isIdentifier(); case ParsingContext.ArrayLiteralMembers: @@ -2468,7 +3321,8 @@ namespace ts { // extends {} implements const next = nextToken(); - return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; + return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken + || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; } return true; @@ -2491,8 +3345,8 @@ namespace ts { function isHeritageClauseExtendsOrImplementsKeyword(): boolean { if ( - token() === SyntaxKind.ImplementsKeyword || - token() === SyntaxKind.ExtendsKeyword + token() === SyntaxKind.ImplementsKeyword + || token() === SyntaxKind.ExtendsKeyword ) { return lookAhead(nextTokenIsStartOfExpression); } @@ -2529,14 +3383,18 @@ namespace ts { case ParsingContext.AssertEntries: return token() === SyntaxKind.CloseBraceToken; case ParsingContext.SwitchClauseStatements: - return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; + return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword + || token() === SyntaxKind.DefaultKeyword; case ParsingContext.HeritageClauseElement: - return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; + return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword + || token() === SyntaxKind.ImplementsKeyword; case ParsingContext.VariableDeclarations: return isVariableDeclaratorListTerminator(); case ParsingContext.TypeParameters: // Tokens other than '>' are here for better error recovery - return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; + return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken + || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword + || token() === SyntaxKind.ImplementsKeyword; case ParsingContext.ArgumentExpressions: // Tokens other than ')' are here for better error recovery return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken; @@ -2548,7 +3406,8 @@ namespace ts { case ParsingContext.Parameters: case ParsingContext.RestProperties: // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery - return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; + return token() === SyntaxKind.CloseParenToken + || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; case ParsingContext.TypeArguments: // All other tokens should cause the type-argument to terminate except comma token return token() !== SyntaxKind.CommaToken; @@ -2624,7 +3483,10 @@ namespace ts { return createNodeArray(list, listPos); } - function parseListElement(parsingContext: ParsingContext, parseElement: () => T): T { + function parseListElement( + parsingContext: ParsingContext, + parseElement: () => T, + ): T { const node = currentNode(parsingContext); if (node) { return consumeNode(node) as T; @@ -2804,8 +3666,8 @@ namespace ts { // may have a method calls "constructor(...)" and we must reparse that // into an actual .ConstructorDeclaration. const methodDeclaration = node as MethodDeclaration; - const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier && - methodDeclaration.name.originalKeywordKind === SyntaxKind.ConstructorKeyword; + const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier + && methodDeclaration.name.originalKeywordKind === SyntaxKind.ConstructorKeyword; return !nameIsConstructor; } @@ -2944,14 +3806,19 @@ namespace ts { case ParsingContext.TypeMembers: return parseErrorAtCurrentToken(Diagnostics.Property_or_signature_expected); case ParsingContext.ClassMembers: - return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected); + return parseErrorAtCurrentToken( + Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected, + ); case ParsingContext.EnumMembers: return parseErrorAtCurrentToken(Diagnostics.Enum_member_expected); case ParsingContext.HeritageClauseElement: return parseErrorAtCurrentToken(Diagnostics.Expression_expected); case ParsingContext.VariableDeclarations: return isKeyword(token()) - ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token())) + ? parseErrorAtCurrentToken( + Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, + tokenToString(token()), + ) : parseErrorAtCurrentToken(Diagnostics.Variable_declaration_expected); case ParsingContext.ObjectBindingElements: return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected); @@ -2967,7 +3834,10 @@ namespace ts { return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); case ParsingContext.Parameters: return isKeyword(token()) - ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token())) + ? parseErrorAtCurrentToken( + Diagnostics._0_is_not_allowed_as_a_parameter_name, + tokenToString(token()), + ) : parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); case ParsingContext.TypeParameters: return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected); @@ -2993,9 +3863,21 @@ namespace ts { } // Parses a comma-delimited list of elements - function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray; - function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray> | undefined; - function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray> | undefined { + function parseDelimitedList( + kind: ParsingContext, + parseElement: () => T, + considerSemicolonAsDelimiter?: boolean, + ): NodeArray; + function parseDelimitedList( + kind: ParsingContext, + parseElement: () => T, + considerSemicolonAsDelimiter?: boolean, + ): NodeArray> | undefined; + function parseDelimitedList( + kind: ParsingContext, + parseElement: () => T, + considerSemicolonAsDelimiter?: boolean, + ): NodeArray> | undefined { const saveParsingContext = parsingContext; parsingContext |= 1 << kind; const list: NonNullable[] = []; @@ -3032,7 +3914,10 @@ namespace ts { // parse errors. For example, this can happen when people do things like use // a semicolon to delimit object literal members. Note: we'll have already // reported an error when we called parseExpected above. - if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) { + if ( + considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken + && !scanner.hasPrecedingLineBreak() + ) { nextToken(); } if (startPos === scanner.getStartPos()) { @@ -3065,7 +3950,8 @@ namespace ts { } function getExpectedCommaDiagnostic(kind: ParsingContext) { - return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or : undefined; + return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or + : undefined; } interface MissingList extends NodeArray { @@ -3082,7 +3968,12 @@ namespace ts { return !!(arr as MissingList).isMissingList; } - function parseBracketedList(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray { + function parseBracketedList( + kind: ParsingContext, + parseElement: () => T, + open: SyntaxKind, + close: SyntaxKind, + ): NodeArray { if (parseExpected(open)) { const result = parseDelimitedList(kind, parseElement); parseExpected(close); @@ -3094,7 +3985,8 @@ namespace ts { function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { const pos = getNodePos(); - let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage); + let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) + : parseIdentifier(diagnosticMessage); let dotPos = getNodePos(); while (parseOptional(SyntaxKind.DotToken)) { if (token() === SyntaxKind.LessThanToken) { @@ -3118,7 +4010,10 @@ namespace ts { return finishNode(factory.createQualifiedName(entity, name), entity.pos); } - function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean): Identifier | PrivateIdentifier { + function parseRightSideOfDot( + allowIdentifierNames: boolean, + allowPrivateIdentifiers: boolean, + ): Identifier | PrivateIdentifier { // Technically a keyword is valid here as all identifiers and keywords are identifier names. // However, often we'll encounter this in error situations when the identifier or keyword // is actually starting another valid construct. @@ -3145,13 +4040,22 @@ namespace ts { // Report that we need an identifier. However, report it right after the dot, // and not on the next token. This is because the next token might actually // be an identifier and the error would be quite confusing. - return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); + return createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ true, + Diagnostics.Identifier_expected, + ); } } if (token() === SyntaxKind.PrivateIdentifier) { const node = parsePrivateIdentifier(); - return allowPrivateIdentifiers ? node : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); + return allowPrivateIdentifiers ? node + : createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ true, + Diagnostics.Identifier_expected, + ); } return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); @@ -3221,7 +4125,11 @@ namespace ts { } else { // TODO(rbuckton): Do we need to call `parseExpectedToken` or can we just call `createMissingNode` directly? - return parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)) as TemplateTail; + return parseExpectedToken( + SyntaxKind.TemplateTail, + Diagnostics._0_expected, + tokenToString(SyntaxKind.CloseBraceToken), + ) as TemplateTail; } } @@ -3251,7 +4159,10 @@ namespace ts { function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail { const fragment = parseLiteralLikeNode(token()); - Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind"); + Debug.assert( + fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, + "Template fragment has wrong token kind", + ); return fragment as TemplateMiddle | TemplateTail; } @@ -3263,17 +4174,29 @@ namespace ts { function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode { const pos = getNodePos(); - const node = isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, scanner.getTokenValue(), getTemplateLiteralRawText(kind), scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags) : + const node = isTemplateLiteralKind(kind) + ? factory.createTemplateLiteralLikeNode( + kind, + scanner.getTokenValue(), + getTemplateLiteralRawText(kind), + scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags, + ) // Octal literals are not allowed in strict mode or ES5 // Note that theoretically the following condition would hold true literals like 009, // which is not octal. But because of how the scanner separates the tokens, we would // never get a token like this. Instead, we would get 00 and 9 as two separate tokens. // We also do not need to check for negatives because any prefix operator would be part of a // parent unary expression. - kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) : - kind === SyntaxKind.StringLiteral ? factory.createStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape()) : - isLiteralKind(kind) ? factory.createLiteralLikeNode(kind, scanner.getTokenValue()) : - Debug.fail(); + : kind === SyntaxKind.NumericLiteral + ? factory.createNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) + : kind === SyntaxKind.StringLiteral + ? factory.createStringLiteral( + scanner.getTokenValue(), + /*isSingleQuote*/ undefined, + scanner.hasExtendedUnicodeEscape(), + ) + : isLiteralKind(kind) ? factory.createLiteralLikeNode(kind, scanner.getTokenValue()) + : Debug.fail(); if (scanner.hasExtendedUnicodeEscape()) { node.hasExtendedUnicodeEscape = true; @@ -3295,7 +4218,12 @@ namespace ts { function parseTypeArgumentsOfTypeReference() { if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) { - return parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + return parseBracketedList( + ParsingContext.TypeArguments, + parseType, + SyntaxKind.LessThanToken, + SyntaxKind.GreaterThanToken, + ); } } @@ -3329,7 +4257,10 @@ namespace ts { function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode { nextToken(); - return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, lhs, parseType()), lhs.pos); + return finishNode( + factory.createTypePredicateNode(/*assertsModifier*/ undefined, lhs, parseType()), + lhs.pos, + ); } function parseThisTypeNode(): ThisTypeNode { @@ -3366,12 +4297,12 @@ namespace ts { // Foo(?= // (?| if ( - token() === SyntaxKind.CommaToken || - token() === SyntaxKind.CloseBraceToken || - token() === SyntaxKind.CloseParenToken || - token() === SyntaxKind.GreaterThanToken || - token() === SyntaxKind.EqualsToken || - token() === SyntaxKind.BarToken + token() === SyntaxKind.CommaToken + || token() === SyntaxKind.CloseBraceToken + || token() === SyntaxKind.CloseParenToken + || token() === SyntaxKind.GreaterThanToken + || token() === SyntaxKind.EqualsToken + || token() === SyntaxKind.BarToken ) { return finishNode(factory.createJSDocUnknownType(), pos); } @@ -3492,16 +4423,21 @@ namespace ts { function parseTypeParameters(): NodeArray | undefined { if (token() === SyntaxKind.LessThanToken) { - return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + return parseBracketedList( + ParsingContext.TypeParameters, + parseTypeParameter, + SyntaxKind.LessThanToken, + SyntaxKind.GreaterThanToken, + ); } } function isStartOfParameter(isJSDocParameter: boolean): boolean { - return token() === SyntaxKind.DotDotDotToken || - isBindingIdentifierOrPrivateIdentifierOrPattern() || - isModifierKind(token()) || - token() === SyntaxKind.AtToken || - isStartOfType(/*inStartOfParameter*/ !isJSDocParameter); + return token() === SyntaxKind.DotDotDotToken + || isBindingIdentifierOrPrivateIdentifierOrPattern() + || isModifierKind(token()) + || token() === SyntaxKind.AtToken + || isStartOfType(/*inStartOfParameter*/ !isJSDocParameter); } function parseNameOfParameter(modifiers: NodeArray | undefined) { @@ -3526,7 +4462,8 @@ namespace ts { // Be permissive about await and yield by calling isBindingIdentifier instead of isIdentifier; disallowing // them during a speculative parse leads to many more follow-on errors than allowing the function to parse then later // complaining about the use of the keywords. - return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken; + return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken + || token() === SyntaxKind.OpenBraceToken; } function parseParameter(inOuterAwaitContext: boolean): ParameterDeclaration { @@ -3538,8 +4475,14 @@ namespace ts { } function parseParameterWorker(inOuterAwaitContext: boolean): ParameterDeclaration; - function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity: false): ParameterDeclaration | undefined; - function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity = true): ParameterDeclaration | undefined { + function parseParameterWorker( + inOuterAwaitContext: boolean, + allowAmbiguity: false, + ): ParameterDeclaration | undefined; + function parseParameterWorker( + inOuterAwaitContext: boolean, + allowAmbiguity = true, + ): ParameterDeclaration | undefined { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); @@ -3547,7 +4490,8 @@ namespace ts { // BindingElement[?Yield,?Await] // Decorators are parsed in the outer [Await] context, the rest of the parameter is parsed in the function's [Await] context. - const decorators = inOuterAwaitContext ? doInAwaitContext(parseDecorators) : doOutsideOfAwaitContext(parseDecorators); + const decorators = inOuterAwaitContext ? doInAwaitContext(parseDecorators) + : doOutsideOfAwaitContext(parseDecorators); if (token() === SyntaxKind.ThisKeyword) { const node = factory.createParameterDeclaration( @@ -3595,14 +4539,23 @@ namespace ts { } function parseReturnType(returnToken: SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode; - function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined; - function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) { + function parseReturnType( + returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, + isType: boolean, + ): TypeNode | undefined; + function parseReturnType( + returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, + isType: boolean, + ) { if (shouldParseReturnType(returnToken, isType)) { return allowConditionalTypesAnd(parseTypeOrTypePredicate); } } - function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean { + function shouldParseReturnType( + returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, + isType: boolean, + ): boolean { if (returnToken === SyntaxKind.EqualsGreaterThanToken) { parseExpected(returnToken); return true; @@ -3620,8 +4573,14 @@ namespace ts { } function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: true): NodeArray; - function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: false): NodeArray | undefined; - function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: boolean): NodeArray | undefined { + function parseParametersWorker( + flags: SignatureFlags, + allowAmbiguity: false, + ): NodeArray | undefined; + function parseParametersWorker( + flags: SignatureFlags, + allowAmbiguity: boolean, + ): NodeArray | undefined { // FormalParameters [Yield,Await]: (modified) // [empty] // FormalParameterList[?Yield,Await] @@ -3641,9 +4600,14 @@ namespace ts { setYieldContext(!!(flags & SignatureFlags.Yield)); setAwaitContext(!!(flags & SignatureFlags.Await)); - const parameters = flags & SignatureFlags.JSDoc ? - parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) : - parseDelimitedList(ParsingContext.Parameters, () => allowAmbiguity ? parseParameter(savedAwaitContext) : parseParameterForSpeculation(savedAwaitContext)); + const parameters = flags & SignatureFlags.JSDoc + ? parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) + : parseDelimitedList( + ParsingContext.Parameters, + () => + allowAmbiguity ? parseParameter(savedAwaitContext) + : parseParameterForSpeculation(savedAwaitContext), + ); setYieldContext(savedYieldContext); setAwaitContext(savedAwaitContext); @@ -3685,7 +4649,9 @@ namespace ts { parseSemicolon(); } - function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration { + function parseSignatureMember( + kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature, + ): CallSignatureDeclaration | ConstructSignatureDeclaration { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); if (kind === SyntaxKind.ConstructSignature) { @@ -3758,11 +4724,22 @@ namespace ts { // If any of the following tokens are after the question mark, it cannot // be a conditional expression, so treat it as an indexer. nextToken(); - return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken; + return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken + || token() === SyntaxKind.CloseBracketToken; } - function parseIndexSignatureDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): IndexSignatureDeclaration { - const parameters = parseBracketedList(ParsingContext.Parameters, () => parseParameter(/*inOuterAwaitContext*/ false), SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + function parseIndexSignatureDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): IndexSignatureDeclaration { + const parameters = parseBracketedList( + ParsingContext.Parameters, + () => parseParameter(/*inOuterAwaitContext*/ false), + SyntaxKind.OpenBracketToken, + SyntaxKind.CloseBracketToken, + ); const type = parseTypeAnnotation(); parseTypeMemberSemicolon(); const node = factory.createIndexSignature(modifiers, parameters, type); @@ -3770,7 +4747,11 @@ namespace ts { return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parsePropertyOrMethodSignature(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): PropertySignature | MethodSignature { + function parsePropertyOrMethodSignature( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): PropertySignature | MethodSignature { const name = parsePropertyName(); const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); let node: PropertySignature | MethodSignature; @@ -3788,7 +4769,9 @@ namespace ts { // Although type literal properties cannot not have initializers, we attempt // to parse an initializer so we can report in the checker that an interface // property or type literal property cannot have an initializer. - if (token() === SyntaxKind.EqualsToken) (node as Mutable).initializer = parseInitializer(); + if (token() === SyntaxKind.EqualsToken) { + (node as Mutable).initializer = parseInitializer(); + } } parseTypeMemberSemicolon(); return withJSDoc(finishNode(node, pos), hasJSDoc); @@ -3797,10 +4780,10 @@ namespace ts { function isTypeMemberStart(): boolean { // Return true if we have the start of a signature member if ( - token() === SyntaxKind.OpenParenToken || - token() === SyntaxKind.LessThanToken || - token() === SyntaxKind.GetKeyword || - token() === SyntaxKind.SetKeyword + token() === SyntaxKind.OpenParenToken + || token() === SyntaxKind.LessThanToken + || token() === SyntaxKind.GetKeyword + || token() === SyntaxKind.SetKeyword ) { return true; } @@ -3822,12 +4805,12 @@ namespace ts { // If we were able to get any potential identifier, check that it is // the start of a member declaration if (idToken) { - return token() === SyntaxKind.OpenParenToken || - token() === SyntaxKind.LessThanToken || - token() === SyntaxKind.QuestionToken || - token() === SyntaxKind.ColonToken || - token() === SyntaxKind.CommaToken || - canParseSemicolon(); + return token() === SyntaxKind.OpenParenToken + || token() === SyntaxKind.LessThanToken + || token() === SyntaxKind.QuestionToken + || token() === SyntaxKind.ColonToken + || token() === SyntaxKind.CommaToken + || canParseSemicolon(); } return false; } @@ -3843,11 +4826,25 @@ namespace ts { const hasJSDoc = hasPrecedingJSDocComment(); const modifiers = parseModifiers(); if (parseContextualModifier(SyntaxKind.GetKeyword)) { - return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.GetAccessor, SignatureFlags.Type); + return parseAccessorDeclaration( + pos, + hasJSDoc, + /*decorators*/ undefined, + modifiers, + SyntaxKind.GetAccessor, + SignatureFlags.Type, + ); } if (parseContextualModifier(SyntaxKind.SetKeyword)) { - return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.SetAccessor, SignatureFlags.Type); + return parseAccessorDeclaration( + pos, + hasJSDoc, + /*decorators*/ undefined, + modifiers, + SyntaxKind.SetAccessor, + SignatureFlags.Type, + ); } if (isIndexSignature()) { @@ -3901,7 +4898,8 @@ namespace ts { if (token() === SyntaxKind.ReadonlyKeyword) { nextToken(); } - return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword; + return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() + && nextToken() === SyntaxKind.InKeyword; } function parseMappedTypeParameter() { @@ -3909,14 +4907,20 @@ namespace ts { const name = parseIdentifierName(); parseExpected(SyntaxKind.InKeyword); const type = parseType(); - return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos); + return finishNode( + factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), + pos, + ); } function parseMappedType() { const pos = getNodePos(); parseExpected(SyntaxKind.OpenBraceToken); let readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined; - if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { + if ( + token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken + || token() === SyntaxKind.MinusToken + ) { readonlyToken = parseTokenNode(); if (readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) { parseExpected(SyntaxKind.ReadonlyKeyword); @@ -3927,7 +4931,10 @@ namespace ts { const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined; parseExpected(SyntaxKind.CloseBracketToken); let questionToken: QuestionToken | PlusToken | MinusToken | undefined; - if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { + if ( + token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken + || token() === SyntaxKind.MinusToken + ) { questionToken = parseTokenNode(); if (questionToken.kind !== SyntaxKind.QuestionToken) { parseExpected(SyntaxKind.QuestionToken); @@ -3937,7 +4944,10 @@ namespace ts { parseSemicolon(); const members = parseList(ParsingContext.TypeMembers, parseTypeMember); parseExpected(SyntaxKind.CloseBraceToken); - return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), pos); + return finishNode( + factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), + pos, + ); } function parseTupleElementType() { @@ -3956,7 +4966,8 @@ namespace ts { } function isNextTokenColonOrQuestionColon() { - return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken); + return nextToken() === SyntaxKind.ColonToken + || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken); } function isTupleElementName() { @@ -3985,7 +4996,12 @@ namespace ts { const pos = getNodePos(); return finishNode( factory.createTupleTypeNode( - parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken), + parseBracketedList( + ParsingContext.TupleElementTypes, + parseTupleElementNameOrTupleElementType, + SyntaxKind.OpenBracketToken, + SyntaxKind.CloseBracketToken, + ), ), pos, ); @@ -4035,9 +5051,11 @@ namespace ts { if (negative) { nextToken(); } - let expression: BooleanLiteral | NullLiteral | LiteralExpression | PrefixUnaryExpression = token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword || token() === SyntaxKind.NullKeyword ? - parseTokenNode() : - parseLiteralLikeNode(token()) as LiteralExpression; + let expression: BooleanLiteral | NullLiteral | LiteralExpression | PrefixUnaryExpression = + token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword + || token() === SyntaxKind.NullKeyword + ? parseTokenNode() + : parseLiteralLikeNode(token()) as LiteralExpression; if (negative) { expression = finishNode(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, expression), pos); } @@ -4062,7 +5080,14 @@ namespace ts { if (lastError && lastError.code === Diagnostics._0_expected.code) { addRelatedInfo( lastError, - createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}"), + createDetachedDiagnostic( + fileName, + openBracePosition, + 1, + Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, + "{", + "}", + ), ); } } @@ -4130,7 +5155,8 @@ namespace ts { case SyntaxKind.NullKeyword: return parseLiteralTypeNode(); case SyntaxKind.MinusToken: - return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference(); + return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) + : parseTypeReference(); case SyntaxKind.VoidKeyword: return parseTokenNode(); case SyntaxKind.ThisKeyword: { @@ -4153,7 +5179,8 @@ namespace ts { case SyntaxKind.ImportKeyword: return parseImportType(); case SyntaxKind.AssertsKeyword: - return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference(); + return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() + : parseTypeReference(); case SyntaxKind.TemplateHead: return parseTemplateType(); default: @@ -4215,7 +5242,8 @@ namespace ts { function isStartOfParenthesizedOrFunctionType() { nextToken(); - return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType(); + return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) + || isStartOfType(); } function parsePostfixTypeOrHigher(): TypeNode { @@ -4254,7 +5282,9 @@ namespace ts { return type; } - function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) { + function parseTypeOperator( + operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, + ) { const pos = getNodePos(); parseExpected(operator); return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos); @@ -4342,11 +5372,19 @@ namespace ts { } function parseIntersectionTypeOrHigher(): TypeNode { - return parseUnionOrIntersectionType(SyntaxKind.AmpersandToken, parseTypeOperatorOrHigher, factory.createIntersectionTypeNode); + return parseUnionOrIntersectionType( + SyntaxKind.AmpersandToken, + parseTypeOperatorOrHigher, + factory.createIntersectionTypeNode, + ); } function parseUnionTypeOrHigher(): TypeNode { - return parseUnionOrIntersectionType(SyntaxKind.BarToken, parseIntersectionTypeOrHigher, factory.createUnionTypeNode); + return parseUnionOrIntersectionType( + SyntaxKind.BarToken, + parseIntersectionTypeOrHigher, + factory.createUnionTypeNode, + ); } function nextTokenIsNewKeyword(): boolean { @@ -4361,8 +5399,8 @@ namespace ts { if (token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType)) { return true; } - return token() === SyntaxKind.NewKeyword || - token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword); + return token() === SyntaxKind.NewKeyword + || token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword); } function skipParameterStart(): boolean { @@ -4394,8 +5432,8 @@ namespace ts { // We successfully skipped modifiers (if any) and an identifier or binding pattern, // now see if we have something that indicates a parameter declaration if ( - token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || - token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken + token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken + || token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken ) { // ( xxx : // ( xxx , @@ -4419,7 +5457,10 @@ namespace ts { const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix); const type = parseType(); if (typePredicateVariable) { - return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), pos); + return finishNode( + factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), + pos, + ); } else { return type; @@ -4452,7 +5493,10 @@ namespace ts { } const pos = getNodePos(); const type = parseUnionTypeOrHigher(); - if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { + if ( + !inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() + && parseOptional(SyntaxKind.ExtendsKeyword) + ) { // The type following 'extends' is not permitted to be another conditional type const extendsType = disallowConditionalTypesAnd(parseType); parseExpected(SyntaxKind.QuestionToken); @@ -4536,11 +5580,11 @@ namespace ts { function isStartOfExpressionStatement(): boolean { // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement. - return token() !== SyntaxKind.OpenBraceToken && - token() !== SyntaxKind.FunctionKeyword && - token() !== SyntaxKind.ClassKeyword && - token() !== SyntaxKind.AtToken && - isStartOfExpression(); + return token() !== SyntaxKind.OpenBraceToken + && token() !== SyntaxKind.FunctionKeyword + && token() !== SyntaxKind.ClassKeyword + && token() !== SyntaxKind.AtToken + && isStartOfExpression(); } function parseExpression(): Expression { @@ -4558,7 +5602,12 @@ namespace ts { let expr = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); let operatorToken: BinaryOperatorToken; while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) { - expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), pos); + expr = makeBinaryExpression( + expr, + operatorToken, + parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), + pos, + ); } if (saveDecoratorContext) { @@ -4568,7 +5617,8 @@ namespace ts { } function parseInitializer(): Expression | undefined { - return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined; + return parseOptional(SyntaxKind.EqualsToken) + ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined; } function parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction: boolean): Expression { @@ -4599,7 +5649,8 @@ namespace ts { // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done // with AssignmentExpression if we see one. - const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction); + const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) + || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction); if (arrowExpression) { return arrowExpression; } @@ -4620,7 +5671,12 @@ namespace ts { // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single // identifier and the current token is an arrow. if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { - return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, /*asyncModifier*/ undefined); + return parseSimpleArrowFunctionExpression( + pos, + expr as Identifier, + allowReturnTypeInArrowFunction, + /*asyncModifier*/ undefined, + ); } // Now see if we might be in cases '2' or '3'. @@ -4630,7 +5686,12 @@ namespace ts { // Note: we call reScanGreaterToken so that we get an appropriately merged token // for cases like `> > =` becoming `>>=` if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) { - return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), pos); + return makeBinaryExpression( + expr, + parseTokenNode(), + parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), + pos, + ); } // It wasn't an assignment or a lambda. This is a conditional expression: @@ -4680,8 +5741,8 @@ namespace ts { nextToken(); if ( - !scanner.hasPrecedingLineBreak() && - (token() === SyntaxKind.AsteriskToken || isStartOfExpression()) + !scanner.hasPrecedingLineBreak() + && (token() === SyntaxKind.AsteriskToken || isStartOfExpression()) ) { return finishNode( factory.createYieldExpression( @@ -4694,12 +5755,23 @@ namespace ts { else { // if the next token is not on the same line as yield. or we don't have an '*' or // the start of an expression, then this is just a simple "yield" expression. - return finishNode(factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), pos); + return finishNode( + factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), + pos, + ); } } - function parseSimpleArrowFunctionExpression(pos: number, identifier: Identifier, allowReturnTypeInArrowFunction: boolean, asyncModifier?: NodeArray | undefined): ArrowFunction { - Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); + function parseSimpleArrowFunctionExpression( + pos: number, + identifier: Identifier, + allowReturnTypeInArrowFunction: boolean, + asyncModifier?: NodeArray | undefined, + ): ArrowFunction { + Debug.assert( + token() === SyntaxKind.EqualsGreaterThanToken, + "parseSimpleArrowFunctionExpression should only have been called if we had a =>", + ); const parameter = factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, @@ -4713,11 +5785,20 @@ namespace ts { const parameters = createNodeArray([parameter], parameter.pos, parameter.end); const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); const body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier, allowReturnTypeInArrowFunction); - const node = factory.createArrowFunction(asyncModifier, /*typeParameters*/ undefined, parameters, /*type*/ undefined, equalsGreaterThanToken, body); + const node = factory.createArrowFunction( + asyncModifier, + /*typeParameters*/ undefined, + parameters, + /*type*/ undefined, + equalsGreaterThanToken, + body, + ); return addJSDocComment(finishNode(node, pos)); } - function tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): Expression | undefined { + function tryParseParenthesizedArrowFunctionExpression( + allowReturnTypeInArrowFunction: boolean, + ): Expression | undefined { const triState = isParenthesizedArrowFunctionExpression(); if (triState === Tristate.False) { // It's definitely not a parenthesized arrow function expression. @@ -4728,9 +5809,12 @@ namespace ts { // following => or { token. Otherwise, we *might* have an arrow function. Try to parse // it out, but don't allow any ambiguity, and return 'undefined' if this could be an // expression instead. - return triState === Tristate.True ? - parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, /*allowReturnTypeInArrowFunction*/ true) : - tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction)); + return triState === Tristate.True + ? parseParenthesizedArrowFunctionExpression( + /*allowAmbiguity*/ true, + /*allowReturnTypeInArrowFunction*/ true, + ) + : tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction)); } // True -> We definitely expect a parenthesized arrow function here. @@ -4738,7 +5822,10 @@ namespace ts { // Unknown -> There *might* be a parenthesized arrow function here. // Speculatively look ahead to be sure, and rollback if not. function isParenthesizedArrowFunctionExpression(): Tristate { - if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) { + if ( + token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken + || token() === SyntaxKind.AsyncKeyword + ) { return lookAhead(isParenthesizedArrowFunctionExpressionWorker); } @@ -4825,7 +5912,10 @@ namespace ts { case SyntaxKind.QuestionToken: nextToken(); // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda. - if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) { + if ( + token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken + || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken + ) { return Tristate.True; } // Otherwise it is definitely not a lambda. @@ -4880,13 +5970,18 @@ namespace ts { } } - function parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { + function parsePossibleParenthesizedArrowFunctionExpression( + allowReturnTypeInArrowFunction: boolean, + ): ArrowFunction | undefined { const tokenPos = scanner.getTokenPos(); if (notParenthesizedArrow?.has(tokenPos)) { return undefined; } - const result = parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ false, allowReturnTypeInArrowFunction); + const result = parseParenthesizedArrowFunctionExpression( + /*allowAmbiguity*/ false, + allowReturnTypeInArrowFunction, + ); if (!result) { (notParenthesizedArrow || (notParenthesizedArrow = new Set())).add(tokenPos); } @@ -4894,14 +5989,21 @@ namespace ts { return result; } - function tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { + function tryParseAsyncSimpleArrowFunctionExpression( + allowReturnTypeInArrowFunction: boolean, + ): ArrowFunction | undefined { // We do a check here so that we won't be doing unnecessarily call to "lookAhead" if (token() === SyntaxKind.AsyncKeyword) { if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) { const pos = getNodePos(); const asyncModifier = parseModifiersForArrowFunction(); const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); - return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, asyncModifier); + return parseSimpleArrowFunctionExpression( + pos, + expr as Identifier, + allowReturnTypeInArrowFunction, + asyncModifier, + ); } } return undefined; @@ -4920,7 +6022,10 @@ namespace ts { } // Check for un-parenthesized AsyncArrowFunction const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); - if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { + if ( + !scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier + && token() === SyntaxKind.EqualsGreaterThanToken + ) { return Tristate.True; } } @@ -4928,7 +6033,10 @@ namespace ts { return Tristate.False; } - function parseParenthesizedArrowFunctionExpression(allowAmbiguity: boolean, allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { + function parseParenthesizedArrowFunctionExpression( + allowAmbiguity: boolean, + allowReturnTypeInArrowFunction: boolean, + ): ArrowFunction | undefined { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); const modifiers = parseModifiersForArrowFunction(); @@ -4988,7 +6096,10 @@ namespace ts { } const hasJSDocFunctionType = unwrappedType && isJSDocFunctionType(unwrappedType); - if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) { + if ( + !allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken + && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken) + ) { // Returning undefined here will cause our caller to rewind to where we started from. return undefined; } @@ -5027,21 +6138,31 @@ namespace ts { } } - const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body); + const node = factory.createArrowFunction( + modifiers, + typeParameters, + parameters, + type, + equalsGreaterThanToken, + body, + ); return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseArrowFunctionExpressionBody(isAsync: boolean, allowReturnTypeInArrowFunction: boolean): Block | Expression { + function parseArrowFunctionExpressionBody( + isAsync: boolean, + allowReturnTypeInArrowFunction: boolean, + ): Block | Expression { if (token() === SyntaxKind.OpenBraceToken) { return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None); } if ( - token() !== SyntaxKind.SemicolonToken && - token() !== SyntaxKind.FunctionKeyword && - token() !== SyntaxKind.ClassKeyword && - isStartOfStatement() && - !isStartOfExpressionStatement() + token() !== SyntaxKind.SemicolonToken + && token() !== SyntaxKind.FunctionKeyword + && token() !== SyntaxKind.ClassKeyword + && isStartOfStatement() + && !isStartOfExpressionStatement() ) { // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations) // @@ -5057,7 +6178,9 @@ namespace ts { // up preemptively closing the containing construct. // // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error. - return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None)); + return parseFunctionBlock( + SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None), + ); } const savedTopLevel = topLevel; @@ -5069,7 +6192,11 @@ namespace ts { return node; } - function parseConditionalExpressionRest(leftOperand: Expression, pos: number, allowReturnTypeInArrowFunction: boolean): Expression { + function parseConditionalExpressionRest( + leftOperand: Expression, + pos: number, + allowReturnTypeInArrowFunction: boolean, + ): Expression { // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); if (!questionToken) { @@ -5083,11 +6210,19 @@ namespace ts { factory.createConditionalExpression( leftOperand, questionToken, - doOutsideOfContext(disallowInAndDecoratorContext, () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false)), + doOutsideOfContext( + disallowInAndDecoratorContext, + () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false), + ), colonToken = parseExpectedToken(SyntaxKind.ColonToken), nodeIsPresent(colonToken) ? parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction) - : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)), + : createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ false, + Diagnostics._0_expected, + tokenToString(SyntaxKind.ColonToken), + ), ), pos, ); @@ -5103,7 +6238,11 @@ namespace ts { return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword; } - function parseBinaryExpressionRest(precedence: OperatorPrecedence, leftOperand: Expression, pos: number): Expression { + function parseBinaryExpressionRest( + precedence: OperatorPrecedence, + leftOperand: Expression, + pos: number, + ): Expression { while (true) { // We either have a binary operator here, or we're finished. We call // reScanGreaterToken so that we merge token sequences like > and = into >= @@ -5132,9 +6271,9 @@ namespace ts { // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand // a ** b - c // ^token; leftOperand = b. Return b to the caller as a rightOperand - const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ? - newPrecedence >= precedence : - newPrecedence > precedence; + const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken + ? newPrecedence >= precedence + : newPrecedence > precedence; if (!consumeCurrentOperator) { break; @@ -5156,12 +6295,18 @@ namespace ts { else { const keywordKind = token(); nextToken(); - leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword ? makeSatisfiesExpression(leftOperand, parseType()) : - makeAsExpression(leftOperand, parseType()); + leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword + ? makeSatisfiesExpression(leftOperand, parseType()) + : makeAsExpression(leftOperand, parseType()); } } else { - leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence), pos); + leftOperand = makeBinaryExpression( + leftOperand, + parseTokenNode(), + parseBinaryExpressionOrHigher(newPrecedence), + pos, + ); } } @@ -5180,7 +6325,12 @@ namespace ts { return finishNode(factory.createSatisfiesExpression(left, right), left.pos); } - function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, pos: number): BinaryExpression { + function makeBinaryExpression( + left: Expression, + operatorToken: BinaryOperatorToken, + right: Expression, + pos: number, + ): BinaryExpression { return finishNode(factory.createBinaryExpression(left, operatorToken, right), pos); } @@ -5190,7 +6340,13 @@ namespace ts { function parsePrefixUnaryExpression() { const pos = getNodePos(); - return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseSimpleUnaryExpression)), pos); + return finishNode( + factory.createPrefixUnaryExpression( + token() as PrefixUnaryOperator, + nextTokenAnd(parseSimpleUnaryExpression), + ), + pos, + ); } function parseDeleteExpression() { @@ -5245,9 +6401,13 @@ namespace ts { if (isUpdateExpression()) { const pos = getNodePos(); const updateExpression = parseUpdateExpression(); - return token() === SyntaxKind.AsteriskAsteriskToken ? - parseBinaryExpressionRest(getBinaryOperatorPrecedence(token()), updateExpression, pos) as BinaryExpression : - updateExpression; + return token() === SyntaxKind.AsteriskAsteriskToken + ? parseBinaryExpressionRest( + getBinaryOperatorPrecedence(token()), + updateExpression, + pos, + ) as BinaryExpression + : updateExpression; } /** @@ -5267,10 +6427,21 @@ namespace ts { const pos = skipTrivia(sourceText, simpleUnaryExpression.pos); const { end } = simpleUnaryExpression; if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) { - parseErrorAt(pos, end, Diagnostics.A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses); + parseErrorAt( + pos, + end, + Diagnostics + .A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, + ); } else { - parseErrorAt(pos, end, Diagnostics.An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, tokenToString(unaryOperator)); + parseErrorAt( + pos, + end, + Diagnostics + .An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, + tokenToString(unaryOperator), + ); } } return simpleUnaryExpression; @@ -5367,9 +6538,18 @@ namespace ts { function parseUpdateExpression(): UpdateExpression { if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) { const pos = getNodePos(); - return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseLeftHandSideExpressionOrHigher)), pos); + return finishNode( + factory.createPrefixUnaryExpression( + token() as PrefixUnaryOperator, + nextTokenAnd(parseLeftHandSideExpressionOrHigher), + ), + pos, + ); } - else if (languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) { + else if ( + languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken + && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan) + ) { // JSXElement is part of primaryExpression return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); } @@ -5377,7 +6557,10 @@ namespace ts { const expression = parseLeftHandSideExpressionOrHigher(); Debug.assert(isLeftHandSideExpression(expression)); - if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { + if ( + (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) + && !scanner.hasPrecedingLineBreak() + ) { const operator = token() as PostfixUnaryOperator; nextToken(); return finishNode(factory.createPostfixUnaryExpression(expression, operator), expression.pos); @@ -5434,7 +6617,10 @@ namespace ts { // This is an 'import.*' metaproperty (i.e. 'import.meta') nextToken(); // advance past the 'import' nextToken(); // advance past the dot - expression = finishNode(factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), pos); + expression = finishNode( + factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), + pos, + ); sourceFlags |= NodeFlags.PossiblyContainsImportMeta; } else { @@ -5442,7 +6628,8 @@ namespace ts { } } else { - expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher(); + expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() + : parseMemberExpressionOrHigher(); } // Now, we *may* be complete. However, we might have consumed the start of a @@ -5518,18 +6705,34 @@ namespace ts { } } - if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) { + if ( + token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken + || token() === SyntaxKind.OpenBracketToken + ) { return expression; } // If we have seen "super" it must be followed by '(' or '.'. // If it wasn't then just try to parse out a '.' and report an error. - parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); + parseExpectedToken( + SyntaxKind.DotToken, + Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access, + ); // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic - return finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true)), pos); + return finishNode( + factory.createPropertyAccessExpression( + expression, + parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true), + ), + pos, + ); } - function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment): JsxElement | JsxSelfClosingElement | JsxFragment { + function parseJsxElementOrSelfClosingElementOrFragment( + inExpressionContext: boolean, + topInvalidNodePosition?: number, + openingTag?: JsxOpeningElement | JsxOpeningFragment, + ): JsxElement | JsxSelfClosingElement | JsxFragment { const pos = getNodePos(); const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); let result: JsxElement | JsxSelfClosingElement | JsxFragment; @@ -5551,7 +6754,11 @@ namespace ts { factory.createJsxElement( lastChild.openingElement, lastChild.children, - finishNode(factory.createJsxClosingElement(finishNode(factory.createIdentifier(""), end, end)), end, end), + finishNode( + factory.createJsxClosingElement(finishNode(factory.createIdentifier(""), end, end)), + end, + end, + ), ), lastChild.openingElement.pos, end, @@ -5563,20 +6770,38 @@ namespace ts { else { closingElement = parseJsxClosingElement(opening, inExpressionContext); if (!tagNamesAreEquivalent(opening.tagName, closingElement.tagName)) { - if (openingTag && isJsxOpeningElement(openingTag) && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName)) { + if ( + openingTag && isJsxOpeningElement(openingTag) + && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName) + ) { // opening incorrectly matched with its parent's closing -- put error on opening - parseErrorAtRange(opening.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, opening.tagName)); + parseErrorAtRange( + opening.tagName, + Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, + getTextOfNodeFromSourceText(sourceText, opening.tagName), + ); } else { // other opening/closing mismatches -- put error on closing - parseErrorAtRange(closingElement.tagName, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, opening.tagName)); + parseErrorAtRange( + closingElement.tagName, + Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, + getTextOfNodeFromSourceText(sourceText, opening.tagName), + ); } } } result = finishNode(factory.createJsxElement(opening, children, closingElement), pos); } else if (opening.kind === SyntaxKind.JsxOpeningFragment) { - result = finishNode(factory.createJsxFragment(opening, parseJsxChildren(opening), parseJsxClosingFragment(inExpressionContext)), pos); + result = finishNode( + factory.createJsxFragment( + opening, + parseJsxChildren(opening), + parseJsxClosingFragment(inExpressionContext), + ), + pos, + ); } else { Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement); @@ -5593,12 +6818,25 @@ namespace ts { // of one sort or another. if (inExpressionContext && token() === SyntaxKind.LessThanToken) { const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition; - const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos)); + const invalidElement = tryParse(() => + parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos) + ); if (invalidElement) { const operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false); setTextRangePosWidth(operatorToken, invalidElement.pos, 0); - parseErrorAt(skipTrivia(sourceText, topBadPos), invalidElement.end, Diagnostics.JSX_expressions_must_have_one_parent_element); - return finishNode(factory.createBinaryExpression(result, operatorToken as Token, invalidElement), pos) as Node as JsxElement; + parseErrorAt( + skipTrivia(sourceText, topBadPos), + invalidElement.end, + Diagnostics.JSX_expressions_must_have_one_parent_element, + ); + return finishNode( + factory.createBinaryExpression( + result, + operatorToken as Token, + invalidElement, + ), + pos, + ) as Node as JsxElement; } } @@ -5607,12 +6845,18 @@ namespace ts { function parseJsxText(): JsxText { const pos = getNodePos(); - const node = factory.createJsxText(scanner.getTokenValue(), currentToken === SyntaxKind.JsxTextAllWhiteSpaces); + const node = factory.createJsxText( + scanner.getTokenValue(), + currentToken === SyntaxKind.JsxTextAllWhiteSpaces, + ); currentToken = scanner.scanJsxToken(); return finishNode(node, pos); } - function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined { + function parseJsxChild( + openingTag: JsxOpeningElement | JsxOpeningFragment, + token: JsxTokenSyntaxKind, + ): JsxChild | undefined { switch (token) { case SyntaxKind.EndOfFileToken: // If we hit EOF, issue the error at the tag that lacks the closing element @@ -5625,7 +6869,12 @@ namespace ts { // or to cover only 'Foo' in < Foo > const tag = openingTag.tagName; const start = skipTrivia(sourceText, tag.pos); - parseErrorAt(start, tag.end, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName)); + parseErrorAt( + start, + tag.end, + Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, + getTextOfNodeFromSourceText(sourceText, openingTag.tagName), + ); } return undefined; case SyntaxKind.LessThanSlashToken: @@ -5637,7 +6886,11 @@ namespace ts { case SyntaxKind.OpenBraceToken: return parseJsxExpression(/*inExpressionContext*/ false); case SyntaxKind.LessThanToken: - return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false, /*topInvalidNodePosition*/ undefined, openingTag); + return parseJsxElementOrSelfClosingElementOrFragment( + /*inExpressionContext*/ false, + /*topInvalidNodePosition*/ undefined, + openingTag, + ); default: return Debug.assertNever(token); } @@ -5670,10 +6923,15 @@ namespace ts { function parseJsxAttributes(): JsxAttributes { const pos = getNodePos(); - return finishNode(factory.createJsxAttributes(parseList(ParsingContext.JsxAttributes, parseJsxAttribute)), pos); + return finishNode( + factory.createJsxAttributes(parseList(ParsingContext.JsxAttributes, parseJsxAttribute)), + pos, + ); } - function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { + function parseJsxOpeningOrSelfClosingElementOrOpeningFragment( + inExpressionContext: boolean, + ): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { const pos = getNodePos(); parseExpected(SyntaxKind.LessThanToken); @@ -5721,10 +6979,16 @@ namespace ts { // primaryExpression in the form of an identifier and "this" keyword // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword // We only want to consider "this" as a primaryExpression - let expression: JsxTagNameExpression = token() === SyntaxKind.ThisKeyword ? - parseTokenNode() : parseIdentifierName(); + let expression: JsxTagNameExpression = token() === SyntaxKind.ThisKeyword + ? parseTokenNode() : parseIdentifierName(); while (parseOptional(SyntaxKind.DotToken)) { - expression = finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false)), pos) as JsxTagNamePropertyAccess; + expression = finishNode( + factory.createPropertyAccessExpression( + expression, + parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false), + ), + pos, + ) as JsxTagNamePropertyAccess; } return expression; } @@ -5811,7 +7075,10 @@ namespace ts { const pos = getNodePos(); parseExpected(SyntaxKind.LessThanSlashToken); if (tokenIsIdentifierOrKeyword(token())) { - parseErrorAtRange(parseJsxElementName(), Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment); + parseErrorAtRange( + parseJsxElementName(), + Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment, + ); } if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { // manually advance the scanner in order to look for jsx text inside jsx @@ -5868,14 +7135,21 @@ namespace ts { return false; } - function parsePropertyAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { + function parsePropertyAccessExpressionRest( + pos: number, + expression: LeftHandSideExpression, + questionDotToken: QuestionDotToken | undefined, + ) { const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true); const isOptionalChain = questionDotToken || tryReparseOptionalChain(expression); - const propertyAccess = isOptionalChain ? - factory.createPropertyAccessChain(expression, questionDotToken, name) : - factory.createPropertyAccessExpression(expression, name); + const propertyAccess = isOptionalChain + ? factory.createPropertyAccessChain(expression, questionDotToken, name) + : factory.createPropertyAccessExpression(expression, name); if (isOptionalChain && isPrivateIdentifier(propertyAccess.name)) { - parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers); + parseErrorAtRange( + propertyAccess.name, + Diagnostics.An_optional_chain_cannot_contain_private_identifiers, + ); } if (isExpressionWithTypeArguments(expression) && expression.typeArguments) { const pos = expression.typeArguments.pos - 1; @@ -5885,10 +7159,18 @@ namespace ts { return finishNode(propertyAccess, pos); } - function parseElementAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { + function parseElementAccessExpressionRest( + pos: number, + expression: LeftHandSideExpression, + questionDotToken: QuestionDotToken | undefined, + ) { let argumentExpression: Expression; if (token() === SyntaxKind.CloseBracketToken) { - argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument); + argumentExpression = createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ true, + Diagnostics.An_element_access_expression_should_take_an_argument, + ); } else { const argument = allowInAnd(parseExpression); @@ -5900,13 +7182,17 @@ namespace ts { parseExpected(SyntaxKind.CloseBracketToken); - const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) ? - factory.createElementAccessChain(expression, questionDotToken, argumentExpression) : - factory.createElementAccessExpression(expression, argumentExpression); + const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) + ? factory.createElementAccessChain(expression, questionDotToken, argumentExpression) + : factory.createElementAccessExpression(expression, argumentExpression); return finishNode(indexedAccess, pos); } - function parseMemberExpressionRest(pos: number, expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression { + function parseMemberExpressionRest( + pos: number, + expression: LeftHandSideExpression, + allowOptionalChain: boolean, + ): MemberExpression { while (true) { let questionDotToken: QuestionDotToken | undefined; let isPropertyAccess = false; @@ -5931,9 +7217,14 @@ namespace ts { if (isTemplateStartOfTaggedTemplate()) { // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments - expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments ? - parseTaggedTemplateRest(pos, (expression as ExpressionWithTypeArguments).expression, questionDotToken, (expression as ExpressionWithTypeArguments).typeArguments) : - parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined); + expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments + ? parseTaggedTemplateRest( + pos, + (expression as ExpressionWithTypeArguments).expression, + questionDotToken, + (expression as ExpressionWithTypeArguments).typeArguments, + ) + : parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined); continue; } @@ -5945,7 +7236,10 @@ namespace ts { } const typeArguments = tryParse(parseTypeArgumentsInExpression); if (typeArguments) { - expression = finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos); + expression = finishNode( + factory.createExpressionWithTypeArguments(expression, typeArguments), + pos, + ); continue; } } @@ -5958,13 +7252,19 @@ namespace ts { return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead; } - function parseTaggedTemplateRest(pos: number, tag: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray | undefined) { + function parseTaggedTemplateRest( + pos: number, + tag: LeftHandSideExpression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: NodeArray | undefined, + ) { const tagExpression = factory.createTaggedTemplateExpression( tag, typeArguments, - token() === SyntaxKind.NoSubstitutionTemplateLiteral ? - (reScanTemplateHeadOrNoSubstitutionTemplate(), parseLiteralNode() as NoSubstitutionTemplateLiteral) : - parseTemplateExpression(/*isTaggedTemplate*/ true), + token() === SyntaxKind.NoSubstitutionTemplateLiteral + ? (reScanTemplateHeadOrNoSubstitutionTemplate(), + parseLiteralNode() as NoSubstitutionTemplateLiteral) + : parseTemplateExpression(/*isTaggedTemplate*/ true), ); if (questionDotToken || tag.flags & NodeFlags.OptionalChain) { (tagExpression as Mutable).flags |= NodeFlags.OptionalChain; @@ -5992,15 +7292,19 @@ namespace ts { expression = (expression as ExpressionWithTypeArguments).expression; } const argumentList = parseArgumentList(); - const callExpr = questionDotToken || tryReparseOptionalChain(expression) ? - factory.createCallChain(expression, questionDotToken, typeArguments, argumentList) : - factory.createCallExpression(expression, typeArguments, argumentList); + const callExpr = questionDotToken || tryReparseOptionalChain(expression) + ? factory.createCallChain(expression, questionDotToken, typeArguments, argumentList) + : factory.createCallExpression(expression, typeArguments, argumentList); expression = finishNode(callExpr, pos); continue; } if (questionDotToken) { // We parsed `?.` but then failed to parse anything, so report a missing identifier here. - const name = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected); + const name = createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ false, + Diagnostics.Identifier_expected, + ); expression = finishNode(factory.createPropertyAccessChain(expression, questionDotToken, name), pos); } break; @@ -6127,9 +7431,9 @@ namespace ts { } function parseArgumentOrArrayLiteralElement(): Expression { - return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() : - token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) : - parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); + return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() + : token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) + : parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); } function parseArgumentExpression(): Expression { @@ -6142,7 +7446,12 @@ namespace ts { const openBracketParsed = parseExpected(SyntaxKind.OpenBracketToken); const multiLine = scanner.hasPrecedingLineBreak(); const elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement); - parseExpectedMatchingBrackets(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, openBracketParsed, openBracketPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenBracketToken, + SyntaxKind.CloseBracketToken, + openBracketParsed, + openBracketPosition, + ); return finishNode(factory.createArrayLiteralExpression(elements, multiLine), pos); } @@ -6159,10 +7468,24 @@ namespace ts { const modifiers = parseModifiers(); if (parseContextualModifier(SyntaxKind.GetKeyword)) { - return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None); + return parseAccessorDeclaration( + pos, + hasJSDoc, + decorators, + modifiers, + SyntaxKind.GetAccessor, + SignatureFlags.None, + ); } if (parseContextualModifier(SyntaxKind.SetKeyword)) { - return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None); + return parseAccessorDeclaration( + pos, + hasJSDoc, + decorators, + modifiers, + SyntaxKind.SetAccessor, + SignatureFlags.None, + ); } const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); @@ -6174,7 +7497,16 @@ namespace ts { const exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken); if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { - return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, exclamationToken); + return parseMethodDeclaration( + pos, + hasJSDoc, + decorators, + modifiers, + asteriskToken, + name, + questionToken, + exclamationToken, + ); } // check if it is short-hand property assignment or normal property assignment @@ -6186,7 +7518,9 @@ namespace ts { const isShorthandPropertyAssignment = tokenIsIdentifier && (token() !== SyntaxKind.ColonToken); if (isShorthandPropertyAssignment) { const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken); - const objectAssignmentInitializer = equalsToken ? allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)) : undefined; + const objectAssignmentInitializer = equalsToken ? allowInAnd(() => + parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) + ) : undefined; node = factory.createShorthandPropertyAssignment(name as Identifier, objectAssignmentInitializer); // Save equals token for error reporting. // TODO(rbuckton): Consider manufacturing this when we need to report an error as it is otherwise not useful. @@ -6194,7 +7528,9 @@ namespace ts { } else { parseExpected(SyntaxKind.ColonToken); - const initializer = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); + const initializer = allowInAnd(() => + parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) + ); node = factory.createPropertyAssignment(name, initializer); } // Decorators, Modifiers, questionToken, and exclamationToken are not supported by property assignments and are reported in the grammar checker @@ -6210,8 +7546,17 @@ namespace ts { const openBracePosition = scanner.getTokenPos(); const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken); const multiLine = scanner.hasPrecedingLineBreak(); - const properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true); - parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); + const properties = parseDelimitedList( + ParsingContext.ObjectLiteralMembers, + parseObjectLiteralElement, + /*considerSemicolonAsDelimiter*/ true, + ); + parseExpectedMatchingBrackets( + SyntaxKind.OpenBraceToken, + SyntaxKind.CloseBraceToken, + openBraceParsed, + openBracePosition, + ); return finishNode(factory.createObjectLiteralExpression(properties, multiLine), pos); } @@ -6231,10 +7576,10 @@ namespace ts { const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; - const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) : - isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) : - isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) : - parseOptionalBindingIdentifier(); + const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) + : isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) + : isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) + : parseOptionalBindingIdentifier(); const typeParameters = parseTypeParameters(); const parameters = parseParameters(isGenerator | isAsync); @@ -6243,7 +7588,15 @@ namespace ts { setDecoratorContext(savedDecoratorContext); - const node = factory.createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body); + const node = factory.createFunctionExpression( + modifiers, + asteriskToken, + name, + typeParameters, + parameters, + type, + body, + ); return withJSDoc(finishNode(node, pos), hasJSDoc); } @@ -6259,7 +7612,11 @@ namespace ts { return finishNode(factory.createMetaProperty(SyntaxKind.NewKeyword, name), pos); } const expressionPos = getNodePos(); - let expression: LeftHandSideExpression = parseMemberExpressionRest(expressionPos, parsePrimaryExpression(), /*allowOptionalChain*/ false); + let expression: LeftHandSideExpression = parseMemberExpressionRest( + expressionPos, + parsePrimaryExpression(), + /*allowOptionalChain*/ false, + ); let typeArguments: NodeArray | undefined; // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) { @@ -6267,7 +7624,10 @@ namespace ts { expression = (expression as ExpressionWithTypeArguments).expression; } if (token() === SyntaxKind.QuestionDotToken) { - parseErrorAtCurrentToken(Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, getTextOfNodeFromSourceText(sourceText, expression)); + parseErrorAtCurrentToken( + Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, + getTextOfNodeFromSourceText(sourceText, expression), + ); } const argumentList = token() === SyntaxKind.OpenParenToken ? parseArgumentList() : undefined; return finishNode(factory.createNewExpression(expression, typeArguments, argumentList), pos); @@ -6282,10 +7642,18 @@ namespace ts { if (openBraceParsed || ignoreMissingOpenBrace) { const multiLine = scanner.hasPrecedingLineBreak(); const statements = parseList(ParsingContext.BlockStatements, parseStatement); - parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenBraceToken, + SyntaxKind.CloseBraceToken, + openBraceParsed, + openBracePosition, + ); const result = withJSDoc(finishNode(factory.createBlock(statements, multiLine), pos), hasJSDoc); if (token() === SyntaxKind.EqualsToken) { - parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected_This_follows_a_block_of_statements_so_if_you_intended_to_write_a_destructuring_assignment_you_might_need_to_wrap_the_the_whole_assignment_in_parentheses); + parseErrorAtCurrentToken( + Diagnostics + .Declaration_or_statement_expected_This_follows_a_block_of_statements_so_if_you_intended_to_write_a_destructuring_assignment_you_might_need_to_wrap_the_the_whole_assignment_in_parentheses, + ); nextToken(); } @@ -6341,10 +7709,18 @@ namespace ts { const openParenPosition = scanner.getTokenPos(); const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); const expression = allowInAnd(parseExpression); - parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenParenToken, + SyntaxKind.CloseParenToken, + openParenParsed, + openParenPosition, + ); const thenStatement = parseStatement(); const elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined; - return withJSDoc(finishNode(factory.createIfStatement(expression, thenStatement, elseStatement), pos), hasJSDoc); + return withJSDoc( + finishNode(factory.createIfStatement(expression, thenStatement, elseStatement), pos), + hasJSDoc, + ); } function parseDoStatement(): DoStatement { @@ -6356,7 +7732,12 @@ namespace ts { const openParenPosition = scanner.getTokenPos(); const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); const expression = allowInAnd(parseExpression); - parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenParenToken, + SyntaxKind.CloseParenToken, + openParenParsed, + openParenPosition, + ); // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in @@ -6373,7 +7754,12 @@ namespace ts { const openParenPosition = scanner.getTokenPos(); const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); const expression = allowInAnd(parseExpression); - parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenParenToken, + SyntaxKind.CloseParenToken, + openParenParsed, + openParenPosition, + ); const statement = parseStatement(); return withJSDoc(finishNode(factory.createWhileStatement(expression, statement), pos), hasJSDoc); } @@ -6387,7 +7773,10 @@ namespace ts { let initializer!: VariableDeclarationList | Expression; if (token() !== SyntaxKind.SemicolonToken) { - if (token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword) { + if ( + token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword + || token() === SyntaxKind.ConstKeyword + ) { initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true); } else { @@ -6397,7 +7786,9 @@ namespace ts { let node: IterationStatement; if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) { - const expression = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); + const expression = allowInAnd(() => + parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) + ); parseExpected(SyntaxKind.CloseParenToken); node = factory.createForOfStatement(awaitToken, initializer, expression, parseStatement()); } @@ -6452,7 +7843,12 @@ namespace ts { const openParenPosition = scanner.getTokenPos(); const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); const expression = allowInAnd(parseExpression); - parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenParenToken, + SyntaxKind.CloseParenToken, + openParenParsed, + openParenPosition, + ); const statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement); return withJSDoc(finishNode(factory.createWithStatement(expression, statement), pos), hasJSDoc); } @@ -6539,7 +7935,10 @@ namespace ts { finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); } - return withJSDoc(finishNode(factory.createTryStatement(tryBlock, catchClause, finallyBlock), pos), hasJSDoc); + return withJSDoc( + finishNode(factory.createTryStatement(tryBlock, catchClause, finallyBlock), pos), + hasJSDoc, + ); } function parseCatchClause(): CatchClause { @@ -6610,7 +8009,9 @@ namespace ts { function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() { nextToken(); - return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak(); + return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral + || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) + && !scanner.hasPrecedingLineBreak(); } function isDeclaration(): boolean { @@ -6668,21 +8069,22 @@ namespace ts { case SyntaxKind.GlobalKeyword: nextToken(); - return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword; + return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier + || token() === SyntaxKind.ExportKeyword; case SyntaxKind.ImportKeyword: nextToken(); - return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken || - token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token()); + return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken + || token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token()); case SyntaxKind.ExportKeyword: let currentToken = nextToken(); if (currentToken === SyntaxKind.TypeKeyword) { currentToken = lookAhead(nextToken); } if ( - currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken || - currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword || - currentToken === SyntaxKind.AsKeyword + currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken + || currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword + || currentToken === SyntaxKind.AsKeyword ) { return true; } @@ -6764,7 +8166,8 @@ namespace ts { function nextTokenIsBindingIdentifierOrStartOfDestructuring() { nextToken(); - return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken; + return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken + || token() === SyntaxKind.OpenBracketToken; } function isLetDeclaration() { @@ -6780,16 +8183,36 @@ namespace ts { case SyntaxKind.OpenBraceToken: return parseBlock(/*ignoreMissingOpenBrace*/ false); case SyntaxKind.VarKeyword: - return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); + return parseVariableStatement( + getNodePos(), + hasPrecedingJSDocComment(), + /*decorators*/ undefined, + /*modifiers*/ undefined, + ); case SyntaxKind.LetKeyword: if (isLetDeclaration()) { - return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); + return parseVariableStatement( + getNodePos(), + hasPrecedingJSDocComment(), + /*decorators*/ undefined, + /*modifiers*/ undefined, + ); } break; case SyntaxKind.FunctionKeyword: - return parseFunctionDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); + return parseFunctionDeclaration( + getNodePos(), + hasPrecedingJSDocComment(), + /*decorators*/ undefined, + /*modifiers*/ undefined, + ); case SyntaxKind.ClassKeyword: - return parseClassDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); + return parseClassDeclaration( + getNodePos(), + hasPrecedingJSDocComment(), + /*decorators*/ undefined, + /*modifiers*/ undefined, + ); case SyntaxKind.IfKeyword: return parseIfStatement(); case SyntaxKind.DoKeyword: @@ -6868,7 +8291,10 @@ namespace ts { for (const m of modifiers!) { (m as Mutable).flags |= NodeFlags.Ambient; } - return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers)); + return doInsideOfContext( + NodeFlags.Ambient, + () => parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers), + ); } else { return parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers); @@ -6884,7 +8310,12 @@ namespace ts { }); } - function parseDeclarationWorker(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): Statement { + function parseDeclarationWorker( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): Statement { switch (token()) { case SyntaxKind.VarKeyword: case SyntaxKind.LetKeyword: @@ -6921,7 +8352,11 @@ namespace ts { if (decorators || modifiers) { // We reached this point because we encountered decorators and/or modifiers and assumed a declaration // would follow. For recovery and error reporting purposes, return an incomplete declaration. - const missing = createMissingNode(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); + const missing = createMissingNode( + SyntaxKind.MissingDeclaration, + /*reportAtCurrentPosition*/ true, + Diagnostics.Declaration_expected, + ); setTextRangePos(missing, pos); missing.illegalDecorators = decorators; missing.modifiers = modifiers; @@ -6936,7 +8371,10 @@ namespace ts { return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral); } - function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined { + function parseFunctionBlockOrSemicolon( + flags: SignatureFlags, + diagnosticMessage?: DiagnosticMessage, + ): Block | undefined { if (token() !== SyntaxKind.OpenBraceToken) { if (flags & SignatureFlags.Type) { parseTypeMemberSemicolon(); @@ -6960,7 +8398,10 @@ namespace ts { const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); const name = parseIdentifierOrPattern(); const initializer = parseInitializer(); - return finishNode(factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), pos); + return finishNode( + factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), + pos, + ); } function parseObjectBindingElement(): BindingElement { @@ -7004,7 +8445,9 @@ namespace ts { || isBindingIdentifier(); } - function parseIdentifierOrPattern(privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier | BindingPattern { + function parseIdentifierOrPattern( + privateIdentifierDiagnosticMessage?: DiagnosticMessage, + ): Identifier | BindingPattern { if (token() === SyntaxKind.OpenBracketToken) { return parseArrayBindingPattern(); } @@ -7021,11 +8464,13 @@ namespace ts { function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); - const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations); + const name = parseIdentifierOrPattern( + Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations, + ); let exclamationToken: ExclamationToken | undefined; if ( - allowExclamation && name.kind === SyntaxKind.Identifier && - token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak() + allowExclamation && name.kind === SyntaxKind.Identifier + && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak() ) { exclamationToken = parseTokenNode>(); } @@ -7071,7 +8516,10 @@ namespace ts { const savedDisallowIn = inDisallowInContext(); setDisallowInContext(inForStatementInitializer); - declarations = parseDelimitedList(ParsingContext.VariableDeclarations, inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation); + declarations = parseDelimitedList( + ParsingContext.VariableDeclarations, + inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation, + ); setDisallowInContext(savedDisallowIn); } @@ -7083,7 +8531,12 @@ namespace ts { return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; } - function parseVariableStatement(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): VariableStatement { + function parseVariableStatement( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): VariableStatement { const declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false); parseSemicolon(); const node = factory.createVariableStatement(modifiers, declarationList); @@ -7092,14 +8545,20 @@ namespace ts { return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseFunctionDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): FunctionDeclaration { + function parseFunctionDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): FunctionDeclaration { const savedAwaitContext = inAwaitContext(); const modifierFlags = modifiersToFlags(modifiers); parseExpected(SyntaxKind.FunctionKeyword); const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); // We don't parse the name here in await context, instead we will report a grammar error in the checker. - const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() : parseBindingIdentifier(); + const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() + : parseBindingIdentifier(); const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; const isAsync = modifierFlags & ModifierFlags.Async ? SignatureFlags.Await : SignatureFlags.None; const typeParameters = parseTypeParameters(); @@ -7108,7 +8567,15 @@ namespace ts { const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected); setAwaitContext(savedAwaitContext); - const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body); + const node = factory.createFunctionDeclaration( + modifiers, + asteriskToken, + name, + typeParameters, + parameters, + type, + body, + ); (node as Mutable).illegalDecorators = decorators; return withJSDoc(finishNode(node, pos), hasJSDoc); } @@ -7125,7 +8592,12 @@ namespace ts { } } - function tryParseConstructorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): ConstructorDeclaration | undefined { + function tryParseConstructorDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): ConstructorDeclaration | undefined { return tryParse(() => { if (parseConstructorName()) { const typeParameters = parseTypeParameters(); @@ -7184,9 +8656,13 @@ namespace ts { name: PropertyName, questionToken: QuestionToken | undefined, ): PropertyDeclaration { - const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined; + const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() + ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined; const type = parseTypeAnnotation(); - const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer); + const initializer = doOutsideOfContext( + NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, + parseInitializer, + ); parseSemicolonAfterPropertyName(name, type, initializer); const node = factory.createPropertyDeclaration( combineDecoratorsAndModifiers(decorators, modifiers), @@ -7210,20 +8686,48 @@ namespace ts { // report an error in the grammar checker. const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { - return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, /*exclamationToken*/ undefined, Diagnostics.or_expected); + return parseMethodDeclaration( + pos, + hasJSDoc, + decorators, + modifiers, + asteriskToken, + name, + questionToken, + /*exclamationToken*/ undefined, + Diagnostics.or_expected, + ); } return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, questionToken); } - function parseAccessorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined, kind: AccessorDeclaration["kind"], flags: SignatureFlags): AccessorDeclaration { + function parseAccessorDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + kind: AccessorDeclaration["kind"], + flags: SignatureFlags, + ): AccessorDeclaration { const name = parsePropertyName(); const typeParameters = parseTypeParameters(); const parameters = parseParameters(SignatureFlags.None); const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); const body = parseFunctionBlockOrSemicolon(flags); const node = kind === SyntaxKind.GetAccessor - ? factory.createGetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, type, body) - : factory.createSetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, body); + ? factory.createGetAccessorDeclaration( + combineDecoratorsAndModifiers(decorators, modifiers), + name, + parameters, + type, + body, + ) + : factory.createSetAccessorDeclaration( + combineDecoratorsAndModifiers(decorators, modifiers), + name, + parameters, + body, + ); // Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors (node as Mutable).typeParameters = typeParameters; if (isSetAccessorDeclaration(node)) (node as Mutable).type = type; @@ -7299,7 +8803,12 @@ namespace ts { return false; } - function parseClassStaticBlockDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: ModifiersArray | undefined): ClassStaticBlockDeclaration { + function parseClassStaticBlockDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: ModifiersArray | undefined, + ): ClassStaticBlockDeclaration { parseExpectedToken(SyntaxKind.StaticKeyword); const body = parseClassStaticBlockBody(); const node = withJSDoc(finishNode(factory.createClassStaticBlockDeclaration(body), pos), hasJSDoc); @@ -7354,7 +8863,11 @@ namespace ts { return list && createNodeArray(list, pos); } - function tryParseModifier(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined { + function tryParseModifier( + permitInvalidConstAsModifier?: boolean, + stopOnStartOfClassStaticBlock?: boolean, + hasSeenStaticModifier?: boolean, + ): Modifier | undefined { const pos = getNodePos(); const kind = token(); @@ -7365,7 +8878,9 @@ namespace ts { return undefined; } } - else if (stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { + else if ( + stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace) + ) { return undefined; } else if (hasSeenStaticModifier && token() === SyntaxKind.StaticKeyword) { @@ -7380,7 +8895,10 @@ namespace ts { return finishNode(factory.createToken(kind as Modifier["kind"]), pos); } - function combineDecoratorsAndModifiers(decorators: NodeArray | undefined, modifiers: NodeArray | undefined): NodeArray | undefined { + function combineDecoratorsAndModifiers( + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): NodeArray | undefined { if (!decorators) return modifiers; if (!modifiers) return decorators; const decoratorsAndModifiers = factory.createNodeArray(concatenate(decorators, modifiers)); @@ -7395,10 +8913,15 @@ namespace ts { * * In such situations, 'permitInvalidConstAsModifier' should be set to true. */ - function parseModifiers(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray | undefined { + function parseModifiers( + permitInvalidConstAsModifier?: boolean, + stopOnStartOfClassStaticBlock?: boolean, + ): NodeArray | undefined { const pos = getNodePos(); let list, modifier, hasSeenStatic = false; - while (modifier = tryParseModifier(permitInvalidConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) { + while ( + modifier = tryParseModifier(permitInvalidConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic) + ) { if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStatic = true; list = append(list, modifier); } @@ -7425,17 +8948,34 @@ namespace ts { const hasJSDoc = hasPrecedingJSDocComment(); const decorators = parseDecorators(); - const modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true); + const modifiers = parseModifiers( + /*permitInvalidConstAsModifier*/ true, + /*stopOnStartOfClassStaticBlock*/ true, + ); if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { return parseClassStaticBlockDeclaration(pos, hasJSDoc, decorators, modifiers); } if (parseContextualModifier(SyntaxKind.GetKeyword)) { - return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None); + return parseAccessorDeclaration( + pos, + hasJSDoc, + decorators, + modifiers, + SyntaxKind.GetAccessor, + SignatureFlags.None, + ); } if (parseContextualModifier(SyntaxKind.SetKeyword)) { - return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None); + return parseAccessorDeclaration( + pos, + hasJSDoc, + decorators, + modifiers, + SyntaxKind.SetAccessor, + SignatureFlags.None, + ); } if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) { @@ -7452,18 +8992,21 @@ namespace ts { // It is very important that we check this *after* checking indexers because // the [ token can start an index signature or a computed property name if ( - tokenIsIdentifierOrKeyword(token()) || - token() === SyntaxKind.StringLiteral || - token() === SyntaxKind.NumericLiteral || - token() === SyntaxKind.AsteriskToken || - token() === SyntaxKind.OpenBracketToken + tokenIsIdentifierOrKeyword(token()) + || token() === SyntaxKind.StringLiteral + || token() === SyntaxKind.NumericLiteral + || token() === SyntaxKind.AsteriskToken + || token() === SyntaxKind.OpenBracketToken ) { const isAmbient = some(modifiers, isDeclareModifier); if (isAmbient) { for (const m of modifiers!) { (m as Mutable).flags |= NodeFlags.Ambient; } - return doInsideOfContext(NodeFlags.Ambient, () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers)); + return doInsideOfContext( + NodeFlags.Ambient, + () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers), + ); } else { return parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers); @@ -7472,8 +9015,19 @@ namespace ts { if (decorators || modifiers) { // treat this as a property declaration with a missing name. - const name = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); - return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, /*questionToken*/ undefined); + const name = createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ true, + Diagnostics.Declaration_expected, + ); + return parsePropertyDeclaration( + pos, + hasJSDoc, + decorators, + modifiers, + name, + /*questionToken*/ undefined, + ); } // 'isClassMemberStart' should have hinted not to attempt parsing. @@ -7481,14 +9035,37 @@ namespace ts { } function parseClassExpression(): ClassExpression { - return parseClassDeclarationOrExpression(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined, SyntaxKind.ClassExpression) as ClassExpression; + return parseClassDeclarationOrExpression( + getNodePos(), + hasPrecedingJSDocComment(), + /*decorators*/ undefined, + /*modifiers*/ undefined, + SyntaxKind.ClassExpression, + ) as ClassExpression; } - function parseClassDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): ClassDeclaration { - return parseClassDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers, SyntaxKind.ClassDeclaration) as ClassDeclaration; + function parseClassDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): ClassDeclaration { + return parseClassDeclarationOrExpression( + pos, + hasJSDoc, + decorators, + modifiers, + SyntaxKind.ClassDeclaration, + ) as ClassDeclaration; } - function parseClassDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration { + function parseClassDeclarationOrExpression( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + kind: ClassLikeDeclaration["kind"], + ): ClassLikeDeclaration { const savedAwaitContext = inAwaitContext(); parseExpected(SyntaxKind.ClassKeyword); @@ -7510,8 +9087,20 @@ namespace ts { } setAwaitContext(savedAwaitContext); const node = kind === SyntaxKind.ClassDeclaration - ? factory.createClassDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members) - : factory.createClassExpression(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members); + ? factory.createClassDeclaration( + combineDecoratorsAndModifiers(decorators, modifiers), + name, + typeParameters, + heritageClauses, + members, + ) + : factory.createClassExpression( + combineDecoratorsAndModifiers(decorators, modifiers), + name, + typeParameters, + heritageClauses, + members, + ); return withJSDoc(finishNode(node, pos), hasJSDoc); } @@ -7561,8 +9150,13 @@ namespace ts { } function tryParseTypeArguments(): NodeArray | undefined { - return token() === SyntaxKind.LessThanToken ? - parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) : undefined; + return token() === SyntaxKind.LessThanToken + ? parseBracketedList( + ParsingContext.TypeArguments, + parseType, + SyntaxKind.LessThanToken, + SyntaxKind.GreaterThanToken, + ) : undefined; } function isHeritageClause(): boolean { @@ -7573,7 +9167,12 @@ namespace ts { return parseList(ParsingContext.ClassMembers, parseClassElement); } - function parseInterfaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): InterfaceDeclaration { + function parseInterfaceDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): InterfaceDeclaration { parseExpected(SyntaxKind.InterfaceKeyword); const name = parseIdentifier(); const typeParameters = parseTypeParameters(); @@ -7584,7 +9183,12 @@ namespace ts { return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseTypeAliasDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): TypeAliasDeclaration { + function parseTypeAliasDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): TypeAliasDeclaration { parseExpected(SyntaxKind.TypeKeyword); const name = parseIdentifier(); const typeParameters = parseTypeParameters(); @@ -7608,12 +9212,19 @@ namespace ts { return withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc); } - function parseEnumDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): EnumDeclaration { + function parseEnumDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): EnumDeclaration { parseExpected(SyntaxKind.EnumKeyword); const name = parseIdentifier(); let members; if (parseExpected(SyntaxKind.OpenBraceToken)) { - members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember)); + members = doOutsideOfYieldAndAwaitContext(() => + parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember) + ); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -7637,20 +9248,37 @@ namespace ts { return finishNode(factory.createModuleBlock(statements), pos); } - function parseModuleOrNamespaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined, flags: NodeFlags): ModuleDeclaration { + function parseModuleOrNamespaceDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + flags: NodeFlags, + ): ModuleDeclaration { // If we are parsing a dotted namespace name, we want to // propagate the 'Namespace' flag across the names if set. const namespaceFlag = flags & NodeFlags.Namespace; const name = parseIdentifier(); const body = parseOptional(SyntaxKind.DotToken) - ? parseModuleOrNamespaceDeclaration(getNodePos(), /*hasJSDoc*/ false, /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) as NamespaceDeclaration + ? parseModuleOrNamespaceDeclaration( + getNodePos(), + /*hasJSDoc*/ false, + /*decorators*/ undefined, + /*modifiers*/ undefined, + NodeFlags.NestedNamespace | namespaceFlag, + ) as NamespaceDeclaration : parseModuleBlock(); const node = factory.createModuleDeclaration(modifiers, name, body, flags); (node as Mutable).illegalDecorators = decorators; return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseAmbientExternalModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): ModuleDeclaration { + function parseAmbientExternalModuleDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): ModuleDeclaration { let flags: NodeFlags = 0; let name; if (token() === SyntaxKind.GlobalKeyword) { @@ -7674,7 +9302,12 @@ namespace ts { return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): ModuleDeclaration { + function parseModuleDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): ModuleDeclaration { let flags: NodeFlags = 0; if (token() === SyntaxKind.GlobalKeyword) { // global augmentation @@ -7693,8 +9326,8 @@ namespace ts { } function isExternalModuleReference() { - return token() === SyntaxKind.RequireKeyword && - lookAhead(nextTokenIsOpenParen); + return token() === SyntaxKind.RequireKeyword + && lookAhead(nextTokenIsOpenParen); } function nextTokenIsOpenParen() { @@ -7709,7 +9342,12 @@ namespace ts { return nextToken() === SyntaxKind.SlashToken; } - function parseNamespaceExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): NamespaceExportDeclaration { + function parseNamespaceExportDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): NamespaceExportDeclaration { parseExpected(SyntaxKind.AsKeyword); parseExpected(SyntaxKind.NamespaceKeyword); const name = parseIdentifier(); @@ -7721,7 +9359,12 @@ namespace ts { return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseImportDeclarationOrImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): ImportEqualsDeclaration | ImportDeclaration { + function parseImportDeclarationOrImportEqualsDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): ImportEqualsDeclaration | ImportDeclaration { parseExpected(SyntaxKind.ImportKeyword); const afterImportPos = scanner.getStartPos(); @@ -7734,9 +9377,9 @@ namespace ts { let isTypeOnly = false; if ( - token() !== SyntaxKind.FromKeyword && - identifier?.escapedText === "type" && - (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration()) + token() !== SyntaxKind.FromKeyword + && identifier?.escapedText === "type" + && (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration()) ) { isTypeOnly = true; identifier = isIdentifier() ? parseIdentifier() : undefined; @@ -7751,9 +9394,9 @@ namespace ts { // import ModuleSpecifier; let importClause: ImportClause | undefined; if ( - identifier || // import id - token() === SyntaxKind.AsteriskToken || // import * - token() === SyntaxKind.OpenBraceToken // import { + identifier // import id + || token() === SyntaxKind.AsteriskToken // import * + || token() === SyntaxKind.OpenBraceToken // import { ) { importClause = parseImportClause(identifier, afterImportPos, isTypeOnly); parseExpected(SyntaxKind.FromKeyword); @@ -7773,7 +9416,8 @@ namespace ts { function parseAssertEntry() { const pos = getNodePos(); - const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral; + const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() + : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral; parseExpected(SyntaxKind.ColonToken); const value = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); return finishNode(factory.createAssertEntry(name, value), pos); @@ -7787,13 +9431,24 @@ namespace ts { const openBracePosition = scanner.getTokenPos(); if (parseExpected(SyntaxKind.OpenBraceToken)) { const multiLine = scanner.hasPrecedingLineBreak(); - const elements = parseDelimitedList(ParsingContext.AssertEntries, parseAssertEntry, /*considerSemicolonAsDelimiter*/ true); + const elements = parseDelimitedList( + ParsingContext.AssertEntries, + parseAssertEntry, + /*considerSemicolonAsDelimiter*/ true, + ); if (!parseExpected(SyntaxKind.CloseBraceToken)) { const lastError = lastOrUndefined(parseDiagnostics); if (lastError && lastError.code === Diagnostics._0_expected.code) { addRelatedInfo( lastError, - createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}"), + createDetachedDiagnostic( + fileName, + openBracePosition, + 1, + Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, + "{", + "}", + ), ); } } @@ -7815,7 +9470,14 @@ namespace ts { return token() === SyntaxKind.CommaToken || token() === SyntaxKind.FromKeyword; } - function parseImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined, identifier: Identifier, isTypeOnly: boolean): ImportEqualsDeclaration { + function parseImportEqualsDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + identifier: Identifier, + isTypeOnly: boolean, + ): ImportEqualsDeclaration { parseExpected(SyntaxKind.EqualsToken); const moduleReference = parseModuleReference(); parseSemicolon(); @@ -7837,10 +9499,11 @@ namespace ts { // parse namespace or named imports let namedBindings: NamespaceImport | NamedImports | undefined; if ( - !identifier || - parseOptional(SyntaxKind.CommaToken) + !identifier + || parseOptional(SyntaxKind.CommaToken) ) { - namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); + namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() + : parseNamedImportsOrExports(SyntaxKind.NamedImports); } return finishNode(factory.createImportClause(isTypeOnly, identifier, namedBindings), pos); @@ -7899,8 +9562,22 @@ namespace ts { // ImportSpecifier // ImportsList, ImportSpecifier const node = kind === SyntaxKind.NamedImports - ? factory.createNamedImports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseImportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)) - : factory.createNamedExports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseExportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)); + ? factory.createNamedImports( + parseBracketedList( + ParsingContext.ImportOrExportSpecifiers, + parseImportSpecifier, + SyntaxKind.OpenBraceToken, + SyntaxKind.CloseBraceToken, + ), + ) + : factory.createNamedExports( + parseBracketedList( + ParsingContext.ImportOrExportSpecifiers, + parseExportSpecifier, + SyntaxKind.OpenBraceToken, + SyntaxKind.CloseBraceToken, + ), + ); return finishNode(node, pos); } @@ -8000,7 +9677,12 @@ namespace ts { return finishNode(factory.createNamespaceExport(parseIdentifierName()), pos); } - function parseExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): ExportDeclaration { + function parseExportDeclaration( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): ExportDeclaration { const savedAwaitContext = inAwaitContext(); setAwaitContext(/*value*/ true); let exportClause: NamedExportBindings | undefined; @@ -8020,7 +9702,10 @@ namespace ts { // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios, // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`) // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect. - if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) { + if ( + token() === SyntaxKind.FromKeyword + || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak()) + ) { parseExpected(SyntaxKind.FromKeyword); moduleSpecifier = parseModuleSpecifier(); } @@ -8030,12 +9715,23 @@ namespace ts { } parseSemicolon(); setAwaitContext(savedAwaitContext); - const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause); + const node = factory.createExportDeclaration( + modifiers, + isTypeOnly, + exportClause, + moduleSpecifier, + assertClause, + ); (node as Mutable).illegalDecorators = decorators; return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseExportAssignment(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): ExportAssignment { + function parseExportAssignment( + pos: number, + hasJSDoc: boolean, + decorators: NodeArray | undefined, + modifiers: NodeArray | undefined, + ): ExportAssignment { const savedAwaitContext = inAwaitContext(); setAwaitContext(/*value*/ true); let isExportEquals: boolean | undefined; @@ -8089,13 +9785,26 @@ namespace ts { } export namespace JSDocParser { - export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression; diagnostics: Diagnostic[]; } | undefined { + export function parseJSDocTypeExpressionForTests( + content: string, + start: number | undefined, + length: number | undefined, + ): { jsDocTypeExpression: JSDocTypeExpression; diagnostics: Diagnostic[]; } | undefined { initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); scanner.setText(content, start, length); currentToken = scanner.scan(); const jsDocTypeExpression = parseJSDocTypeExpression(); - const sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false, [], factory.createToken(SyntaxKind.EndOfFileToken), NodeFlags.None, noop); + const sourceFile = createSourceFile( + "file.js", + ScriptTarget.Latest, + ScriptKind.JS, + /*isDeclarationFile*/ false, + [], + factory.createToken(SyntaxKind.EndOfFileToken), + NodeFlags.None, + noop, + ); const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); if (jsDocDiagnostics) { sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); @@ -8139,7 +9848,11 @@ namespace ts { return finishNode(result, pos); } - export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc; diagnostics: Diagnostic[]; } | undefined { + export function parseIsolatedJSDocComment( + content: string, + start: number | undefined, + length: number | undefined, + ): { jsDoc: JSDoc; diagnostics: Diagnostic[]; } | undefined { initializeState("", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length)); @@ -8286,7 +9999,13 @@ namespace ts { if (!linkEnd) { removeLeadingNewlines(comments); } - parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentEnd)); + parts.push( + finishNode( + factory.createJSDocText(comments.join("")), + linkEnd ?? start, + commentEnd, + ), + ); parts.push(link); comments = []; linkEnd = scanner.getTextPos(); @@ -8305,11 +10024,26 @@ namespace ts { } removeTrailingWhitespace(comments); if (parts.length && comments.length) { - parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentsPos)); + parts.push( + finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentsPos), + ); + } + if (parts.length && tags) { + Debug.assertIsDefined( + commentsPos, + "having parsed tags implies that the end of the comment span should be set", + ); } - if (parts.length && tags) Debug.assertIsDefined(commentsPos, "having parsed tags implies that the end of the comment span should be set"); const tagsArray = tags && createNodeArray(tags, tagsPos, tagsEnd); - return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : comments.length ? comments.join("") : undefined, tagsArray), start, end); + return finishNode( + factory.createJSDocComment( + parts.length ? createNodeArray(parts, start, commentsPos) + : comments.length ? comments.join("") : undefined, + tagsArray, + ), + start, + end, + ); }); function removeLeadingNewlines(comments: string[]) { @@ -8358,7 +10092,10 @@ namespace ts { let precedingLineBreak = scanner.hasPrecedingLineBreak(); let seenLineBreak = false; let indentText = ""; - while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { + while ( + (precedingLineBreak && token() === SyntaxKind.AsteriskToken) + || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia + ) { indentText += scanner.getTokenText(); if (token() === SyntaxKind.NewLineTrivia) { precedingLineBreak = true; @@ -8460,7 +10197,10 @@ namespace ts { return parseTagComments(margin, indentText.slice(margin)); } - function parseTagComments(indent: number, initialMargin?: string): string | NodeArray | undefined { + function parseTagComments( + indent: number, + initialMargin?: string, + ): string | NodeArray | undefined { const commentsPos = getNodePos(); let comments: string[] = []; const parts: JSDocComment[] = []; @@ -8495,7 +10235,8 @@ namespace ts { case SyntaxKind.AtToken: if ( state === JSDocState.SavingBackticks - || state === JSDocState.SavingComments && (!previousWhitespace || lookAhead(isNextJSDocTokenWhitespace)) + || state === JSDocState.SavingComments + && (!previousWhitespace || lookAhead(isNextJSDocTokenWhitespace)) ) { // @ doesn't start a new tag inside ``, and inside a comment, only after whitespace or not before whitespace comments.push(scanner.getTokenText()); @@ -8525,7 +10266,13 @@ namespace ts { const linkStart = scanner.getTextPos() - 1; const link = parseJSDocLink(linkStart); if (link) { - parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos, commentEnd)); + parts.push( + finishNode( + factory.createJSDocText(comments.join("")), + linkEnd ?? commentsPos, + commentEnd, + ), + ); parts.push(link); comments = []; linkEnd = scanner.getTextPos(); @@ -8601,7 +10348,10 @@ namespace ts { } } const text = []; - while (token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia && token() !== SyntaxKind.EndOfFileToken) { + while ( + token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia + && token() !== SyntaxKind.EndOfFileToken + ) { text.push(scanner.getTokenText()); nextTokenJSDoc(); } @@ -8628,7 +10378,13 @@ namespace ts { } function parseUnknownTag(start: number, tagName: Identifier, indent: number, indentText: string) { - return finishNode(factory.createJSDocUnknownTag(tagName, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); + return finishNode( + factory.createJSDocUnknownTag( + tagName, + parseTrailingTagComments(start, getNodePos(), indent, indentText), + ), + start, + ); } function addTag(tag: JSDocTag | undefined): void { @@ -8682,11 +10438,17 @@ namespace ts { case SyntaxKind.ArrayType: return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType); default: - return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object" && !node.typeArguments; + return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) + && node.typeName.escapedText === "Object" && !node.typeArguments; } } - function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag { + function parseParameterOrPropertyTag( + start: number, + tagName: Identifier, + target: PropertyLikeParse, + indent: number, + ): JSDocParameterTag | JSDocPropertyTag { let typeExpression = tryParseTypeExpression(); let isNameFirst = !typeExpression; skipWhitespaceOrAsterisk(); @@ -8700,62 +10462,133 @@ namespace ts { const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); - const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent); + const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter + && parseNestedTypeLiteral(typeExpression, name, target, indent); if (nestedTypeLiteral) { typeExpression = nestedTypeLiteral; isNameFirst = true; } const result = target === PropertyLikeParse.Property - ? factory.createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment) - : factory.createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment); + ? factory.createJSDocPropertyTag( + tagName, + name, + isBracketed, + typeExpression, + isNameFirst, + comment, + ) + : factory.createJSDocParameterTag( + tagName, + name, + isBracketed, + typeExpression, + isNameFirst, + comment, + ); return finishNode(result, start); } - function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) { + function parseNestedTypeLiteral( + typeExpression: JSDocTypeExpression | undefined, + name: EntityName, + target: PropertyLikeParse, + indent: number, + ) { if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) { const pos = getNodePos(); let child: JSDocPropertyLikeTag | JSDocTypeTag | false; let children: JSDocPropertyLikeTag[] | undefined; while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) { - if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) { + if ( + child.kind === SyntaxKind.JSDocParameterTag + || child.kind === SyntaxKind.JSDocPropertyTag + ) { children = append(children, child); } } if (children) { - const literal = finishNode(factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), pos); + const literal = finishNode( + factory.createJSDocTypeLiteral( + children, + typeExpression.type.kind === SyntaxKind.ArrayType, + ), + pos, + ); return finishNode(factory.createJSDocTypeExpression(literal), pos); } } } - function parseReturnTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocReturnTag { + function parseReturnTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocReturnTag { if (some(tags, isJSDocReturnTag)) { - parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); + parseErrorAt( + tagName.pos, + scanner.getTokenPos(), + Diagnostics._0_tag_already_specified, + tagName.escapedText, + ); } const typeExpression = tryParseTypeExpression(); - return finishNode(factory.createJSDocReturnTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); + return finishNode( + factory.createJSDocReturnTag( + tagName, + typeExpression, + parseTrailingTagComments(start, getNodePos(), indent, indentText), + ), + start, + ); } - function parseTypeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocTypeTag { + function parseTypeTag( + start: number, + tagName: Identifier, + indent?: number, + indentText?: string, + ): JSDocTypeTag { if (some(tags, isJSDocTypeTag)) { - parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); + parseErrorAt( + tagName.pos, + scanner.getTokenPos(), + Diagnostics._0_tag_already_specified, + tagName.escapedText, + ); } const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); - const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; + const comments = indent !== undefined && indentText !== undefined + ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; return finishNode(factory.createJSDocTypeTag(tagName, typeExpression, comments), start); } - function parseSeeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocSeeTag { + function parseSeeTag( + start: number, + tagName: Identifier, + indent?: number, + indentText?: string, + ): JSDocSeeTag { const isMarkdownOrJSDocLink = token() === SyntaxKind.OpenBracketToken - || lookAhead(() => nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) && isJSDocLinkTag(scanner.getTokenValue())); + || lookAhead(() => + nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) + && isJSDocLinkTag(scanner.getTokenValue()) + ); const nameExpression = isMarkdownOrJSDocLink ? undefined : parseJSDocNameReference(); - const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; + const comments = indent !== undefined && indentText !== undefined + ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start); } - function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag { + function parseAuthorTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocAuthorTag { const commentStart = getNodePos(); const textOnly = parseAuthorNameAndEmail(); let commentEnd = scanner.getStartPos(); @@ -8764,7 +10597,10 @@ namespace ts { commentEnd = scanner.getStartPos(); } const allParts = typeof comments !== "string" - ? createNodeArray(concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], commentStart) // cast away readonly + ? createNodeArray( + concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], + commentStart, + ) // cast away readonly : textOnly.text + comments; return finishNode(factory.createJSDocAuthorTag(tagName, allParts), start); } @@ -8792,22 +10628,50 @@ namespace ts { return factory.createJSDocText(comments.join("")); } - function parseImplementsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImplementsTag { + function parseImplementsTag( + start: number, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocImplementsTag { const className = parseExpressionWithTypeArgumentsForAugments(); - return finishNode(factory.createJSDocImplementsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + return finishNode( + factory.createJSDocImplementsTag( + tagName, + className, + parseTrailingTagComments(start, getNodePos(), margin, indentText), + ), + start, + ); } - function parseAugmentsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocAugmentsTag { + function parseAugmentsTag( + start: number, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocAugmentsTag { const className = parseExpressionWithTypeArgumentsForAugments(); - return finishNode(factory.createJSDocAugmentsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + return finishNode( + factory.createJSDocAugmentsTag( + tagName, + className, + parseTrailingTagComments(start, getNodePos(), margin, indentText), + ), + start, + ); } - function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression; } { + function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { + expression: Identifier | PropertyAccessEntityNameExpression; + } { const usedBrace = parseOptional(SyntaxKind.OpenBraceToken); const pos = getNodePos(); const expression = parsePropertyAccessEntityNameExpression(); const typeArguments = tryParseTypeArguments(); - const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression; }; + const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as + & ExpressionWithTypeArguments + & { expression: Identifier | PropertyAccessEntityNameExpression; }; const res = finishNode(node, pos); if (usedBrace) { parseExpected(SyntaxKind.CloseBraceToken); @@ -8820,28 +10684,72 @@ namespace ts { let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(); while (parseOptional(SyntaxKind.DotToken)) { const name = parseJSDocIdentifierName(); - node = finishNode(factory.createPropertyAccessExpression(node, name), pos) as PropertyAccessEntityNameExpression; + node = finishNode( + factory.createPropertyAccessExpression(node, name), + pos, + ) as PropertyAccessEntityNameExpression; } return node; } - function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: string | NodeArray) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag { - return finishNode(createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + function parseSimpleTag( + start: number, + createTag: ( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ) => JSDocTag, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocTag { + return finishNode( + createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), + start, + ); } - function parseThisTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocThisTag { + function parseThisTag( + start: number, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocThisTag { const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); skipWhitespace(); - return finishNode(factory.createJSDocThisTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + return finishNode( + factory.createJSDocThisTag( + tagName, + typeExpression, + parseTrailingTagComments(start, getNodePos(), margin, indentText), + ), + start, + ); } - function parseEnumTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocEnumTag { + function parseEnumTag( + start: number, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocEnumTag { const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); skipWhitespace(); - return finishNode(factory.createJSDocEnumTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + return finishNode( + factory.createJSDocEnumTag( + tagName, + typeExpression, + parseTrailingTagComments(start, getNodePos(), margin, indentText), + ), + start, + ); } - function parseTypedefTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTypedefTag { + function parseTypedefTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocTypedefTag { let typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined = tryParseTypeExpression(); skipWhitespaceOrAsterisk(); @@ -8859,9 +10767,19 @@ namespace ts { hasChildren = true; if (child.kind === SyntaxKind.JSDocTypeTag) { if (childTypeTag) { - const lastError = parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags); + const lastError = parseErrorAtCurrentToken( + Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags, + ); if (lastError) { - addRelatedInfo(lastError, createDetachedDiagnostic(fileName, 0, 0, Diagnostics.The_tag_was_first_specified_here)); + addRelatedInfo( + lastError, + createDetachedDiagnostic( + fileName, + 0, + 0, + Diagnostics.The_tag_was_first_specified_here, + ), + ); } break; } @@ -8876,17 +10794,18 @@ namespace ts { if (hasChildren) { const isArrayType = typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType; const jsdocTypeLiteral = factory.createJSDocTypeLiteral(jsDocPropertyTags, isArrayType); - typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ? - childTypeTag.typeExpression : - finishNode(jsdocTypeLiteral, start); + typeExpression = childTypeTag && childTypeTag.typeExpression + && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) + ? childTypeTag.typeExpression + : finishNode(jsdocTypeLiteral, start); end = typeExpression.end; } } // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace - end = end || comment !== undefined ? - getNodePos() : - (fullName ?? typeExpression ?? tagName).end; + end = end || comment !== undefined + ? getNodePos() + : (fullName ?? typeExpression ?? tagName).end; if (!comment) { comment = parseTrailingTagComments(start, end, indent, indentText); @@ -8923,13 +10842,25 @@ namespace ts { const pos = getNodePos(); let child: JSDocParameterTag | false; let parameters; - while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) { + while ( + child = tryParse(() => + parseChildParameterOrPropertyTag( + PropertyLikeParse.CallbackParameter, + indent, + ) as JSDocParameterTag + ) + ) { parameters = append(parameters, child); } return createNodeArray(parameters || [], pos); } - function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag { + function parseCallbackTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocCallbackTag { const fullName = parseJSDocTypeNameWithNamespace(); skipWhitespace(); let comment = parseTagComments(indent); @@ -8942,12 +10873,19 @@ namespace ts { } } }); - const typeExpression = finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start); + const typeExpression = finishNode( + factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), + start, + ); if (!comment) { comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); } const end = comment !== undefined ? getNodePos() : typeExpression.end; - return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end); + return finishNode( + factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), + start, + end, + ); } function escapedTextsEqual(a: EntityName, b: EntityName): boolean { @@ -8964,10 +10902,17 @@ namespace ts { } function parseChildPropertyTag(indent: number) { - return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false; + return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as + | JSDocTypeTag + | JSDocPropertyTag + | false; } - function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { + function parseChildParameterOrPropertyTag( + target: PropertyLikeParse, + indent: number, + name?: EntityName, + ): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { let canParseTag = true; let seenAsterisk = false; while (true) { @@ -8976,9 +10921,12 @@ namespace ts { if (canParseTag) { const child = tryParseChildTag(target, indent); if ( - child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) && - target !== PropertyLikeParse.CallbackParameter && - name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left)) + child + && (child.kind === SyntaxKind.JSDocParameterTag + || child.kind === SyntaxKind.JSDocPropertyTag) + && target !== PropertyLikeParse.CallbackParameter + && name + && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left)) ) { return false; } @@ -9005,7 +10953,10 @@ namespace ts { } } - function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { + function tryParseChildTag( + target: PropertyLikeParse, + indent: number, + ): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { Debug.assert(token() === SyntaxKind.AtToken); const start = scanner.getStartPos(); nextTokenJSDoc(); @@ -9040,7 +10991,9 @@ namespace ts { if (isBracketed) { skipWhitespace(); } - const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); + const name = parseJSDocIdentifierName( + Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces, + ); let defaultType: TypeNode | undefined; if (isBracketed) { @@ -9053,7 +11006,15 @@ namespace ts { if (nodeIsMissing(name)) { return undefined; } - return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos); + return finishNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + name, + /*constraint*/ undefined, + defaultType, + ), + typeParameterPos, + ); } function parseTemplateTagTypeParameters() { @@ -9071,7 +11032,12 @@ namespace ts { return createNodeArray(typeParameters, pos); } - function parseTemplateTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTemplateTag { + function parseTemplateTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocTemplateTag { // The template tag looks like one of the following: // @template T,U,V // @template {Constraint} T @@ -9085,7 +11051,15 @@ namespace ts { // TODO: Consider only parsing a single type parameter if there is a constraint. const constraint = token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; const typeParameters = parseTemplateTagTypeParameters(); - return finishNode(factory.createJSDocTemplateTag(tagName, constraint, typeParameters, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); + return finishNode( + factory.createJSDocTemplateTag( + tagName, + constraint, + typeParameters, + parseTrailingTagComments(start, getNodePos(), indent, indentText), + ), + start, + ); } function parseOptionalJsdoc(t: JSDocSyntaxKind): boolean { @@ -9116,7 +11090,11 @@ namespace ts { function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier { if (!tokenIsIdentifierOrKeyword(token())) { - return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected); + return createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ !message, + message || Diagnostics.Identifier_expected, + ); } identifierCount++; @@ -9124,7 +11102,11 @@ namespace ts { const end = scanner.getTextPos(); const originalKeywordKind = token(); const text = internIdentifier(scanner.getTokenValue()); - const result = finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), pos, end); + const result = finishNode( + factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), + pos, + end, + ); nextTokenJSDoc(); return result; } @@ -9133,7 +11115,12 @@ namespace ts { } namespace IncrementalParser { - export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile { + export function updateSourceFile( + sourceFile: SourceFile, + newText: string, + textChangeRange: TextChangeRange, + aggressiveChecks: boolean, + ): SourceFile { aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive); checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks); @@ -9145,7 +11132,15 @@ namespace ts { if (sourceFile.statements.length === 0) { // If we don't have any statements in the current source file, then there's no real // way to incrementally parse. So just do a full parse instead. - return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); + return Parser.parseSourceFile( + sourceFile.fileName, + newText, + sourceFile.languageVersion, + /*syntaxCursor*/ undefined, + /*setParentNodes*/ true, + sourceFile.scriptKind, + sourceFile.setExternalModuleIndicator, + ); } // Make sure we're not trying to incrementally update a source file more than once. Once @@ -9170,7 +11165,10 @@ namespace ts { // earlier in the file. Debug.assert(changeRange.span.start <= textChangeRange.span.start); Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span)); - Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange))); + Debug.assert( + textSpanEnd(textChangeRangeNewSpan(changeRange)) + === textSpanEnd(textChangeRangeNewSpan(textChangeRange)), + ); // The is the amount the nodes after the edit range need to be adjusted. It can be // positive (if the edit added characters), negative (if the edit deleted characters) @@ -9196,7 +11194,16 @@ namespace ts { // // Also, mark any syntax elements that intersect the changed span. We know, up front, // that we cannot reuse these elements. - updateTokenPositionsAndMarkElements(incrementalSourceFile, changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks); + updateTokenPositionsAndMarkElements( + incrementalSourceFile, + changeRange.span.start, + textSpanEnd(changeRange.span), + textSpanEnd(textChangeRangeNewSpan(changeRange)), + delta, + oldText, + newText, + aggressiveChecks, + ); // Now that we've set up our internal incremental state just proceed and parse the // source file in the normal fashion. When possible the parser will retrieve and @@ -9208,7 +11215,15 @@ namespace ts { // inconsistent tree. Setting the parents on the new tree should be very fast. We // will immediately bail out of walking any subtrees when we can see that their parents // are already correct. - const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); + const result = Parser.parseSourceFile( + sourceFile.fileName, + newText, + sourceFile.languageVersion, + syntaxCursor, + /*setParentNodes*/ true, + sourceFile.scriptKind, + sourceFile.setExternalModuleIndicator, + ); result.commentDirectives = getNewCommentDirectives( sourceFile.commentDirectives, result.commentDirectives, @@ -9252,7 +11267,10 @@ namespace ts { }; commentDirectives = append(commentDirectives, updatedDirective); if (aggressiveChecks) { - Debug.assert(oldText.substring(range.pos, range.end) === newText.substring(updatedDirective.range.pos, updatedDirective.range.end)); + Debug.assert( + oldText.substring(range.pos, range.end) + === newText.substring(updatedDirective.range.pos, updatedDirective.range.end), + ); } } // Ignore ranges that fall in change range @@ -9272,7 +11290,14 @@ namespace ts { } } - function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { + function moveElementEntirelyPastChangeRange( + element: IncrementalElement, + isArray: boolean, + delta: number, + oldText: string, + newText: string, + aggressiveChecks: boolean, + ) { if (isArray) { visitArray(element as IncrementalNodeArray); } @@ -9329,9 +11354,18 @@ namespace ts { return false; } - function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { + function adjustIntersectingElement( + element: IncrementalElement, + changeStart: number, + changeRangeOldEnd: number, + changeRangeNewEnd: number, + delta: number, + ) { Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); - Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); + Debug.assert( + element.pos <= changeRangeOldEnd, + "Adjusting an element that was entirely after the change range", + ); Debug.assert(element.pos <= element.end); // We have an element that intersects the change range in some way. It may have its @@ -9387,12 +11421,12 @@ namespace ts { // However any element that ended after that will have their pos adjusted to be // at the end of the new range. i.e. any node that ended in the 'Y' range will // be adjusted to have their end at the end of the 'Z' range. - const end = element.end >= changeRangeOldEnd ? + const end = element.end >= changeRangeOldEnd // Element ends after the change range. Always adjust the end pos. - element.end + delta : + ? element.end + delta // Element ends in the change range. The element will keep its position if // possible. Or Move backward to the new-end if it's in the 'Y' range. - Math.min(element.end, changeRangeNewEnd); + : Math.min(element.end, changeRangeNewEnd); Debug.assert(pos <= end); if (element.parent) { @@ -9438,7 +11472,14 @@ namespace ts { if (child.pos > changeRangeOldEnd) { // Node is entirely past the change range. We need to move both its pos and // end, forward or backward appropriately. - moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks); + moveElementEntirelyPastChangeRange( + child, + /*isArray*/ false, + delta, + oldText, + newText, + aggressiveChecks, + ); return; } @@ -9471,7 +11512,14 @@ namespace ts { if (array.pos > changeRangeOldEnd) { // Array is entirely after the change range. We need to move it, and move any of // its children. - moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks); + moveElementEntirelyPastChangeRange( + array, + /*isArray*/ true, + delta, + oldText, + newText, + aggressiveChecks, + ); return; } @@ -9613,10 +11661,17 @@ namespace ts { } } - function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) { + function checkChangeRange( + sourceFile: SourceFile, + newText: string, + textChangeRange: TextChangeRange, + aggressiveChecks: boolean, + ) { const oldText = sourceFile.text; if (textChangeRange) { - Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length); + Debug.assert( + (oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length, + ); if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) { const oldTextPrefix = oldText.substr(0, textChangeRange.span.start); @@ -9624,7 +11679,10 @@ namespace ts { Debug.assert(oldTextPrefix === newTextPrefix); const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length); - const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length); + const newTextSuffix = newText.substring( + textSpanEnd(textChangeRangeNewSpan(textChangeRange)), + newText.length, + ); Debug.assert(oldTextSuffix === newTextSuffix); } } @@ -9776,7 +11834,12 @@ namespace ts { moduleName?: string; } - function parseResolutionMode(mode: string | undefined, pos: number, end: number, reportDiagnostic: PragmaDiagnosticReporter): ModuleKind.ESNext | ModuleKind.CommonJS | undefined { + function parseResolutionMode( + mode: string | undefined, + pos: number, + end: number, + reportDiagnostic: PragmaDiagnosticReporter, + ): ModuleKind.ESNext | ModuleKind.CommonJS | undefined { if (!mode) { return undefined; } @@ -9841,7 +11904,12 @@ namespace ts { } else if (types) { const parsed = parseResolutionMode(res, types.pos, types.end, reportDiagnostic); - typeReferenceDirectives.push({ pos: types.pos, end: types.end, fileName: types.value, ...(parsed ? { resolutionMode: parsed } : {}) }); + typeReferenceDirectives.push({ + pos: types.pos, + end: types.end, + fileName: types.value, + ...(parsed ? { resolutionMode: parsed } : {}), + }); } else if (lib) { libReferenceDirectives.push({ pos: lib.pos, end: lib.end, fileName: lib.value }); @@ -9850,7 +11918,11 @@ namespace ts { referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value }); } else { - reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax); + reportDiagnostic( + arg.range.pos, + arg.range.end - arg.range.pos, + Diagnostics.Invalid_reference_directive_syntax, + ); } }); break; @@ -9867,7 +11939,11 @@ namespace ts { for (const entry of entryOrList) { if (context.moduleName) { // TODO: It's probably fine to issue this diagnostic on all instances of the pragma - reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments); + reportDiagnostic( + entry.range.pos, + entry.range.end - entry.range.pos, + Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments, + ); } context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name; } @@ -9915,7 +11991,8 @@ namespace ts { const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im; const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im; function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string) { - const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text); + const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia + && tripleSlashXMLCommentStartRegEx.exec(text); if (tripleSlash) { const name = tripleSlash[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks const pragma = commentPragmas[name] as PragmaDefinition; @@ -9967,7 +12044,12 @@ namespace ts { } } - function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) { + function addPragmaForMatch( + pragmas: PragmaPseudoMapEntry[], + range: CommentRange, + kind: PragmaKindFlags, + match: RegExpExecArray, + ) { if (!match) return; const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks const pragma = commentPragmas[name] as PragmaDefinition; @@ -9981,7 +12063,10 @@ namespace ts { return; } - function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): { [index: string]: string; } | "fail" { + function getNamedPragmaArguments( + pragma: PragmaDefinition, + text: string | undefined, + ): { [index: string]: string; } | "fail" { if (!text) return {}; if (!pragma.args) return {}; const args = trimString(text).split(/\s+/); @@ -10016,7 +12101,10 @@ namespace ts { // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element - return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText && - tagNamesAreEquivalent((lhs as PropertyAccessExpression).expression as JsxTagNameExpression, (rhs as PropertyAccessExpression).expression as JsxTagNameExpression); + return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText + && tagNamesAreEquivalent( + (lhs as PropertyAccessExpression).expression as JsxTagNameExpression, + (rhs as PropertyAccessExpression).expression as JsxTagNameExpression, + ); } } diff --git a/src/compiler/path.ts b/src/compiler/path.ts index e7768f50adbd5..73171f556b235 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -104,8 +104,8 @@ namespace ts { //// Path Parsing function isVolumeCharacter(charCode: number) { - return (charCode >= CharacterCodes.a && charCode <= CharacterCodes.z) || - (charCode >= CharacterCodes.A && charCode <= CharacterCodes.Z); + return (charCode >= CharacterCodes.a && charCode <= CharacterCodes.z) + || (charCode >= CharacterCodes.A && charCode <= CharacterCodes.Z); } function getFileUrlVolumeSeparatorEnd(url: string, start: number) { @@ -155,8 +155,8 @@ namespace ts { const scheme = path.slice(0, schemeEnd); const authority = path.slice(authorityStart, authorityEnd); if ( - scheme === "file" && (authority === "" || authority === "localhost") && - isVolumeCharacter(path.charCodeAt(authorityEnd + 1)) + scheme === "file" && (authority === "" || authority === "localhost") + && isVolumeCharacter(path.charCodeAt(authorityEnd + 1)) ) { const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2); if (volumeSeparatorEnd !== -1) { @@ -329,11 +329,16 @@ namespace ts { // separator but not including any trailing directory separator. path = removeTrailingDirectorySeparator(path); const name = path.slice(Math.max(getRootLength(path), path.lastIndexOf(directorySeparator) + 1)); - const extension = extensions !== undefined && ignoreCase !== undefined ? getAnyExtensionFromPath(name, extensions, ignoreCase) : undefined; + const extension = extensions !== undefined && ignoreCase !== undefined + ? getAnyExtensionFromPath(name, extensions, ignoreCase) : undefined; return extension ? name.slice(0, name.length - extension.length) : name; } - function tryGetExtensionFromPath(path: string, extension: string, stringEqualityComparer: (a: string, b: string) => boolean) { + function tryGetExtensionFromPath( + path: string, + extension: string, + stringEqualityComparer: (a: string, b: string) => boolean, + ) { if (!startsWith(extension, ".")) extension = "." + extension; if (path.length >= extension.length && path.charCodeAt(path.length - extension.length) === CharacterCodes.dot) { const pathExtension = path.slice(path.length - extension.length); @@ -343,7 +348,11 @@ namespace ts { } } - function getAnyExtensionFromPathWorker(path: string, extensions: string | readonly string[], stringEqualityComparer: (a: string, b: string) => boolean) { + function getAnyExtensionFromPathWorker( + path: string, + extensions: string | readonly string[], + stringEqualityComparer: (a: string, b: string) => boolean, + ) { if (typeof extensions === "string") { return tryGetExtensionFromPath(path, extensions, stringEqualityComparer) || ""; } @@ -374,12 +383,24 @@ namespace ts { * getAnyExtensionFromPath("/path/to/file.js", [".ext", ".js"], true) === ".js" * getAnyExtensionFromPath("/path/to/file.ext", ".EXT", false) === "" */ - export function getAnyExtensionFromPath(path: string, extensions: string | readonly string[], ignoreCase: boolean): string; - export function getAnyExtensionFromPath(path: string, extensions?: string | readonly string[], ignoreCase?: boolean): string { + export function getAnyExtensionFromPath( + path: string, + extensions: string | readonly string[], + ignoreCase: boolean, + ): string; + export function getAnyExtensionFromPath( + path: string, + extensions?: string | readonly string[], + ignoreCase?: boolean, + ): string { // Retrieves any string from the final "." onwards from a base file name. // Unlike extensionFromPath, which throws an exception on unrecognized extensions. if (extensions) { - return getAnyExtensionFromPathWorker(removeTrailingDirectorySeparator(path), extensions, ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive); + return getAnyExtensionFromPathWorker( + removeTrailingDirectorySeparator(path), + extensions, + ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive, + ); } const baseFileName = getBaseFileName(path); const extensionIndex = baseFileName.lastIndexOf("."); @@ -565,7 +586,8 @@ namespace ts { } // Other paths require full normalization const normalized = getPathFromPathComponents(reducePathComponents(getPathComponents(path))); - return normalized && hasTrailingDirectorySeparator(path) ? ensureTrailingDirectorySeparator(normalized) : normalized; + return normalized && hasTrailingDirectorySeparator(path) ? ensureTrailingDirectorySeparator(normalized) + : normalized; } function getPathWithoutRoot(pathComponents: readonly string[]) { @@ -577,7 +599,11 @@ namespace ts { return getPathWithoutRoot(getNormalizedPathComponents(fileName, currentDirectory)); } - export function toPath(fileName: string, basePath: string | undefined, getCanonicalFileName: (path: string) => string): Path { + export function toPath( + fileName: string, + basePath: string | undefined, + getCanonicalFileName: (path: string) => string, + ): Path { const nonCanonicalizedPath = isRootedDiskPath(fileName) ? normalizePath(fileName) : getNormalizedAbsolutePath(fileName, basePath); @@ -654,9 +680,20 @@ namespace ts { * changeAnyExtension("/path/to/file.ext", ".js", [".ext", ".ts"]) === "/path/to/file.js" * ``` */ - export function changeAnyExtension(path: string, ext: string, extensions: string | readonly string[], ignoreCase: boolean): string; - export function changeAnyExtension(path: string, ext: string, extensions?: string | readonly string[], ignoreCase?: boolean) { - const pathext = extensions !== undefined && ignoreCase !== undefined ? getAnyExtensionFromPath(path, extensions, ignoreCase) : getAnyExtensionFromPath(path); + export function changeAnyExtension( + path: string, + ext: string, + extensions: string | readonly string[], + ignoreCase: boolean, + ): string; + export function changeAnyExtension( + path: string, + ext: string, + extensions?: string | readonly string[], + ignoreCase?: boolean, + ) { + const pathext = extensions !== undefined && ignoreCase !== undefined + ? getAnyExtensionFromPath(path, extensions, ignoreCase) : getAnyExtensionFromPath(path); return pathext ? path.slice(0, path.length - pathext.length) + (startsWith(ext, ".") ? ext : "." + ext) : path; } @@ -735,8 +772,18 @@ namespace ts { * Determines whether a `parent` path contains a `child` path using the provide case sensitivity. */ export function containsPath(parent: string, child: string, ignoreCase?: boolean): boolean; - export function containsPath(parent: string, child: string, currentDirectory: string, ignoreCase?: boolean): boolean; - export function containsPath(parent: string, child: string, currentDirectory?: string | boolean, ignoreCase?: boolean) { + export function containsPath( + parent: string, + child: string, + currentDirectory: string, + ignoreCase?: boolean, + ): boolean; + export function containsPath( + parent: string, + child: string, + currentDirectory?: string | boolean, + ignoreCase?: boolean, + ) { if (typeof currentDirectory === "string") { parent = combinePaths(currentDirectory, parent); child = combinePaths(currentDirectory, child); @@ -769,15 +816,25 @@ namespace ts { * * Use `containsPath` if file names are not already reduced and absolute. */ - export function startsWithDirectory(fileName: string, directoryName: string, getCanonicalFileName: GetCanonicalFileName): boolean { + export function startsWithDirectory( + fileName: string, + directoryName: string, + getCanonicalFileName: GetCanonicalFileName, + ): boolean { const canonicalFileName = getCanonicalFileName(fileName); const canonicalDirectoryName = getCanonicalFileName(directoryName); - return startsWith(canonicalFileName, canonicalDirectoryName + "/") || startsWith(canonicalFileName, canonicalDirectoryName + "\\"); + return startsWith(canonicalFileName, canonicalDirectoryName + "/") + || startsWith(canonicalFileName, canonicalDirectoryName + "\\"); } //// Relative Paths - export function getPathComponentsRelativeTo(from: string, to: string, stringEqualityComparer: (a: string, b: string) => boolean, getCanonicalFileName: GetCanonicalFileName) { + export function getPathComponentsRelativeTo( + from: string, + to: string, + stringEqualityComparer: (a: string, b: string) => boolean, + getCanonicalFileName: GetCanonicalFileName, + ) { const fromComponents = reducePathComponents(getPathComponents(from)); const toComponents = reducePathComponents(getPathComponents(to)); @@ -808,26 +865,62 @@ namespace ts { /** * Gets a relative path that can be used to traverse between `from` and `to`. */ - export function getRelativePathFromDirectory(fromDirectory: string, to: string, getCanonicalFileName: GetCanonicalFileName): string; // eslint-disable-line @typescript-eslint/unified-signatures - export function getRelativePathFromDirectory(fromDirectory: string, to: string, getCanonicalFileNameOrIgnoreCase: GetCanonicalFileName | boolean) { - Debug.assert((getRootLength(fromDirectory) > 0) === (getRootLength(to) > 0), "Paths must either both be absolute or both be relative"); - const getCanonicalFileName = typeof getCanonicalFileNameOrIgnoreCase === "function" ? getCanonicalFileNameOrIgnoreCase : identity; - const ignoreCase = typeof getCanonicalFileNameOrIgnoreCase === "boolean" ? getCanonicalFileNameOrIgnoreCase : false; - const pathComponents = getPathComponentsRelativeTo(fromDirectory, to, ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive, getCanonicalFileName); + export function getRelativePathFromDirectory( + fromDirectory: string, + to: string, + getCanonicalFileName: GetCanonicalFileName, + ): string; // eslint-disable-line @typescript-eslint/unified-signatures + export function getRelativePathFromDirectory( + fromDirectory: string, + to: string, + getCanonicalFileNameOrIgnoreCase: GetCanonicalFileName | boolean, + ) { + Debug.assert( + (getRootLength(fromDirectory) > 0) === (getRootLength(to) > 0), + "Paths must either both be absolute or both be relative", + ); + const getCanonicalFileName = typeof getCanonicalFileNameOrIgnoreCase === "function" + ? getCanonicalFileNameOrIgnoreCase : identity; + const ignoreCase = typeof getCanonicalFileNameOrIgnoreCase === "boolean" ? getCanonicalFileNameOrIgnoreCase + : false; + const pathComponents = getPathComponentsRelativeTo( + fromDirectory, + to, + ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive, + getCanonicalFileName, + ); return getPathFromPathComponents(pathComponents); } - export function convertToRelativePath(absoluteOrRelativePath: string, basePath: string, getCanonicalFileName: (path: string) => string): string { + export function convertToRelativePath( + absoluteOrRelativePath: string, + basePath: string, + getCanonicalFileName: (path: string) => string, + ): string { return !isRootedDiskPath(absoluteOrRelativePath) ? absoluteOrRelativePath - : getRelativePathToDirectoryOrUrl(basePath, absoluteOrRelativePath, basePath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); + : getRelativePathToDirectoryOrUrl( + basePath, + absoluteOrRelativePath, + basePath, + getCanonicalFileName, + /*isAbsolutePathAnUrl*/ false, + ); } export function getRelativePathFromFile(from: string, to: string, getCanonicalFileName: GetCanonicalFileName) { - return ensurePathIsNonModuleName(getRelativePathFromDirectory(getDirectoryPath(from), to, getCanonicalFileName)); + return ensurePathIsNonModuleName( + getRelativePathFromDirectory(getDirectoryPath(from), to, getCanonicalFileName), + ); } - export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, isAbsolutePathAnUrl: boolean) { + export function getRelativePathToDirectoryOrUrl( + directoryPathOrUrl: string, + relativeOrAbsolutePath: string, + currentDirectory: string, + getCanonicalFileName: GetCanonicalFileName, + isAbsolutePathAnUrl: boolean, + ) { const pathComponents = getPathComponentsRelativeTo( resolvePath(currentDirectory, directoryPathOrUrl), resolvePath(currentDirectory, relativeOrAbsolutePath), @@ -849,9 +942,18 @@ namespace ts { /** * Calls `callback` on `directory` and every ancestor directory it has, returning the first defined result. */ - export function forEachAncestorDirectory(directory: Path, callback: (directory: Path) => T | undefined): T | undefined; - export function forEachAncestorDirectory(directory: string, callback: (directory: string) => T | undefined): T | undefined; - export function forEachAncestorDirectory(directory: Path, callback: (directory: Path) => T | undefined): T | undefined { + export function forEachAncestorDirectory( + directory: Path, + callback: (directory: Path) => T | undefined, + ): T | undefined; + export function forEachAncestorDirectory( + directory: string, + callback: (directory: string) => T | undefined, + ): T | undefined; + export function forEachAncestorDirectory( + directory: Path, + callback: (directory: Path) => T | undefined, + ): T | undefined { while (true) { const result = callback(directory); if (result !== undefined) { diff --git a/src/compiler/performanceCore.ts b/src/compiler/performanceCore.ts index a2d34417ce858..b84a88e980d12 100644 --- a/src/compiler/performanceCore.ts +++ b/src/compiler/performanceCore.ts @@ -37,7 +37,9 @@ namespace ts { observe(options: { entryTypes: readonly ("mark" | "measure")[]; }): void; } - export type PerformanceObserverConstructor = new (callback: (list: PerformanceObserverEntryList, observer: PerformanceObserver) => void) => PerformanceObserver; + export type PerformanceObserverConstructor = new ( + callback: (list: PerformanceObserverEntryList, observer: PerformanceObserver) => void, + ) => PerformanceObserver; export type PerformanceEntryList = PerformanceEntry[]; // Browser globals for the Web Performance User Timings API @@ -46,22 +48,25 @@ namespace ts { declare const PerformanceObserver: PerformanceObserverConstructor | undefined; // eslint-disable-next-line @typescript-eslint/naming-convention - function hasRequiredAPI(performance: Performance | undefined, PerformanceObserver: PerformanceObserverConstructor | undefined) { - return typeof performance === "object" && - typeof performance.timeOrigin === "number" && - typeof performance.mark === "function" && - typeof performance.measure === "function" && - typeof performance.now === "function" && - typeof performance.clearMarks === "function" && - typeof performance.clearMeasures === "function" && - typeof PerformanceObserver === "function"; + function hasRequiredAPI( + performance: Performance | undefined, + PerformanceObserver: PerformanceObserverConstructor | undefined, + ) { + return typeof performance === "object" + && typeof performance.timeOrigin === "number" + && typeof performance.mark === "function" + && typeof performance.measure === "function" + && typeof performance.now === "function" + && typeof performance.clearMarks === "function" + && typeof performance.clearMeasures === "function" + && typeof PerformanceObserver === "function"; } function tryGetWebPerformanceHooks(): PerformanceHooks | undefined { if ( - typeof performance === "object" && - typeof PerformanceObserver === "function" && - hasRequiredAPI(performance, PerformanceObserver) + typeof performance === "object" + && typeof PerformanceObserver === "function" + && hasRequiredAPI(performance, PerformanceObserver) ) { return { // For now we always write native performance events when running in the browser. We may @@ -75,10 +80,15 @@ namespace ts { } function tryGetNodePerformanceHooks(): PerformanceHooks | undefined { - if (typeof process !== "undefined" && process.nextTick && !process.browser && typeof module === "object" && typeof require === "function") { + if ( + typeof process !== "undefined" && process.nextTick && !process.browser && typeof module === "object" + && typeof require === "function" + ) { try { let performance: Performance; - const { performance: nodePerformance, PerformanceObserver } = require("perf_hooks") as typeof import("perf_hooks"); + const { performance: nodePerformance, PerformanceObserver } = require( + "perf_hooks", + ) as typeof import("perf_hooks"); if (hasRequiredAPI(nodePerformance as unknown as Performance, PerformanceObserver)) { performance = nodePerformance as unknown as Performance; // There is a bug in Node's performance.measure prior to 12.16.3/13.13.0 that does not @@ -140,7 +150,7 @@ namespace ts { } /** Gets a timestamp with (at least) ms resolution */ - export const timestamp = nativePerformance ? () => nativePerformance.now() : - Date.now ? Date.now : - () => +(new Date()); + export const timestamp = nativePerformance ? () => nativePerformance.now() + : Date.now ? Date.now + : () => +(new Date()); } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index bb8f4734042a6..d641bbb49d2b8 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1,5 +1,9 @@ namespace ts { - export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string | undefined { + export function findConfigFile( + searchPath: string, + fileExists: (fileName: string) => boolean, + configName = "tsconfig.json", + ): string | undefined { return forEachAncestorDirectory(searchPath, ancestor => { const fileName = combinePaths(ancestor, configName); return fileExists(fileName) ? fileName : undefined; @@ -13,7 +17,11 @@ namespace ts { } /* @internal */ - export function computeCommonSourceDirectoryOfFilenames(fileNames: readonly string[], currentDirectory: string, getCanonicalFileName: GetCanonicalFileName): string { + export function computeCommonSourceDirectoryOfFilenames( + fileNames: readonly string[], + currentDirectory: string, + getCanonicalFileName: GetCanonicalFileName, + ): string { let commonPathComponents: string[] | undefined; const failed = forEach(fileNames, sourceFile => { // Each file contributes into common source file path @@ -63,10 +71,18 @@ namespace ts { } /*@internal*/ - export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost { + export function createCompilerHostWorker( + options: CompilerOptions, + setParentNodes?: boolean, + system = sys, + ): CompilerHost { const existingDirectories = new Map(); const getCanonicalFileName = createGetCanonicalFileName(system.useCaseSensitiveFileNames); - function getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void): SourceFile | undefined { + function getSourceFile( + fileName: string, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + onError?: (message: string) => void, + ): SourceFile | undefined { let text: string | undefined; try { performance.mark("beforeIORead"); @@ -80,7 +96,8 @@ namespace ts { } text = ""; } - return text !== undefined ? createSourceFile(fileName, text, languageVersionOrOptions, setParentNodes) : undefined; + return text !== undefined ? createSourceFile(fileName, text, languageVersionOrOptions, setParentNodes) + : undefined; } function directoryExists(directoryPath: string): boolean { @@ -94,7 +111,12 @@ namespace ts { return false; } - function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) { + function writeFile( + fileName: string, + data: string, + writeByteOrderMark: boolean, + onError?: (message: string) => void, + ) { try { performance.mark("beforeIOWrite"); @@ -142,7 +164,8 @@ namespace ts { getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "", getDirectories: (path: string) => system.getDirectories(path), realpath, - readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth), + readDirectory: (path, extensions, include, exclude, depth) => + system.readDirectory(path, extensions, include, exclude, depth), createDirectory: d => system.createDirectory(d), createHash: maybeBind(system, system.createHash), }; @@ -197,17 +220,18 @@ namespace ts { return setReadFileCache(key, fileName); }; - const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersion, onError, shouldCreateNewSourceFile) => { - const key = toPath(fileName); - const value = sourceFileCache.get(key); - if (value) return value; + const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile + ? (fileName, languageVersion, onError, shouldCreateNewSourceFile) => { + const key = toPath(fileName); + const value = sourceFileCache.get(key); + if (value) return value; - const sourceFile = getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); - if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) { - sourceFileCache.set(key, sourceFile); - } - return sourceFile; - } : undefined; + const sourceFile = getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); + if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) { + sourceFileCache.set(key, sourceFile); + } + return sourceFile; + } : undefined; // fileExists for any kind of extension host.fileExists = fileName => { @@ -269,9 +293,21 @@ namespace ts { }; } - export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; - /*@internal*/ export function getPreEmitDiagnostics(program: BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; // eslint-disable-line @typescript-eslint/unified-signatures - export function getPreEmitDiagnostics(program: Program | BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { + export function getPreEmitDiagnostics( + program: Program, + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[]; + /*@internal*/ export function getPreEmitDiagnostics( + program: BuilderProgram, + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[]; // eslint-disable-line @typescript-eslint/unified-signatures + export function getPreEmitDiagnostics( + program: Program | BuilderProgram, + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[] { let diagnostics: Diagnostic[] | undefined; diagnostics = addRange(diagnostics, program.getConfigFileParsingDiagnostics()); diagnostics = addRange(diagnostics, program.getOptionsDiagnostics(cancellationToken)); @@ -302,12 +338,18 @@ namespace ts { } export function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string { - const errorMessage = `${diagnosticCategoryName(diagnostic)} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`; + const errorMessage = `${diagnosticCategoryName(diagnostic)} TS${diagnostic.code}: ${ + flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine()) + }${host.getNewLine()}`; if (diagnostic.file) { const { line, character } = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); // TODO: GH#18217 const fileName = diagnostic.file.fileName; - const relativeFileName = convertToRelativePath(fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName)); + const relativeFileName = convertToRelativePath( + fileName, + host.getCurrentDirectory(), + fileName => host.getCanonicalFileName(fileName), + ); return `${relativeFileName}(${line + 1},${character + 1}): ` + errorMessage; } @@ -346,7 +388,14 @@ namespace ts { return formatStyle + text + resetEscapeSequence; } - function formatCodeSpan(file: SourceFile, start: number, length: number, indent: string, squiggleColor: ForegroundColorEscapeSequences, host: FormatDiagnosticsHost) { + function formatCodeSpan( + file: SourceFile, + start: number, + length: number, + indent: string, + squiggleColor: ForegroundColorEscapeSequences, + host: FormatDiagnosticsHost, + ) { const { line: firstLine, character: firstLineChar } = getLineAndCharacterOfPosition(file, start); const { line: lastLine, character: lastLineChar } = getLineAndCharacterOfPosition(file, start + length); const lastLineInFile = getLineAndCharacterOfPosition(file, file.text.length).line; @@ -363,7 +412,8 @@ namespace ts { // If the error spans over 5 lines, we'll only show the first 2 and last 2 lines, // so we'll skip ahead to the second-to-last line. if (hasMoreThanFiveLines && firstLine + 1 < i && i < lastLine - 1) { - context += indent + formatColorAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + host.getNewLine(); + context += indent + formatColorAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + + gutterSeparator + host.getNewLine(); i = lastLine - 1; } @@ -374,7 +424,8 @@ namespace ts { lineContent = lineContent.replace(/\t/g, " "); // convert tabs to single spaces // Output the gutter and the actual contents of the line. - context += indent + formatColorAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator; + context += indent + formatColorAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + + gutterSeparator; context += lineContent + host.getNewLine(); // Output the gutter and the error span for the line using tildes. @@ -401,9 +452,19 @@ namespace ts { } /* @internal */ - export function formatLocation(file: SourceFile, start: number, host: FormatDiagnosticsHost, color = formatColorAndReset) { + export function formatLocation( + file: SourceFile, + start: number, + host: FormatDiagnosticsHost, + color = formatColorAndReset, + ) { const { line: firstLine, character: firstLineChar } = getLineAndCharacterOfPosition(file, start); // TODO: GH#18217 - const relativeFileName = host ? convertToRelativePath(file.fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName)) : file.fileName; + const relativeFileName = host + ? convertToRelativePath( + file.fileName, + host.getCurrentDirectory(), + fileName => host.getCanonicalFileName(fileName), + ) : file.fileName; let output = ""; output += color(relativeFileName, ForegroundColorEscapeSequences.Cyan); @@ -414,7 +475,10 @@ namespace ts { return output; } - export function formatDiagnosticsWithColorAndContext(diagnostics: readonly Diagnostic[], host: FormatDiagnosticsHost): string { + export function formatDiagnosticsWithColorAndContext( + diagnostics: readonly Diagnostic[], + host: FormatDiagnosticsHost, + ): string { let output = ""; for (const diagnostic of diagnostics) { if (diagnostic.file) { @@ -429,7 +493,14 @@ namespace ts { if (diagnostic.file) { output += host.getNewLine(); - output += formatCodeSpan(diagnostic.file, diagnostic.start!, diagnostic.length!, "", getCategoryFormat(diagnostic.category), host); // TODO: GH#18217 + output += formatCodeSpan( + diagnostic.file, + diagnostic.start!, + diagnostic.length!, + "", + getCategoryFormat(diagnostic.category), + host, + ); // TODO: GH#18217 } if (diagnostic.relatedInformation) { output += host.getNewLine(); @@ -437,7 +508,14 @@ namespace ts { if (file) { output += host.getNewLine(); output += halfIndent + formatLocation(file, start!, host); // TODO: GH#18217 - output += formatCodeSpan(file, start!, length!, indent, ForegroundColorEscapeSequences.Cyan, host); // TODO: GH#18217 + output += formatCodeSpan( + file, + start!, + length!, + indent, + ForegroundColorEscapeSequences.Cyan, + host, + ); // TODO: GH#18217 } output += host.getNewLine(); output += indent + flattenDiagnosticMessageText(messageText, host.getNewLine()); @@ -448,7 +526,11 @@ namespace ts { return output; } - export function flattenDiagnosticMessageText(diag: string | DiagnosticMessageChain | undefined, newLine: string, indent = 0): string { + export function flattenDiagnosticMessageText( + diag: string | DiagnosticMessageChain | undefined, + newLine: string, + indent = 0, + ): string { if (isString(diag)) { return diag; } @@ -474,7 +556,18 @@ namespace ts { } /* @internal */ - export function loadWithTypeDirectiveCache(names: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, containingFileMode: SourceFile["impliedNodeFormat"], loader: (name: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined, resolutionMode: SourceFile["impliedNodeFormat"]) => T): T[] { + export function loadWithTypeDirectiveCache( + names: string[] | readonly FileReference[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + containingFileMode: SourceFile["impliedNodeFormat"], + loader: ( + name: string, + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + resolutionMode: SourceFile["impliedNodeFormat"], + ) => T, + ): T[] { if (names.length === 0) { return []; } @@ -514,7 +607,10 @@ namespace ts { * Calculates the resulting resolution mode for some reference in some file - this is generally the explicitly * provided resolution mode in the reference, unless one is not present, in which case it is the mode of the containing file. */ - export function getModeForFileReference(ref: FileReference | string, containingFileMode: SourceFile["impliedNodeFormat"]) { + export function getModeForFileReference( + ref: FileReference | string, + containingFileMode: SourceFile["impliedNodeFormat"], + ) { return (isString(ref) ? containingFileMode : ref.resolutionMode) || containingFileMode; } @@ -525,11 +621,20 @@ namespace ts { * @param file File to fetch the resolution mode within * @param index Index into the file's complete resolution list to get the resolution of - this is a concatenation of the file's imports and module augmentations */ - export function getModeForResolutionAtIndex(file: SourceFile, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; + export function getModeForResolutionAtIndex( + file: SourceFile, + index: number, + ): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; /** @internal */ // eslint-disable-next-line @typescript-eslint/unified-signatures - export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; - export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined { + export function getModeForResolutionAtIndex( + file: SourceFileImportsList, + index: number, + ): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; + export function getModeForResolutionAtIndex( + file: SourceFileImportsList, + index: number, + ): ModuleKind.CommonJS | ModuleKind.ESNext | undefined { if (file.impliedNodeFormat === undefined) return undefined; // we ensure all elements of file.imports and file.moduleAugmentations have the relevant parent pointers set during program setup, // so it's safe to use them even pre-bind @@ -556,7 +661,10 @@ namespace ts { * @param usage The module reference string * @returns The final resolution mode of the import */ - export function getModeForUsageLocation(file: { impliedNodeFormat?: SourceFile["impliedNodeFormat"]; }, usage: StringLiteralLike) { + export function getModeForUsageLocation( + file: { impliedNodeFormat?: SourceFile["impliedNodeFormat"]; }, + usage: StringLiteralLike, + ) { if (file.impliedNodeFormat === undefined) return undefined; if ((isImportDeclaration(usage.parent) || isExportDeclaration(usage.parent))) { const isTypeOnly = isExclusivelyTypeOnlyImportOrExport(usage.parent); @@ -580,20 +688,31 @@ namespace ts { // in esm files, import=require statements are cjs format, otherwise everything is esm // imports are only parent'd up to their containing declaration/expression, so access farther parents with care const exprParentParent = walkUpParenthesizedExpressions(usage.parent)?.parent; - return exprParentParent && isImportEqualsDeclaration(exprParentParent) ? ModuleKind.CommonJS : ModuleKind.ESNext; + return exprParentParent && isImportEqualsDeclaration(exprParentParent) ? ModuleKind.CommonJS + : ModuleKind.ESNext; } /* @internal */ - export function getResolutionModeOverrideForClause(clause: AssertClause | undefined, grammarErrorOnNode?: (node: Node, diagnostic: DiagnosticMessage) => void) { + export function getResolutionModeOverrideForClause( + clause: AssertClause | undefined, + grammarErrorOnNode?: (node: Node, diagnostic: DiagnosticMessage) => void, + ) { if (!clause) return undefined; if (length(clause.elements) !== 1) { - grammarErrorOnNode?.(clause, Diagnostics.Type_import_assertions_should_have_exactly_one_key_resolution_mode_with_value_import_or_require); + grammarErrorOnNode?.( + clause, + Diagnostics + .Type_import_assertions_should_have_exactly_one_key_resolution_mode_with_value_import_or_require, + ); return undefined; } const elem = clause.elements[0]; if (!isStringLiteralLike(elem.name)) return undefined; if (elem.name.text !== "resolution-mode") { - grammarErrorOnNode?.(elem.name, Diagnostics.resolution_mode_is_the_only_valid_key_for_type_import_assertions); + grammarErrorOnNode?.( + elem.name, + Diagnostics.resolution_mode_is_the_only_valid_key_for_type_import_assertions, + ); return undefined; } if (!isStringLiteralLike(elem.value)) return undefined; @@ -605,7 +724,18 @@ namespace ts { } /* @internal */ - export function loadWithModeAwareCache(names: string[], containingFile: SourceFile, containingFileName: string, redirectedReference: ResolvedProjectReference | undefined, loader: (name: string, resolverMode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, containingFileName: string, redirectedReference: ResolvedProjectReference | undefined) => T): T[] { + export function loadWithModeAwareCache( + names: string[], + containingFile: SourceFile, + containingFileName: string, + redirectedReference: ResolvedProjectReference | undefined, + loader: ( + name: string, + resolverMode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, + containingFileName: string, + redirectedReference: ResolvedProjectReference | undefined, + ) => T, + ): T[] { if (names.length === 0) { return []; } @@ -631,16 +761,30 @@ namespace ts { /* @internal */ export function forEachResolvedProjectReference( resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined, - cb: (resolvedProjectReference: ResolvedProjectReference, parent: ResolvedProjectReference | undefined) => T | undefined, + cb: ( + resolvedProjectReference: ResolvedProjectReference, + parent: ResolvedProjectReference | undefined, + ) => T | undefined, ): T | undefined { - return forEachProjectReference(/*projectReferences*/ undefined, resolvedProjectReferences, (resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent)); + return forEachProjectReference( + /*projectReferences*/ undefined, + resolvedProjectReferences, + (resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent), + ); } function forEachProjectReference( projectReferences: readonly ProjectReference[] | undefined, resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined, - cbResolvedRef: (resolvedRef: ResolvedProjectReference | undefined, parent: ResolvedProjectReference | undefined, index: number) => T | undefined, - cbRef?: (projectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReference | undefined) => T | undefined, + cbResolvedRef: ( + resolvedRef: ResolvedProjectReference | undefined, + parent: ResolvedProjectReference | undefined, + index: number, + ) => T | undefined, + cbRef?: ( + projectReferences: readonly ProjectReference[] | undefined, + parent: ResolvedProjectReference | undefined, + ) => T | undefined, ): T | undefined { let seenResolvedRefs: Set | undefined; @@ -709,19 +853,28 @@ namespace ts { } /*@internal*/ - export function isReferenceFileLocation(location: ReferenceFileLocation | SyntheticReferenceFileLocation): location is ReferenceFileLocation { + export function isReferenceFileLocation( + location: ReferenceFileLocation | SyntheticReferenceFileLocation, + ): location is ReferenceFileLocation { return (location as ReferenceFileLocation).pos !== undefined; } /*@internal*/ - export function getReferencedFileLocation(getSourceFileByPath: (path: Path) => SourceFile | undefined, ref: ReferencedFile): ReferenceFileLocation | SyntheticReferenceFileLocation { + export function getReferencedFileLocation( + getSourceFileByPath: (path: Path) => SourceFile | undefined, + ref: ReferencedFile, + ): ReferenceFileLocation | SyntheticReferenceFileLocation { const file = Debug.checkDefined(getSourceFileByPath(ref.file)); const { kind, index } = ref; - let pos: number | undefined, end: number | undefined, packageId: PackageId | undefined, resolutionMode: FileReference["resolutionMode"] | undefined; + let pos: number | undefined, + end: number | undefined, + packageId: PackageId | undefined, + resolutionMode: FileReference["resolutionMode"] | undefined; switch (kind) { case FileIncludeKind.Import: const importLiteral = getModuleNameStringLiteralAt(file, index); - packageId = file.resolvedModules?.get(importLiteral.text, getModeForResolutionAtIndex(file, index))?.packageId; + packageId = file.resolvedModules?.get(importLiteral.text, getModeForResolutionAtIndex(file, index)) + ?.packageId; if (importLiteral.pos === -1) return { file, packageId, text: importLiteral.text }; pos = skipTrivia(file.text, importLiteral.pos); end = importLiteral.end; @@ -731,7 +884,10 @@ namespace ts { break; case FileIncludeKind.TypeReferenceDirective: ({ pos, end, resolutionMode } = file.typeReferenceDirectives[index]); - packageId = file.resolvedTypeReferenceDirectiveNames?.get(toFileNameLowerCase(file.typeReferenceDirectives[index].fileName), resolutionMode || file.impliedNodeFormat)?.packageId; + packageId = file.resolvedTypeReferenceDirectiveNames?.get( + toFileNameLowerCase(file.typeReferenceDirectives[index].fileName), + resolutionMode || file.impliedNodeFormat, + )?.packageId; break; case FileIncludeKind.LibReferenceDirective: ({ pos, end } = file.libReferenceDirectives[index]); @@ -780,13 +936,15 @@ namespace ts { // If everything matches but the text of config file is changed, // error locations can change for program options, so update the program - if (currentOptions.configFile && newOptions.configFile) return currentOptions.configFile.text === newOptions.configFile.text; + if (currentOptions.configFile && newOptions.configFile) { + return currentOptions.configFile.text === newOptions.configFile.text; + } return true; function sourceFileNotUptoDate(sourceFile: SourceFile) { - return !sourceFileVersionUptoDate(sourceFile) || - hasInvalidatedResolutions(sourceFile.path); + return !sourceFileVersionUptoDate(sourceFile) + || hasInvalidatedResolutions(sourceFile.path); } function sourceFileVersionUptoDate(sourceFile: SourceFile) { @@ -794,11 +952,14 @@ namespace ts { } function projectReferenceUptoDate(oldRef: ProjectReference, newRef: ProjectReference, index: number) { - return projectReferenceIsEqualTo(oldRef, newRef) && - resolvedProjectReferenceUptoDate(program!.getResolvedProjectReferences()![index], oldRef); + return projectReferenceIsEqualTo(oldRef, newRef) + && resolvedProjectReferenceUptoDate(program!.getResolvedProjectReferences()![index], oldRef); } - function resolvedProjectReferenceUptoDate(oldResolvedRef: ResolvedProjectReference | undefined, oldRef: ProjectReference): boolean { + function resolvedProjectReferenceUptoDate( + oldResolvedRef: ResolvedProjectReference | undefined, + oldRef: ProjectReference, + ): boolean { if (oldResolvedRef) { // Assume true if (contains(seenResolvedRefs, oldResolvedRef)) return true; @@ -810,7 +971,9 @@ namespace ts { if (!newParsedCommandLine) return false; // If change in source file - if (oldResolvedRef.commandLine.options.configFile !== newParsedCommandLine.options.configFile) return false; + if (oldResolvedRef.commandLine.options.configFile !== newParsedCommandLine.options.configFile) { + return false; + } // check file names if (!arrayIsEqualTo(oldResolvedRef.commandLine.fileNames, newParsedCommandLine.fileNames)) return false; @@ -819,7 +982,14 @@ namespace ts { (seenResolvedRefs || (seenResolvedRefs = [])).push(oldResolvedRef); // If child project references are upto date, this project reference is uptodate - return !forEach(oldResolvedRef.references, (childResolvedRef, index) => !resolvedProjectReferenceUptoDate(childResolvedRef, oldResolvedRef.commandLine.projectReferences![index])); + return !forEach( + oldResolvedRef.references, + (childResolvedRef, index) => + !resolvedProjectReferenceUptoDate( + childResolvedRef, + oldResolvedRef.commandLine.projectReferences![index], + ), + ); } // In old program, not able to resolve project reference path, @@ -830,9 +1000,9 @@ namespace ts { } export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): readonly Diagnostic[] { - return configFileParseResult.options.configFile ? - [...configFileParseResult.options.configFile.parseDiagnostics, ...configFileParseResult.errors] : - configFileParseResult.errors; + return configFileParseResult.options.configFile + ? [...configFileParseResult.options.configFile.parseDiagnostics, ...configFileParseResult.errors] + : configFileParseResult.errors; } /** @@ -845,7 +1015,12 @@ namespace ts { * @param options The compiler options to perform the analysis under - relevant options are `moduleResolution` and `traceResolution` * @returns `undefined` if the path has no relevant implied format, `ModuleKind.ESNext` for esm format, and `ModuleKind.CommonJS` for cjs format */ - export function getImpliedNodeFormatForFile(fileName: Path, packageJsonInfoCache: PackageJsonInfoCache | undefined, host: ModuleResolutionHost, options: CompilerOptions): ModuleKind.ESNext | ModuleKind.CommonJS | undefined { + export function getImpliedNodeFormatForFile( + fileName: Path, + packageJsonInfoCache: PackageJsonInfoCache | undefined, + host: ModuleResolutionHost, + options: CompilerOptions, + ): ModuleKind.ESNext | ModuleKind.CommonJS | undefined { const result = getImpliedNodeFormatForFileWorker(fileName, packageJsonInfoCache, host, options); return typeof result === "object" ? result.impliedNodeFormat : result; } @@ -860,10 +1035,18 @@ namespace ts { switch (getEmitModuleResolutionKind(options)) { case ModuleResolutionKind.Node16: case ModuleResolutionKind.NodeNext: - return fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Mjs]) ? ModuleKind.ESNext : - fileExtensionIsOneOf(fileName, [Extension.Dcts, Extension.Cts, Extension.Cjs]) ? ModuleKind.CommonJS : - fileExtensionIsOneOf(fileName, [Extension.Dts, Extension.Ts, Extension.Tsx, Extension.Js, Extension.Jsx]) ? lookupFromPackageJson() : - undefined; // other extensions, like `json` or `tsbuildinfo`, are set as `undefined` here but they should never be fed through the transformer pipeline + return fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Mjs]) + ? ModuleKind.ESNext + : fileExtensionIsOneOf(fileName, [Extension.Dcts, Extension.Cts, Extension.Cjs]) + ? ModuleKind.CommonJS + : fileExtensionIsOneOf(fileName, [ + Extension.Dts, + Extension.Ts, + Extension.Tsx, + Extension.Js, + Extension.Jsx, + ]) ? lookupFromPackageJson() + : undefined; // other extensions, like `json` or `tsbuildinfo`, are set as `undefined` here but they should never be fed through the transformer pipeline default: return undefined; } @@ -873,7 +1056,8 @@ namespace ts { state.failedLookupLocations = packageJsonLocations; state.affectingLocations = packageJsonLocations; const packageJsonScope = getPackageScopeForPath(fileName, state); - const impliedNodeFormat = packageJsonScope?.contents.packageJsonContent.type === "module" ? ModuleKind.ESNext : ModuleKind.CommonJS; + const impliedNodeFormat = packageJsonScope?.contents.packageJsonContent.type === "module" + ? ModuleKind.ESNext : ModuleKind.CommonJS; return { impliedNodeFormat, packageJsonLocations, packageJsonScope }; } } @@ -886,11 +1070,14 @@ namespace ts { Diagnostics.Another_export_default_is_here.code, Diagnostics.The_first_export_default_is_here.code, Diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module.code, - Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode.code, + Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode + .code, Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here.code, Diagnostics.constructor_is_a_reserved_word.code, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode.code, - Diagnostics.Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode.code, + Diagnostics + .Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode + .code, Diagnostics.Invalid_use_of_0_Modules_are_automatically_in_strict_mode.code, Diagnostics.Invalid_use_of_0_in_strict_mode.code, Diagnostics.A_label_is_not_allowed_here.code, @@ -929,10 +1116,14 @@ namespace ts { Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable.code, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause.code, Diagnostics.Catch_clause_variable_cannot_have_an_initializer.code, - Diagnostics.Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator.code, + Diagnostics + .Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator + .code, Diagnostics.Classes_can_only_extend_a_single_class.code, Diagnostics.Classes_may_not_have_a_field_named_constructor.code, - Diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern.code, + Diagnostics + .Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern + .code, Diagnostics.Duplicate_label_0.code, Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments.code, Diagnostics.For_await_loops_cannot_be_used_inside_a_class_static_block.code, @@ -946,7 +1137,9 @@ namespace ts { Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement.code, Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement.code, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies.code, - Diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression.code, + Diagnostics + .Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression + .code, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_identifier.code, Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain.code, Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async.code, @@ -985,7 +1178,13 @@ namespace ts { return optionsHaveChanges(program.getCompilerOptions(), newOptions, sourceFileAffectingCompilerOptions); } - function createCreateProgramOptions(rootNames: readonly string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: readonly Diagnostic[]): CreateProgramOptions { + function createCreateProgramOptions( + rootNames: readonly string[], + options: CompilerOptions, + host?: CompilerHost, + oldProgram?: Program, + configFileParsingDiagnostics?: readonly Diagnostic[], + ): CreateProgramOptions { return { rootNames, options, @@ -1020,9 +1219,28 @@ namespace ts { * @param configFileParsingDiagnostics - error during config file parsing * @returns A 'Program' object. */ - export function createProgram(rootNames: readonly string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: readonly Diagnostic[]): Program; - export function createProgram(rootNamesOrOptions: readonly string[] | CreateProgramOptions, _options?: CompilerOptions, _host?: CompilerHost, _oldProgram?: Program, _configFileParsingDiagnostics?: readonly Diagnostic[]): Program { - const createProgramOptions = isArray(rootNamesOrOptions) ? createCreateProgramOptions(rootNamesOrOptions, _options!, _host, _oldProgram, _configFileParsingDiagnostics) : rootNamesOrOptions; // TODO: GH#18217 + export function createProgram( + rootNames: readonly string[], + options: CompilerOptions, + host?: CompilerHost, + oldProgram?: Program, + configFileParsingDiagnostics?: readonly Diagnostic[], + ): Program; + export function createProgram( + rootNamesOrOptions: readonly string[] | CreateProgramOptions, + _options?: CompilerOptions, + _host?: CompilerHost, + _oldProgram?: Program, + _configFileParsingDiagnostics?: readonly Diagnostic[], + ): Program { + const createProgramOptions = isArray(rootNamesOrOptions) + ? createCreateProgramOptions( + rootNamesOrOptions, + _options!, + _host, + _oldProgram, + _configFileParsingDiagnostics, + ) : rootNamesOrOptions; // TODO: GH#18217 const { rootNames, options, configFileParsingDiagnostics, projectReferences } = createProgramOptions; let { oldProgram } = createProgramOptions; @@ -1048,7 +1266,8 @@ namespace ts { // - This calls resolveModuleNames, and then calls findSourceFile for each resolved module. // As all these operations happen - and are nested - within the createProgram call, they close over the below variables. // The current resolution depth is tracked by incrementing/decrementing as the depth first search progresses. - const maxNodeModuleJsDepth = typeof options.maxNodeModuleJsDepth === "number" ? options.maxNodeModuleJsDepth : 0; + const maxNodeModuleJsDepth = typeof options.maxNodeModuleJsDepth === "number" ? options.maxNodeModuleJsDepth + : 0; let currentNodeModulesDepth = 0; // If a module has some of its imports skipped due to being at the depth limit under node_modules, then track @@ -1058,7 +1277,10 @@ namespace ts { // Track source files that are source files found by searching under node_modules, as these shouldn't be compiled. const sourceFilesFoundSearchingNodeModules = new Map(); - tracing?.push(tracing.Phase.Program, "createProgram", { configFilePath: options.configFilePath, rootDir: options.rootDir }, /*separateBeginAndEnd*/ true); + tracing?.push(tracing.Phase.Program, "createProgram", { + configFilePath: options.configFilePath, + rootDir: options.rootDir, + }, /*separateBeginAndEnd*/ true); performance.mark("beforeProgram"); const host = createProgramOptions.host || createCompilerHost(options); @@ -1066,11 +1288,15 @@ namespace ts { let skipDefaultLib = options.noLib; const getDefaultLibraryFileName = memoize(() => host.getDefaultLibFileName(options)); - const defaultLibraryPath = host.getDefaultLibLocation ? host.getDefaultLibLocation() : getDirectoryPath(getDefaultLibraryFileName()); + const defaultLibraryPath = host.getDefaultLibLocation ? host.getDefaultLibLocation() + : getDirectoryPath(getDefaultLibraryFileName()); const programDiagnostics = createDiagnosticCollection(); const currentDirectory = host.getCurrentDirectory(); const supportedExtensions = getSupportedExtensions(options); - const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions); + const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule( + options, + supportedExtensions, + ); // Map storing if there is emit blocking diagnostics for given input const hasEmitBlockingDiagnostics = new Map(); @@ -1078,44 +1304,123 @@ namespace ts { let moduleResolutionCache: ModuleResolutionCache | undefined; let typeReferenceDirectiveResolutionCache: TypeReferenceDirectiveResolutionCache | undefined; - let actualResolveModuleNamesWorker: (moduleNames: string[], containingFile: SourceFile, containingFileName: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference) => ResolvedModuleFull[]; + let actualResolveModuleNamesWorker: ( + moduleNames: string[], + containingFile: SourceFile, + containingFileName: string, + reusedNames?: string[], + redirectedReference?: ResolvedProjectReference, + ) => ResolvedModuleFull[]; const hasInvalidatedResolutions = host.hasInvalidatedResolutions || returnFalse; if (host.resolveModuleNames) { - actualResolveModuleNamesWorker = (moduleNames, containingFile, containingFileName, reusedNames, redirectedReference) => - host.resolveModuleNames!(Debug.checkEachDefined(moduleNames), containingFileName, reusedNames, redirectedReference, options, containingFile).map(resolved => { - // An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName. - if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) { - return resolved as ResolvedModuleFull; - } - const withExtension = clone(resolved) as ResolvedModuleFull; - withExtension.extension = extensionFromPath(resolved.resolvedFileName); - return withExtension; - }); + actualResolveModuleNamesWorker = ( + moduleNames, + containingFile, + containingFileName, + reusedNames, + redirectedReference, + ) => host.resolveModuleNames!( + Debug.checkEachDefined(moduleNames), + containingFileName, + reusedNames, + redirectedReference, + options, + containingFile, + ).map(resolved => { + // An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName. + if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) { + return resolved as ResolvedModuleFull; + } + const withExtension = clone(resolved) as ResolvedModuleFull; + withExtension.extension = extensionFromPath(resolved.resolvedFileName); + return withExtension; + }); moduleResolutionCache = host.getModuleResolutionCache?.(); } else { moduleResolutionCache = createModuleResolutionCache(currentDirectory, getCanonicalFileName, options); - const loader = (moduleName: string, resolverMode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, containingFileName: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFileName, options, host, moduleResolutionCache, redirectedReference, resolverMode).resolvedModule!; // TODO: GH#18217 - actualResolveModuleNamesWorker = (moduleNames, containingFile, containingFileName, _reusedNames, redirectedReference) => loadWithModeAwareCache(Debug.checkEachDefined(moduleNames), containingFile, containingFileName, redirectedReference, loader); + const loader = ( + moduleName: string, + resolverMode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, + containingFileName: string, + redirectedReference: ResolvedProjectReference | undefined, + ) => resolveModuleName( + moduleName, + containingFileName, + options, + host, + moduleResolutionCache, + redirectedReference, + resolverMode, + ).resolvedModule!; // TODO: GH#18217 + actualResolveModuleNamesWorker = ( + moduleNames, + containingFile, + containingFileName, + _reusedNames, + redirectedReference, + ) => loadWithModeAwareCache( + Debug.checkEachDefined(moduleNames), + containingFile, + containingFileName, + redirectedReference, + loader, + ); } - let actualResolveTypeReferenceDirectiveNamesWorker: (typeDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined) => (ResolvedTypeReferenceDirective | undefined)[]; + let actualResolveTypeReferenceDirectiveNamesWorker: ( + typeDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference?: ResolvedProjectReference, + containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, + ) => (ResolvedTypeReferenceDirective | undefined)[]; if (host.resolveTypeReferenceDirectives) { - actualResolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile, redirectedReference, containingFileMode) => host.resolveTypeReferenceDirectives!(Debug.checkEachDefined(typeDirectiveNames), containingFile, redirectedReference, options, containingFileMode); + actualResolveTypeReferenceDirectiveNamesWorker = ( + typeDirectiveNames, + containingFile, + redirectedReference, + containingFileMode, + ) => host.resolveTypeReferenceDirectives!( + Debug.checkEachDefined(typeDirectiveNames), + containingFile, + redirectedReference, + options, + containingFileMode, + ); } else { - typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache(currentDirectory, getCanonicalFileName, /*options*/ undefined, moduleResolutionCache?.getPackageJsonInfoCache()); - const loader = (typesRef: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined, resolutionMode: SourceFile["impliedNodeFormat"] | undefined) => - resolveTypeReferenceDirective( - typesRef, - containingFile, - options, - host, - redirectedReference, - typeReferenceDirectiveResolutionCache, - resolutionMode, - ).resolvedTypeReferenceDirective!; // TODO: GH#18217 - actualResolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile, redirectedReference, containingFileMode) => loadWithTypeDirectiveCache(Debug.checkEachDefined(typeReferenceDirectiveNames), containingFile, redirectedReference, containingFileMode, loader); + typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache( + currentDirectory, + getCanonicalFileName, + /*options*/ undefined, + moduleResolutionCache?.getPackageJsonInfoCache(), + ); + const loader = ( + typesRef: string, + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + resolutionMode: SourceFile["impliedNodeFormat"] | undefined, + ) => resolveTypeReferenceDirective( + typesRef, + containingFile, + options, + host, + redirectedReference, + typeReferenceDirectiveResolutionCache, + resolutionMode, + ).resolvedTypeReferenceDirective!; // TODO: GH#18217 + actualResolveTypeReferenceDirectiveNamesWorker = ( + typeReferenceDirectiveNames, + containingFile, + redirectedReference, + containingFileMode, + ) => loadWithTypeDirectiveCache( + Debug.checkEachDefined(typeReferenceDirectiveNames), + containingFile, + redirectedReference, + containingFileMode, + loader, + ); } // Map from a stringified PackageId to the source file with that id. @@ -1146,17 +1451,18 @@ namespace ts { let mapFromFileToProjectReferenceRedirects: ESMap | undefined; let mapFromToProjectReferenceRedirectSource: ESMap | undefined; - const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect?.() && - !options.disableSourceOfProjectReferenceRedirect; - const { onProgramCreateComplete, fileExists, directoryExists } = updateHostForUseSourceOfProjectReferenceRedirect({ - compilerHost: host, - getSymlinkCache, - useSourceOfProjectReferenceRedirect, - toPath, - getResolvedProjectReferences, - getSourceOfProjectReferenceRedirect, - forEachResolvedProjectReference, - }); + const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect?.() + && !options.disableSourceOfProjectReferenceRedirect; + const { onProgramCreateComplete, fileExists, directoryExists } = + updateHostForUseSourceOfProjectReferenceRedirect({ + compilerHost: host, + getSymlinkCache, + useSourceOfProjectReferenceRedirect, + toPath, + getResolvedProjectReferences, + getSourceOfProjectReferenceRedirect, + forEachResolvedProjectReference, + }); const readFile = host.readFile.bind(host) as typeof host.readFile; tracing?.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram }); @@ -1183,19 +1489,40 @@ namespace ts { if (useSourceOfProjectReferenceRedirect) { if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) { for (const fileName of parsedRef.commandLine.fileNames) { - processProjectReferenceFile(fileName, { kind: FileIncludeKind.SourceFromProjectReference, index }); + processProjectReferenceFile(fileName, { + kind: FileIncludeKind.SourceFromProjectReference, + index, + }); } } } else { if (out) { - processProjectReferenceFile(changeExtension(out, ".d.ts"), { kind: FileIncludeKind.OutputFromProjectReference, index }); + processProjectReferenceFile(changeExtension(out, ".d.ts"), { + kind: FileIncludeKind.OutputFromProjectReference, + index, + }); } else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) { - const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(parsedRef.commandLine, !host.useCaseSensitiveFileNames())); + const getCommonSourceDirectory = memoize(() => + getCommonSourceDirectoryOfConfig( + parsedRef.commandLine, + !host.useCaseSensitiveFileNames(), + ) + ); for (const fileName of parsedRef.commandLine.fileNames) { - if (!isDeclarationFileName(fileName) && !fileExtensionIs(fileName, Extension.Json)) { - processProjectReferenceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory), { kind: FileIncludeKind.OutputFromProjectReference, index }); + if ( + !isDeclarationFileName(fileName) && !fileExtensionIs(fileName, Extension.Json) + ) { + processProjectReferenceFile( + getOutputDeclarationFileName( + fileName, + parsedRef.commandLine, + !host.useCaseSensitiveFileNames(), + getCommonSourceDirectory, + ), + { kind: FileIncludeKind.OutputFromProjectReference, index }, + ); } } } @@ -1205,21 +1532,34 @@ namespace ts { } tracing?.push(tracing.Phase.Program, "processRootFiles", { count: rootNames.length }); - forEach(rootNames, (name, index) => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.RootFile, index })); + forEach( + rootNames, + (name, index) => + processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, { + kind: FileIncludeKind.RootFile, + index, + }), + ); tracing?.pop(); // load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders - const typeReferences: string[] = rootNames.length ? getAutomaticTypeDirectiveNames(options, host) : emptyArray; + const typeReferences: string[] = rootNames.length ? getAutomaticTypeDirectiveNames(options, host) + : emptyArray; if (typeReferences.length) { tracing?.push(tracing.Phase.Program, "processTypeReferences", { count: typeReferences.length }); // This containingFilename needs to match with the one used in managed-side - const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : host.getCurrentDirectory(); + const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) + : host.getCurrentDirectory(); const containingFilename = combinePaths(containingDirectory, inferredTypesContainingFile); const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeReferences, containingFilename); for (let i = 0; i < typeReferences.length; i++) { // under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode - processTypeReferenceDirective(typeReferences[i], /*mode*/ undefined, resolutions[i], { kind: FileIncludeKind.AutomaticTypeDirectiveFile, typeReference: typeReferences[i], packageId: resolutions[i]?.packageId }); + processTypeReferenceDirective(typeReferences[i], /*mode*/ undefined, resolutions[i], { + kind: FileIncludeKind.AutomaticTypeDirectiveFile, + typeReference: typeReferences[i], + packageId: resolutions[i]?.packageId, + }); } tracing?.pop(); } @@ -1233,16 +1573,28 @@ namespace ts { // otherwise, using options specified in '--lib' instead of '--target' default library file const defaultLibraryFileName = getDefaultLibraryFileName(); if (!options.lib && defaultLibraryFileName) { - processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile }); + processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { + kind: FileIncludeKind.LibFile, + }); } else { forEach(options.lib, (libFileName, index) => { - processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile, index }); + processRootFile( + pathForLibFile(libFileName), + /*isDefaultLib*/ true, + /*ignoreNoDefaultLib*/ false, + { kind: FileIncludeKind.LibFile, index }, + ); }); } } - missingFilePaths = arrayFrom(mapDefinedIterator(filesByName.entries(), ([path, file]) => file === undefined ? path as Path : undefined)); + missingFilePaths = arrayFrom( + mapDefinedIterator( + filesByName.entries(), + ([path, file]) => file === undefined ? path as Path : undefined, + ), + ); files = stableSort(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles); processingDefaultLibFiles = undefined; processingOtherFiles = undefined; @@ -1257,17 +1609,27 @@ namespace ts { for (const oldSourceFile of oldSourceFiles) { const newFile = getSourceFileByPath(oldSourceFile.resolvedPath); if ( - shouldCreateNewSourceFile || !newFile || newFile.impliedNodeFormat !== oldSourceFile.impliedNodeFormat || + shouldCreateNewSourceFile || !newFile + || newFile.impliedNodeFormat !== oldSourceFile.impliedNodeFormat // old file wasn't redirect but new file is - (oldSourceFile.resolvedPath === oldSourceFile.path && newFile.resolvedPath !== oldSourceFile.path) + || (oldSourceFile.resolvedPath === oldSourceFile.path + && newFile.resolvedPath !== oldSourceFile.path) ) { - host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path)); + host.onReleaseOldSourceFile( + oldSourceFile, + oldProgram.getCompilerOptions(), + !!getSourceFileByPath(oldSourceFile.path), + ); } } if (!host.getParsedCommandLine) { oldProgram.forEachResolvedProjectReference(resolvedProjectReference => { if (!getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) { - host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false); + host.onReleaseOldSourceFile!( + resolvedProjectReference.sourceFile, + oldProgram!.getCompilerOptions(), + /*hasSourceFileByPath*/ false, + ); } }); } @@ -1279,7 +1641,8 @@ namespace ts { oldProgram.getProjectReferences(), oldProgram.getResolvedProjectReferences(), (oldResolvedRef, parent, index) => { - const oldReference = parent?.commandLine.projectReferences![index] || oldProgram!.getProjectReferences()![index]; + const oldReference = parent?.commandLine.projectReferences![index] + || oldProgram!.getProjectReferences()![index]; const oldRefPath = resolveProjectReferencePath(oldReference); if (!projectReferenceRedirects?.has(toPath(oldRefPath))) { host.onReleaseParsedCommandLine!(oldRefPath, oldResolvedRef, oldProgram!.getCompilerOptions()); @@ -1359,10 +1722,28 @@ namespace ts { fileProcessingDiagnostics?.forEach(diagnostic => { switch (diagnostic.kind) { case FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic: - return programDiagnostics.add(createDiagnosticExplainingFile(diagnostic.file && getSourceFileByPath(diagnostic.file), diagnostic.fileProcessingReason, diagnostic.diagnostic, diagnostic.args || emptyArray)); + return programDiagnostics.add( + createDiagnosticExplainingFile( + diagnostic.file && getSourceFileByPath(diagnostic.file), + diagnostic.fileProcessingReason, + diagnostic.diagnostic, + diagnostic.args || emptyArray, + ), + ); case FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic: - const { file, pos, end } = getReferencedFileLocation(getSourceFileByPath, diagnostic.reason) as ReferenceFileLocation; - return programDiagnostics.add(createFileDiagnostic(file, Debug.checkDefined(pos), Debug.checkDefined(end) - pos, diagnostic.diagnostic, ...diagnostic.args || emptyArray)); + const { file, pos, end } = getReferencedFileLocation( + getSourceFileByPath, + diagnostic.reason, + ) as ReferenceFileLocation; + return programDiagnostics.add( + createFileDiagnostic( + file, + Debug.checkDefined(pos), + Debug.checkDefined(end) - pos, + diagnostic.diagnostic, + ...diagnostic.args || emptyArray, + ), + ); default: Debug.assertNever(diagnostic); } @@ -1391,7 +1772,8 @@ namespace ts { let i = 0; for (const n of names) { // mimics logic done in the resolution cache, should be resilient to upgrading it to use `FileReference`s for non-type-reference modal lookups to make it rely on the index in the list less - const mode = typeof n === "string" ? getModeForResolutionAtIndex(containingFile, i) : getModeForFileReference(n, containingFileMode); + const mode = typeof n === "string" ? getModeForResolutionAtIndex(containingFile, i) + : getModeForFileReference(n, containingFileMode); const name = typeof n === "string" ? n : n.fileName; i++; // only nonrelative names hit the cache, and, at least as of right now, only nonrelative names can issue diagnostics @@ -1400,18 +1782,30 @@ namespace ts { // When it is, how we extract diagnostics from the module name resolver will have the be refined - the current cache // APIs wrapping the underlying resolver make it almost impossible to smuggle the diagnostics out in a generalized way if (isExternalModuleNameRelative(name)) continue; - const diags = moduleResolutionCache.getOrCreateCacheForModuleName(name, mode, redirectedReference).get(containingDir)?.resolutionDiagnostics; + const diags = moduleResolutionCache.getOrCreateCacheForModuleName(name, mode, redirectedReference).get( + containingDir, + )?.resolutionDiagnostics; addResolutionDiagnostics(diags); } } - function resolveModuleNamesWorker(moduleNames: string[], containingFile: SourceFile, reusedNames: string[] | undefined): readonly ResolvedModuleFull[] { + function resolveModuleNamesWorker( + moduleNames: string[], + containingFile: SourceFile, + reusedNames: string[] | undefined, + ): readonly ResolvedModuleFull[] { if (!moduleNames.length) return emptyArray; const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory); const redirectedReference = getRedirectReferenceForResolution(containingFile); tracing?.push(tracing.Phase.Program, "resolveModuleNamesWorker", { containingFileName }); performance.mark("beforeResolveModule"); - const result = actualResolveModuleNamesWorker(moduleNames, containingFile, containingFileName, reusedNames, redirectedReference); + const result = actualResolveModuleNamesWorker( + moduleNames, + containingFile, + containingFileName, + reusedNames, + redirectedReference, + ); performance.mark("afterResolveModule"); performance.measure("ResolveModule", "beforeResolveModule", "afterResolveModule"); tracing?.pop(); @@ -1419,14 +1813,24 @@ namespace ts { return result; } - function resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string | SourceFile): readonly (ResolvedTypeReferenceDirective | undefined)[] { + function resolveTypeReferenceDirectiveNamesWorker( + typeDirectiveNames: string[] | readonly FileReference[], + containingFile: string | SourceFile, + ): readonly (ResolvedTypeReferenceDirective | undefined)[] { if (!typeDirectiveNames.length) return []; - const containingFileName = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile; - const redirectedReference = !isString(containingFile) ? getRedirectReferenceForResolution(containingFile) : undefined; + const containingFileName = !isString(containingFile) + ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile; + const redirectedReference = !isString(containingFile) ? getRedirectReferenceForResolution(containingFile) + : undefined; const containingFileMode = !isString(containingFile) ? containingFile.impliedNodeFormat : undefined; tracing?.push(tracing.Phase.Program, "resolveTypeReferenceDirectiveNamesWorker", { containingFileName }); performance.mark("beforeResolveTypeReference"); - const result = actualResolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFileName, redirectedReference, containingFileMode); + const result = actualResolveTypeReferenceDirectiveNamesWorker( + typeDirectiveNames, + containingFileName, + redirectedReference, + containingFileMode, + ); performance.mark("afterResolveTypeReference"); performance.measure("ResolveTypeReference", "beforeResolveTypeReference", "afterResolveTypeReference"); tracing?.pop(); @@ -1446,9 +1850,13 @@ namespace ts { // but the resolved real path may be the .d.ts from project reference // Note:: Currently we try the real path only if the // file is from node_modules to avoid having to run real path on all file paths - if (!host.realpath || !options.preserveSymlinks || !stringContains(file.originalFileName, nodeModulesPathPart)) return undefined; + if ( + !host.realpath || !options.preserveSymlinks + || !stringContains(file.originalFileName, nodeModulesPathPart) + ) return undefined; const realDeclarationPath = toPath(host.realpath(file.originalFileName)); - return realDeclarationPath === file.path ? undefined : getRedirectReferenceForResolutionFromSourceOfProject(realDeclarationPath); + return realDeclarationPath === file.path ? undefined + : getRedirectReferenceForResolutionFromSourceOfProject(realDeclarationPath); } function getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path) { @@ -1478,8 +1886,13 @@ namespace ts { return libs.length + 2; } - function getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, mode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined { - return moduleResolutionCache && resolveModuleNameFromCache(moduleName, containingFile, moduleResolutionCache, mode); + function getResolvedModuleWithFailedLookupLocationsFromCache( + moduleName: string, + containingFile: string, + mode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): ResolvedModuleWithFailedLookupLocations | undefined { + return moduleResolutionCache + && resolveModuleNameFromCache(moduleName, containingFile, moduleResolutionCache, mode); } function toPath(fileName: string): Path { @@ -1514,7 +1927,10 @@ namespace ts { return classifiableNames; } - function resolveModuleNamesReusingOldState(moduleNames: string[], file: SourceFile): readonly (ResolvedModuleFull | undefined)[] { + function resolveModuleNamesReusingOldState( + moduleNames: string[], + file: SourceFile, + ): readonly (ResolvedModuleFull | undefined)[] { if (structureIsReused === StructureIsReused.Not && !file.ambientModuleNames.length) { // If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules, // the best we can do is fallback to the default logic. @@ -1565,14 +1981,20 @@ namespace ts { const moduleName = moduleNames[i]; // If the source file is unchanged and doesnt have invalidated resolution, reuse the module resolutions if (file === oldSourceFile && !hasInvalidatedResolutions(oldSourceFile.path)) { - const oldResolvedModule = getResolvedModule(oldSourceFile, moduleName, getModeForResolutionAtIndex(oldSourceFile, i)); + const oldResolvedModule = getResolvedModule( + oldSourceFile, + moduleName, + getModeForResolutionAtIndex(oldSourceFile, i), + ); if (oldResolvedModule) { if (isTraceEnabled(options, host)) { trace( host, - oldResolvedModule.packageId ? - Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 : - Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2, + oldResolvedModule.packageId + ? Diagnostics + .Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 + : Diagnostics + .Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2, moduleName, getNormalizedAbsolutePath(file.originalFileName, currentDirectory), oldResolvedModule.resolvedFileName, @@ -1592,11 +2014,19 @@ namespace ts { if (contains(file.ambientModuleNames, moduleName)) { resolvesToAmbientModuleInNonModifiedFile = true; if (isTraceEnabled(options, host)) { - trace(host, Diagnostics.Module_0_was_resolved_as_locally_declared_ambient_module_in_file_1, moduleName, getNormalizedAbsolutePath(file.originalFileName, currentDirectory)); + trace( + host, + Diagnostics.Module_0_was_resolved_as_locally_declared_ambient_module_in_file_1, + moduleName, + getNormalizedAbsolutePath(file.originalFileName, currentDirectory), + ); } } else { - resolvesToAmbientModuleInNonModifiedFile = moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName, i); + resolvesToAmbientModuleInNonModifiedFile = moduleNameResolvesToAmbientModuleInNonModifiedFile( + moduleName, + i, + ); } if (resolvesToAmbientModuleInNonModifiedFile) { @@ -1641,7 +2071,11 @@ namespace ts { // we should adjust the value returned here. function moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName: string, index: number): boolean { if (index >= length(oldSourceFile?.imports) + length(oldSourceFile?.moduleAugmentations)) return false; // mode index out of bounds, don't reuse resolution - const resolutionToFile = getResolvedModule(oldSourceFile, moduleName, oldSourceFile && getModeForResolutionAtIndex(oldSourceFile, index)); + const resolutionToFile = getResolvedModule( + oldSourceFile, + moduleName, + oldSourceFile && getModeForResolutionAtIndex(oldSourceFile, index), + ); const resolvedFile = resolutionToFile && oldProgram!.getSourceFile(resolutionToFile.resolvedFileName); if (resolutionToFile && resolvedFile) { // In the old program, we resolved to an ambient module that was in the same @@ -1659,7 +2093,13 @@ namespace ts { } if (isTraceEnabled(options, host)) { - trace(host, Diagnostics.Module_0_was_resolved_as_ambient_module_declared_in_1_since_this_file_was_not_modified, moduleName, unmodifiedFile); + trace( + host, + Diagnostics + .Module_0_was_resolved_as_ambient_module_declared_in_1_since_this_file_was_not_modified, + moduleName, + unmodifiedFile, + ); } return true; } @@ -1674,9 +2114,12 @@ namespace ts { const newResolvedRef = parseProjectReferenceConfigFile(newRef); if (oldResolvedRef) { // Resolved project reference has gone missing or changed - return !newResolvedRef || - newResolvedRef.sourceFile !== oldResolvedRef.sourceFile || - !arrayIsEqualTo(oldResolvedRef.commandLine.fileNames, newResolvedRef.commandLine.fileNames); + return !newResolvedRef + || newResolvedRef.sourceFile !== oldResolvedRef.sourceFile + || !arrayIsEqualTo( + oldResolvedRef.commandLine.fileNames, + newResolvedRef.commandLine.fileNames, + ); } else { // A previously-unresolved reference may be resolved now @@ -1685,7 +2128,9 @@ namespace ts { }, (oldProjectReferences, parent) => { // If array of references is changed, we cant resue old program - const newReferences = parent ? getResolvedProjectReferenceByPath(parent.sourceFile.path)!.commandLine.projectReferences : projectReferences; + const newReferences = parent + ? getResolvedProjectReferenceByPath(parent.sourceFile.path)!.commandLine.projectReferences + : projectReferences; return !arrayIsEqualTo(oldProjectReferences, newReferences, projectReferenceIsEqualTo); }, ); @@ -1737,18 +2182,40 @@ namespace ts { const seenPackageNames = new Map(); for (const oldSourceFile of oldSourceFiles) { - const sourceFileOptions = getCreateSourceFileOptions(oldSourceFile.fileName, moduleResolutionCache, host, options); + const sourceFileOptions = getCreateSourceFileOptions( + oldSourceFile.fileName, + moduleResolutionCache, + host, + options, + ); let newSourceFile = host.getSourceFileByPath - ? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.resolvedPath, sourceFileOptions, /*onError*/ undefined, shouldCreateNewSourceFile || sourceFileOptions.impliedNodeFormat !== oldSourceFile.impliedNodeFormat) - : host.getSourceFile(oldSourceFile.fileName, sourceFileOptions, /*onError*/ undefined, shouldCreateNewSourceFile || sourceFileOptions.impliedNodeFormat !== oldSourceFile.impliedNodeFormat); // TODO: GH#18217 + ? host.getSourceFileByPath( + oldSourceFile.fileName, + oldSourceFile.resolvedPath, + sourceFileOptions, + /*onError*/ undefined, + shouldCreateNewSourceFile + || sourceFileOptions.impliedNodeFormat !== oldSourceFile.impliedNodeFormat, + ) + : host.getSourceFile( + oldSourceFile.fileName, + sourceFileOptions, + /*onError*/ undefined, + shouldCreateNewSourceFile + || sourceFileOptions.impliedNodeFormat !== oldSourceFile.impliedNodeFormat, + ); // TODO: GH#18217 if (!newSourceFile) { return StructureIsReused.Not; } - newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; + newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length + ? sourceFileOptions.packageJsonLocations : undefined; newSourceFile.packageJsonScope = sourceFileOptions.packageJsonScope; - Debug.assert(!newSourceFile.redirectInfo, "Host should not return a redirect source file from `getSourceFile`"); + Debug.assert( + !newSourceFile.redirectInfo, + "Host should not return a redirect source file from `getSourceFile`", + ); let fileChanged: boolean; if (oldSourceFile.redirectInfo) { @@ -1784,7 +2251,10 @@ namespace ts { // they might become redirects. So we must rebuild the program. const prevKind = seenPackageNames.get(packageName); const newKind = fileChanged ? SeenPackageName.Modified : SeenPackageName.Exists; - if ((prevKind !== undefined && newKind === SeenPackageName.Modified) || prevKind === SeenPackageName.Modified) { + if ( + (prevKind !== undefined && newKind === SeenPackageName.Modified) + || prevKind === SeenPackageName.Modified + ) { return StructureIsReused.Not; } seenPackageNames.set(packageName, newKind); @@ -1795,7 +2265,13 @@ namespace ts { structureIsReused = StructureIsReused.SafeModules; } // The `newSourceFile` object was created for the new program. - else if (!arrayIsEqualTo(oldSourceFile.libReferenceDirectives, newSourceFile.libReferenceDirectives, fileReferenceIsEqualTo)) { + else if ( + !arrayIsEqualTo( + oldSourceFile.libReferenceDirectives, + newSourceFile.libReferenceDirectives, + fileReferenceIsEqualTo, + ) + ) { // 'lib' references has changed. Matches behavior in changesAffectModuleResolution structureIsReused = StructureIsReused.SafeModules; } @@ -1805,7 +2281,13 @@ namespace ts { structureIsReused = StructureIsReused.SafeModules; } // check tripleslash references - else if (!arrayIsEqualTo(oldSourceFile.referencedFiles, newSourceFile.referencedFiles, fileReferenceIsEqualTo)) { + else if ( + !arrayIsEqualTo( + oldSourceFile.referencedFiles, + newSourceFile.referencedFiles, + fileReferenceIsEqualTo, + ) + ) { // tripleslash references has changed structureIsReused = StructureIsReused.SafeModules; } @@ -1816,15 +2298,30 @@ namespace ts { // imports has changed structureIsReused = StructureIsReused.SafeModules; } - else if (!arrayIsEqualTo(oldSourceFile.moduleAugmentations, newSourceFile.moduleAugmentations, moduleNameIsEqualTo)) { + else if ( + !arrayIsEqualTo( + oldSourceFile.moduleAugmentations, + newSourceFile.moduleAugmentations, + moduleNameIsEqualTo, + ) + ) { // moduleAugmentations has changed structureIsReused = StructureIsReused.SafeModules; } - else if ((oldSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) !== (newSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags)) { + else if ( + (oldSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) + !== (newSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) + ) { // dynamicImport has changed structureIsReused = StructureIsReused.SafeModules; } - else if (!arrayIsEqualTo(oldSourceFile.typeReferenceDirectives, newSourceFile.typeReferenceDirectives, fileReferenceIsEqualTo)) { + else if ( + !arrayIsEqualTo( + oldSourceFile.typeReferenceDirectives, + newSourceFile.typeReferenceDirectives, + fileReferenceIsEqualTo, + ) + ) { // 'types' references has changed structureIsReused = StructureIsReused.SafeModules; } @@ -1862,7 +2359,13 @@ namespace ts { const moduleNames = getModuleNames(newSourceFile); const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFile); // ensure that module resolution results are still correct - const resolutionsChanged = hasChangesInResolutions(moduleNames, resolutions, oldSourceFile.resolvedModules, oldSourceFile, moduleResolutionIsEqualTo); + const resolutionsChanged = hasChangesInResolutions( + moduleNames, + resolutions, + oldSourceFile.resolvedModules, + oldSourceFile, + moduleResolutionIsEqualTo, + ); if (resolutionsChanged) { structureIsReused = StructureIsReused.SafeModules; newSourceFile.resolvedModules = zipToModeAwareCache(newSourceFile, moduleNames, resolutions); @@ -1871,15 +2374,29 @@ namespace ts { newSourceFile.resolvedModules = oldSourceFile.resolvedModules; } const typesReferenceDirectives = newSourceFile.typeReferenceDirectives; - const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesWorker(typesReferenceDirectives, newSourceFile); + const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesWorker( + typesReferenceDirectives, + newSourceFile, + ); // ensure that types resolutions are still correct - const typeReferenceResolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, typeReferenceResolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, oldSourceFile, typeDirectiveIsEqualTo); + const typeReferenceResolutionsChanged = hasChangesInResolutions( + typesReferenceDirectives, + typeReferenceResolutions, + oldSourceFile.resolvedTypeReferenceDirectiveNames, + oldSourceFile, + typeDirectiveIsEqualTo, + ); if (typeReferenceResolutionsChanged) { structureIsReused = StructureIsReused.SafeModules; - newSourceFile.resolvedTypeReferenceDirectiveNames = zipToModeAwareCache(newSourceFile, typesReferenceDirectives, typeReferenceResolutions); + newSourceFile.resolvedTypeReferenceDirectiveNames = zipToModeAwareCache( + newSourceFile, + typesReferenceDirectives, + typeReferenceResolutions, + ); } else { - newSourceFile.resolvedTypeReferenceDirectiveNames = oldSourceFile.resolvedTypeReferenceDirectiveNames; + newSourceFile.resolvedTypeReferenceDirectiveNames = + oldSourceFile.resolvedTypeReferenceDirectiveNames; } } @@ -1887,7 +2404,9 @@ namespace ts { return structureIsReused; } - if (changesAffectingProgramStructure(oldOptions, options) || host.hasChangedAutomaticTypeDirectiveNames?.()) { + if ( + changesAffectingProgramStructure(oldOptions, options) || host.hasChangedAutomaticTypeDirectiveNames?.() + ) { return StructureIsReused.SafeModules; } @@ -2032,7 +2551,8 @@ namespace ts { // If '--lib' is not specified, include default library file according to '--target' // otherwise, using options specified in '--lib' instead of '--target' default library file - const equalityComparer = host.useCaseSensitiveFileNames() ? equateStringsCaseSensitive : equateStringsCaseInsensitive; + const equalityComparer = host.useCaseSensitiveFileNames() ? equateStringsCaseSensitive + : equateStringsCaseInsensitive; if (!options.lib) { return equalityComparer(file.fileName, getDefaultLibraryFileName()); } @@ -2045,9 +2565,26 @@ namespace ts { return typeChecker || (typeChecker = createTypeChecker(program)); } - function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, transformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult { + function emit( + sourceFile?: SourceFile, + writeFileCallback?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + transformers?: CustomTransformers, + forceDtsEmit?: boolean, + ): EmitResult { tracing?.push(tracing.Phase.Emit, "emit", { path: sourceFile?.path }, /*separateBeginAndEnd*/ true); - const result = runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers, forceDtsEmit)); + const result = runWithCancellationToken(() => + emitWorker( + program, + sourceFile, + writeFileCallback, + cancellationToken, + emitOnlyDtsFiles, + transformers, + forceDtsEmit, + ) + ); tracing?.pop(); return result; } @@ -2056,7 +2593,15 @@ namespace ts { return hasEmitBlockingDiagnostics.has(toPath(emitFileName)); } - function emitWorker(program: Program, sourceFile: SourceFile | undefined, writeFileCallback: WriteFileCallback | undefined, cancellationToken: CancellationToken | undefined, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult { + function emitWorker( + program: Program, + sourceFile: SourceFile | undefined, + writeFileCallback: WriteFileCallback | undefined, + cancellationToken: CancellationToken | undefined, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + forceDtsEmit?: boolean, + ): EmitResult { if (!forceDtsEmit) { const result = handleNoEmitOptions(program, sourceFile, writeFileCallback, cancellationToken); if (result) return result; @@ -2070,7 +2615,10 @@ namespace ts { // This is because in the -out scenario all files need to be emitted, and therefore all // files need to be type checked. And the way to specify that all files need to be type // checked is to not pass the file to getEmitResolver. - const emitResolver = getTypeChecker().getEmitResolver(outFile(options) ? undefined : sourceFile, cancellationToken); + const emitResolver = getTypeChecker().getEmitResolver( + outFile(options) ? undefined : sourceFile, + cancellationToken, + ); performance.mark("beforeEmit"); @@ -2113,11 +2661,17 @@ namespace ts { })); } - function getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] { + function getSyntacticDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[] { return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile, cancellationToken); } - function getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { + function getSemanticDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[] { return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile, cancellationToken); } @@ -2127,7 +2681,10 @@ namespace ts { : cachedBindAndCheckDiagnosticsForFile.allDiagnostics; } - function getBindAndCheckDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { + function getBindAndCheckDiagnostics( + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[] { return getBindAndCheckDiagnosticsForFile(sourceFile, cancellationToken); } @@ -2141,10 +2698,17 @@ namespace ts { return programDiagnosticsInFile; } - return getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, programDiagnosticsInFile).diagnostics; + return getDiagnosticsWithPrecedingDirectives( + sourceFile, + sourceFile.commentDirectives, + programDiagnosticsInFile, + ).diagnostics; } - function getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] { + function getDeclarationDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[] { const options = program.getCompilerOptions(); // collect diagnostics from the program only once if either no source file was specified or out/outFile is set (bundled emit) if (!sourceFile || outFile(options)) { @@ -2182,18 +2746,32 @@ namespace ts { } } - function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] { + function getSemanticDiagnosticsForFile( + sourceFile: SourceFile, + cancellationToken: CancellationToken | undefined, + ): readonly Diagnostic[] { return concatenate( filterSemanticDiagnostics(getBindAndCheckDiagnosticsForFile(sourceFile, cancellationToken), options), getProgramDiagnostics(sourceFile), ); } - function getBindAndCheckDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] { - return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedBindAndCheckDiagnosticsForFile, getBindAndCheckDiagnosticsForFileNoCache); + function getBindAndCheckDiagnosticsForFile( + sourceFile: SourceFile, + cancellationToken: CancellationToken | undefined, + ): readonly Diagnostic[] { + return getAndCacheDiagnostics( + sourceFile, + cancellationToken, + cachedBindAndCheckDiagnosticsForFile, + getBindAndCheckDiagnosticsForFileNoCache, + ); } - function getBindAndCheckDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] { + function getBindAndCheckDiagnosticsForFileNoCache( + sourceFile: SourceFile, + cancellationToken: CancellationToken | undefined, + ): readonly Diagnostic[] { return runWithCancellationToken(() => { if (skipTypeChecking(sourceFile, options, program)) { return emptyArray; @@ -2212,29 +2790,53 @@ namespace ts { // - plain JS: .js files with no // ts-check and checkJs: undefined // - check JS: .js files with either // ts-check or checkJs: true // - external: files that are added by plugins - const includeBindAndCheckDiagnostics = !isTsNoCheck && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX - || sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred); - let bindDiagnostics: readonly Diagnostic[] = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray; - let checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray; + const includeBindAndCheckDiagnostics = !isTsNoCheck + && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX + || sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs + || sourceFile.scriptKind === ScriptKind.Deferred); + let bindDiagnostics: readonly Diagnostic[] = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics + : emptyArray; + let checkDiagnostics = includeBindAndCheckDiagnostics + ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray; if (isPlainJs) { bindDiagnostics = filter(bindDiagnostics, d => plainJSErrors.has(d.code)); checkDiagnostics = filter(checkDiagnostics, d => plainJSErrors.has(d.code)); } // skip ts-expect-error errors in plain JS files, and skip JSDoc errors except in checked JS - return getMergedBindAndCheckDiagnostics(sourceFile, includeBindAndCheckDiagnostics && !isPlainJs, bindDiagnostics, checkDiagnostics, isCheckJs ? sourceFile.jsDocDiagnostics : undefined); + return getMergedBindAndCheckDiagnostics( + sourceFile, + includeBindAndCheckDiagnostics && !isPlainJs, + bindDiagnostics, + checkDiagnostics, + isCheckJs ? sourceFile.jsDocDiagnostics : undefined, + ); }); } - function getMergedBindAndCheckDiagnostics(sourceFile: SourceFile, includeBindAndCheckDiagnostics: boolean, ...allDiagnostics: (readonly Diagnostic[] | undefined)[]) { + function getMergedBindAndCheckDiagnostics( + sourceFile: SourceFile, + includeBindAndCheckDiagnostics: boolean, + ...allDiagnostics: (readonly Diagnostic[] | undefined)[] + ) { const flatDiagnostics = flatten(allDiagnostics); if (!includeBindAndCheckDiagnostics || !sourceFile.commentDirectives?.length) { return flatDiagnostics; } - const { diagnostics, directives } = getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, flatDiagnostics); + const { diagnostics, directives } = getDiagnosticsWithPrecedingDirectives( + sourceFile, + sourceFile.commentDirectives, + flatDiagnostics, + ); for (const errorExpectation of directives.getUnusedExpectations()) { - diagnostics.push(createDiagnosticForRange(sourceFile, errorExpectation.range, Diagnostics.Unused_ts_expect_error_directive)); + diagnostics.push( + createDiagnosticForRange( + sourceFile, + errorExpectation.range, + Diagnostics.Unused_ts_expect_error_directive, + ), + ); } return diagnostics; @@ -2244,16 +2846,25 @@ namespace ts { * Creates a map of comment directives along with the diagnostics immediately preceded by one of them. * Comments that match to any of those diagnostics are marked as used. */ - function getDiagnosticsWithPrecedingDirectives(sourceFile: SourceFile, commentDirectives: CommentDirective[], flatDiagnostics: Diagnostic[]) { + function getDiagnosticsWithPrecedingDirectives( + sourceFile: SourceFile, + commentDirectives: CommentDirective[], + flatDiagnostics: Diagnostic[], + ) { // Diagnostics are only reported if there is no comment directive preceding them // This will modify the directives map by marking "used" ones with a corresponding diagnostic const directives = createCommentDirectivesMap(sourceFile, commentDirectives); - const diagnostics = flatDiagnostics.filter(diagnostic => markPrecedingCommentDirectiveLine(diagnostic, directives) === -1); + const diagnostics = flatDiagnostics.filter(diagnostic => + markPrecedingCommentDirectiveLine(diagnostic, directives) === -1 + ); return { diagnostics, directives }; } - function getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] { + function getSuggestionDiagnostics( + sourceFile: SourceFile, + cancellationToken: CancellationToken, + ): readonly DiagnosticWithLocation[] { return runWithCancellationToken(() => { return getTypeChecker().getSuggestionDiagnostics(sourceFile, cancellationToken); }); @@ -2305,8 +2916,17 @@ namespace ts { case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.MethodDeclaration: - if ((parent as ParameterDeclaration | PropertyDeclaration | MethodDeclaration).questionToken === node) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?")); + if ( + (parent as ParameterDeclaration | PropertyDeclaration | MethodDeclaration).questionToken + === node + ) { + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, + "?", + ), + ); return "skip"; } // falls through @@ -2319,8 +2939,19 @@ namespace ts { case SyntaxKind.ArrowFunction: case SyntaxKind.VariableDeclaration: // type annotation - if ((parent as FunctionLikeDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration).type === node) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files)); + if ( + (parent as + | FunctionLikeDeclaration + | VariableDeclaration + | ParameterDeclaration + | PropertyDeclaration).type === node + ) { + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } } @@ -2328,64 +2959,133 @@ namespace ts { switch (node.kind) { case SyntaxKind.ImportClause: if ((node as ImportClause).isTypeOnly) { - diagnostics.push(createDiagnosticForNode(parent, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "import type")); + diagnostics.push( + createDiagnosticForNode( + parent, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + "import type", + ), + ); return "skip"; } break; case SyntaxKind.ExportDeclaration: if ((node as ExportDeclaration).isTypeOnly) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "export type")); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + "export type", + ), + ); return "skip"; } break; case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: if ((node as ImportOrExportSpecifier).isTypeOnly) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, isImportSpecifier(node) ? "import...type" : "export...type")); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + isImportSpecifier(node) ? "import...type" : "export...type", + ), + ); return "skip"; } break; case SyntaxKind.ImportEqualsDeclaration: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_TypeScript_files), + ); return "skip"; case SyntaxKind.ExportAssignment: if ((node as ExportAssignment).isExportEquals) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.export_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } break; case SyntaxKind.HeritageClause: const heritageClause = node as HeritageClause; if (heritageClause.token === SyntaxKind.ImplementsKeyword) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.implements_clauses_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } break; case SyntaxKind.InterfaceDeclaration: const interfaceKeyword = tokenToString(SyntaxKind.InterfaceKeyword); Debug.assertIsDefined(interfaceKeyword); - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, interfaceKeyword)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + interfaceKeyword, + ), + ); return "skip"; case SyntaxKind.ModuleDeclaration: - const moduleKeyword = node.flags & NodeFlags.Namespace ? tokenToString(SyntaxKind.NamespaceKeyword) : tokenToString(SyntaxKind.ModuleKeyword); + const moduleKeyword = node.flags & NodeFlags.Namespace + ? tokenToString(SyntaxKind.NamespaceKeyword) : tokenToString(SyntaxKind.ModuleKeyword); Debug.assertIsDefined(moduleKeyword); - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, moduleKeyword)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + moduleKeyword, + ), + ); return "skip"; case SyntaxKind.TypeAliasDeclaration: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; case SyntaxKind.EnumDeclaration: const enumKeyword = Debug.checkDefined(tokenToString(SyntaxKind.EnumKeyword)); - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, enumKeyword)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + enumKeyword, + ), + ); return "skip"; case SyntaxKind.NonNullExpression: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; case SyntaxKind.AsExpression: - diagnostics.push(createDiagnosticForNode((node as AsExpression).type, Diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + (node as AsExpression).type, + Diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; case SyntaxKind.SatisfiesExpression: - diagnostics.push(createDiagnosticForNode((node as SatisfiesExpression).type, Diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + (node as SatisfiesExpression).type, + Diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; case SyntaxKind.TypeAssertionExpression: Debug.fail(); // Won't parse these in a JS file anyway, as they are interpreted as JSX. @@ -2393,8 +3093,17 @@ namespace ts { } function walkArray(nodes: NodeArray, parent: Node) { - if (canHaveModifiers(parent) && parent.modifiers === nodes && some(nodes, isDecorator) && !options.experimentalDecorators) { - diagnostics.push(createDiagnosticForNode(parent, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_in_your_tsconfig_or_jsconfig_to_remove_this_warning)); + if ( + canHaveModifiers(parent) && parent.modifiers === nodes && some(nodes, isDecorator) + && !options.experimentalDecorators + ) { + diagnostics.push( + createDiagnosticForNode( + parent, + Diagnostics + .Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_in_your_tsconfig_or_jsconfig_to_remove_this_warning, + ), + ); } switch (parent.kind) { @@ -2409,7 +3118,12 @@ namespace ts { case SyntaxKind.ArrowFunction: // Check type parameters if (nodes === (parent as DeclarationWithTypeParameterChildren).typeParameters) { - diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNodeArray( + nodes, + Diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } // falls through @@ -2417,7 +3131,10 @@ namespace ts { case SyntaxKind.VariableStatement: // Check modifiers if (nodes === (parent as VariableStatement).modifiers) { - checkModifiers((parent as VariableStatement).modifiers!, parent.kind === SyntaxKind.VariableStatement); + checkModifiers( + (parent as VariableStatement).modifiers!, + parent.kind === SyntaxKind.VariableStatement, + ); return "skip"; } break; @@ -2430,7 +3147,13 @@ namespace ts { && modifier.kind !== SyntaxKind.StaticKeyword && modifier.kind !== SyntaxKind.AccessorKeyword ) { - diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind))); + diagnostics.push( + createDiagnosticForNode( + modifier, + Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, + tokenToString(modifier.kind), + ), + ); } } return "skip"; @@ -2439,7 +3162,12 @@ namespace ts { case SyntaxKind.Parameter: // Check modifiers of parameter declaration if (nodes === (parent as ParameterDeclaration).modifiers && some(nodes, isModifier)) { - diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNodeArray( + nodes, + Diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } break; @@ -2451,7 +3179,12 @@ namespace ts { case SyntaxKind.TaggedTemplateExpression: // Check type arguments if (nodes === (parent as NodeWithTypeArguments).typeArguments) { - diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Type_arguments_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNodeArray( + nodes, + Diagnostics.Type_arguments_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } break; @@ -2476,7 +3209,13 @@ namespace ts { case SyntaxKind.OverrideKeyword: case SyntaxKind.InKeyword: case SyntaxKind.OutKeyword: - diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind))); + diagnostics.push( + createDiagnosticForNode( + modifier, + Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, + tokenToString(modifier.kind), + ), + ); break; // These are all legal modifiers. @@ -2488,24 +3227,47 @@ namespace ts { } } - function createDiagnosticForNodeArray(nodes: NodeArray, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation { + function createDiagnosticForNodeArray( + nodes: NodeArray, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + ): DiagnosticWithLocation { const start = nodes.pos; return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2); } // Since these are syntactic diagnostics, parent might not have been set // this means the sourceFile cannot be infered from the node - function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation { + function createDiagnosticForNode( + node: Node, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + ): DiagnosticWithLocation { return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2); } }); } - function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] { - return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache); + function getDeclarationDiagnosticsWorker( + sourceFile: SourceFile | undefined, + cancellationToken: CancellationToken | undefined, + ): readonly DiagnosticWithLocation[] { + return getAndCacheDiagnostics( + sourceFile, + cancellationToken, + cachedDeclarationDiagnosticsForFile, + getDeclarationDiagnosticsForFileNoCache, + ); } - function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] { + function getDeclarationDiagnosticsForFileNoCache( + sourceFile: SourceFile | undefined, + cancellationToken: CancellationToken | undefined, + ): readonly DiagnosticWithLocation[] { return runWithCancellationToken(() => { const resolver = getTypeChecker().getEmitResolver(sourceFile, cancellationToken); // Don't actually write any files since we're just getting diagnostics. @@ -2536,7 +3298,10 @@ namespace ts { return result; } - function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] { + function getDeclarationDiagnosticsForFile( + sourceFile: SourceFile, + cancellationToken: CancellationToken, + ): readonly DiagnosticWithLocation[] { return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken); } @@ -2551,21 +3316,36 @@ namespace ts { if (!options.configFile) return emptyArray; let diagnostics = programDiagnostics.getDiagnostics(options.configFile.fileName); forEachResolvedProjectReference(resolvedRef => { - diagnostics = concatenate(diagnostics, programDiagnostics.getDiagnostics(resolvedRef.sourceFile.fileName)); + diagnostics = concatenate( + diagnostics, + programDiagnostics.getDiagnostics(resolvedRef.sourceFile.fileName), + ); }); return diagnostics; } function getGlobalDiagnostics(): SortedReadonlyArray { - return rootNames.length ? sortAndDeduplicateDiagnostics(getTypeChecker().getGlobalDiagnostics().slice()) : emptyArray as any as SortedReadonlyArray; + return rootNames.length ? sortAndDeduplicateDiagnostics(getTypeChecker().getGlobalDiagnostics().slice()) + : emptyArray as any as SortedReadonlyArray; } function getConfigFileParsingDiagnostics(): readonly Diagnostic[] { return configFileParsingDiagnostics || emptyArray; } - function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason) { - processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined, reason); + function processRootFile( + fileName: string, + isDefaultLib: boolean, + ignoreNoDefaultLib: boolean, + reason: FileIncludeReason, + ) { + processSourceFile( + normalizePath(fileName), + isDefaultLib, + ignoreNoDefaultLib, + /*packageId*/ undefined, + reason, + ); } function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean { @@ -2580,7 +3360,12 @@ namespace ts { function createSyntheticImport(text: string, file: SourceFile) { const externalHelpersModuleReference = factory.createStringLiteral(text); - const importDecl = factory.createImportDeclaration(/*modifiers*/ undefined, /*importClause*/ undefined, externalHelpersModuleReference, /*assertClause*/ undefined); + const importDecl = factory.createImportDeclaration( + /*modifiers*/ undefined, + /*importClause*/ undefined, + externalHelpersModuleReference, + /*assertClause*/ undefined, + ); addEmitFlags(importDecl, EmitFlags.NeverApplyImportHelper); setParent(externalHelpersModuleReference, importDecl); setParent(importDecl, file); @@ -2640,7 +3425,10 @@ namespace ts { // TypeScript 1.0 spec (April 2014): 12.1.6 // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules // only through top - level external module names. Relative external module names are not permitted. - if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text && (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text))) { + if ( + moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text + && (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text)) + ) { setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here imports = append(imports, moduleNameExpr); if (!usesUriStyleNodeCoreModules && currentNodeModulesDepth === 0 && !file.isDeclarationFile) { @@ -2649,7 +3437,11 @@ namespace ts { } } else if (isModuleDeclaration(node)) { - if (isAmbientModule(node) && (inAmbientModule || hasSyntacticModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) { + if ( + isAmbientModule(node) + && (inAmbientModule || hasSyntacticModifier(node, ModifierFlags.Ambient) + || file.isDeclarationFile) + ) { (node.name as Mutable).parent = node; const nameText = getTextOfIdentifierOrLiteral(node.name); // Ambient module declarations can be interpreted as augmentations for some existing external modules. @@ -2691,7 +3483,9 @@ namespace ts { imports = append(imports, node.arguments[0]); } // we have to check the argument list has length of at least 1. We will still have to process these even though we have parsing error. - else if (isImportCall(node) && node.arguments.length >= 1 && isStringLiteralLike(node.arguments[0])) { + else if ( + isImportCall(node) && node.arguments.length >= 1 && isStringLiteralLike(node.arguments[0]) + ) { setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here imports = append(imports, node.arguments[0]); } @@ -2706,12 +3500,18 @@ namespace ts { function getNodeAtPosition(sourceFile: SourceFile, position: number): Node { let current: Node = sourceFile; const getContainingChild = (child: Node) => { - if (child.pos <= position && (position < child.end || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken)))) { + if ( + child.pos <= position + && (position < child.end + || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken))) + ) { return child; } }; while (true) { - const child = isJavaScriptFile && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) || forEachChild(current, getContainingChild); + const child = + isJavaScriptFile && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) + || forEachChild(current, getContainingChild); if (!child) { return current; } @@ -2729,8 +3529,14 @@ namespace ts { } /** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */ - function getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined { - return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), getSourceFile); + function getSourceFileFromReference( + referencingFile: SourceFile | UnparsedSource, + ref: FileReference, + ): SourceFile | undefined { + return getSourceFileFromReferenceWorker( + resolveTripleslashReference(ref.fileName, referencingFile.fileName), + getSourceFile, + ); } function getSourceFileFromReferenceWorker( @@ -2741,13 +3547,26 @@ namespace ts { ): SourceFile | undefined { if (hasExtension(fileName)) { const canonicalFileName = host.getCanonicalFileName(fileName); - if (!options.allowNonTsExtensions && !forEach(flatten(supportedExtensionsWithJsonIfResolveJsonModule), extension => fileExtensionIs(canonicalFileName, extension))) { + if ( + !options.allowNonTsExtensions + && !forEach( + flatten(supportedExtensionsWithJsonIfResolveJsonModule), + extension => fileExtensionIs(canonicalFileName, extension), + ) + ) { if (fail) { if (hasJSFileExtension(canonicalFileName)) { - fail(Diagnostics.File_0_is_a_JavaScript_file_Did_you_mean_to_enable_the_allowJs_option, fileName); + fail( + Diagnostics.File_0_is_a_JavaScript_file_Did_you_mean_to_enable_the_allowJs_option, + fileName, + ); } else { - fail(Diagnostics.File_0_has_an_unsupported_extension_The_only_supported_extensions_are_1, fileName, "'" + flatten(supportedExtensions).join("', '") + "'"); + fail( + Diagnostics.File_0_has_an_unsupported_extension_The_only_supported_extensions_are_1, + fileName, + "'" + flatten(supportedExtensions).join("', '") + "'", + ); } } return undefined; @@ -2764,7 +3583,10 @@ namespace ts { fail(Diagnostics.File_0_not_found, fileName); } } - else if (isReferencedFile(reason) && canonicalFileName === host.getCanonicalFileName(getSourceFileByPath(reason.file)!.fileName)) { + else if ( + isReferencedFile(reason) + && canonicalFileName === host.getCanonicalFileName(getSourceFileByPath(reason.file)!.fileName) + ) { fail(Diagnostics.A_file_cannot_have_a_reference_to_itself); } } @@ -2780,44 +3602,90 @@ namespace ts { } // Only try adding extensions from the first supported group (which should be .ts/.tsx/.d.ts) - const sourceFileWithAddedExtension = forEach(supportedExtensions[0], extension => getSourceFile(fileName + extension)); - if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.Could_not_resolve_the_path_0_with_the_extensions_Colon_1, fileName, "'" + flatten(supportedExtensions).join("', '") + "'"); + const sourceFileWithAddedExtension = forEach( + supportedExtensions[0], + extension => getSourceFile(fileName + extension), + ); + if (fail && !sourceFileWithAddedExtension) { + fail( + Diagnostics.Could_not_resolve_the_path_0_with_the_extensions_Colon_1, + fileName, + "'" + flatten(supportedExtensions).join("', '") + "'", + ); + } return sourceFileWithAddedExtension; } } /** This has side effects through `findSourceFile`. */ - function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, reason: FileIncludeReason): void { + function processSourceFile( + fileName: string, + isDefaultLib: boolean, + ignoreNoDefaultLib: boolean, + packageId: PackageId | undefined, + reason: FileIncludeReason, + ): void { getSourceFileFromReferenceWorker( fileName, fileName => findSourceFile(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId), // TODO: GH#18217 - (diagnostic, ...args) => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args), + (diagnostic, ...args) => + addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args), reason, ); } function processProjectReferenceFile(fileName: string, reason: ProjectReferenceFile) { - return processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, reason); + return processSourceFile( + fileName, + /*isDefaultLib*/ false, + /*ignoreNoDefaultLib*/ false, + /*packageId*/ undefined, + reason, + ); } - function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFile: SourceFile, reason: FileIncludeReason): void { - const hasExistingReasonToReportErrorOn = !isReferencedFile(reason) && some(fileReasons.get(existingFile.path), isReferencedFile); + function reportFileNamesDifferOnlyInCasingError( + fileName: string, + existingFile: SourceFile, + reason: FileIncludeReason, + ): void { + const hasExistingReasonToReportErrorOn = !isReferencedFile(reason) + && some(fileReasons.get(existingFile.path), isReferencedFile); if (hasExistingReasonToReportErrorOn) { - addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing, [existingFile.fileName, fileName]); + addFilePreprocessingFileExplainingDiagnostic( + existingFile, + reason, + Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing, + [existingFile.fileName, fileName], + ); } else { - addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, [fileName, existingFile.fileName]); + addFilePreprocessingFileExplainingDiagnostic( + existingFile, + reason, + Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, + [fileName, existingFile.fileName], + ); } } - function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path, resolvedPath: Path, originalFileName: string, sourceFileOptions: CreateSourceFileOptions): SourceFile { + function createRedirectSourceFile( + redirectTarget: SourceFile, + unredirected: SourceFile, + fileName: string, + path: Path, + resolvedPath: Path, + originalFileName: string, + sourceFileOptions: CreateSourceFileOptions, + ): SourceFile { const redirect: SourceFile = Object.create(redirectTarget); redirect.fileName = fileName; redirect.path = path; redirect.resolvedPath = resolvedPath; redirect.originalFileName = originalFileName; redirect.redirectInfo = { redirectTarget, unredirected }; - redirect.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; + redirect.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length + ? sourceFileOptions.packageJsonLocations : undefined; redirect.packageJsonScope = sourceFileOptions.packageJsonScope; sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0); Object.defineProperties(redirect, { @@ -2842,7 +3710,13 @@ namespace ts { } // Get source file from normalized fileName - function findSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined { + function findSourceFile( + fileName: string, + isDefaultLib: boolean, + ignoreNoDefaultLib: boolean, + reason: FileIncludeReason, + packageId: PackageId | undefined, + ): SourceFile | undefined { tracing?.push(tracing.Phase.Program, "findSourceFile", { fileName, isDefaultLib: isDefaultLib || undefined, @@ -2853,19 +3727,35 @@ namespace ts { return result; } - function getCreateSourceFileOptions(fileName: string, moduleResolutionCache: ModuleResolutionCache | undefined, host: CompilerHost, options: CompilerOptions): CreateSourceFileOptions { + function getCreateSourceFileOptions( + fileName: string, + moduleResolutionCache: ModuleResolutionCache | undefined, + host: CompilerHost, + options: CompilerOptions, + ): CreateSourceFileOptions { // It's a _little odd_ that we can't set `impliedNodeFormat` until the program step - but it's the first and only time we have a resolution cache // and a freshly made source file node on hand at the same time, and we need both to set the field. Persisting the resolution cache all the way // to the check and emit steps would be bad - so we much prefer detecting and storing the format information on the source file node upfront. - const result = getImpliedNodeFormatForFileWorker(getNormalizedAbsolutePath(fileName, currentDirectory), moduleResolutionCache?.getPackageJsonInfoCache(), host, options); + const result = getImpliedNodeFormatForFileWorker( + getNormalizedAbsolutePath(fileName, currentDirectory), + moduleResolutionCache?.getPackageJsonInfoCache(), + host, + options, + ); const languageVersion = getEmitScriptTarget(options); const setExternalModuleIndicator = getSetExternalModuleIndicator(options); - return typeof result === "object" ? - { ...result, languageVersion, setExternalModuleIndicator } : - { languageVersion, impliedNodeFormat: result, setExternalModuleIndicator }; + return typeof result === "object" + ? { ...result, languageVersion, setExternalModuleIndicator } + : { languageVersion, impliedNodeFormat: result, setExternalModuleIndicator }; } - function findSourceFileWorker(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined { + function findSourceFileWorker( + fileName: string, + isDefaultLib: boolean, + ignoreNoDefaultLib: boolean, + reason: FileIncludeReason, + packageId: PackageId | undefined, + ): SourceFile | undefined { const path = toPath(fileName); if (useSourceOfProjectReferenceRedirect) { let source = getSourceOfProjectReferenceRedirect(path); @@ -2874,19 +3764,19 @@ namespace ts { // Note:: Currently we try the real path only if the // file is from node_modules to avoid having to run real path on all file paths if ( - !source && - host.realpath && - options.preserveSymlinks && - isDeclarationFileName(fileName) && - stringContains(fileName, nodeModulesPathPart) + !source + && host.realpath + && options.preserveSymlinks + && isDeclarationFileName(fileName) + && stringContains(fileName, nodeModulesPathPart) ) { const realPath = toPath(host.realpath(fileName)); if (realPath !== path) source = getSourceOfProjectReferenceRedirect(realPath); } if (source) { - const file = isString(source) ? - findSourceFile(source, isDefaultLib, ignoreNoDefaultLib, reason, packageId) : - undefined; + const file = isString(source) + ? findSourceFile(source, isDefaultLib, ignoreNoDefaultLib, reason, packageId) + : undefined; if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined); return file; } @@ -2961,8 +3851,16 @@ namespace ts { const file = host.getSourceFile( fileName, sourceFileOptions, - hostErrorMessage => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_read_file_0_Colon_1, [fileName, hostErrorMessage]), - shouldCreateNewSourceFile || (oldProgram?.getSourceFileByPath(toPath(fileName))?.impliedNodeFormat !== sourceFileOptions.impliedNodeFormat), + hostErrorMessage => + addFilePreprocessingFileExplainingDiagnostic( + /*file*/ undefined, + reason, + Diagnostics.Cannot_read_file_0_Colon_1, + [fileName, hostErrorMessage], + ), + shouldCreateNewSourceFile + || (oldProgram?.getSourceFileByPath(toPath(fileName))?.impliedNodeFormat + !== sourceFileOptions.impliedNodeFormat), ); if (packageId) { @@ -2971,7 +3869,15 @@ namespace ts { if (fileFromPackageId) { // Some other SourceFile already exists with this package name and version. // Instead of creating a duplicate, just redirect to the existing one. - const dupFile = createRedirectSourceFile(fileFromPackageId, file!, fileName, path, toPath(fileName), originalFileName, sourceFileOptions); + const dupFile = createRedirectSourceFile( + fileFromPackageId, + file!, + fileName, + path, + toPath(fileName), + originalFileName, + sourceFileOptions, + ); redirectTargetsMap.add(fileFromPackageId.path, fileName); addFileToFilesByName(dupFile, path, redirectedPath); addFileIncludeReason(dupFile, reason); @@ -2993,7 +3899,8 @@ namespace ts { file.path = path; file.resolvedPath = toPath(fileName); file.originalFileName = originalFileName; - file.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; + file.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length + ? sourceFileOptions.packageJsonLocations : undefined; file.packageJsonScope = sourceFileOptions.packageJsonScope; addFileIncludeReason(file, reason); @@ -3053,7 +3960,10 @@ namespace ts { function getProjectReferenceRedirectProject(fileName: string) { // Ignore dts or any json files - if (!resolvedProjectReferences || !resolvedProjectReferences.length || isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json)) { + if ( + !resolvedProjectReferences || !resolvedProjectReferences.length || isDeclarationFileName(fileName) + || fileExtensionIs(fileName, Extension.Json) + ) { return undefined; } @@ -3064,9 +3974,13 @@ namespace ts { function getProjectReferenceOutputName(referencedProject: ResolvedProjectReference, fileName: string) { const out = outFile(referencedProject.commandLine.options); - return out ? - changeExtension(out, Extension.Dts) : - getOutputDeclarationFileName(fileName, referencedProject.commandLine, !host.useCaseSensitiveFileNames()); + return out + ? changeExtension(out, Extension.Dts) + : getOutputDeclarationFileName( + fileName, + referencedProject.commandLine, + !host.useCaseSensitiveFileNames(), + ); } /** @@ -3078,7 +3992,9 @@ namespace ts { forEachResolvedProjectReference(referencedProject => { // not input file from the referenced project, ignore if (toPath(options.configFilePath!) !== referencedProject.sourceFile.path) { - referencedProject.commandLine.fileNames.forEach(f => mapFromFileToProjectReferenceRedirects!.set(toPath(f), referencedProject.sourceFile.path)); + referencedProject.commandLine.fileNames.forEach(f => + mapFromFileToProjectReferenceRedirects!.set(toPath(f), referencedProject.sourceFile.path) + ); } }); } @@ -3105,10 +4021,17 @@ namespace ts { mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), true); } else { - const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(resolvedRef.commandLine, !host.useCaseSensitiveFileNames())); + const getCommonSourceDirectory = memoize(() => + getCommonSourceDirectoryOfConfig(resolvedRef.commandLine, !host.useCaseSensitiveFileNames()) + ); forEach(resolvedRef.commandLine.fileNames, fileName => { if (!isDeclarationFileName(fileName) && !fileExtensionIs(fileName, Extension.Json)) { - const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory); + const outputDts = getOutputDeclarationFileName( + fileName, + resolvedRef.commandLine, + !host.useCaseSensitiveFileNames(), + getCommonSourceDirectory, + ); mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName); } }); @@ -3156,10 +4079,24 @@ namespace ts { const fileName = toFileNameLowerCase(ref.fileName); setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective); const mode = ref.resolutionMode || file.impliedNodeFormat; - if (mode && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext) { - programDiagnostics.add(createDiagnosticForRange(file, ref, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext)); + if ( + mode && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 + && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext + ) { + programDiagnostics.add( + createDiagnosticForRange( + file, + ref, + Diagnostics + .resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext, + ), + ); } - processTypeReferenceDirective(fileName, mode, resolvedTypeReferenceDirective, { kind: FileIncludeKind.TypeReferenceDirective, file: file.path, index }); + processTypeReferenceDirective(fileName, mode, resolvedTypeReferenceDirective, { + kind: FileIncludeKind.TypeReferenceDirective, + file: file.path, + index, + }); } } @@ -3169,7 +4106,12 @@ namespace ts { resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined, reason: FileIncludeReason, ): void { - tracing?.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolvedTypeReferenceDirective, refKind: reason.kind, refPath: isReferencedFile(reason) ? reason.file : undefined }); + tracing?.push(tracing.Phase.Program, "processTypeReferenceDirective", { + directive: typeReferenceDirective, + hasResolved: !!resolvedTypeReferenceDirective, + refKind: reason.kind, + refPath: isReferencedFile(reason) ? reason.file : undefined, + }); processTypeReferenceDirectiveWorker(typeReferenceDirective, mode, resolvedTypeReferenceDirective, reason); tracing?.pop(); } @@ -3191,7 +4133,13 @@ namespace ts { if (resolvedTypeReferenceDirective.primary) { // resolved from the primary path - processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason); // TODO: GH#18217 + processSourceFile( + resolvedTypeReferenceDirective.resolvedFileName!, + /*isDefaultLib*/ false, + /*ignoreNoDefaultLib*/ false, + resolvedTypeReferenceDirective.packageId, + reason, + ); // TODO: GH#18217 } else { // If we already resolved to this file, it must have been a secondary reference. Check file contents @@ -3205,8 +4153,13 @@ namespace ts { addFilePreprocessingFileExplainingDiagnostic( existingFile, reason, - Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict, - [typeReferenceDirective, resolvedTypeReferenceDirective.resolvedFileName, previousResolution.resolvedFileName], + Diagnostics + .Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict, + [ + typeReferenceDirective, + resolvedTypeReferenceDirective.resolvedFileName, + previousResolution.resolvedFileName, + ], ); } } @@ -3215,14 +4168,25 @@ namespace ts { } else { // First resolution of this library - processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason); + processSourceFile( + resolvedTypeReferenceDirective.resolvedFileName!, + /*isDefaultLib*/ false, + /*ignoreNoDefaultLib*/ false, + resolvedTypeReferenceDirective.packageId, + reason, + ); } } if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--; } else { - addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_find_type_definition_file_for_0, [typeReferenceDirective]); + addFilePreprocessingFileExplainingDiagnostic( + /*file*/ undefined, + reason, + Diagnostics.Cannot_find_type_definition_file_for_0, + [typeReferenceDirective], + ); } if (saveResolution) { @@ -3242,7 +4206,13 @@ namespace ts { i++; } const resolveFrom = combinePaths(currentDirectory, `__lib_node_modules_lookup_${libFileName}__.ts`); - const localOverrideModuleResult = resolveModuleName("@typescript/lib-" + path, resolveFrom, { moduleResolution: ModuleResolutionKind.NodeJs }, host, moduleResolutionCache); + const localOverrideModuleResult = resolveModuleName( + "@typescript/lib-" + path, + resolveFrom, + { moduleResolution: ModuleResolutionKind.NodeJs }, + host, + moduleResolutionCache, + ); if (localOverrideModuleResult?.resolvedModule) { return localOverrideModuleResult.resolvedModule.resolvedFileName; } @@ -3255,12 +4225,17 @@ namespace ts { const libFileName = libMap.get(libName); if (libFileName) { // we ignore any 'no-default-lib' reference set on this file. - processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index }); + processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { + kind: FileIncludeKind.LibReferenceDirective, + file: file.path, + index, + }); } else { const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts"); const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity); - const diagnostic = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0; + const diagnostic = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 + : Diagnostics.Cannot_find_lib_definition_for_0; (fileProcessingDiagnostics ||= []).push({ kind: FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic, reason: { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index }, @@ -3282,7 +4257,9 @@ namespace ts { const moduleNames = getModuleNames(file); const resolutions = resolveModuleNamesReusingOldState(moduleNames, file); Debug.assert(resolutions.length === moduleNames.length); - const optionsForFile = (useSourceOfProjectReferenceRedirect ? getRedirectReferenceForResolution(file)?.commandLine.options : undefined) || options; + const optionsForFile = + (useSourceOfProjectReferenceRedirect ? getRedirectReferenceForResolution(file)?.commandLine.options + : undefined) || options; for (let index = 0; index < moduleNames.length; index++) { const resolution = resolutions[index]; setResolvedModule(file, moduleNames[index], resolution, getModeForResolutionAtIndex(file, index)); @@ -3342,10 +4319,14 @@ namespace ts { function checkSourceFilesBelongToPath(sourceFiles: readonly SourceFile[], rootDirectory: string): boolean { let allFilesBelongToPath = true; - const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory)); + const absoluteRootDirectoryPath = host.getCanonicalFileName( + getNormalizedAbsolutePath(rootDirectory, currentDirectory), + ); for (const sourceFile of sourceFiles) { if (!sourceFile.isDeclarationFile) { - const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory)); + const absoluteSourceFilePath = host.getCanonicalFileName( + getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory), + ); if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) { addProgramDiagnosticExplainingFile( sourceFile, @@ -3395,7 +4376,13 @@ namespace ts { projectReferenceRedirects.set(sourceFilePath, false); return undefined; } - commandLine = parseJsonSourceFileConfigFileContent(sourceFile, configParsingHost, basePath, /*existingOptions*/ undefined, refPath); + commandLine = parseJsonSourceFileConfigFileContent( + sourceFile, + configParsingHost, + basePath, + /*existingOptions*/ undefined, + refPath, + ); } sourceFile.fileName = refPath; sourceFile.path = sourceFilePath; @@ -3412,48 +4399,88 @@ namespace ts { function verifyCompilerOptions() { if (options.strictPropertyInitialization && !getStrictOptionValue(options, "strictNullChecks")) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "strictPropertyInitialization", "strictNullChecks"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "strictPropertyInitialization", + "strictNullChecks", + ); } if (options.exactOptionalPropertyTypes && !getStrictOptionValue(options, "strictNullChecks")) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "exactOptionalPropertyTypes", "strictNullChecks"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "exactOptionalPropertyTypes", + "strictNullChecks", + ); } if (options.isolatedModules) { if (options.out) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "isolatedModules"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "out", + "isolatedModules", + ); } if (options.outFile) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "outFile", "isolatedModules"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "outFile", + "isolatedModules", + ); } } if (options.inlineSourceMap) { if (options.sourceMap) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceMap", "inlineSourceMap"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "sourceMap", + "inlineSourceMap", + ); } if (options.mapRoot) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "mapRoot", + "inlineSourceMap", + ); } } if (options.composite) { if (options.declaration === false) { - createDiagnosticForOptionName(Diagnostics.Composite_projects_may_not_disable_declaration_emit, "declaration"); + createDiagnosticForOptionName( + Diagnostics.Composite_projects_may_not_disable_declaration_emit, + "declaration", + ); } if (options.incremental === false) { - createDiagnosticForOptionName(Diagnostics.Composite_projects_may_not_disable_incremental_compilation, "declaration"); + createDiagnosticForOptionName( + Diagnostics.Composite_projects_may_not_disable_incremental_compilation, + "declaration", + ); } } const outputFile = outFile(options); if (options.tsBuildInfoFile) { if (!isIncrementalCompilation(options)) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "tsBuildInfoFile", "incremental", "composite"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, + "tsBuildInfoFile", + "incremental", + "composite", + ); } } else if (options.incremental && !outputFile && !options.configFilePath) { - programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified)); + programDiagnostics.add( + createCompilerDiagnostic( + Diagnostics + .Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified, + ), + ); } verifyProjectReferences(); @@ -3466,7 +4493,8 @@ namespace ts { if (sourceFileMayBeEmitted(file, program) && !rootPaths.has(file.path)) { addProgramDiagnosticExplainingFile( file, - Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, + Diagnostics + .File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, [file.fileName, options.configFilePath || ""], ); } @@ -3479,41 +4507,82 @@ namespace ts { continue; } if (!hasZeroOrOneAsteriskCharacter(key)) { - createDiagnosticForOptionPaths(/*onKey*/ true, key, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key); + createDiagnosticForOptionPaths( + /*onKey*/ true, + key, + Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, + key, + ); } if (isArray(options.paths[key])) { const len = options.paths[key].length; if (len === 0) { - createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, key); + createDiagnosticForOptionPaths( + /*onKey*/ false, + key, + Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, + key, + ); } for (let i = 0; i < len; i++) { const subst = options.paths[key][i]; const typeOfSubst = typeof subst; if (typeOfSubst === "string") { if (!hasZeroOrOneAsteriskCharacter(subst)) { - createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_in_pattern_1_can_have_at_most_one_Asterisk_character, subst, key); + createDiagnosticForOptionPathKeyValue( + key, + i, + Diagnostics.Substitution_0_in_pattern_1_can_have_at_most_one_Asterisk_character, + subst, + key, + ); } if (!options.baseUrl && !pathIsRelative(subst) && !pathIsAbsolute(subst)) { - createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Non_relative_paths_are_not_allowed_when_baseUrl_is_not_set_Did_you_forget_a_leading_Slash); + createDiagnosticForOptionPathKeyValue( + key, + i, + Diagnostics + .Non_relative_paths_are_not_allowed_when_baseUrl_is_not_set_Did_you_forget_a_leading_Slash, + ); } } else { - createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst); + createDiagnosticForOptionPathKeyValue( + key, + i, + Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, + subst, + key, + typeOfSubst, + ); } } } else { - createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_should_be_an_array, key); + createDiagnosticForOptionPaths( + /*onKey*/ false, + key, + Diagnostics.Substitutions_for_pattern_0_should_be_an_array, + key, + ); } } } if (!options.sourceMap && !options.inlineSourceMap) { if (options.inlineSources) { - createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources"); + createDiagnosticForOptionName( + Diagnostics + .Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, + "inlineSources", + ); } if (options.sourceRoot) { - createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot"); + createDiagnosticForOptionName( + Diagnostics + .Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, + "sourceRoot", + ); } } @@ -3523,20 +4592,39 @@ namespace ts { if (options.mapRoot && !(options.sourceMap || options.declarationMap)) { // Error to specify --mapRoot without --sourcemap - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "mapRoot", "sourceMap", "declarationMap"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, + "mapRoot", + "sourceMap", + "declarationMap", + ); } if (options.declarationDir) { if (!getEmitDeclarations(options)) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationDir", "declaration", "composite"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, + "declarationDir", + "declaration", + "composite", + ); } if (outputFile) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declarationDir", options.out ? "out" : "outFile"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "declarationDir", + options.out ? "out" : "outFile", + ); } } if (options.declarationMap && !getEmitDeclarations(options)) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationMap", "declaration", "composite"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, + "declarationMap", + "declaration", + "composite", + ); } if (options.lib && options.noLib) { @@ -3544,142 +4632,275 @@ namespace ts { } if (options.noImplicitUseStrict && getStrictOptionValue(options, "alwaysStrict")) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "noImplicitUseStrict", + "alwaysStrict", + ); } const languageVersion = getEmitScriptTarget(options); - const firstNonAmbientExternalModuleSourceFile = find(files, f => isExternalModule(f) && !f.isDeclarationFile); + const firstNonAmbientExternalModuleSourceFile = find( + files, + f => isExternalModule(f) && !f.isDeclarationFile, + ); if (options.isolatedModules) { if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) { - createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target"); + createDiagnosticForOptionName( + Diagnostics + .Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, + "isolatedModules", + "target", + ); } if (options.preserveConstEnums === false) { - createDiagnosticForOptionName(Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_isolatedModules_is_enabled, "preserveConstEnums", "isolatedModules"); + createDiagnosticForOptionName( + Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_isolatedModules_is_enabled, + "preserveConstEnums", + "isolatedModules", + ); } for (const file of files) { - if (!isExternalModule(file) && !isSourceFileJS(file) && !file.isDeclarationFile && file.scriptKind !== ScriptKind.JSON) { + if ( + !isExternalModule(file) && !isSourceFileJS(file) && !file.isDeclarationFile + && file.scriptKind !== ScriptKind.JSON + ) { const span = getErrorSpanForNode(file, file); - programDiagnostics.add(createFileDiagnostic(file, span.start, span.length, Diagnostics._0_cannot_be_compiled_under_isolatedModules_because_it_is_considered_a_global_script_file_Add_an_import_export_or_an_empty_export_statement_to_make_it_a_module, getBaseFileName(file.fileName))); + programDiagnostics.add( + createFileDiagnostic( + file, + span.start, + span.length, + Diagnostics + ._0_cannot_be_compiled_under_isolatedModules_because_it_is_considered_a_global_script_file_Add_an_import_export_or_an_empty_export_statement_to_make_it_a_module, + getBaseFileName(file.fileName), + ), + ); } } } - else if (firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 && options.module === ModuleKind.None) { + else if ( + firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 + && options.module === ModuleKind.None + ) { // We cannot use createDiagnosticFromNode because nodes do not have parents yet - const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!); - programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none)); + const span = getErrorSpanForNode( + firstNonAmbientExternalModuleSourceFile, + typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" + ? firstNonAmbientExternalModuleSourceFile + : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!, + ); + programDiagnostics.add( + createFileDiagnostic( + firstNonAmbientExternalModuleSourceFile, + span.start, + span.length, + Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none, + ), + ); } // Cannot specify module gen that isn't amd or system with --out if (outputFile && !options.emitDeclarationOnly) { if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) { - createDiagnosticForOptionName(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile", "module"); + createDiagnosticForOptionName( + Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, + options.out ? "out" : "outFile", + "module", + ); } else if (options.module === undefined && firstNonAmbientExternalModuleSourceFile) { - const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!); - programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, options.out ? "out" : "outFile")); + const span = getErrorSpanForNode( + firstNonAmbientExternalModuleSourceFile, + typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" + ? firstNonAmbientExternalModuleSourceFile + : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!, + ); + programDiagnostics.add( + createFileDiagnostic( + firstNonAmbientExternalModuleSourceFile, + span.start, + span.length, + Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, + options.out ? "out" : "outFile", + ), + ); } } if (options.resolveJsonModule) { if ( - getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs && - getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 && - getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext + getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs + && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 + && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext ) { - createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy, "resolveJsonModule"); + createDiagnosticForOptionName( + Diagnostics + .Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy, + "resolveJsonModule", + ); } // Any emit other than common js, amd, es2015 or esnext is error else if (!hasJsonModuleEmitEnabled(options)) { - createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs_amd_es2015_or_esNext, "resolveJsonModule", "module"); + createDiagnosticForOptionName( + Diagnostics + .Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs_amd_es2015_or_esNext, + "resolveJsonModule", + "module", + ); } } // there has to be common source directory if user specified --outdir || --rootDir || --sourceRoot // if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted if ( - options.outDir || // there is --outDir specified - options.rootDir || // there is --rootDir specified - options.sourceRoot || // there is --sourceRoot specified - options.mapRoot + options.outDir // there is --outDir specified + || options.rootDir // there is --rootDir specified + || options.sourceRoot // there is --sourceRoot specified + || options.mapRoot ) { // there is --mapRoot specified // Precalculate and cache the common source directory const dir = getCommonSourceDirectory(); // If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure if (options.outDir && dir === "" && files.some(file => getRootLength(file.fileName) > 1)) { - createDiagnosticForOptionName(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, "outDir"); + createDiagnosticForOptionName( + Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, + "outDir", + ); } } if (options.useDefineForClassFields && languageVersion === ScriptTarget.ES3) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_target_is_ES3, "useDefineForClassFields"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_target_is_ES3, + "useDefineForClassFields", + ); } if (options.checkJs && !getAllowJSCompilerOption(options)) { - programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "checkJs", "allowJs")); + programDiagnostics.add( + createCompilerDiagnostic( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "checkJs", + "allowJs", + ), + ); } if (options.emitDeclarationOnly) { if (!getEmitDeclarations(options)) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "emitDeclarationOnly", "declaration", "composite"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, + "emitDeclarationOnly", + "declaration", + "composite", + ); } if (options.noEmit) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "emitDeclarationOnly", "noEmit"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "emitDeclarationOnly", + "noEmit", + ); } } if ( - options.emitDecoratorMetadata && - !options.experimentalDecorators + options.emitDecoratorMetadata + && !options.experimentalDecorators ) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "emitDecoratorMetadata", + "experimentalDecorators", + ); } if (options.jsxFactory) { if (options.reactNamespace) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "reactNamespace", + "jsxFactory", + ); } if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFactory", inverseJsxOptionMap.get("" + options.jsx)); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, + "jsxFactory", + inverseJsxOptionMap.get("" + options.jsx), + ); } if (!parseIsolatedEntityName(options.jsxFactory, languageVersion)) { - createOptionValueDiagnostic("jsxFactory", Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory); + createOptionValueDiagnostic( + "jsxFactory", + Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, + options.jsxFactory, + ); } } else if (options.reactNamespace && !isIdentifierText(options.reactNamespace, languageVersion)) { - createOptionValueDiagnostic("reactNamespace", Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace); + createOptionValueDiagnostic( + "reactNamespace", + Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, + options.reactNamespace, + ); } if (options.jsxFragmentFactory) { if (!options.jsxFactory) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "jsxFragmentFactory", "jsxFactory"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "jsxFragmentFactory", + "jsxFactory", + ); } if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFragmentFactory", inverseJsxOptionMap.get("" + options.jsx)); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, + "jsxFragmentFactory", + inverseJsxOptionMap.get("" + options.jsx), + ); } if (!parseIsolatedEntityName(options.jsxFragmentFactory, languageVersion)) { - createOptionValueDiagnostic("jsxFragmentFactory", Diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFragmentFactory); + createOptionValueDiagnostic( + "jsxFragmentFactory", + Diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, + options.jsxFragmentFactory, + ); } } if (options.reactNamespace) { if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "reactNamespace", inverseJsxOptionMap.get("" + options.jsx)); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, + "reactNamespace", + inverseJsxOptionMap.get("" + options.jsx), + ); } } if (options.jsxImportSource) { if (options.jsx === JsxEmit.React) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxImportSource", inverseJsxOptionMap.get("" + options.jsx)); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, + "jsxImportSource", + inverseJsxOptionMap.get("" + options.jsx), + ); } } if (options.preserveValueImports && getEmitModuleKind(options) < ModuleKind.ES2015) { - createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_preserveValueImports_can_only_be_used_when_module_is_set_to_es2015_or_later); + createOptionValueDiagnostic( + "importsNotUsedAsValues", + Diagnostics.Option_preserveValueImports_can_only_be_used_when_module_is_set_to_es2015_or_later, + ); } // If the emit is enabled make sure that every output file is unique and not overwriting any of the input files @@ -3703,17 +4924,32 @@ namespace ts { let chain: DiagnosticMessageChain | undefined; if (!options.configFilePath) { // The program is from either an inferred project or an external project - chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Adding_a_tsconfig_json_file_will_help_organize_projects_that_contain_both_TypeScript_and_JavaScript_files_Learn_more_at_https_Colon_Slash_Slashaka_ms_Slashtsconfig); + chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics + .Adding_a_tsconfig_json_file_will_help_organize_projects_that_contain_both_TypeScript_and_JavaScript_files_Learn_more_at_https_Colon_Slash_Slashaka_ms_Slashtsconfig, + ); } - chain = chainDiagnosticMessages(chain, Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file, emitFileName); + chain = chainDiagnosticMessages( + chain, + Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file, + emitFileName, + ); blockEmittingOfFile(emitFileName, createCompilerDiagnosticFromMessageChain(chain)); } - const emitFileKey = !host.useCaseSensitiveFileNames() ? toFileNameLowerCase(emitFilePath) : emitFilePath; + const emitFileKey = !host.useCaseSensitiveFileNames() ? toFileNameLowerCase(emitFilePath) + : emitFilePath; // Report error if multiple files write into same file if (emitFilesSeen.has(emitFileKey)) { // Already seen the same emit file - report error - blockEmittingOfFile(emitFileName, createCompilerDiagnostic(Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, emitFileName)); + blockEmittingOfFile( + emitFileName, + createCompilerDiagnostic( + Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, + emitFileName, + ), + ); } else { emitFilesSeen.add(emitFileKey); @@ -3722,7 +4958,12 @@ namespace ts { } } - function createDiagnosticExplainingFile(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason | undefined, diagnostic: DiagnosticMessage, args: (string | number | undefined)[] | undefined): Diagnostic { + function createDiagnosticExplainingFile( + file: SourceFile | undefined, + fileProcessingReason: FileIncludeReason | undefined, + diagnostic: DiagnosticMessage, + args: (string | number | undefined)[] | undefined, + ): Diagnostic { let fileIncludeReasons: DiagnosticMessageChain[] | undefined; let relatedInfo: Diagnostic[] | undefined; let locationReason = isReferencedFile(fileProcessingReason) ? fileProcessingReason : undefined; @@ -3731,12 +4972,24 @@ namespace ts { // If we have location and there is only one reason file is in which is the location, dont add details for file include if (locationReason && fileIncludeReasons?.length === 1) fileIncludeReasons = undefined; const location = locationReason && getReferencedFileLocation(getSourceFileByPath, locationReason); - const fileIncludeReasonDetails = fileIncludeReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon); + const fileIncludeReasonDetails = fileIncludeReasons + && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon); const redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file); - const chain = chainDiagnosticMessages(redirectInfo ? fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo : fileIncludeReasonDetails, diagnostic, ...args || emptyArray); - return location && isReferenceFileLocation(location) ? - createFileDiagnosticFromMessageChain(location.file, location.pos, location.end - location.pos, chain, relatedInfo) : - createCompilerDiagnosticFromMessageChain(chain, relatedInfo); + const chain = chainDiagnosticMessages( + redirectInfo ? fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo + : fileIncludeReasonDetails, + diagnostic, + ...args || emptyArray, + ); + return location && isReferenceFileLocation(location) + ? createFileDiagnosticFromMessageChain( + location.file, + location.pos, + location.end - location.pos, + chain, + relatedInfo, + ) + : createCompilerDiagnosticFromMessageChain(chain, relatedInfo); function processReason(reason: FileIncludeReason) { (fileIncludeReasons ||= []).push(fileIncludeReasonToDiagnostics(program, reason)); @@ -3752,7 +5005,12 @@ namespace ts { } } - function addFilePreprocessingFileExplainingDiagnostic(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) { + function addFilePreprocessingFileExplainingDiagnostic( + file: SourceFile | undefined, + fileProcessingReason: FileIncludeReason, + diagnostic: DiagnosticMessage, + args?: (string | number | undefined)[], + ) { (fileProcessingDiagnostics ||= []).push({ kind: FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic, file: file && file.path, @@ -3762,8 +5020,14 @@ namespace ts { }); } - function addProgramDiagnosticExplainingFile(file: SourceFile, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) { - programDiagnostics.add(createDiagnosticExplainingFile(file, /*fileProcessingReason*/ undefined, diagnostic, args)); + function addProgramDiagnosticExplainingFile( + file: SourceFile, + diagnostic: DiagnosticMessage, + args?: (string | number | undefined)[], + ) { + programDiagnostics.add( + createDiagnosticExplainingFile(file, /*fileProcessingReason*/ undefined, diagnostic, args), + ); } function fileIncludeReasonToRelatedInformation(reason: FileIncludeReason): DiagnosticWithLocation | undefined { @@ -3816,19 +5080,28 @@ namespace ts { case FileIncludeKind.SourceFromProjectReference: case FileIncludeKind.OutputFromProjectReference: const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]); - const referenceInfo = forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => resolvedRef === referencedResolvedRef ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined); + const referenceInfo = forEachProjectReference( + projectReferences, + resolvedProjectReferences, + (resolvedRef, parent, index) => + resolvedRef === referencedResolvedRef + ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined, + ); if (!referenceInfo) return undefined; const { sourceFile, index } = referenceInfo; - const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile as TsConfigSourceFile, "references"), property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined); - return referencesSyntax && referencesSyntax.elements.length > index ? - createDiagnosticForNodeInSourceFile( + const referencesSyntax = firstDefined( + getTsConfigPropArray(sourceFile as TsConfigSourceFile, "references"), + property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined, + ); + return referencesSyntax && referencesSyntax.elements.length > index + ? createDiagnosticForNodeInSourceFile( sourceFile, referencesSyntax.elements[index], - reason.kind === FileIncludeKind.OutputFromProjectReference ? - Diagnostics.File_is_output_from_referenced_project_specified_here : - Diagnostics.File_is_source_from_referenced_project_specified_here, - ) : - undefined; + reason.kind === FileIncludeKind.OutputFromProjectReference + ? Diagnostics.File_is_output_from_referenced_project_specified_here + : Diagnostics.File_is_source_from_referenced_project_specified_here, + ) + : undefined; case FileIncludeKind.AutomaticTypeDirectiveFile: if (!options.types) return undefined; configFileNode = getOptionsSyntaxByArrayElementValue("types", reason.typeReference); @@ -3840,7 +5113,10 @@ namespace ts { message = Diagnostics.File_is_library_specified_here; break; } - const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === getEmitScriptTarget(options) ? key : undefined); + const target = forEachEntry( + targetOptionDeclaration.type, + (value, key) => value === getEmitScriptTarget(options) ? key : undefined, + ); configFileNode = target ? getOptionsSyntaxByValue("target", target) : undefined; message = Diagnostics.File_is_default_library_for_target_specified_here; break; @@ -3855,7 +5131,8 @@ namespace ts { } function verifyProjectReferences() { - const buildInfoPath = !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) : undefined; + const buildInfoPath = !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) + : undefined; forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => { const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index]; const parentFile = parent && parent.sourceFile as JsonSourceFile; @@ -3868,29 +5145,68 @@ namespace ts { // ok to not have composite if the current program is container only const inputs = parent ? parent.commandLine.fileNames : rootNames; if (inputs.length) { - if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path); - if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path); + if (!options.composite) { + createDiagnosticForReference( + parentFile, + index, + Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, + ref.path, + ); + } + if (options.noEmit) { + createDiagnosticForReference( + parentFile, + index, + Diagnostics.Referenced_project_0_may_not_disable_emit, + ref.path, + ); + } } } if (ref.prepend) { const out = outFile(options); if (out) { if (!host.fileExists(out)) { - createDiagnosticForReference(parentFile, index, Diagnostics.Output_file_0_from_project_1_does_not_exist, out, ref.path); + createDiagnosticForReference( + parentFile, + index, + Diagnostics.Output_file_0_from_project_1_does_not_exist, + out, + ref.path, + ); } } else { - createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, ref.path); + createDiagnosticForReference( + parentFile, + index, + Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, + ref.path, + ); } } if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) { - createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path); + createDiagnosticForReference( + parentFile, + index, + Diagnostics + .Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, + buildInfoPath, + ref.path, + ); hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true); } }); } - function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) { + function createDiagnosticForOptionPathKeyValue( + key: string, + valueIndex: number, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + ) { let needCompilerDiagnostic = true; const pathsSyntax = getOptionPathsSyntax(); for (const pathProp of pathsSyntax) { @@ -3898,7 +5214,16 @@ namespace ts { for (const keyProps of getPropertyAssignment(pathProp.initializer, key)) { const initializer = keyProps.initializer; if (isArrayLiteralExpression(initializer) && initializer.elements.length > valueIndex) { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, arg0, arg1, arg2)); + programDiagnostics.add( + createDiagnosticForNodeInSourceFile( + options.configFile!, + initializer.elements[valueIndex], + message, + arg0, + arg1, + arg2, + ), + ); needCompilerDiagnostic = false; } } @@ -3910,13 +5235,18 @@ namespace ts { } } - function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, arg0: string | number) { + function createDiagnosticForOptionPaths( + onKey: boolean, + key: string, + message: DiagnosticMessage, + arg0: string | number, + ) { let needCompilerDiagnostic = true; const pathsSyntax = getOptionPathsSyntax(); for (const pathProp of pathsSyntax) { if ( - isObjectLiteralExpression(pathProp.initializer) && - createOptionDiagnosticInObjectLiteralSyntax( + isObjectLiteralExpression(pathProp.initializer) + && createOptionDiagnosticInObjectLiteralSyntax( pathProp.initializer, onKey, key, @@ -3935,7 +5265,8 @@ namespace ts { function getOptionsSyntaxByName(name: string) { const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); - return compilerOptionsObjectLiteralSyntax && getPropertyAssignment(compilerOptionsObjectLiteralSyntax, name); + return compilerOptionsObjectLiteralSyntax + && getPropertyAssignment(compilerOptionsObjectLiteralSyntax, name); } function getOptionPathsSyntax() { @@ -3944,36 +5275,87 @@ namespace ts { function getOptionsSyntaxByValue(name: string, value: string) { const syntaxByName = getOptionsSyntaxByName(name); - return syntaxByName && firstDefined(syntaxByName, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined); + return syntaxByName + && firstDefined( + syntaxByName, + property => + isStringLiteral(property.initializer) && property.initializer.text === value + ? property.initializer : undefined, + ); } function getOptionsSyntaxByArrayElementValue(name: string, value: string) { const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); - return compilerOptionsObjectLiteralSyntax && getPropertyArrayElementValue(compilerOptionsObjectLiteralSyntax, name, value); + return compilerOptionsObjectLiteralSyntax + && getPropertyArrayElementValue(compilerOptionsObjectLiteralSyntax, name, value); } - function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string, option3?: string) { + function createDiagnosticForOptionName( + message: DiagnosticMessage, + option1: string, + option2?: string, + option3?: string, + ) { createDiagnosticForOption(/*onKey*/ true, option1, option2, message, option1, option2, option3); } - function createOptionValueDiagnostic(option1: string, message: DiagnosticMessage, arg0?: string, arg1?: string) { + function createOptionValueDiagnostic( + option1: string, + message: DiagnosticMessage, + arg0?: string, + arg1?: string, + ) { createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, arg0, arg1); } - function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number) { - const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile || options.configFile, "references"), property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined); + function createDiagnosticForReference( + sourceFile: JsonSourceFile | undefined, + index: number, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + ) { + const referencesSyntax = firstDefined( + getTsConfigPropArray(sourceFile || options.configFile, "references"), + property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined, + ); if (referencesSyntax && referencesSyntax.elements.length > index) { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, arg0, arg1)); + programDiagnostics.add( + createDiagnosticForNodeInSourceFile( + sourceFile || options.configFile!, + referencesSyntax.elements[index], + message, + arg0, + arg1, + ), + ); } else { programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1)); } } - function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) { + function createDiagnosticForOption( + onKey: boolean, + option1: string, + option2: string | undefined, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + ) { const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); - const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax || - !createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, arg0, arg1, arg2); + const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax + || !createOptionDiagnosticInObjectLiteralSyntax( + compilerOptionsObjectLiteralSyntax, + onKey, + option1, + option2, + message, + arg0, + arg1, + arg2, + ); if (needCompilerDiagnostic) { programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2)); @@ -3996,10 +5378,28 @@ namespace ts { return _compilerOptionsObjectLiteralSyntax || undefined; } - function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean { + function createOptionDiagnosticInObjectLiteralSyntax( + objectLiteral: ObjectLiteralExpression, + onKey: boolean, + key1: string, + key2: string | undefined, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + ): boolean { const props = getPropertyAssignment(objectLiteral, key1, key2); for (const prop of props) { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, arg0, arg1, arg2)); + programDiagnostics.add( + createDiagnosticForNodeInSourceFile( + options.configFile!, + onKey ? prop.name : prop.initializer, + message, + arg0, + arg1, + arg2, + ), + ); } return !!props.length; } @@ -4027,7 +5427,10 @@ namespace ts { } // If declarationDir is specified, return if its a file in that directory - if (options.declarationDir && containsPath(options.declarationDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames())) { + if ( + options.declarationDir + && containsPath(options.declarationDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames()) + ) { return true; } @@ -4039,14 +5442,15 @@ namespace ts { if (fileExtensionIsOneOf(filePath, supportedJSExtensionsFlat) || isDeclarationFileName(filePath)) { // Otherwise just check if sourceFile with the name exists const filePathWithoutExtension = removeFileExtension(filePath); - return !!getSourceFileByPath((filePathWithoutExtension + Extension.Ts) as Path) || - !!getSourceFileByPath((filePathWithoutExtension + Extension.Tsx) as Path); + return !!getSourceFileByPath((filePathWithoutExtension + Extension.Ts) as Path) + || !!getSourceFileByPath((filePathWithoutExtension + Extension.Tsx) as Path); } return false; } function isSameFile(file1: string, file2: string) { - return comparePaths(file1, file2, currentDirectory, !host.useCaseSensitiveFileNames()) === Comparison.EqualTo; + return comparePaths(file1, file2, currentDirectory, !host.useCaseSensitiveFileNames()) + === Comparison.EqualTo; } function getSymlinkCache(): SymlinkCache { @@ -4070,7 +5474,9 @@ namespace ts { toPath(fileName: string): Path; getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined; getSourceOfProjectReferenceRedirect(path: Path): SourceOfProjectReferenceRedirect | undefined; - forEachResolvedProjectReference(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined; + forEachResolvedProjectReference( + cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, + ): T | undefined; } function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSourceOfProjectReferenceRedirect) { @@ -4106,7 +5512,8 @@ namespace ts { } else { // Set declaration's in different locations only, if they are next to source the directory present doesnt change - const declarationDir = ref.commandLine.options.declarationDir || ref.commandLine.options.outDir; + const declarationDir = ref.commandLine.options.declarationDir + || ref.commandLine.options.outDir; if (declarationDir) { setOfDeclarationDirectories!.add(host.toPath(declarationDir)); } @@ -4122,16 +5529,17 @@ namespace ts { // Call getDirectories only if directory actually present on the host // This is needed to ensure that we arent getting directories that we fake about presence for host.compilerHost.getDirectories = path => - !host.getResolvedProjectReferences() || (originalDirectoryExists && originalDirectoryExists.call(host.compilerHost, path)) ? - originalGetDirectories.call(host.compilerHost, path) : - []; + !host.getResolvedProjectReferences() + || (originalDirectoryExists && originalDirectoryExists.call(host.compilerHost, path)) + ? originalGetDirectories.call(host.compilerHost, path) + : []; } // This is something we keep for life time of the host if (originalRealpath) { host.compilerHost.realpath = s => - host.getSymlinkCache().getSymlinkedFiles()?.get(host.toPath(s)) || - originalRealpath.call(host.compilerHost, s); + host.getSymlinkCache().getSymlinkedFiles()?.get(host.toPath(s)) + || originalRealpath.call(host.compilerHost, s); } return { onProgramCreateComplete, fileExists, directoryExists }; @@ -4157,9 +5565,9 @@ namespace ts { function fileExistsIfProjectReferenceDts(file: string) { const source = host.getSourceOfProjectReferenceRedirect(host.toPath(file)); - return source !== undefined ? - isString(source) ? originalFileExists.call(host.compilerHost, source) as boolean : true : - undefined; + return source !== undefined + ? isString(source) ? originalFileExists.call(host.compilerHost, source) as boolean : true + : undefined; } function directoryExistsIfProjectReferenceDeclDir(dir: string) { @@ -4168,11 +5576,11 @@ namespace ts { return forEachKey( setOfDeclarationDirectories!, declDirPath => - dirPath === declDirPath || + dirPath === declDirPath // Any parent directory of declaration dir - startsWith(declDirPath, dirPathWithTrailingDirectorySeparator) || + || startsWith(declDirPath, dirPathWithTrailingDirectorySeparator) // Any directory inside declaration dir - startsWith(dirPath, `${declDirPath}/`), + || startsWith(dirPath, `${declDirPath}/`), ); } @@ -4188,8 +5596,8 @@ namespace ts { const real = normalizePath(originalRealpath.call(host.compilerHost, directory)); let realPath: Path; if ( - real === directory || - (realPath = ensureTrailingDirectorySeparator(host.toPath(real))) === directoryPath + real === directory + || (realPath = ensureTrailingDirectorySeparator(host.toPath(real))) === directoryPath ) { // not symlinked symlinkCache.setSymlinkedDirectory(directoryPath, false); @@ -4203,9 +5611,9 @@ namespace ts { } function fileOrDirectoryExistsUsingSource(fileOrDirectory: string, isFile: boolean): boolean { - const fileOrDirectoryExistsUsingSource = isFile ? - (file: string) => fileExistsIfProjectReferenceDts(file) : - (dir: string) => directoryExistsIfProjectReferenceDeclDir(dir); + const fileOrDirectoryExistsUsingSource = isFile + ? (file: string) => fileExistsIfProjectReferenceDts(file) + : (dir: string) => directoryExistsIfProjectReferenceDeclDir(dir); // Check current directory or file const result = fileOrDirectoryExistsUsingSource(fileOrDirectory); if (result !== undefined) return result; @@ -4222,10 +5630,15 @@ namespace ts { symlinkedDirectories.entries(), ([directoryPath, symlinkedDirectory]) => { if (!symlinkedDirectory || !startsWith(fileOrDirectoryPath, directoryPath)) return undefined; - const result = fileOrDirectoryExistsUsingSource(fileOrDirectoryPath.replace(directoryPath, symlinkedDirectory.realPath)); + const result = fileOrDirectoryExistsUsingSource( + fileOrDirectoryPath.replace(directoryPath, symlinkedDirectory.realPath), + ); if (isFile && result) { // Store the real path for the file' - const absolutePath = getNormalizedAbsolutePath(fileOrDirectory, host.compilerHost.getCurrentDirectory()); + const absolutePath = getNormalizedAbsolutePath( + fileOrDirectory, + host.compilerHost.getCurrentDirectory(), + ); symlinkCache.setSymlinkedFile( fileOrDirectoryPath, `${symlinkedDirectory.real}${absolutePath.replace(new RegExp(directoryPath, "i"), "")}`, @@ -4238,7 +5651,12 @@ namespace ts { } /*@internal*/ - export const emitSkippedWithNoDiagnostics: EmitResult = { diagnostics: emptyArray, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true }; + export const emitSkippedWithNoDiagnostics: EmitResult = { + diagnostics: emptyArray, + sourceMaps: undefined, + emittedFiles: undefined, + emitSkipped: true, + }; /*@internal*/ export function handleNoEmitOptions( @@ -4251,9 +5669,9 @@ namespace ts { if (options.noEmit) { // Cache the semantic diagnostics program.getSemanticDiagnostics(sourceFile, cancellationToken); - return sourceFile || outFile(options) ? - emitSkippedWithNoDiagnostics : - program.emitBuildInfo(writeFile, cancellationToken); + return sourceFile || outFile(options) + ? emitSkippedWithNoDiagnostics + : program.emitBuildInfo(writeFile, cancellationToken); } // If the noEmitOnError flag is set, then check if we have any errors so far. If so, @@ -4282,7 +5700,10 @@ namespace ts { } /*@internal*/ - export function filterSemanticDiagnostics(diagnostic: readonly Diagnostic[], option: CompilerOptions): readonly Diagnostic[] { + export function filterSemanticDiagnostics( + diagnostic: readonly Diagnostic[], + option: CompilerOptions, + ): readonly Diagnostic[] { return filter(diagnostic, d => !d.skippedOn || !option[d.skippedOn]); } @@ -4292,17 +5713,29 @@ namespace ts { getCurrentDirectory(): string; fileExists(fileName: string): boolean; readFile(fileName: string): string | undefined; - readDirectory?(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[], depth?: number): string[]; + readDirectory?( + rootDir: string, + extensions: readonly string[], + excludes: readonly string[] | undefined, + includes: readonly string[], + depth?: number, + ): string[]; trace?(s: string): void; onUnRecoverableConfigFileDiagnostic?: DiagnosticReporter; } /* @internal */ - export function parseConfigHostFromCompilerHostLike(host: CompilerHostLike, directoryStructureHost: DirectoryStructureHost = host): ParseConfigFileHost { + export function parseConfigHostFromCompilerHostLike( + host: CompilerHostLike, + directoryStructureHost: DirectoryStructureHost = host, + ): ParseConfigFileHost { return { fileExists: f => directoryStructureHost.fileExists(f), readDirectory(root, extensions, excludes, includes, depth) { - Debug.assertIsDefined(directoryStructureHost.readDirectory, "'CompilerHost.readDirectory' must be implemented to correctly process 'projectReferences'"); + Debug.assertIsDefined( + directoryStructureHost.readDirectory, + "'CompilerHost.readDirectory' must be implemented to correctly process 'projectReferences'", + ); return directoryStructureHost.readDirectory(root, extensions, excludes, includes, depth); }, readFile: f => directoryStructureHost.readFile(f), @@ -4319,7 +5752,11 @@ namespace ts { } /* @internal */ - export function createPrependNodes(projectReferences: readonly ProjectReference[] | undefined, getCommandLine: (ref: ProjectReference, index: number) => ParsedCommandLine | undefined, readFile: (path: string) => string | undefined) { + export function createPrependNodes( + projectReferences: readonly ProjectReference[] | undefined, + getCommandLine: (ref: ProjectReference, index: number) => ParsedCommandLine | undefined, + readFile: (path: string) => string | undefined, + ) { if (!projectReferences) return emptyArray; let nodes: InputFiles[] | undefined; for (let i = 0; i < projectReferences.length; i++) { @@ -4330,8 +5767,16 @@ namespace ts { // Upstream project didn't have outFile set -- skip (error will have been issued earlier) if (!out) continue; - const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = getOutputPathsForBundle(resolvedRefOpts.options, /*forceDtsPaths*/ true); - const node = createInputFiles(readFile, jsFilePath!, sourceMapFilePath, declarationFilePath!, declarationMapPath, buildInfoPath); + const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = + getOutputPathsForBundle(resolvedRefOpts.options, /*forceDtsPaths*/ true); + const node = createInputFiles( + readFile, + jsFilePath!, + sourceMapFilePath, + declarationFilePath!, + declarationMapPath, + buildInfoPath, + ); (nodes || (nodes = [])).push(node); } } @@ -4342,8 +5787,14 @@ namespace ts { * Note: The file might not exist. */ export function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName; - /** @deprecated */ export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName; - export function resolveProjectReferencePath(hostOrRef: ResolveProjectReferencePathHost | ProjectReference, ref?: ProjectReference): ResolvedConfigFileName { + /** @deprecated */ export function resolveProjectReferencePath( + host: ResolveProjectReferencePathHost, + ref: ProjectReference, + ): ResolvedConfigFileName; + export function resolveProjectReferencePath( + hostOrRef: ResolveProjectReferencePathHost | ProjectReference, + ref?: ProjectReference, + ): ResolvedConfigFileName { const passedInRef = ref ? ref : hostOrRef as ProjectReference; return resolveConfigFileProjectName(passedInRef.path); } @@ -4354,7 +5805,10 @@ namespace ts { * The DiagnosticMessage's parameters are the imported module name, and the filename it resolved to. * This returns a diagnostic even if the module will be an untyped module. */ - export function getResolutionDiagnostic(options: CompilerOptions, { extension }: ResolvedModuleFull): DiagnosticMessage | undefined { + export function getResolutionDiagnostic( + options: CompilerOptions, + { extension }: ResolvedModuleFull, + ): DiagnosticMessage | undefined { switch (extension) { case Extension.Ts: case Extension.Dts: @@ -4374,10 +5828,12 @@ namespace ts { return options.jsx ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set; } function needAllowJs() { - return getAllowJSCompilerOption(options) || !getStrictOptionValue(options, "noImplicitAny") ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type; + return getAllowJSCompilerOption(options) || !getStrictOptionValue(options, "noImplicitAny") ? undefined + : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type; } function needResolveJsonModule() { - return options.resolveJsonModule ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_resolveJsonModule_is_not_used; + return options.resolveJsonModule ? undefined + : Diagnostics.Module_0_was_resolved_to_1_but_resolveJsonModule_is_not_used; } } @@ -4393,7 +5849,10 @@ namespace ts { } /* @internal */ - export function getModuleNameStringLiteralAt({ imports, moduleAugmentations }: SourceFileImportsList, index: number): StringLiteralLike { + export function getModuleNameStringLiteralAt( + { imports, moduleAugmentations }: SourceFileImportsList, + index: number, + ): StringLiteralLike { if (index < imports.length) return imports[index]; let augIndex = imports.length; for (const aug of moduleAugmentations) { diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index ab61e8284ef67..fdaaf7e347a97 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -5,16 +5,35 @@ namespace ts { startRecordingFilesWithChangedResolutions(): void; finishRecordingFilesWithChangedResolutions(): Path[] | undefined; - resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference?: ResolvedProjectReference, containingSourceFile?: SourceFile): (ResolvedModuleFull | undefined)[]; - getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): CachedResolvedModuleWithFailedLookupLocations | undefined; - resolveTypeReferenceDirectives(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, containingFileMode?: SourceFile["impliedNodeFormat"]): (ResolvedTypeReferenceDirective | undefined)[]; + resolveModuleNames( + moduleNames: string[], + containingFile: string, + reusedNames: string[] | undefined, + redirectedReference?: ResolvedProjectReference, + containingSourceFile?: SourceFile, + ): (ResolvedModuleFull | undefined)[]; + getResolvedModuleWithFailedLookupLocationsFromCache( + moduleName: string, + containingFile: string, + resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): CachedResolvedModuleWithFailedLookupLocations | undefined; + resolveTypeReferenceDirectives( + typeDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference?: ResolvedProjectReference, + containingFileMode?: SourceFile["impliedNodeFormat"], + ): (ResolvedTypeReferenceDirective | undefined)[]; invalidateResolutionsOfFailedLookupLocations(): boolean; invalidateResolutionOfFile(filePath: Path): void; removeResolutionsOfFile(filePath: Path): void; removeResolutionsFromProjectReferenceRedirects(filePath: Path): void; - setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: ESMap): void; - createHasInvalidatedResolutions(customHasInvalidatedResolutions: HasInvalidatedResolutions): HasInvalidatedResolutions; + setFilesWithInvalidatedNonRelativeUnresolvedImports( + filesWithUnresolvedImports: ESMap, + ): void; + createHasInvalidatedResolutions( + customHasInvalidatedResolutions: HasInvalidatedResolutions, + ): HasInvalidatedResolutions; hasChangedAutomaticTypeDirectiveNames(): boolean; isFileWithInvalidatedNonRelativeUnresolvedImports(path: Path): boolean; @@ -43,20 +62,32 @@ namespace ts { packagetId?: PackageId; } - interface CachedResolvedModuleWithFailedLookupLocations extends ResolvedModuleWithFailedLookupLocations, ResolutionWithFailedLookupLocations { + interface CachedResolvedModuleWithFailedLookupLocations + extends ResolvedModuleWithFailedLookupLocations, ResolutionWithFailedLookupLocations + { } - interface CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations extends ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolutionWithFailedLookupLocations { + interface CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations + extends ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolutionWithFailedLookupLocations + { } export interface ResolutionCacheHost extends MinimalResolutionCacheHost { toPath(fileName: string): Path; getCanonicalFileName: GetCanonicalFileName; getCompilationSettings(): CompilerOptions; - watchDirectoryOfFailedLookupLocation(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher; + watchDirectoryOfFailedLookupLocation( + directory: string, + cb: DirectoryWatcherCallback, + flags: WatchDirectoryFlags, + ): FileWatcher; watchAffectingFileLocation(file: string, cb: FileWatcherCallback): FileWatcher; onInvalidatedResolution(): void; - watchTypeRootsDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher; + watchTypeRootsDirectory( + directory: string, + cb: DirectoryWatcherCallback, + flags: WatchDirectoryFlags, + ): FileWatcher; onChangedAutomaticTypeDirectiveNames(): void; scheduleInvalidateResolutionsOfFailedLookupLocations(): void; getCachedDirectoryStructureHost(): CachedDirectoryStructureHost | undefined; @@ -98,9 +129,9 @@ namespace ts { return removeSuffix(path, "/.staging") as Path; } - return some(ignoredPaths, searchPath => stringContains(path, searchPath)) ? - undefined : - path; + return some(ignoredPaths, searchPath => stringContains(path, searchPath)) + ? undefined + : path; } /** @@ -125,9 +156,9 @@ namespace ts { let pathPartForUserCheck = dirPath.substring(rootLength, nextDirectorySeparator + 1); const isNonDirectorySeparatorRoot = rootLength > 1 || dirPath.charCodeAt(0) !== CharacterCodes.slash; if ( - isNonDirectorySeparatorRoot && - dirPath.search(/[a-zA-Z]:/) !== 0 && // Non dos style paths - pathPartForUserCheck.search(/[a-zA-z]\$\//) === 0 + isNonDirectorySeparatorRoot + && dirPath.search(/[a-zA-Z]:/) !== 0 // Non dos style paths + && pathPartForUserCheck.search(/[a-zA-z]\$\//) === 0 ) { // Dos style nextPart nextDirectorySeparator = dirPath.indexOf(directorySeparator, nextDirectorySeparator + 1); if (nextDirectorySeparator === -1) { @@ -135,12 +166,15 @@ namespace ts { return false; } - pathPartForUserCheck = dirPath.substring(rootLength + pathPartForUserCheck.length, nextDirectorySeparator + 1); + pathPartForUserCheck = dirPath.substring( + rootLength + pathPartForUserCheck.length, + nextDirectorySeparator + 1, + ); } if ( - isNonDirectorySeparatorRoot && - pathPartForUserCheck.search(/users\//i) !== 0 + isNonDirectorySeparatorRoot + && pathPartForUserCheck.search(/users\//i) !== 0 ) { // Paths like c:/folderAtRoot/subFolder are allowed return true; @@ -156,9 +190,16 @@ namespace ts { return true; } - type GetResolutionWithResolvedFileName = (resolution: T) => R | undefined; + type GetResolutionWithResolvedFileName< + T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName, + > = (resolution: T) => R | undefined; - export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string | undefined, logChangesWhenResolvingModule: boolean): ResolutionCache { + export function createResolutionCache( + resolutionHost: ResolutionCacheHost, + rootDirForResolution: string | undefined, + logChangesWhenResolvingModule: boolean, + ): ResolutionCache { let filesWithChangedSetOfUnresolvedImports: Path[] | undefined; let filesWithInvalidatedResolutions: Set | undefined; let filesWithInvalidatedNonRelativeUnresolvedImports: ReadonlyESMap | undefined; @@ -183,7 +224,9 @@ namespace ts { // The key in the map is source file's path. // The values are Map of resolutions with key being name lookedup. const resolvedModuleNames = new Map>(); - const perDirectoryResolvedModuleNames: CacheWithRedirects> = createCacheWithRedirects(); + const perDirectoryResolvedModuleNames: CacheWithRedirects< + ModeAwareCache + > = createCacheWithRedirects(); const nonRelativeModuleNameCache: CacheWithRedirects = createCacheWithRedirects(); const moduleResolutionCache = createModuleResolutionCache( getCurrentDirectory(), @@ -193,8 +236,13 @@ namespace ts { nonRelativeModuleNameCache, ); - const resolvedTypeReferenceDirectives = new Map>(); - const perDirectoryResolvedTypeReferenceDirectives: CacheWithRedirects> = createCacheWithRedirects(); + const resolvedTypeReferenceDirectives = new Map< + Path, + ModeAwareCache + >(); + const perDirectoryResolvedTypeReferenceDirectives: CacheWithRedirects< + ModeAwareCache + > = createCacheWithRedirects(); const typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache( getCurrentDirectory(), resolutionHost.getCanonicalFileName, @@ -209,12 +257,19 @@ namespace ts { * This helps in not having to comb through all resolutions when files are added/removed * Note that .d.ts file also has .d.ts extension hence will be part of default extensions */ - const failedLookupDefaultExtensions = [Extension.Ts, Extension.Tsx, Extension.Js, Extension.Jsx, Extension.Json]; + const failedLookupDefaultExtensions = [ + Extension.Ts, + Extension.Tsx, + Extension.Js, + Extension.Jsx, + Extension.Json, + ]; const customFailedLookupPaths = new Map(); const directoryWatchesOfFailedLookups = new Map(); const fileWatchesOfAffectingLocations = new Map(); - const rootDir = rootDirForResolution && removeTrailingDirectorySeparator(getNormalizedAbsolutePath(rootDirForResolution, getCurrentDirectory())); + const rootDir = rootDirForResolution + && removeTrailingDirectorySeparator(getNormalizedAbsolutePath(rootDirForResolution, getCurrentDirectory())); const rootPath = (rootDir && resolutionHost.toPath(rootDir)) as Path; // TODO: GH#18217 const rootSplitLength = rootPath !== undefined ? rootPath.split(directorySeparator).length : 0; @@ -249,7 +304,9 @@ namespace ts { return resolution.resolvedModule; } - function getResolvedTypeReferenceDirective(resolution: CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations) { + function getResolvedTypeReferenceDirective( + resolution: CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations, + ) { return resolution.resolvedTypeReferenceDirective; } @@ -302,15 +359,17 @@ namespace ts { return !!value && !!value.length; } - function createHasInvalidatedResolutions(customHasInvalidatedResolutions: HasInvalidatedResolutions): HasInvalidatedResolutions { + function createHasInvalidatedResolutions( + customHasInvalidatedResolutions: HasInvalidatedResolutions, + ): HasInvalidatedResolutions { // Ensure pending resolutions are applied invalidateResolutionsOfFailedLookupLocations(); const collected = filesWithInvalidatedResolutions; filesWithInvalidatedResolutions = undefined; return path => - customHasInvalidatedResolutions(path) || - !!collected?.has(path) || - isFileWithInvalidatedNonRelativeUnresolvedImports(path); + customHasInvalidatedResolutions(path) + || !!collected?.has(path) + || isFileWithInvalidatedNonRelativeUnresolvedImports(path); } function startCachingPerDirectoryResolution() { @@ -329,7 +388,8 @@ namespace ts { // Update file watches if (newProgram !== oldProgram) { newProgram?.getSourceFiles().forEach(newFile => { - const expected = isExternalOrCommonJsModule(newFile) ? newFile.packageJsonLocations?.length ?? 0 : 0; + const expected = isExternalOrCommonJsModule(newFile) ? newFile.packageJsonLocations?.length ?? 0 + : 0; const existing = impliedFormatPackageJsons.get(newFile.path) ?? emptyArray; for (let i = existing.length; i < expected; i++) { createFileWatcherOfAffectingLocation(newFile.packageJsonLocations![i], /*forResolution*/ false); @@ -365,8 +425,24 @@ namespace ts { hasChangedAutomaticTypeDirectiveNames = false; } - function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference, _containingSourceFile?: never, mode?: ModuleKind.CommonJS | ModuleKind.ESNext | undefined): CachedResolvedModuleWithFailedLookupLocations { - const primaryResult = ts.resolveModuleName(moduleName, containingFile, compilerOptions, host, moduleResolutionCache, redirectedReference, mode); + function resolveModuleName( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + redirectedReference?: ResolvedProjectReference, + _containingSourceFile?: never, + mode?: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, + ): CachedResolvedModuleWithFailedLookupLocations { + const primaryResult = ts.resolveModuleName( + moduleName, + containingFile, + compilerOptions, + host, + moduleResolutionCache, + redirectedReference, + mode, + ); // return result immediately only if global cache support is not enabled or if it is .ts, .tsx or .d.ts if (!resolutionHost.getGlobalCache) { return primaryResult; @@ -374,7 +450,10 @@ namespace ts { // otherwise try to load typings from @types const globalCache = resolutionHost.getGlobalCache(); - if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension))) { + if ( + globalCache !== undefined && !isExternalModuleNameRelative(moduleName) + && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension)) + ) { // create different collection of failed lookup locations for second pass // if it will fail and we've already found something during the first pass - we don't want to pollute its results const { resolvedModule, failedLookupLocations, affectingLocations } = loadModuleFromGlobalCache( @@ -398,17 +477,44 @@ namespace ts { return primaryResult; } - function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string | undefined, options: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference, _containingSourceFile?: SourceFile, resolutionMode?: SourceFile["impliedNodeFormat"] | undefined): CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations { - return ts.resolveTypeReferenceDirective(typeReferenceDirectiveName, containingFile, options, host, redirectedReference, typeReferenceDirectiveResolutionCache, resolutionMode); + function resolveTypeReferenceDirective( + typeReferenceDirectiveName: string, + containingFile: string | undefined, + options: CompilerOptions, + host: ModuleResolutionHost, + redirectedReference?: ResolvedProjectReference, + _containingSourceFile?: SourceFile, + resolutionMode?: SourceFile["impliedNodeFormat"] | undefined, + ): CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations { + return ts.resolveTypeReferenceDirective( + typeReferenceDirectiveName, + containingFile, + options, + host, + redirectedReference, + typeReferenceDirectiveResolutionCache, + resolutionMode, + ); } - interface ResolveNamesWithLocalCacheInput { + interface ResolveNamesWithLocalCacheInput< + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + > { names: readonly string[] | readonly FileReference[]; containingFile: string; redirectedReference: ResolvedProjectReference | undefined; cache: ESMap>; perDirectoryCacheWithRedirects: CacheWithRedirects>; - loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference, containingSourceFile?: SourceFile, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext | undefined) => T; + loader: ( + name: string, + containingFile: string, + options: CompilerOptions, + host: ModuleResolutionHost, + redirectedReference?: ResolvedProjectReference, + containingSourceFile?: SourceFile, + resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, + ) => T; getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName; shouldRetryResolution: (t: T) => boolean; reusedNames?: readonly string[]; @@ -416,7 +522,10 @@ namespace ts { containingSourceFile?: SourceFile; containingSourceFileMode?: SourceFile["impliedNodeFormat"]; } - function resolveNamesWithLocalCache({ + function resolveNamesWithLocalCache< + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + >({ names, containingFile, redirectedReference, @@ -433,7 +542,9 @@ namespace ts { const path = resolutionHost.toPath(containingFile); const resolutionsInFile = cache.get(path) || cache.set(path, createModeAwareCache()).get(path)!; const dirPath = getDirectoryPath(path); - const perDirectoryCache = perDirectoryCacheWithRedirects.getOrCreateMapOfCacheRedirects(redirectedReference); + const perDirectoryCache = perDirectoryCacheWithRedirects.getOrCreateMapOfCacheRedirects( + redirectedReference, + ); let perDirectoryResolution = perDirectoryCache.get(dirPath); if (!perDirectoryResolution) { perDirectoryResolution = createModeAwareCache(); @@ -441,14 +552,15 @@ namespace ts { } const resolvedModules: (R | undefined)[] = []; const compilerOptions = resolutionHost.getCompilationSettings(); - const hasInvalidatedNonRelativeUnresolvedImport = logChanges && isFileWithInvalidatedNonRelativeUnresolvedImports(path); + const hasInvalidatedNonRelativeUnresolvedImport = logChanges + && isFileWithInvalidatedNonRelativeUnresolvedImports(path); // All the resolutions in this file are invalidated if this file wasn't resolved using same redirect const program = resolutionHost.getCurrentProgram(); const oldRedirect = program && program.getResolvedProjectReferenceToRedirect(containingFile); - const unmatchedRedirects = oldRedirect ? - !redirectedReference || redirectedReference.sourceFile.path !== oldRedirect.sourceFile.path : - !!redirectedReference; + const unmatchedRedirects = oldRedirect + ? !redirectedReference || redirectedReference.sourceFile.path !== oldRedirect.sourceFile.path + : !!redirectedReference; const seenNamesInFile = createModeAwareCache(); let i = 0; @@ -459,17 +571,18 @@ namespace ts { // import's syntax may override the file's default mode. // Type references instead supply a `containingSourceFileMode` and a non-string entry which contains // a default file mode override if applicable. - const mode = !isString(entry) ? getModeForFileReference(entry, containingSourceFileMode) : - containingSourceFile ? getModeForResolutionAtIndex(containingSourceFile, i) : undefined; + const mode = !isString(entry) ? getModeForFileReference(entry, containingSourceFileMode) + : containingSourceFile ? getModeForResolutionAtIndex(containingSourceFile, i) : undefined; i++; let resolution = resolutionsInFile.get(name, mode); // Resolution is valid if it is present and not invalidated if ( - !seenNamesInFile.has(name, mode) && - unmatchedRedirects || - !resolution || resolution.isInvalidated || + !seenNamesInFile.has(name, mode) + && unmatchedRedirects + || !resolution || resolution.isInvalidated // If the name is unresolved import that was invalidated, recalculate - (hasInvalidatedNonRelativeUnresolvedImport && !isExternalModuleNameRelative(name) && shouldRetryResolution(resolution)) + || (hasInvalidatedNonRelativeUnresolvedImport && !isExternalModuleNameRelative(name) + && shouldRetryResolution(resolution)) ) { const existingResolution = resolution; const resolutionInDirectory = perDirectoryResolution.get(name, mode); @@ -480,17 +593,23 @@ namespace ts { const resolved = getResolutionWithResolvedFileName(resolution); trace( host, - loader === resolveModuleName as unknown ? - resolved?.resolvedFileName ? - resolved.packagetId ? - Diagnostics.Reusing_resolution_of_module_0_from_1_found_in_cache_from_location_2_it_was_successfully_resolved_to_3_with_Package_ID_4 : - Diagnostics.Reusing_resolution_of_module_0_from_1_found_in_cache_from_location_2_it_was_successfully_resolved_to_3 : - Diagnostics.Reusing_resolution_of_module_0_from_1_found_in_cache_from_location_2_it_was_not_resolved : - resolved?.resolvedFileName ? - resolved.packagetId ? - Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_found_in_cache_from_location_2_it_was_successfully_resolved_to_3_with_Package_ID_4 : - Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_found_in_cache_from_location_2_it_was_successfully_resolved_to_3 : - Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_found_in_cache_from_location_2_it_was_not_resolved, + loader === resolveModuleName as unknown + ? resolved?.resolvedFileName + ? resolved.packagetId + ? Diagnostics + .Reusing_resolution_of_module_0_from_1_found_in_cache_from_location_2_it_was_successfully_resolved_to_3_with_Package_ID_4 + : Diagnostics + .Reusing_resolution_of_module_0_from_1_found_in_cache_from_location_2_it_was_successfully_resolved_to_3 + : Diagnostics + .Reusing_resolution_of_module_0_from_1_found_in_cache_from_location_2_it_was_not_resolved + : resolved?.resolvedFileName + ? resolved.packagetId + ? Diagnostics + .Reusing_resolution_of_type_reference_directive_0_from_1_found_in_cache_from_location_2_it_was_successfully_resolved_to_3_with_Package_ID_4 + : Diagnostics + .Reusing_resolution_of_type_reference_directive_0_from_1_found_in_cache_from_location_2_it_was_successfully_resolved_to_3 + : Diagnostics + .Reusing_resolution_of_type_reference_directive_0_from_1_found_in_cache_from_location_2_it_was_not_resolved, name, containingFile, getDirectoryPath(containingFile), @@ -500,19 +619,39 @@ namespace ts { } } else { - resolution = loader(name, containingFile, compilerOptions, resolutionHost.getCompilerHost?.() || resolutionHost, redirectedReference, containingSourceFile, mode); + resolution = loader( + name, + containingFile, + compilerOptions, + resolutionHost.getCompilerHost?.() || resolutionHost, + redirectedReference, + containingSourceFile, + mode, + ); perDirectoryResolution.set(name, mode, resolution); if (resolutionHost.onDiscoveredSymlink && resolutionIsSymlink(resolution)) { resolutionHost.onDiscoveredSymlink(); } } resolutionsInFile.set(name, mode, resolution); - watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution, path, getResolutionWithResolvedFileName); + watchFailedLookupLocationsOfExternalModuleResolutions( + name, + resolution, + path, + getResolutionWithResolvedFileName, + ); if (existingResolution) { - stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolutionWithResolvedFileName); + stopWatchFailedLookupLocationOfResolution( + existingResolution, + path, + getResolutionWithResolvedFileName, + ); } - if (logChanges && filesWithChangedSetOfUnresolvedImports && !resolutionIsEqualTo(existingResolution, resolution)) { + if ( + logChanges && filesWithChangedSetOfUnresolvedImports + && !resolutionIsEqualTo(existingResolution, resolution) + ) { filesWithChangedSetOfUnresolvedImports.push(path); // reset log changes to avoid recording the same file multiple times logChanges = false; @@ -524,17 +663,23 @@ namespace ts { const resolved = getResolutionWithResolvedFileName(resolution); trace( host, - loader === resolveModuleName as unknown ? - resolved?.resolvedFileName ? - resolved.packagetId ? - Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 : - Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2 : - Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved : - resolved?.resolvedFileName ? - resolved.packagetId ? - Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 : - Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2 : - Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_not_resolved, + loader === resolveModuleName as unknown + ? resolved?.resolvedFileName + ? resolved.packagetId + ? Diagnostics + .Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 + : Diagnostics + .Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2 + : Diagnostics + .Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved + : resolved?.resolvedFileName + ? resolved.packagetId + ? Diagnostics + .Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 + : Diagnostics + .Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2 + : Diagnostics + .Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_not_resolved, name, containingFile, resolved?.resolvedFileName, @@ -576,8 +721,16 @@ namespace ts { } } - function resolveTypeReferenceDirectives(typeDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, containingFileMode?: SourceFile["impliedNodeFormat"]): (ResolvedTypeReferenceDirective | undefined)[] { - return resolveNamesWithLocalCache({ + function resolveTypeReferenceDirectives( + typeDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference?: ResolvedProjectReference, + containingFileMode?: SourceFile["impliedNodeFormat"], + ): (ResolvedTypeReferenceDirective | undefined)[] { + return resolveNamesWithLocalCache< + CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations, + ResolvedTypeReferenceDirective + >({ names: typeDirectiveNames, containingFile, redirectedReference, @@ -590,7 +743,13 @@ namespace ts { }); } - function resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference?: ResolvedProjectReference, containingSourceFile?: SourceFile): (ResolvedModuleFull | undefined)[] { + function resolveModuleNames( + moduleNames: string[], + containingFile: string, + reusedNames: string[] | undefined, + redirectedReference?: ResolvedProjectReference, + containingSourceFile?: SourceFile, + ): (ResolvedModuleFull | undefined)[] { return resolveNamesWithLocalCache({ names: moduleNames, containingFile, @@ -599,14 +758,19 @@ namespace ts { perDirectoryCacheWithRedirects: perDirectoryResolvedModuleNames, loader: resolveModuleName, getResolutionWithResolvedFileName: getResolvedModule, - shouldRetryResolution: resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension), + shouldRetryResolution: resolution => + !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension), reusedNames, logChanges: logChangesWhenResolvingModule, containingSourceFile, }); } - function getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): CachedResolvedModuleWithFailedLookupLocations | undefined { + function getResolvedModuleWithFailedLookupLocationsFromCache( + moduleName: string, + containingFile: string, + resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): CachedResolvedModuleWithFailedLookupLocations | undefined { const cache = resolvedModuleNames.get(resolutionHost.toPath(containingFile)); if (!cache) return undefined; return cache.get(moduleName, resolutionMode); @@ -616,13 +780,20 @@ namespace ts { return endsWith(dirPath, "/node_modules/@types"); } - function getDirectoryToWatchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path): DirectoryOfFailedLookupWatch | undefined { + function getDirectoryToWatchFailedLookupLocation( + failedLookupLocation: string, + failedLookupLocationPath: Path, + ): DirectoryOfFailedLookupWatch | undefined { if (isInDirectoryPath(rootPath, failedLookupLocationPath)) { // Ensure failed look up is normalized path - failedLookupLocation = isRootedDiskPath(failedLookupLocation) ? normalizePath(failedLookupLocation) : getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory()); + failedLookupLocation = isRootedDiskPath(failedLookupLocation) ? normalizePath(failedLookupLocation) + : getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory()); const failedLookupPathSplit = failedLookupLocationPath.split(directorySeparator); const failedLookupSplit = failedLookupLocation.split(directorySeparator); - Debug.assert(failedLookupSplit.length === failedLookupPathSplit.length, `FailedLookup: ${failedLookupLocation} failedLookupLocationPath: ${failedLookupLocationPath}`); + Debug.assert( + failedLookupSplit.length === failedLookupPathSplit.length, + `FailedLookup: ${failedLookupLocation} failedLookupLocationPath: ${failedLookupLocationPath}`, + ); if (failedLookupPathSplit.length > rootSplitLength + 1) { // Instead of watching root, watch directory in root to avoid watching excluded directories not needed for module resolution return { @@ -646,7 +817,10 @@ namespace ts { ); } - function getDirectoryToWatchFromFailedLookupLocationDirectory(dir: string, dirPath: Path): DirectoryOfFailedLookupWatch | undefined { + function getDirectoryToWatchFromFailedLookupLocationDirectory( + dir: string, + dirPath: Path, + ): DirectoryOfFailedLookupWatch | undefined { // If directory path contains node module, get the most parent node_modules directory for watching while (pathContainsNodeModules(dirPath)) { dir = getDirectoryPath(dir); @@ -675,14 +849,18 @@ namespace ts { } } - return canWatchDirectoryOrFile(dirPath) ? { dir: subDirectory || dir, dirPath: subDirectoryPath || dirPath, nonRecursive } : undefined; + return canWatchDirectoryOrFile(dirPath) + ? { dir: subDirectory || dir, dirPath: subDirectoryPath || dirPath, nonRecursive } : undefined; } function isPathWithDefaultFailedLookupExtension(path: Path) { return fileExtensionIsOneOf(path, failedLookupDefaultExtensions); } - function watchFailedLookupLocationsOfExternalModuleResolutions( + function watchFailedLookupLocationsOfExternalModuleResolutions< + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + >( name: string, resolution: T, filePath: Path, @@ -745,7 +923,10 @@ namespace ts { watchAffectingLocationsOfResolution(resolution, !failedLookupLocations.length); } - function watchAffectingLocationsOfResolution(resolution: ResolutionWithFailedLookupLocations, addToResolutionsWithOnlyAffectingLocations: boolean) { + function watchAffectingLocationsOfResolution( + resolution: ResolutionWithFailedLookupLocations, + addToResolutionsWithOnlyAffectingLocations: boolean, + ) { Debug.assert(!!resolution.refCount); const { affectingLocations } = resolution; if (!affectingLocations.length) return; @@ -779,9 +960,13 @@ namespace ts { } const paths = new Set(); paths.add(locationToWatch); - let actualWatcher = canWatchDirectoryOrFile(resolutionHost.toPath(locationToWatch)) ? - resolutionHost.watchAffectingFileLocation(locationToWatch, (fileName, eventKind) => { - cachedDirectoryStructureHost?.addOrDeleteFile(fileName, resolutionHost.toPath(locationToWatch), eventKind); + let actualWatcher = canWatchDirectoryOrFile(resolutionHost.toPath(locationToWatch)) + ? resolutionHost.watchAffectingFileLocation(locationToWatch, (fileName, eventKind) => { + cachedDirectoryStructureHost?.addOrDeleteFile( + fileName, + resolutionHost.toPath(locationToWatch), + eventKind, + ); const packageJsonMap = moduleResolutionCache.getPackageJsonInfoCache().getInternalMap(); paths.forEach(path => { if (watcher.resolutions) (affectingPathChecks ??= new Set()).add(path); @@ -809,13 +994,18 @@ namespace ts { } } - function watchFailedLookupLocationOfNonRelativeModuleResolutions(resolutions: ResolutionWithFailedLookupLocations[], name: string) { + function watchFailedLookupLocationOfNonRelativeModuleResolutions( + resolutions: ResolutionWithFailedLookupLocations[], + name: string, + ) { const program = resolutionHost.getCurrentProgram(); if (!program || !program.getTypeChecker().tryFindAmbientModuleWithoutAugmentations(name)) { resolutions.forEach(watchFailedLookupLocationOfResolution); } else { - resolutions.forEach(resolution => watchAffectingLocationsOfResolution(resolution, /*addToResolutionWithOnlyAffectingLocations*/ true)); + resolutions.forEach(resolution => + watchAffectingLocationsOfResolution(resolution, /*addToResolutionWithOnlyAffectingLocations*/ true) + ); } } @@ -826,11 +1016,18 @@ namespace ts { dirWatcher.refCount++; } else { - directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath, nonRecursive), refCount: 1, nonRecursive }); + directoryWatchesOfFailedLookups.set(dirPath, { + watcher: createDirectoryWatcher(dir, dirPath, nonRecursive), + refCount: 1, + nonRecursive, + }); } } - function stopWatchFailedLookupLocationOfResolution( + function stopWatchFailedLookupLocationOfResolution< + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + >( resolution: T, filePath: Path, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName, @@ -850,7 +1047,10 @@ namespace ts { let removeAtRoot = false; for (const failedLookupLocation of failedLookupLocations) { const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); - const toWatch = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); + const toWatch = getDirectoryToWatchFailedLookupLocation( + failedLookupLocation, + failedLookupLocationPath, + ); if (toWatch) { const { dirPath } = toWatch; const refCount = customFailedLookupPaths.get(failedLookupLocationPath); @@ -900,11 +1100,17 @@ namespace ts { cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); } - scheduleInvalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath); + scheduleInvalidateResolutionOfFailedLookupLocation( + fileOrDirectoryPath, + dirPath === fileOrDirectoryPath, + ); }, nonRecursive ? WatchDirectoryFlags.None : WatchDirectoryFlags.Recursive); } - function removeResolutionsOfFileFromCache( + function removeResolutionsOfFileFromCache< + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + >( cache: ESMap>, filePath: Path, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName, @@ -912,7 +1118,9 @@ namespace ts { // Deleted file, stop watching failed lookups for all the resolutions in the file const resolutions = cache.get(filePath); if (resolutions) { - resolutions.forEach(resolution => stopWatchFailedLookupLocationOfResolution(resolution, filePath, getResolutionWithResolvedFileName)); + resolutions.forEach(resolution => + stopWatchFailedLookupLocationOfResolution(resolution, filePath, getResolutionWithResolvedFileName) + ); cache.delete(filePath); } } @@ -928,15 +1136,24 @@ namespace ts { if (!resolvedProjectReference) return; // filePath is for the projectReference and the containing file is from this project reference, invalidate the resolution - resolvedProjectReference.commandLine.fileNames.forEach(f => removeResolutionsOfFile(resolutionHost.toPath(f))); + resolvedProjectReference.commandLine.fileNames.forEach(f => + removeResolutionsOfFile(resolutionHost.toPath(f)) + ); } function removeResolutionsOfFile(filePath: Path) { removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModule); - removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirective); + removeResolutionsOfFileFromCache( + resolvedTypeReferenceDirectives, + filePath, + getResolvedTypeReferenceDirective, + ); } - function invalidateResolutions(resolutions: ResolutionWithFailedLookupLocations[] | undefined, canInvalidate: (resolution: ResolutionWithFailedLookupLocations) => boolean) { + function invalidateResolutions( + resolutions: ResolutionWithFailedLookupLocations[] | undefined, + canInvalidate: (resolution: ResolutionWithFailedLookupLocations) => boolean, + ) { if (!resolutions) return false; let invalidated = false; for (const resolution of resolutions) { @@ -945,7 +1162,8 @@ namespace ts { for (const containingFilePath of Debug.checkDefined(resolution.files)) { (filesWithInvalidatedResolutions ??= new Set()).add(containingFilePath); // When its a file with inferred types resolution, invalidate type reference directive resolution - hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames || endsWith(containingFilePath, inferredTypesContainingFile); + hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames + || endsWith(containingFilePath, inferredTypesContainingFile); } } return invalidated; @@ -956,20 +1174,26 @@ namespace ts { // Resolution is invalidated if the resulting file name is same as the deleted file path const prevHasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames; if ( - invalidateResolutions(resolvedFileToResolution.get(filePath), returnTrue) && - hasChangedAutomaticTypeDirectiveNames && - !prevHasChangedAutomaticTypeDirectiveNames + invalidateResolutions(resolvedFileToResolution.get(filePath), returnTrue) + && hasChangedAutomaticTypeDirectiveNames + && !prevHasChangedAutomaticTypeDirectiveNames ) { resolutionHost.onChangedAutomaticTypeDirectiveNames(); } } function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: ReadonlyESMap) { - Debug.assert(filesWithInvalidatedNonRelativeUnresolvedImports === filesMap || filesWithInvalidatedNonRelativeUnresolvedImports === undefined); + Debug.assert( + filesWithInvalidatedNonRelativeUnresolvedImports === filesMap + || filesWithInvalidatedNonRelativeUnresolvedImports === undefined, + ); filesWithInvalidatedNonRelativeUnresolvedImports = filesMap; } - function scheduleInvalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath: Path, isCreatingWatchedDirectory: boolean) { + function scheduleInvalidateResolutionOfFailedLookupLocation( + fileOrDirectoryPath: Path, + isCreatingWatchedDirectory: boolean, + ) { if (isCreatingWatchedDirectory) { // Watching directory is created // Invalidate any resolution has failed lookup in this directory @@ -990,15 +1214,19 @@ namespace ts { // Return early if it does not have any of the watching extension or not the custom failed lookup path const dirOfFileOrDirectory = getDirectoryPath(fileOrDirectoryPath); if ( - isNodeModulesAtTypesDirectory(fileOrDirectoryPath) || isNodeModulesDirectory(fileOrDirectoryPath) || - isNodeModulesAtTypesDirectory(dirOfFileOrDirectory) || isNodeModulesDirectory(dirOfFileOrDirectory) + isNodeModulesAtTypesDirectory(fileOrDirectoryPath) || isNodeModulesDirectory(fileOrDirectoryPath) + || isNodeModulesAtTypesDirectory(dirOfFileOrDirectory) + || isNodeModulesDirectory(dirOfFileOrDirectory) ) { // Invalidate any resolution from this directory (failedLookupChecks ||= new Set()).add(fileOrDirectoryPath); (startsWithPathChecks ||= new Set()).add(fileOrDirectoryPath); } else { - if (!isPathWithDefaultFailedLookupExtension(fileOrDirectoryPath) && !customFailedLookupPaths.has(fileOrDirectoryPath)) { + if ( + !isPathWithDefaultFailedLookupExtension(fileOrDirectoryPath) + && !customFailedLookupPaths.has(fileOrDirectoryPath) + ) { return false; } // Ignore emits from the program @@ -1034,15 +1262,21 @@ namespace ts { return invalidated; } - invalidated = invalidateResolutions(resolutionsWithFailedLookups, canInvalidateFailedLookupResolution) || invalidated; + invalidated = invalidateResolutions(resolutionsWithFailedLookups, canInvalidateFailedLookupResolution) + || invalidated; const packageJsonMap = moduleResolutionCache.getPackageJsonInfoCache().getInternalMap(); if (packageJsonMap && (failedLookupChecks || startsWithPathChecks || isInDirectoryChecks)) { - packageJsonMap.forEach((_value, path) => isInvalidatedFailedLookup(path) ? packageJsonMap.delete(path) : undefined); + packageJsonMap.forEach((_value, path) => + isInvalidatedFailedLookup(path) ? packageJsonMap.delete(path) : undefined + ); } failedLookupChecks = undefined; startsWithPathChecks = undefined; isInDirectoryChecks = undefined; - invalidated = invalidateResolutions(resolutionsWithOnlyAffectingLocations, canInvalidatedFailedLookupResolutionWithAffectingLocation) || invalidated; + invalidated = invalidateResolutions( + resolutionsWithOnlyAffectingLocations, + canInvalidatedFailedLookupResolutionWithAffectingLocation, + ) || invalidated; affectingPathChecks = undefined; return invalidated; } @@ -1050,24 +1284,38 @@ namespace ts { function canInvalidateFailedLookupResolution(resolution: ResolutionWithFailedLookupLocations) { if (canInvalidatedFailedLookupResolutionWithAffectingLocation(resolution)) return true; if (!failedLookupChecks && !startsWithPathChecks && !isInDirectoryChecks) return false; - return resolution.failedLookupLocations.some(location => isInvalidatedFailedLookup(resolutionHost.toPath(location))); + return resolution.failedLookupLocations.some(location => + isInvalidatedFailedLookup(resolutionHost.toPath(location)) + ); } function isInvalidatedFailedLookup(locationPath: Path) { - return failedLookupChecks?.has(locationPath) || - firstDefinedIterator(startsWithPathChecks?.keys() || emptyIterator, fileOrDirectoryPath => startsWith(locationPath, fileOrDirectoryPath) ? true : undefined) || - firstDefinedIterator(isInDirectoryChecks?.keys() || emptyIterator, fileOrDirectoryPath => isInDirectoryPath(fileOrDirectoryPath, locationPath) ? true : undefined); + return failedLookupChecks?.has(locationPath) + || firstDefinedIterator( + startsWithPathChecks?.keys() || emptyIterator, + fileOrDirectoryPath => startsWith(locationPath, fileOrDirectoryPath) ? true : undefined, + ) + || firstDefinedIterator( + isInDirectoryChecks?.keys() || emptyIterator, + fileOrDirectoryPath => isInDirectoryPath(fileOrDirectoryPath, locationPath) ? true : undefined, + ); } - function canInvalidatedFailedLookupResolutionWithAffectingLocation(resolution: ResolutionWithFailedLookupLocations) { - return !!affectingPathChecks && resolution.affectingLocations.some(location => affectingPathChecks!.has(location)); + function canInvalidatedFailedLookupResolutionWithAffectingLocation( + resolution: ResolutionWithFailedLookupLocations, + ) { + return !!affectingPathChecks + && resolution.affectingLocations.some(location => affectingPathChecks!.has(location)); } function closeTypeRootsWatch() { clearMap(typeRootsWatches, closeFileWatcher); } - function getDirectoryToWatchFailedLookupLocationFromTypeRoot(typeRoot: string, typeRootPath: Path): Path | undefined { + function getDirectoryToWatchFailedLookupLocationFromTypeRoot( + typeRoot: string, + typeRootPath: Path, + ): Path | undefined { if (isInDirectoryPath(rootPath, typeRootPath)) { return rootPath; } @@ -1094,7 +1342,10 @@ namespace ts { // So handle to failed lookup locations here as well to ensure we are invalidating resolutions const dirPath = getDirectoryToWatchFailedLookupLocationFromTypeRoot(typeRoot, typeRootPath); if (dirPath) { - scheduleInvalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath); + scheduleInvalidateResolutionOfFailedLookupLocation( + fileOrDirectoryPath, + dirPath === fileOrDirectoryPath, + ); } }, WatchDirectoryFlags.Recursive); } @@ -1114,7 +1365,10 @@ namespace ts { // we need to assume the directories exist to ensure that we can get all the type root directories that get included // But filter directories that are at root level to say directory doesnt exist, so that we arent watching them - const typeRoots = getEffectiveTypeRoots(options, { directoryExists: directoryExistsForTypeRootWatch, getCurrentDirectory }); + const typeRoots = getEffectiveTypeRoots(options, { + directoryExists: directoryExistsForTypeRootWatch, + getCurrentDirectory, + }); if (typeRoots) { mutateMap( typeRootsWatches, @@ -1144,8 +1398,9 @@ namespace ts { function resolutionIsSymlink(resolution: ResolutionWithFailedLookupLocations) { return !!( - (resolution as ResolvedModuleWithFailedLookupLocations).resolvedModule?.originalPath || - (resolution as ResolvedTypeReferenceDirectiveWithFailedLookupLocations).resolvedTypeReferenceDirective?.originalPath + (resolution as ResolvedModuleWithFailedLookupLocations).resolvedModule?.originalPath + || (resolution as ResolvedTypeReferenceDirectiveWithFailedLookupLocations).resolvedTypeReferenceDirective + ?.originalPath ); } } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 13dc2d819d611..04788c5c7be4b 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -334,17 +334,17 @@ namespace ts { } /* @internal */ export function isUnicodeIdentifierStart(code: number, languageVersion: ScriptTarget | undefined) { - return languageVersion! >= ScriptTarget.ES2015 ? - lookupInUnicodeMap(code, unicodeESNextIdentifierStart) : - languageVersion === ScriptTarget.ES5 ? lookupInUnicodeMap(code, unicodeES5IdentifierStart) : - lookupInUnicodeMap(code, unicodeES3IdentifierStart); + return languageVersion! >= ScriptTarget.ES2015 + ? lookupInUnicodeMap(code, unicodeESNextIdentifierStart) + : languageVersion === ScriptTarget.ES5 ? lookupInUnicodeMap(code, unicodeES5IdentifierStart) + : lookupInUnicodeMap(code, unicodeES3IdentifierStart); } function isUnicodeIdentifierPart(code: number, languageVersion: ScriptTarget | undefined) { - return languageVersion! >= ScriptTarget.ES2015 ? - lookupInUnicodeMap(code, unicodeESNextIdentifierPart) : - languageVersion === ScriptTarget.ES5 ? lookupInUnicodeMap(code, unicodeES5IdentifierPart) : - lookupInUnicodeMap(code, unicodeES3IdentifierPart); + return languageVersion! >= ScriptTarget.ES2015 + ? lookupInUnicodeMap(code, unicodeESNextIdentifierPart) + : languageVersion === ScriptTarget.ES5 ? lookupInUnicodeMap(code, unicodeES5IdentifierPart) + : lookupInUnicodeMap(code, unicodeES3IdentifierPart); } function makeReverseMap(source: ESMap): string[] { @@ -397,22 +397,48 @@ namespace ts { export function getPositionOfLineAndCharacter(sourceFile: SourceFileLike, line: number, character: number): number; /* @internal */ - export function getPositionOfLineAndCharacter(sourceFile: SourceFileLike, line: number, character: number, allowEdits?: true): number; // eslint-disable-line @typescript-eslint/unified-signatures - export function getPositionOfLineAndCharacter(sourceFile: SourceFileLike, line: number, character: number, allowEdits?: true): number { - return sourceFile.getPositionOfLineAndCharacter ? - sourceFile.getPositionOfLineAndCharacter(line, character, allowEdits) : - computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text, allowEdits); + export function getPositionOfLineAndCharacter( + sourceFile: SourceFileLike, + line: number, + character: number, + allowEdits?: true, + ): number; // eslint-disable-line @typescript-eslint/unified-signatures + export function getPositionOfLineAndCharacter( + sourceFile: SourceFileLike, + line: number, + character: number, + allowEdits?: true, + ): number { + return sourceFile.getPositionOfLineAndCharacter + ? sourceFile.getPositionOfLineAndCharacter(line, character, allowEdits) + : computePositionOfLineAndCharacter( + getLineStarts(sourceFile), + line, + character, + sourceFile.text, + allowEdits, + ); } /* @internal */ - export function computePositionOfLineAndCharacter(lineStarts: readonly number[], line: number, character: number, debugText?: string, allowEdits?: true): number { + export function computePositionOfLineAndCharacter( + lineStarts: readonly number[], + line: number, + character: number, + debugText?: string, + allowEdits?: true, + ): number { if (line < 0 || line >= lineStarts.length) { if (allowEdits) { // Clamp line to nearest allowable value line = line < 0 ? 0 : line >= lineStarts.length ? lineStarts.length - 1 : line; } else { - Debug.fail(`Bad line number. Line: ${line}, lineStarts.length: ${lineStarts.length} , line map is correct? ${debugText !== undefined ? arraysEqual(lineStarts, computeLineStarts(debugText)) : "unknown"}`); + Debug.fail( + `Bad line number. Line: ${line}, lineStarts.length: ${lineStarts.length} , line map is correct? ${ + debugText !== undefined ? arraysEqual(lineStarts, computeLineStarts(debugText)) : "unknown" + }`, + ); } } @@ -421,7 +447,8 @@ namespace ts { // Clamp to nearest allowable values to allow the underlying to be edited without crashing (accuracy is lost, instead) // TODO: Somehow track edits between file as it was during the creation of sourcemap we have and the current file and // apply them to the computed position to improve accuracy - return res > lineStarts[line + 1] ? lineStarts[line + 1] : typeof debugText === "string" && res > debugText.length ? debugText.length : res; + return res > lineStarts[line + 1] ? lineStarts[line + 1] + : typeof debugText === "string" && res > debugText.length ? debugText.length : res; } if (line < lineStarts.length - 1) { Debug.assert(res < lineStarts[line + 1]); @@ -438,7 +465,10 @@ namespace ts { } /* @internal */ - export function computeLineAndCharacterOfPosition(lineStarts: readonly number[], position: number): LineAndCharacter { + export function computeLineAndCharacterOfPosition( + lineStarts: readonly number[], + position: number, + ): LineAndCharacter { const lineNumber = computeLineOfPosition(lineStarts, position); return { line: lineNumber, @@ -490,18 +520,18 @@ namespace ts { export function isWhiteSpaceSingleLine(ch: number): boolean { // Note: nextLine is in the Zs space, and should be considered to be a whitespace. // It is explicitly not a line-break as it isn't in the exact set specified by EcmaScript. - return ch === CharacterCodes.space || - ch === CharacterCodes.tab || - ch === CharacterCodes.verticalTab || - ch === CharacterCodes.formFeed || - ch === CharacterCodes.nonBreakingSpace || - ch === CharacterCodes.nextLine || - ch === CharacterCodes.ogham || - ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace || - ch === CharacterCodes.narrowNoBreakSpace || - ch === CharacterCodes.mathematicalSpace || - ch === CharacterCodes.ideographicSpace || - ch === CharacterCodes.byteOrderMark; + return ch === CharacterCodes.space + || ch === CharacterCodes.tab + || ch === CharacterCodes.verticalTab + || ch === CharacterCodes.formFeed + || ch === CharacterCodes.nonBreakingSpace + || ch === CharacterCodes.nextLine + || ch === CharacterCodes.ogham + || ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace + || ch === CharacterCodes.narrowNoBreakSpace + || ch === CharacterCodes.mathematicalSpace + || ch === CharacterCodes.ideographicSpace + || ch === CharacterCodes.byteOrderMark; } export function isLineBreak(ch: number): boolean { @@ -516,10 +546,10 @@ namespace ts { // Only the characters in Table 3 are treated as line terminators. Other new line or line // breaking characters are treated as white space but not as line terminators. - return ch === CharacterCodes.lineFeed || - ch === CharacterCodes.carriageReturn || - ch === CharacterCodes.lineSeparator || - ch === CharacterCodes.paragraphSeparator; + return ch === CharacterCodes.lineFeed + || ch === CharacterCodes.carriageReturn + || ch === CharacterCodes.lineSeparator + || ch === CharacterCodes.paragraphSeparator; } function isDigit(ch: number): boolean { @@ -527,7 +557,8 @@ namespace ts { } function isHexDigit(ch: number): boolean { - return isDigit(ch) || ch >= CharacterCodes.A && ch <= CharacterCodes.F || ch >= CharacterCodes.a && ch <= CharacterCodes.f; + return isDigit(ch) || ch >= CharacterCodes.A && ch <= CharacterCodes.F + || ch >= CharacterCodes.a && ch <= CharacterCodes.f; } function isCodePoint(code: number): boolean { @@ -567,7 +598,13 @@ namespace ts { } /* @internal */ - export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean, stopAtComments?: boolean, inJSDoc?: boolean): number { + export function skipTrivia( + text: string, + pos: number, + stopAfterLineBreak?: boolean, + stopAtComments?: boolean, + inJSDoc?: boolean, + ): number { if (positionIsSynthesized(pos)) { return pos; } @@ -613,7 +650,10 @@ namespace ts { if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { pos += 2; while (pos < text.length) { - if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + if ( + text.charCodeAt(pos) === CharacterCodes.asterisk + && text.charCodeAt(pos + 1) === CharacterCodes.slash + ) { pos += 2; break; } @@ -680,15 +720,19 @@ namespace ts { } } - return ch === CharacterCodes.equals || - text.charCodeAt(pos + mergeConflictMarkerLength) === CharacterCodes.space; + return ch === CharacterCodes.equals + || text.charCodeAt(pos + mergeConflictMarkerLength) === CharacterCodes.space; } } return false; } - function scanConflictMarkerTrivia(text: string, pos: number, error?: (diag: DiagnosticMessage, pos?: number, len?: number) => void) { + function scanConflictMarkerTrivia( + text: string, + pos: number, + error?: (diag: DiagnosticMessage, pos?: number, len?: number) => void, + ) { if (error) { error(Diagnostics.Merge_conflict_marker_encountered, pos, mergeConflictMarkerLength); } @@ -707,7 +751,10 @@ namespace ts { // of the next ======= or >>>>>>> marker. while (pos < len) { const currentChar = text.charCodeAt(pos); - if ((currentChar === CharacterCodes.equals || currentChar === CharacterCodes.greaterThan) && currentChar !== ch && isConflictMarkerTrivia(text, pos)) { + if ( + (currentChar === CharacterCodes.equals || currentChar === CharacterCodes.greaterThan) + && currentChar !== ch && isConflictMarkerTrivia(text, pos) + ) { break; } @@ -754,7 +801,22 @@ namespace ts { * @returns If "reduce" is true, the accumulated value. If "reduce" is false, the first truthy * return value of the callback. */ - function iterateCommentRanges(reduce: boolean, text: string, pos: number, trailing: boolean, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U | undefined) => U, state: T, initial?: U): U | undefined { + function iterateCommentRanges( + reduce: boolean, + text: string, + pos: number, + trailing: boolean, + cb: ( + pos: number, + end: number, + kind: CommentKind, + hasTrailingNewLine: boolean, + state: T, + memo: U | undefined, + ) => U, + state: T, + initial?: U, + ): U | undefined { let pendingPos!: number; let pendingEnd!: number; let pendingKind!: CommentKind; @@ -800,7 +862,8 @@ namespace ts { const nextChar = text.charCodeAt(pos + 1); let hasTrailingNewLine = false; if (nextChar === CharacterCodes.slash || nextChar === CharacterCodes.asterisk) { - const kind = nextChar === CharacterCodes.slash ? SyntaxKind.SingleLineCommentTrivia : SyntaxKind.MultiLineCommentTrivia; + const kind = nextChar === CharacterCodes.slash ? SyntaxKind.SingleLineCommentTrivia + : SyntaxKind.MultiLineCommentTrivia; const startPos = pos; pos += 2; if (nextChar === CharacterCodes.slash) { @@ -814,7 +877,10 @@ namespace ts { } else { while (pos < text.length) { - if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + if ( + text.charCodeAt(pos) === CharacterCodes.asterisk + && text.charCodeAt(pos + 1) === CharacterCodes.slash + ) { pos += 2; break; } @@ -824,7 +890,14 @@ namespace ts { if (collecting) { if (hasPendingCommentRange) { - accumulator = cb(pendingPos, pendingEnd, pendingKind, pendingHasTrailingNewLine, state, accumulator); + accumulator = cb( + pendingPos, + pendingEnd, + pendingKind, + pendingHasTrailingNewLine, + state, + accumulator, + ); if (!reduce && accumulator) { // If we are not reducing and we have a truthy result, return it. return accumulator; @@ -860,27 +933,74 @@ namespace ts { return accumulator; } - export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U): U | undefined; - export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; - export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined { + export function forEachLeadingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U, + ): U | undefined; + export function forEachLeadingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state: T, + ): U | undefined; + export function forEachLeadingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state?: T, + ): U | undefined { return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ false, cb, state); } - export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U): U | undefined; - export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; - export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined { + export function forEachTrailingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U, + ): U | undefined; + export function forEachTrailingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state: T, + ): U | undefined; + export function forEachTrailingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state?: T, + ): U | undefined { return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ true, cb, state); } - export function reduceEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U) { + export function reduceEachLeadingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, + state: T, + initial: U, + ) { return iterateCommentRanges(/*reduce*/ true, text, pos, /*trailing*/ false, cb, state, initial); } - export function reduceEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U) { + export function reduceEachTrailingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, + state: T, + initial: U, + ) { return iterateCommentRanges(/*reduce*/ true, text, pos, /*trailing*/ true, cb, state, initial); } - function appendCommentRange(pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, _state: any, comments: CommentRange[]) { + function appendCommentRange( + pos: number, + end: number, + kind: CommentKind, + hasTrailingNewLine: boolean, + _state: any, + comments: CommentRange[], + ) { if (!comments) { comments = []; } @@ -894,7 +1014,13 @@ namespace ts { } export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] | undefined { - return reduceEachTrailingCommentRange(text, pos, appendCommentRange, /*state*/ undefined, /*initial*/ undefined); + return reduceEachTrailingCommentRange( + text, + pos, + appendCommentRange, + /*state*/ undefined, + /*initial*/ undefined, + ); } /** Optionally, get the shebang */ @@ -906,21 +1032,30 @@ namespace ts { } export function isIdentifierStart(ch: number, languageVersion: ScriptTarget | undefined): boolean { - return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z || - ch === CharacterCodes.$ || ch === CharacterCodes._ || - ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierStart(ch, languageVersion); + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z + || ch === CharacterCodes.$ || ch === CharacterCodes._ + || ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierStart(ch, languageVersion); } - export function isIdentifierPart(ch: number, languageVersion: ScriptTarget | undefined, identifierVariant?: LanguageVariant): boolean { - return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z || - ch >= CharacterCodes._0 && ch <= CharacterCodes._9 || ch === CharacterCodes.$ || ch === CharacterCodes._ || + export function isIdentifierPart( + ch: number, + languageVersion: ScriptTarget | undefined, + identifierVariant?: LanguageVariant, + ): boolean { + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z + || ch >= CharacterCodes._0 && ch <= CharacterCodes._9 || ch === CharacterCodes.$ || ch === CharacterCodes._ // "-" and ":" are valid in JSX Identifiers - (identifierVariant === LanguageVariant.JSX ? (ch === CharacterCodes.minus || ch === CharacterCodes.colon) : false) || - ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierPart(ch, languageVersion); + || (identifierVariant === LanguageVariant.JSX ? (ch === CharacterCodes.minus || ch === CharacterCodes.colon) + : false) + || ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierPart(ch, languageVersion); } /* @internal */ - export function isIdentifierText(name: string, languageVersion: ScriptTarget | undefined, identifierVariant?: LanguageVariant): boolean { + export function isIdentifierText( + name: string, + languageVersion: ScriptTarget | undefined, + identifierVariant?: LanguageVariant, + ): boolean { let ch = codePointAt(name, 0); if (!isIdentifierStart(ch, languageVersion)) { return false; @@ -936,7 +1071,15 @@ namespace ts { } // Creates a scanner over a (possibly unspecified) range of a piece of text. - export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean, languageVariant = LanguageVariant.Standard, textInitial?: string, onError?: ErrorCallback, start?: number, length?: number): Scanner { + export function createScanner( + languageVersion: ScriptTarget, + skipTrivia: boolean, + languageVariant = LanguageVariant.Standard, + textInitial?: string, + onError?: ErrorCallback, + start?: number, + length?: number, + ): Scanner { let text = textInitial!; // Current position (end position of text of current token) @@ -1079,7 +1222,9 @@ namespace ts { if (text.charCodeAt(pos) === CharacterCodes.E || text.charCodeAt(pos) === CharacterCodes.e) { pos++; tokenFlags |= TokenFlags.Scientific; - if (text.charCodeAt(pos) === CharacterCodes.plus || text.charCodeAt(pos) === CharacterCodes.minus) pos++; + if (text.charCodeAt(pos) === CharacterCodes.plus || text.charCodeAt(pos) === CharacterCodes.minus) { + pos++; + } const preNumericPart = pos; const finalFragment = scanNumberFragment(); if (!finalFragment) { @@ -1105,7 +1250,10 @@ namespace ts { } if (decimalFragment !== undefined || tokenFlags & TokenFlags.Scientific) { - checkForIdentifierStartAfterNumericLiteral(start, decimalFragment === undefined && !!(tokenFlags & TokenFlags.Scientific)); + checkForIdentifierStartAfterNumericLiteral( + start, + decimalFragment === undefined && !!(tokenFlags & TokenFlags.Scientific), + ); return { type: SyntaxKind.NumericLiteral, value: "" + +result, // if value is not an integer, it can be safely coerced to a number @@ -1129,14 +1277,26 @@ namespace ts { if (length === 1 && text[identifierStart] === "n") { if (isScientific) { - error(Diagnostics.A_bigint_literal_cannot_use_exponential_notation, numericStart, identifierStart - numericStart + 1); + error( + Diagnostics.A_bigint_literal_cannot_use_exponential_notation, + numericStart, + identifierStart - numericStart + 1, + ); } else { - error(Diagnostics.A_bigint_literal_must_be_an_integer, numericStart, identifierStart - numericStart + 1); + error( + Diagnostics.A_bigint_literal_must_be_an_integer, + numericStart, + identifierStart - numericStart + 1, + ); } } else { - error(Diagnostics.An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal, identifierStart, length); + error( + Diagnostics.An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal, + identifierStart, + length, + ); pos = identifierStart; } } @@ -1192,8 +1352,8 @@ namespace ts { ch += CharacterCodes.a - CharacterCodes.A; // standardize hex literals to lowercase } else if ( - !((ch >= CharacterCodes._0 && ch <= CharacterCodes._9) || - (ch >= CharacterCodes.a && ch <= CharacterCodes.f)) + !((ch >= CharacterCodes._0 && ch <= CharacterCodes._9) + || (ch >= CharacterCodes.a && ch <= CharacterCodes.f)) ) { break; } @@ -1262,7 +1422,8 @@ namespace ts { contents += text.substring(start, pos); tokenFlags |= TokenFlags.Unterminated; error(Diagnostics.Unterminated_template_literal); - resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail; + resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral + : SyntaxKind.TemplateTail; break; } @@ -1272,12 +1433,16 @@ namespace ts { if (currChar === CharacterCodes.backtick) { contents += text.substring(start, pos); pos++; - resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail; + resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral + : SyntaxKind.TemplateTail; break; } // '${' - if (currChar === CharacterCodes.$ && pos + 1 < end && text.charCodeAt(pos + 1) === CharacterCodes.openBrace) { + if ( + currChar === CharacterCodes.$ && pos + 1 < end + && text.charCodeAt(pos + 1) === CharacterCodes.openBrace + ) { contents += text.substring(start, pos); pos += 2; resultingToken = startedWithBacktick ? SyntaxKind.TemplateHead : SyntaxKind.TemplateMiddle; @@ -1354,7 +1519,10 @@ namespace ts { if (isTaggedTemplate) { // '\u' or '\u0' or '\u00' or '\u000' for (let escapePos = pos; escapePos < pos + 4; escapePos++) { - if (escapePos < end && !isHexDigit(text.charCodeAt(escapePos)) && text.charCodeAt(escapePos) !== CharacterCodes.openBrace) { + if ( + escapePos < end && !isHexDigit(text.charCodeAt(escapePos)) + && text.charCodeAt(escapePos) !== CharacterCodes.openBrace + ) { pos = escapePos; tokenFlags |= TokenFlags.ContainsInvalidEscape; return text.substring(start, pos); @@ -1485,7 +1653,10 @@ namespace ts { } function peekExtendedUnicodeEscape(): number { - if (codePointAt(text, pos + 1) === CharacterCodes.u && codePointAt(text, pos + 2) === CharacterCodes.openBrace) { + if ( + codePointAt(text, pos + 1) === CharacterCodes.u + && codePointAt(text, pos + 2) === CharacterCodes.openBrace + ) { const start = pos; pos += 3; const escapedValueString = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ false); @@ -1639,7 +1810,10 @@ namespace ts { continue; } else { - if (ch === CharacterCodes.carriageReturn && pos + 1 < end && text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) { + if ( + ch === CharacterCodes.carriageReturn && pos + 1 < end + && text.charCodeAt(pos + 1) === CharacterCodes.lineFeed + ) { // consume both CR and LF pos += 2; } @@ -1762,7 +1936,10 @@ namespace ts { tokenValue = scanNumber().value; return token = SyntaxKind.NumericLiteral; } - if (text.charCodeAt(pos + 1) === CharacterCodes.dot && text.charCodeAt(pos + 2) === CharacterCodes.dot) { + if ( + text.charCodeAt(pos + 1) === CharacterCodes.dot + && text.charCodeAt(pos + 2) === CharacterCodes.dot + ) { return pos += 3, token = SyntaxKind.DotDotDotToken; } pos++; @@ -1796,7 +1973,10 @@ namespace ts { // Multi-line comment if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { pos += 2; - if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) !== CharacterCodes.slash) { + if ( + text.charCodeAt(pos) === CharacterCodes.asterisk + && text.charCodeAt(pos + 1) !== CharacterCodes.slash + ) { tokenFlags |= TokenFlags.PrecedingJSDocComment; } @@ -1805,7 +1985,9 @@ namespace ts { while (pos < end) { const ch = text.charCodeAt(pos); - if (ch === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + if ( + ch === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash + ) { pos += 2; commentClosed = true; break; @@ -1819,7 +2001,12 @@ namespace ts { } } - commentDirectives = appendIfCommentDirective(commentDirectives, text.slice(lastLineStart, pos), commentDirectiveRegExMultiLine, lastLineStart); + commentDirectives = appendIfCommentDirective( + commentDirectives, + text.slice(lastLineStart, pos), + commentDirectiveRegExMultiLine, + lastLineStart, + ); if (!commentClosed) { error(Diagnostics.Asterisk_Slash_expected); @@ -1844,7 +2031,11 @@ namespace ts { return token = SyntaxKind.SlashToken; case CharacterCodes._0: - if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.X || text.charCodeAt(pos + 1) === CharacterCodes.x)) { + if ( + pos + 2 < end + && (text.charCodeAt(pos + 1) === CharacterCodes.X + || text.charCodeAt(pos + 1) === CharacterCodes.x) + ) { pos += 2; tokenValue = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ true); if (!tokenValue) { @@ -1855,7 +2046,11 @@ namespace ts { tokenFlags |= TokenFlags.HexSpecifier; return token = checkBigIntSuffix(); } - else if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.B || text.charCodeAt(pos + 1) === CharacterCodes.b)) { + else if ( + pos + 2 < end + && (text.charCodeAt(pos + 1) === CharacterCodes.B + || text.charCodeAt(pos + 1) === CharacterCodes.b) + ) { pos += 2; tokenValue = scanBinaryOrOctalDigits(/* base */ 2); if (!tokenValue) { @@ -1866,7 +2061,11 @@ namespace ts { tokenFlags |= TokenFlags.BinarySpecifier; return token = checkBigIntSuffix(); } - else if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.O || text.charCodeAt(pos + 1) === CharacterCodes.o)) { + else if ( + pos + 2 < end + && (text.charCodeAt(pos + 1) === CharacterCodes.O + || text.charCodeAt(pos + 1) === CharacterCodes.o) + ) { pos += 2; tokenValue = scanBinaryOrOctalDigits(/* base */ 8); if (!tokenValue) { @@ -1925,9 +2124,9 @@ namespace ts { return pos += 2, token = SyntaxKind.LessThanEqualsToken; } if ( - languageVariant === LanguageVariant.JSX && - text.charCodeAt(pos + 1) === CharacterCodes.slash && - text.charCodeAt(pos + 2) !== CharacterCodes.asterisk + languageVariant === LanguageVariant.JSX + && text.charCodeAt(pos + 1) === CharacterCodes.slash + && text.charCodeAt(pos + 2) !== CharacterCodes.asterisk ) { return pos += 2, token = SyntaxKind.LessThanSlashToken; } @@ -2111,7 +2310,10 @@ namespace ts { } function reScanInvalidIdentifier(): SyntaxKind { - Debug.assert(token === SyntaxKind.Unknown, "'reScanInvalidIdentifier' should only be called when the current token is 'SyntaxKind.Unknown'."); + Debug.assert( + token === SyntaxKind.Unknown, + "'reScanInvalidIdentifier' should only be called when the current token is 'SyntaxKind.Unknown'.", + ); pos = tokenPos = startPos; tokenFlags = 0; const ch = codePointAt(text, pos); @@ -2160,7 +2362,10 @@ namespace ts { } function reScanAsteriskEqualsToken(): SyntaxKind { - Debug.assert(token === SyntaxKind.AsteriskEqualsToken, "'reScanAsteriskEqualsToken' should only be called on a '*='"); + Debug.assert( + token === SyntaxKind.AsteriskEqualsToken, + "'reScanAsteriskEqualsToken' should only be called on a '*='", + ); pos = tokenPos + 1; return token = SyntaxKind.EqualsToken; } @@ -2292,7 +2497,10 @@ namespace ts { } function reScanQuestionToken(): SyntaxKind { - Debug.assert(token === SyntaxKind.QuestionQuestionToken, "'reScanQuestionToken' should only be called on a '??'"); + Debug.assert( + token === SyntaxKind.QuestionQuestionToken, + "'reScanQuestionToken' should only be called on a '??'", + ); pos = tokenPos + 1; return token = SyntaxKind.QuestionToken; } @@ -2503,7 +2711,10 @@ namespace ts { if (isIdentifierStart(ch, languageVersion)) { let char = ch; - while (pos < end && isIdentifierPart(char = codePointAt(text, pos), languageVersion) || text.charCodeAt(pos) === CharacterCodes.minus) pos += charSize(char); + while ( + pos < end && isIdentifierPart(char = codePointAt(text, pos), languageVersion) + || text.charCodeAt(pos) === CharacterCodes.minus + ) pos += charSize(char); tokenValue = text.substring(tokenPos, pos); if (char === CharacterCodes.backslash) { tokenValue += scanIdentifierParts(); @@ -2612,25 +2823,26 @@ namespace ts { } /* @internal */ - const codePointAt: (s: string, i: number) => number = (String.prototype as any).codePointAt ? (s, i) => (s as any).codePointAt(i) : function codePointAt(str, i): number { - // from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt - const size = str.length; - // Account for out-of-bounds indices: - if (i < 0 || i >= size) { - return undefined!; // String.codePointAt returns `undefined` for OOB indexes - } - // Get the first code unit - const first = str.charCodeAt(i); - // check if it’s the start of a surrogate pair - if (first >= 0xD800 && first <= 0xDBFF && size > i + 1) { // high surrogate and there is a next code unit - const second = str.charCodeAt(i + 1); - if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate - // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae - return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; - } - } - return first; - }; + const codePointAt: (s: string, i: number) => number = (String.prototype as any).codePointAt + ? (s, i) => (s as any).codePointAt(i) : function codePointAt(str, i): number { + // from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt + const size = str.length; + // Account for out-of-bounds indices: + if (i < 0 || i >= size) { + return undefined!; // String.codePointAt returns `undefined` for OOB indexes + } + // Get the first code unit + const first = str.charCodeAt(i); + // check if it’s the start of a surrogate pair + if (first >= 0xD800 && first <= 0xDBFF && size > i + 1) { // high surrogate and there is a next code unit + const second = str.charCodeAt(i + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + return first; + }; /* @internal */ function charSize(ch: number) { @@ -2654,7 +2866,8 @@ namespace ts { return String.fromCharCode(codeUnit1, codeUnit2); } - const utf16EncodeAsStringWorker: (codePoint: number) => string = (String as any).fromCodePoint ? codePoint => (String as any).fromCodePoint(codePoint) : utf16EncodeAsStringFallback; + const utf16EncodeAsStringWorker: (codePoint: number) => string = (String as any).fromCodePoint + ? codePoint => (String as any).fromCodePoint(codePoint) : utf16EncodeAsStringFallback; /* @internal */ export function utf16EncodeAsString(codePoint: number) { diff --git a/src/compiler/semver.ts b/src/compiler/semver.ts index dae5e898dafed..d75aa8246ebf8 100644 --- a/src/compiler/semver.ts +++ b/src/compiler/semver.ts @@ -7,7 +7,8 @@ namespace ts { // // NOTE: We differ here in that we allow X and X.Y, with missing parts having the default // value of `0`. - const versionRegExp = /^(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i; + const versionRegExp = + /^(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i; // https://semver.org/#spec-item-9 // > A pre-release version MAY be denoted by appending a hyphen and a series of dot separated @@ -41,8 +42,20 @@ namespace ts { readonly build: readonly string[]; constructor(text: string); - constructor(major: number, minor?: number, patch?: number, prerelease?: string | readonly string[], build?: string | readonly string[]); - constructor(major: number | string, minor = 0, patch = 0, prerelease: string | readonly string[] = "", build: string | readonly string[] = "") { + constructor( + major: number, + minor?: number, + patch?: number, + prerelease?: string | readonly string[], + build?: string | readonly string[], + ); + constructor( + major: number | string, + minor = 0, + patch = 0, + prerelease: string | readonly string[] = "", + build: string | readonly string[] = "", + ) { if (typeof major === "string") { const result = Debug.checkDefined(tryParseComponents(major), "Invalid version"); ({ major, minor, patch, prerelease, build } = result); @@ -107,7 +120,15 @@ namespace ts { } } - with(fields: { major?: number; minor?: number; patch?: number; prerelease?: string | readonly string[]; build?: string | readonly string[]; }) { + with( + fields: { + major?: number; + minor?: number; + patch?: number; + prerelease?: string | readonly string[]; + build?: string | readonly string[]; + }, + ) { const { major = this.major, minor = this.minor, @@ -165,7 +186,9 @@ namespace ts { if (leftIsNumeric || rightIsNumeric) { // https://semver.org/#spec-item-11 // > Numeric identifiers always have lower precedence than non-numeric identifiers. - if (leftIsNumeric !== rightIsNumeric) return leftIsNumeric ? Comparison.LessThan : Comparison.GreaterThan; + if (leftIsNumeric !== rightIsNumeric) { + return leftIsNumeric ? Comparison.LessThan : Comparison.GreaterThan; + } // https://semver.org/#spec-item-11 // > identifiers consisting of only digits are compared numerically @@ -243,7 +266,8 @@ namespace ts { // build ::= parts // parts ::= part ( '.' part ) * // part ::= nr | [-0-9A-Za-z]+ - const partialRegExp = /^([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i; + const partialRegExp = + /^([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i; // https://github.com/npm/node-semver#range-grammar // @@ -308,9 +332,9 @@ namespace ts { if (!isWildcard(rightResult.major)) { comparators.push( - isWildcard(rightResult.minor) ? createComparator("<", rightResult.version.increment("major")) : - isWildcard(rightResult.patch) ? createComparator("<", rightResult.version.increment("minor")) : - createComparator("<=", rightResult.version), + isWildcard(rightResult.minor) ? createComparator("<", rightResult.version.increment("major")) + : isWildcard(rightResult.patch) ? createComparator("<", rightResult.version.increment("minor")) + : createComparator("<=", rightResult.version), ); } @@ -329,8 +353,8 @@ namespace ts { comparators.push(createComparator( "<", version.increment( - isWildcard(minor) ? "major" : - "minor", + isWildcard(minor) ? "major" + : "minor", ), )); break; @@ -339,32 +363,46 @@ namespace ts { comparators.push(createComparator( "<", version.increment( - version.major > 0 || isWildcard(minor) ? "major" : - version.minor > 0 || isWildcard(patch) ? "minor" : - "patch", + version.major > 0 || isWildcard(minor) ? "major" + : version.minor > 0 || isWildcard(patch) ? "minor" + : "patch", ), )); break; case "<": case ">=": comparators.push( - isWildcard(minor) || isWildcard(patch) ? createComparator(operator, version.with({ prerelease: "0" })) : - createComparator(operator, version), + isWildcard(minor) || isWildcard(patch) + ? createComparator(operator, version.with({ prerelease: "0" })) + : createComparator(operator, version), ); break; case "<=": case ">": comparators.push( - isWildcard(minor) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("major").with({ prerelease: "0" })) : - isWildcard(patch) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("minor").with({ prerelease: "0" })) : - createComparator(operator, version), + isWildcard(minor) + ? createComparator( + operator === "<=" ? "<" : ">=", + version.increment("major").with({ prerelease: "0" }), + ) + : isWildcard(patch) + ? createComparator( + operator === "<=" ? "<" : ">=", + version.increment("minor").with({ prerelease: "0" }), + ) + : createComparator(operator, version), ); break; case "=": case undefined: if (isWildcard(minor) || isWildcard(patch)) { comparators.push(createComparator(">=", version.with({ prerelease: "0" }))); - comparators.push(createComparator("<", version.increment(isWildcard(minor) ? "major" : "minor").with({ prerelease: "0" }))); + comparators.push( + createComparator( + "<", + version.increment(isWildcard(minor) ? "major" : "minor").with({ prerelease: "0" }), + ), + ); } else { comparators.push(createComparator("=", version)); diff --git a/src/compiler/sourcemap.ts b/src/compiler/sourcemap.ts index e1b832489eec3..7378dd00c5dd3 100644 --- a/src/compiler/sourcemap.ts +++ b/src/compiler/sourcemap.ts @@ -4,7 +4,13 @@ namespace ts { extendedDiagnostics?: boolean; } - export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoot: string, sourcesDirectoryPath: string, generatorOptions: SourceMapGeneratorOptions): SourceMapGenerator { + export function createSourceMapGenerator( + host: EmitHost, + file: string, + sourceRoot: string, + sourcesDirectoryPath: string, + generatorOptions: SourceMapGeneratorOptions, + ): SourceMapGenerator { const { enter, exit } = generatorOptions.extendedDiagnostics ? performance.createTimer("Source Map", "beforeSourcemap", "afterSourcemap") : performance.nullTimer; @@ -52,7 +58,13 @@ namespace ts { function addSource(fileName: string) { enter(); - const source = getRelativePathToDirectoryOrUrl(sourcesDirectoryPath, fileName, host.getCurrentDirectory(), host.getCanonicalFileName, /*isAbsolutePathAnUrl*/ true); + const source = getRelativePathToDirectoryOrUrl( + sourcesDirectoryPath, + fileName, + host.getCurrentDirectory(), + host.getCanonicalFileName, + /*isAbsolutePathAnUrl*/ true, + ); let sourceIndex = sourceToSourceIndexMap.get(source); if (sourceIndex === undefined) { @@ -98,7 +110,11 @@ namespace ts { || pendingGeneratedCharacter !== generatedCharacter; } - function isBacktrackingSourcePosition(sourceIndex: number | undefined, sourceLine: number | undefined, sourceCharacter: number | undefined) { + function isBacktrackingSourcePosition( + sourceIndex: number | undefined, + sourceLine: number | undefined, + sourceCharacter: number | undefined, + ) { return sourceIndex !== undefined && sourceLine !== undefined && sourceCharacter !== undefined @@ -107,7 +123,14 @@ namespace ts { || pendingSourceLine === sourceLine && pendingSourceCharacter > sourceCharacter); } - function addMapping(generatedLine: number, generatedCharacter: number, sourceIndex?: number, sourceLine?: number, sourceCharacter?: number, nameIndex?: number) { + function addMapping( + generatedLine: number, + generatedCharacter: number, + sourceIndex?: number, + sourceLine?: number, + sourceCharacter?: number, + nameIndex?: number, + ) { Debug.assert(generatedLine >= pendingGeneratedLine, "generatedLine cannot backtrack"); Debug.assert(generatedCharacter >= 0, "generatedCharacter cannot be negative"); Debug.assert(sourceIndex === undefined || sourceIndex >= 0, "sourceIndex cannot be negative"); @@ -116,8 +139,8 @@ namespace ts { enter(); // If this location wasn't recorded or the location in source is going backwards, record the mapping if ( - isNewGeneratedPosition(generatedLine, generatedCharacter) || - isBacktrackingSourcePosition(sourceIndex, sourceLine, sourceCharacter) + isNewGeneratedPosition(generatedLine, generatedCharacter) + || isBacktrackingSourcePosition(sourceIndex, sourceLine, sourceCharacter) ) { commitPendingMapping(); pendingGeneratedLine = generatedLine; @@ -140,7 +163,14 @@ namespace ts { exit(); } - function appendSourceMap(generatedLine: number, generatedCharacter: number, map: RawSourceMap, sourceMapPath: string, start?: LineAndCharacter, end?: LineAndCharacter) { + function appendSourceMap( + generatedLine: number, + generatedCharacter: number, + map: RawSourceMap, + sourceMapPath: string, + start?: LineAndCharacter, + end?: LineAndCharacter, + ) { Debug.assert(generatedLine >= pendingGeneratedLine, "generatedLine cannot backtrack"); Debug.assert(generatedCharacter >= 0, "generatedCharacter cannot be negative"); enter(); @@ -152,8 +182,8 @@ namespace ts { const raw = iterResult.value; if ( end && ( - raw.generatedLine > end.line || - (raw.generatedLine === end.line && raw.generatedCharacter > end.character) + raw.generatedLine > end.line + || (raw.generatedLine === end.line && raw.generatedCharacter > end.character) ) ) { break; @@ -161,8 +191,8 @@ namespace ts { if ( start && ( - raw.generatedLine < start.line || - (start.line === raw.generatedLine && raw.generatedCharacter < start.character) + raw.generatedLine < start.line + || (start.line === raw.generatedLine && raw.generatedCharacter < start.character) ) ) { continue; @@ -191,16 +221,27 @@ namespace ts { if (!nameIndexToNewNameIndexMap) nameIndexToNewNameIndexMap = []; newNameIndex = nameIndexToNewNameIndexMap[raw.nameIndex]; if (newNameIndex === undefined) { - nameIndexToNewNameIndexMap[raw.nameIndex] = newNameIndex = addName(map.names[raw.nameIndex]); + nameIndexToNewNameIndexMap[raw.nameIndex] = newNameIndex = addName( + map.names[raw.nameIndex], + ); } } } const rawGeneratedLine = raw.generatedLine - (start ? start.line : 0); const newGeneratedLine = rawGeneratedLine + generatedLine; - const rawGeneratedCharacter = start && start.line === raw.generatedLine ? raw.generatedCharacter - start.character : raw.generatedCharacter; - const newGeneratedCharacter = rawGeneratedLine === 0 ? rawGeneratedCharacter + generatedCharacter : rawGeneratedCharacter; - addMapping(newGeneratedLine, newGeneratedCharacter, newSourceIndex, newSourceLine, newSourceCharacter, newNameIndex); + const rawGeneratedCharacter = start && start.line === raw.generatedLine + ? raw.generatedCharacter - start.character : raw.generatedCharacter; + const newGeneratedCharacter = rawGeneratedLine === 0 ? rawGeneratedCharacter + generatedCharacter + : rawGeneratedCharacter; + addMapping( + newGeneratedLine, + newGeneratedCharacter, + newSourceIndex, + newSourceLine, + newSourceCharacter, + newNameIndex, + ); } exit(); } @@ -373,7 +414,8 @@ namespace ts { && typeof x.mappings === "string" && isArray(x.sources) && every(x.sources, isString) && (x.sourceRoot === undefined || x.sourceRoot === null || typeof x.sourceRoot === "string") - && (x.sourcesContent === undefined || x.sourcesContent === null || isArray(x.sourcesContent) && every(x.sourcesContent, isStringOrNull)) + && (x.sourcesContent === undefined || x.sourcesContent === null + || isArray(x.sourcesContent) && every(x.sourcesContent, isStringOrNull)) && (x.names === undefined || x.names === null || isArray(x.names) && every(x.names, isString)); } /* eslint-enable no-null/no-null */ @@ -464,12 +506,16 @@ namespace ts { sourceIndex += base64VLQFormatDecode(); if (hasReportedError()) return stopIterating(); if (sourceIndex < 0) return setErrorAndStopIterating("Invalid sourceIndex found"); - if (isSourceMappingSegmentEnd()) return setErrorAndStopIterating("Unsupported Format: No entries after sourceIndex"); + if (isSourceMappingSegmentEnd()) { + return setErrorAndStopIterating("Unsupported Format: No entries after sourceIndex"); + } sourceLine += base64VLQFormatDecode(); if (hasReportedError()) return stopIterating(); if (sourceLine < 0) return setErrorAndStopIterating("Invalid sourceLine found"); - if (isSourceMappingSegmentEnd()) return setErrorAndStopIterating("Unsupported Format: No entries after sourceLine"); + if (isSourceMappingSegmentEnd()) { + return setErrorAndStopIterating("Unsupported Format: No entries after sourceLine"); + } sourceCharacter += base64VLQFormatDecode(); if (hasReportedError()) return stopIterating(); @@ -481,7 +527,9 @@ namespace ts { if (hasReportedError()) return stopIterating(); if (nameIndex < 0) return setErrorAndStopIterating("Invalid nameIndex found"); - if (!isSourceMappingSegmentEnd()) return setErrorAndStopIterating("Unsupported Error Format: Entries after nameIndex"); + if (!isSourceMappingSegmentEnd()) { + return setErrorAndStopIterating("Unsupported Error Format: Entries after nameIndex"); + } } } @@ -526,9 +574,9 @@ namespace ts { } function isSourceMappingSegmentEnd() { - return (pos === mappings.length || - mappings.charCodeAt(pos) === CharacterCodes.comma || - mappings.charCodeAt(pos) === CharacterCodes.semicolon); + return (pos === mappings.length + || mappings.charCodeAt(pos) === CharacterCodes.comma + || mappings.charCodeAt(pos) === CharacterCodes.semicolon); } function base64VLQFormatDecode(): number { @@ -537,7 +585,9 @@ namespace ts { let value = 0; for (; moreDigits; pos++) { - if (pos >= mappings.length) return setError("Error in decoding base64VLQFormatDecode, past the mapping string"), -1; + if (pos >= mappings.length) { + return setError("Error in decoding base64VLQFormatDecode, past the mapping string"), -1; + } // 6 digit number const currentByte = base64FormatDecode(mappings.charCodeAt(pos)); @@ -583,21 +633,21 @@ namespace ts { } function base64FormatEncode(value: number) { - return value >= 0 && value < 26 ? CharacterCodes.A + value : - value >= 26 && value < 52 ? CharacterCodes.a + value - 26 : - value >= 52 && value < 62 ? CharacterCodes._0 + value - 52 : - value === 62 ? CharacterCodes.plus : - value === 63 ? CharacterCodes.slash : - Debug.fail(`${value}: not a base64 value`); + return value >= 0 && value < 26 ? CharacterCodes.A + value + : value >= 26 && value < 52 ? CharacterCodes.a + value - 26 + : value >= 52 && value < 62 ? CharacterCodes._0 + value - 52 + : value === 62 ? CharacterCodes.plus + : value === 63 ? CharacterCodes.slash + : Debug.fail(`${value}: not a base64 value`); } function base64FormatDecode(ch: number) { - return ch >= CharacterCodes.A && ch <= CharacterCodes.Z ? ch - CharacterCodes.A : - ch >= CharacterCodes.a && ch <= CharacterCodes.z ? ch - CharacterCodes.a + 26 : - ch >= CharacterCodes._0 && ch <= CharacterCodes._9 ? ch - CharacterCodes._0 + 52 : - ch === CharacterCodes.plus ? 62 : - ch === CharacterCodes.slash ? 63 : - -1; + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z ? ch - CharacterCodes.A + : ch >= CharacterCodes.a && ch <= CharacterCodes.z ? ch - CharacterCodes.a + 26 + : ch >= CharacterCodes._0 && ch <= CharacterCodes._9 ? ch - CharacterCodes._0 + 52 + : ch === CharacterCodes.plus ? 62 + : ch === CharacterCodes.slash ? 63 + : -1; } interface MappedPosition { @@ -644,13 +694,19 @@ namespace ts { return value.generatedPosition; } - export function createDocumentPositionMapper(host: DocumentPositionMapperHost, map: RawSourceMap, mapPath: string): DocumentPositionMapper { + export function createDocumentPositionMapper( + host: DocumentPositionMapperHost, + map: RawSourceMap, + mapPath: string, + ): DocumentPositionMapper { const mapDirectory = getDirectoryPath(mapPath); const sourceRoot = map.sourceRoot ? getNormalizedAbsolutePath(map.sourceRoot, mapDirectory) : mapDirectory; const generatedAbsoluteFilePath = getNormalizedAbsolutePath(map.file, mapDirectory); const generatedFile = host.getSourceFileLike(generatedAbsoluteFilePath); const sourceFileAbsolutePaths = map.sources.map(source => getNormalizedAbsolutePath(source, sourceRoot)); - const sourceToSourceIndexMap = new Map(sourceFileAbsolutePaths.map((source, i) => [host.getCanonicalFileName(source), i])); + const sourceToSourceIndexMap = new Map( + sourceFileAbsolutePaths.map((source, i) => [host.getCanonicalFileName(source), i]), + ); let decodedMappings: readonly MappedPosition[] | undefined; let generatedMappings: SortedReadonlyArray | undefined; let sourceMappings: readonly SortedReadonlyArray[] | undefined; @@ -662,7 +718,12 @@ namespace ts { function processMapping(mapping: Mapping): MappedPosition { const generatedPosition = generatedFile !== undefined - ? getPositionOfLineAndCharacter(generatedFile, mapping.generatedLine, mapping.generatedCharacter, /*allowEdits*/ true) + ? getPositionOfLineAndCharacter( + generatedFile, + mapping.generatedLine, + mapping.generatedCharacter, + /*allowEdits*/ true, + ) : -1; let source: string | undefined; let sourcePosition: number | undefined; @@ -670,7 +731,12 @@ namespace ts { const sourceFile = host.getSourceFileLike(sourceFileAbsolutePaths[mapping.sourceIndex]); source = map.sources[mapping.sourceIndex]; sourcePosition = sourceFile !== undefined - ? getPositionOfLineAndCharacter(sourceFile, mapping.sourceLine, mapping.sourceCharacter, /*allowEdits*/ true) + ? getPositionOfLineAndCharacter( + sourceFile, + mapping.sourceLine, + mapping.sourceCharacter, + /*allowEdits*/ true, + ) : -1; } return { @@ -708,7 +774,9 @@ namespace ts { if (!list) lists[mapping.sourceIndex] = list = []; list.push(mapping); } - sourceMappings = lists.map(list => sortAndDeduplicate(list, compareSourcePositions, sameMappedPosition)); + sourceMappings = lists.map(list => + sortAndDeduplicate(list, compareSourcePositions, sameMappedPosition) + ); } return sourceMappings[sourceIndex]; } diff --git a/src/compiler/symbolWalker.ts b/src/compiler/symbolWalker.ts index 12705aabcb733..da706ccd1b265 100644 --- a/src/compiler/symbolWalker.ts +++ b/src/compiler/symbolWalker.ts @@ -22,7 +22,10 @@ namespace ts { walkType: type => { try { visitType(type); - return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) }; + return { + visitedTypes: getOwnValues(visitedTypes), + visitedSymbols: getOwnValues(visitedSymbols), + }; } finally { clear(visitedTypes); @@ -32,7 +35,10 @@ namespace ts { walkSymbol: symbol => { try { visitSymbol(symbol); - return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) }; + return { + visitedTypes: getOwnValues(visitedTypes), + visitedSymbols: getOwnValues(visitedSymbols), + }; } finally { clear(visitedTypes); diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 3505d79a10927..e0665f3aa1130 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -49,15 +49,28 @@ namespace ts { } /* @internal */ - export type HostWatchFile = (fileName: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined) => FileWatcher; + export type HostWatchFile = ( + fileName: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, + ) => FileWatcher; /* @internal */ - export type HostWatchDirectory = (fileName: string, callback: DirectoryWatcherCallback, recursive: boolean, options: WatchOptions | undefined) => FileWatcher; + export type HostWatchDirectory = ( + fileName: string, + callback: DirectoryWatcherCallback, + recursive: boolean, + options: WatchOptions | undefined, + ) => FileWatcher; /* @internal */ export const missingFileModifiedTime = new Date(0); // Any subsequent modification will occur after this time /* @internal */ - export function getModifiedTime(host: { getModifiedTime: NonNullable; }, fileName: string) { + export function getModifiedTime( + host: { getModifiedTime: NonNullable; }, + fileName: string, + ) { return host.getModifiedTime(fileName) || missingFileModifiedTime; } @@ -85,8 +98,10 @@ namespace ts { return; } const pollingIntervalChanged = setCustomLevels("TSC_WATCH_POLLINGINTERVAL", PollingInterval); - pollingChunkSize = getCustomPollingBasedLevels("TSC_WATCH_POLLINGCHUNKSIZE", defaultChunkLevels) || pollingChunkSize; - unchangedPollThresholds = getCustomPollingBasedLevels("TSC_WATCH_UNCHANGEDPOLLTHRESHOLDS", defaultChunkLevels) || unchangedPollThresholds; + pollingChunkSize = getCustomPollingBasedLevels("TSC_WATCH_POLLINGCHUNKSIZE", defaultChunkLevels) + || pollingChunkSize; + unchangedPollThresholds = getCustomPollingBasedLevels("TSC_WATCH_UNCHANGEDPOLLTHRESHOLDS", defaultChunkLevels) + || unchangedPollThresholds; function getLevel(envVar: string, level: keyof Levels) { return system.getEnvironmentVariable(`${envVar}_${level.toUpperCase()}`); @@ -124,8 +139,10 @@ namespace ts { function getCustomPollingBasedLevels(baseVariable: string, defaultLevels: Levels) { const customLevels = getCustomLevels(baseVariable); - return (pollingIntervalChanged || customLevels) && - createPollingIntervalBasedLevels(customLevels ? { ...defaultLevels, ...customLevels } : defaultLevels); + return (pollingIntervalChanged || customLevels) + && createPollingIntervalBasedLevels( + customLevels ? { ...defaultLevels, ...customLevels } : defaultLevels, + ); } } @@ -208,7 +225,11 @@ namespace ts { const highPollingIntervalQueue = createPollingIntervalQueue(PollingInterval.High); return watchFile; - function watchFile(fileName: string, callback: FileWatcherCallback, defaultPollingInterval: PollingInterval): FileWatcher { + function watchFile( + fileName: string, + callback: FileWatcherCallback, + defaultPollingInterval: PollingInterval, + ): FileWatcher { const file: WatchedFileWithUnchangedPolls = { fileName, callback, @@ -237,7 +258,12 @@ namespace ts { } function pollPollingIntervalQueue(queue: PollingIntervalQueue) { - queue.pollIndex = pollQueue(queue, queue.pollingInterval, queue.pollIndex, pollingChunkSize[queue.pollingInterval]); + queue.pollIndex = pollQueue( + queue, + queue.pollingInterval, + queue.pollIndex, + pollingChunkSize[queue.pollingInterval], + ); // Set the next polling index and timeout if (queue.length) { scheduleNextPoll(queue.pollingInterval); @@ -261,7 +287,12 @@ namespace ts { } } - function pollQueue(queue: (WatchedFileWithUnchangedPolls | undefined)[], pollingInterval: PollingInterval, pollIndex: number, chunkSize: number) { + function pollQueue( + queue: (WatchedFileWithUnchangedPolls | undefined)[], + pollingInterval: PollingInterval, + pollIndex: number, + chunkSize: number, + ) { return pollWatchedFileQueue( host, queue, @@ -270,7 +301,11 @@ namespace ts { onWatchFileStat, ); - function onWatchFileStat(watchedFile: WatchedFileWithUnchangedPolls, pollIndex: number, fileChanged: boolean) { + function onWatchFileStat( + watchedFile: WatchedFileWithUnchangedPolls, + pollIndex: number, + fileChanged: boolean, + ) { if (fileChanged) { watchedFile.unchangedPolls = 0; // Changed files go to changedFilesInLastPoll queue @@ -291,7 +326,10 @@ namespace ts { else if (pollingInterval !== PollingInterval.High) { watchedFile.unchangedPolls++; queue[pollIndex] = undefined; - addToPollingIntervalQueue(watchedFile, pollingInterval === PollingInterval.Low ? PollingInterval.Medium : PollingInterval.High); + addToPollingIntervalQueue( + watchedFile, + pollingInterval === PollingInterval.Low ? PollingInterval.Medium : PollingInterval.High, + ); } } } @@ -324,23 +362,35 @@ namespace ts { } function scheduleNextPoll(pollingInterval: PollingInterval) { - pollingIntervalQueue(pollingInterval).pollScheduled = host.setTimeout(pollingInterval === PollingInterval.Low ? pollLowPollingIntervalQueue : pollPollingIntervalQueue, pollingInterval, pollingIntervalQueue(pollingInterval)); + pollingIntervalQueue(pollingInterval).pollScheduled = host.setTimeout( + pollingInterval === PollingInterval.Low ? pollLowPollingIntervalQueue : pollPollingIntervalQueue, + pollingInterval, + pollingIntervalQueue(pollingInterval), + ); } } - function createUseFsEventsOnParentDirectoryWatchFile(fsWatch: FsWatch, useCaseSensitiveFileNames: boolean): HostWatchFile { + function createUseFsEventsOnParentDirectoryWatchFile( + fsWatch: FsWatch, + useCaseSensitiveFileNames: boolean, + ): HostWatchFile { // One file can have multiple watchers const fileWatcherCallbacks = createMultiMap(); const dirWatchers = new Map(); const toCanonicalName = createGetCanonicalFileName(useCaseSensitiveFileNames); return nonPollingWatchFile; - function nonPollingWatchFile(fileName: string, callback: FileWatcherCallback, _pollingInterval: PollingInterval, fallbackOptions: WatchOptions | undefined): FileWatcher { + function nonPollingWatchFile( + fileName: string, + callback: FileWatcherCallback, + _pollingInterval: PollingInterval, + fallbackOptions: WatchOptions | undefined, + ): FileWatcher { const filePath = toCanonicalName(fileName); fileWatcherCallbacks.add(filePath, callback); const dirPath = getDirectoryPath(filePath) || "."; - const watcher = dirWatchers.get(dirPath) || - createDirectoryWatcher(getDirectoryPath(fileName) || ".", dirPath, fallbackOptions); + const watcher = dirWatchers.get(dirPath) + || createDirectoryWatcher(getDirectoryPath(fileName) || ".", dirPath, fallbackOptions); watcher.referenceCount++; return { close: () => { @@ -441,7 +491,8 @@ namespace ts { watcher: createWatcher( ( // Cant infer types correctly so lets satisfy checker - (param1: any, param2: never, param3: any) => cache.get(path)?.callbacks.slice().forEach(cb => cb(param1, param2, param3)) + (param1: any, param2: never, param3: any) => + cache.get(path)?.callbacks.slice().forEach(cb => cb(param1, param2, param3)) ) as T, ), callbacks: [callback], @@ -539,21 +590,28 @@ namespace ts { const cache = new Map(); const callbackCache = createMultiMap(); - const cacheToUpdateChildWatches = new Map(); + const cacheToUpdateChildWatches = new Map< + Path, + { dirName: string; options: WatchOptions | undefined; fileNames: string[]; } + >(); let timerToUpdateChildWatches: any; const filePathComparer = getStringComparer(!useCaseSensitiveFileNames); const toCanonicalFilePath = createGetCanonicalFileName(useCaseSensitiveFileNames); return (dirName, callback, recursive, options) => - recursive ? - createDirectoryWatcher(dirName, options, callback) : - watchDirectory(dirName, callback, recursive, options); + recursive + ? createDirectoryWatcher(dirName, options, callback) + : watchDirectory(dirName, callback, recursive, options); /** * Create the directory watcher for the dirPath. */ - function createDirectoryWatcher(dirName: string, options: WatchOptions | undefined, callback?: DirectoryWatcherCallback): ChildDirectoryWatcher { + function createDirectoryWatcher( + dirName: string, + options: WatchOptions | undefined, + callback?: DirectoryWatcherCallback, + ): ChildDirectoryWatcher { const dirPath = toCanonicalFilePath(dirName) as Path; let directoryWatcher = cache.get(dirPath); if (directoryWatcher) { @@ -623,7 +681,10 @@ namespace ts { // Call the actual callback callbackCache.forEach((callbacks, rootDirName) => { if (invokeMap && invokeMap.get(rootDirName) === true) return; - if (rootDirName === dirPath || (startsWith(dirPath, rootDirName) && dirPath[rootDirName.length] === directorySeparator)) { + if ( + rootDirName === dirPath + || (startsWith(dirPath, rootDirName) && dirPath[rootDirName.length] === directorySeparator) + ) { if (invokeMap) { if (fileNames) { const existing = invokeMap.get(rootDirName); @@ -645,7 +706,12 @@ namespace ts { }); } - function nonSyncUpdateChildWatches(dirName: string, dirPath: Path, fileName: string, options: WatchOptions | undefined) { + function nonSyncUpdateChildWatches( + dirName: string, + dirPath: Path, + fileName: string, + options: WatchOptions | undefined, + ) { // Iterate through existing children and update the watches if needed const parentWatcher = cache.get(dirPath); if (parentWatcher && fileSystemEntryExists(dirName, FileSystemEntryKind.Directory)) { @@ -659,7 +725,12 @@ namespace ts { removeChildWatches(parentWatcher); } - function scheduleUpdateChildWatches(dirName: string, dirPath: Path, fileName: string, options: WatchOptions | undefined) { + function scheduleUpdateChildWatches( + dirName: string, + dirPath: Path, + fileName: string, + options: WatchOptions | undefined, + ) { const existing = cacheToUpdateChildWatches.get(dirPath); if (existing) { existing.fileNames.push(fileName); @@ -691,7 +762,9 @@ namespace ts { invokeCallbacks(dirPath, invokeMap, hasChanges ? undefined : fileNames); } - sysLog(`sysLog:: invokingWatchers:: Elapsed:: ${timestamp() - start}ms:: ${cacheToUpdateChildWatches.size}`); + sysLog( + `sysLog:: invokingWatchers:: Elapsed:: ${timestamp() - start}ms:: ${cacheToUpdateChildWatches.size}`, + ); callbackCache.forEach((callbacks, rootDirName) => { const existing = invokeMap.get(rootDirName); if (existing) { @@ -707,7 +780,9 @@ namespace ts { }); const elapsed = timestamp() - start; - sysLog(`sysLog:: Elapsed:: ${elapsed}ms:: onTimerToUpdateChildWatches:: ${cacheToUpdateChildWatches.size} ${timerToUpdateChildWatches}`); + sysLog( + `sysLog:: Elapsed:: ${elapsed}ms:: onTimerToUpdateChildWatches:: ${cacheToUpdateChildWatches.size} ${timerToUpdateChildWatches}`, + ); } function removeChildWatches(parentWatcher: HostDirectoryWatcher | undefined) { @@ -726,12 +801,15 @@ namespace ts { if (!parentWatcher) return false; let newChildWatches: ChildDirectoryWatcher[] | undefined; const hasChanges = enumerateInsertsAndDeletes( - fileSystemEntryExists(parentDir, FileSystemEntryKind.Directory) ? mapDefined(getAccessibleSortedChildDirectories(parentDir), child => { - const childFullName = getNormalizedAbsolutePath(child, parentDir); - // Filter our the symbolic link directories since those arent included in recursive watch - // which is same behaviour when recursive: true is passed to fs.watch - return !isIgnoredPath(childFullName, options) && filePathComparer(childFullName, normalizePath(realpath(childFullName))) === Comparison.EqualTo ? childFullName : undefined; - }) : emptyArray, + fileSystemEntryExists(parentDir, FileSystemEntryKind.Directory) + ? mapDefined(getAccessibleSortedChildDirectories(parentDir), child => { + const childFullName = getNormalizedAbsolutePath(child, parentDir); + // Filter our the symbolic link directories since those arent included in recursive watch + // which is same behaviour when recursive: true is passed to fs.watch + return !isIgnoredPath(childFullName, options) + && filePathComparer(childFullName, normalizePath(realpath(childFullName))) + === Comparison.EqualTo ? childFullName : undefined; + }) : emptyArray, parentWatcher.childWatches, (child, childWatcher) => filePathComparer(child, childWatcher.dirName), createAndAddChildDirectoryWatcher, @@ -758,8 +836,8 @@ namespace ts { } function isIgnoredPath(path: string, options: WatchOptions | undefined) { - return some(ignoredPaths, searchPath => isInPath(path, searchPath)) || - isIgnoredByWatchOptions(path, options, useCaseSensitiveFileNames, getCurrentDirectory); + return some(ignoredPaths, searchPath => isInPath(path, searchPath)) + || isIgnoredByWatchOptions(path, options, useCaseSensitiveFileNames, getCurrentDirectory); } function isInPath(path: string, searchPath: string) { @@ -770,15 +848,30 @@ namespace ts { } /*@internal*/ - export type FsWatchCallback = (eventName: "rename" | "change", relativeFileName: string | undefined, modifiedTime?: Date) => void; + export type FsWatchCallback = ( + eventName: "rename" | "change", + relativeFileName: string | undefined, + modifiedTime?: Date, + ) => void; /*@internal*/ - export type FsWatch = (fileOrDirectory: string, entryKind: FileSystemEntryKind, callback: FsWatchCallback, recursive: boolean, fallbackPollingInterval: PollingInterval, fallbackOptions: WatchOptions | undefined) => FileWatcher; + export type FsWatch = ( + fileOrDirectory: string, + entryKind: FileSystemEntryKind, + callback: FsWatchCallback, + recursive: boolean, + fallbackPollingInterval: PollingInterval, + fallbackOptions: WatchOptions | undefined, + ) => FileWatcher; /*@internal*/ export interface FsWatchWorkerWatcher extends FileWatcher { on(eventName: string, listener: () => void): void; } /*@internal*/ - export type FsWatchWorker = (fileOrDirectory: string, recursive: boolean, callback: FsWatchCallback) => FsWatchWorkerWatcher; + export type FsWatchWorker = ( + fileOrDirectory: string, + recursive: boolean, + callback: FsWatchCallback, + ) => FsWatchWorkerWatcher; /*@internal*/ export const enum FileSystemEntryKind { File, @@ -786,7 +879,8 @@ namespace ts { } function createFileWatcherCallback(callback: FsWatchCallback): FileWatcherCallback { - return (_fileName, eventKind, modifiedTime) => callback(eventKind === FileWatcherEventKind.Changed ? "change" : "rename", "", modifiedTime); + return (_fileName, eventKind, modifiedTime) => + callback(eventKind === FileWatcherEventKind.Changed ? "change" : "rename", "", modifiedTime); } function createFsWatchCallbackForFileWatcherCallback( @@ -798,7 +892,12 @@ namespace ts { if (eventName === "rename") { // Check time stamps rather than file system entry checks modifiedTime ||= getModifiedTime(fileName) || missingFileModifiedTime; - callback(fileName, modifiedTime !== missingFileModifiedTime ? FileWatcherEventKind.Created : FileWatcherEventKind.Deleted, modifiedTime); + callback( + fileName, + modifiedTime !== missingFileModifiedTime ? FileWatcherEventKind.Created + : FileWatcherEventKind.Deleted, + modifiedTime, + ); } else { // Change @@ -814,8 +913,13 @@ namespace ts { getCurrentDirectory: System["getCurrentDirectory"], ) { return (options?.excludeDirectories || options?.excludeFiles) && ( - matchesExclude(pathToCheck, options?.excludeFiles, useCaseSensitiveFileNames, getCurrentDirectory()) || - matchesExclude(pathToCheck, options?.excludeDirectories, useCaseSensitiveFileNames, getCurrentDirectory()) + matchesExclude(pathToCheck, options?.excludeFiles, useCaseSensitiveFileNames, getCurrentDirectory()) + || matchesExclude( + pathToCheck, + options?.excludeDirectories, + useCaseSensitiveFileNames, + getCurrentDirectory(), + ) ); } @@ -832,8 +936,12 @@ namespace ts { // event name is "change") if (eventName === "rename") { // When deleting a file, the passed baseFileName is null - const fileName = !relativeFileName ? directoryName : normalizePath(combinePaths(directoryName, relativeFileName)); - if (!relativeFileName || !isIgnoredByWatchOptions(fileName, options, useCaseSensitiveFileNames, getCurrentDirectory)) { + const fileName = !relativeFileName ? directoryName + : normalizePath(combinePaths(directoryName, relativeFileName)); + if ( + !relativeFileName + || !isIgnoredByWatchOptions(fileName, options, useCaseSensitiveFileNames, getCurrentDirectory) + ) { callback(fileName); } } @@ -899,7 +1007,12 @@ namespace ts { watchDirectory, }; - function watchFile(fileName: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined): FileWatcher { + function watchFile( + fileName: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, + ): FileWatcher { options = updateOptionsForWatchFile(options, useNonPollingWatchers); const watchFileKind = Debug.checkDefined(options.watchFile); switch (watchFileKind) { @@ -910,7 +1023,12 @@ namespace ts { case WatchFileKind.DynamicPriorityPolling: return ensureDynamicPollingWatchFile()(fileName, callback, pollingInterval, /*options*/ undefined); case WatchFileKind.FixedChunkSizePolling: - return ensureFixedChunkSizePollingWatchFile()(fileName, callback, /* pollingInterval */ undefined!, /*options*/ undefined); + return ensureFixedChunkSizePollingWatchFile()( + fileName, + callback, + /* pollingInterval */ undefined!, + /*options*/ undefined, + ); case WatchFileKind.UseFsEvents: return fsWatch( fileName, @@ -922,7 +1040,10 @@ namespace ts { ); case WatchFileKind.UseFsEventsOnParentDirectory: if (!nonPollingWatchFile) { - nonPollingWatchFile = createUseFsEventsOnParentDirectoryWatchFile(fsWatch, useCaseSensitiveFileNames); + nonPollingWatchFile = createUseFsEventsOnParentDirectoryWatchFile( + fsWatch, + useCaseSensitiveFileNames, + ); } return nonPollingWatchFile(fileName, callback, pollingInterval, getFallbackOptions(options)); default: @@ -935,10 +1056,16 @@ namespace ts { } function ensureFixedChunkSizePollingWatchFile() { - return fixedChunkSizePollingWatchFile ||= createFixedChunkSizePollingWatchFile({ getModifiedTime, setTimeout }); + return fixedChunkSizePollingWatchFile ||= createFixedChunkSizePollingWatchFile({ + getModifiedTime, + setTimeout, + }); } - function updateOptionsForWatchFile(options: WatchOptions | undefined, useNonPollingWatchers?: boolean): WatchOptions { + function updateOptionsForWatchFile( + options: WatchOptions | undefined, + useNonPollingWatchers?: boolean, + ): WatchOptions { if (options && options.watchFile !== undefined) return options; switch (tscWatchFile) { case "PriorityPollingInterval": @@ -949,19 +1076,31 @@ namespace ts { return { watchFile: WatchFileKind.DynamicPriorityPolling }; case "UseFsEvents": // Use notifications from FS to watch with falling back to fs.watchFile - return generateWatchFileOptions(WatchFileKind.UseFsEvents, PollingWatchKind.PriorityInterval, options); + return generateWatchFileOptions( + WatchFileKind.UseFsEvents, + PollingWatchKind.PriorityInterval, + options, + ); case "UseFsEventsWithFallbackDynamicPolling": // Use notifications from FS to watch with falling back to dynamic watch file - return generateWatchFileOptions(WatchFileKind.UseFsEvents, PollingWatchKind.DynamicPriority, options); + return generateWatchFileOptions( + WatchFileKind.UseFsEvents, + PollingWatchKind.DynamicPriority, + options, + ); case "UseFsEventsOnParentDirectory": useNonPollingWatchers = true; // fall through default: - return useNonPollingWatchers ? + return useNonPollingWatchers // Use notifications from FS to watch with falling back to fs.watchFile - generateWatchFileOptions(WatchFileKind.UseFsEventsOnParentDirectory, PollingWatchKind.PriorityInterval, options) : + ? generateWatchFileOptions( + WatchFileKind.UseFsEventsOnParentDirectory, + PollingWatchKind.PriorityInterval, + options, + ) // Default to using fs events - { watchFile: WatchFileKind.UseFsEvents }; + : { watchFile: WatchFileKind.UseFsEvents }; } } @@ -973,18 +1112,29 @@ namespace ts { const defaultFallbackPolling = options?.fallbackPolling; return { watchFile, - fallbackPolling: defaultFallbackPolling === undefined ? - fallbackPolling : - defaultFallbackPolling, + fallbackPolling: defaultFallbackPolling === undefined + ? fallbackPolling + : defaultFallbackPolling, }; } - function watchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean, options: WatchOptions | undefined): FileWatcher { + function watchDirectory( + directoryName: string, + callback: DirectoryWatcherCallback, + recursive: boolean, + options: WatchOptions | undefined, + ): FileWatcher { if (fsSupportsRecursiveFsWatch) { return fsWatch( directoryName, FileSystemEntryKind.Directory, - createFsWatchCallbackForDirectoryWatcherCallback(directoryName, callback, options, useCaseSensitiveFileNames, getCurrentDirectory), + createFsWatchCallbackForDirectoryWatcherCallback( + directoryName, + callback, + options, + useCaseSensitiveFileNames, + getCurrentDirectory, + ), recursive, PollingInterval.Medium, getFallbackOptions(options), @@ -1006,7 +1156,12 @@ namespace ts { return hostRecursiveDirectoryWatcher(directoryName, callback, recursive, options); } - function nonRecursiveWatchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean, options: WatchOptions | undefined): FileWatcher { + function nonRecursiveWatchDirectory( + directoryName: string, + callback: DirectoryWatcherCallback, + recursive: boolean, + options: WatchOptions | undefined, + ): FileWatcher { Debug.assert(!recursive); const watchDirectoryOptions = updateOptionsForWatchDirectory(options); const watchDirectoryKind = Debug.checkDefined(watchDirectoryOptions.watchDirectory); @@ -1036,7 +1191,13 @@ namespace ts { return fsWatch( directoryName, FileSystemEntryKind.Directory, - createFsWatchCallbackForDirectoryWatcherCallback(directoryName, callback, options, useCaseSensitiveFileNames, getCurrentDirectory), + createFsWatchCallbackForDirectoryWatcherCallback( + directoryName, + callback, + options, + useCaseSensitiveFileNames, + getCurrentDirectory, + ), recursive, PollingInterval.Medium, getFallbackOptions(watchDirectoryOptions), @@ -1059,14 +1220,19 @@ namespace ts { const defaultFallbackPolling = options?.fallbackPolling; return { watchDirectory: WatchDirectoryKind.UseFsEvents, - fallbackPolling: defaultFallbackPolling !== undefined ? - defaultFallbackPolling : - undefined, + fallbackPolling: defaultFallbackPolling !== undefined + ? defaultFallbackPolling + : undefined, }; } } - function pollingWatchFile(fileName: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined) { + function pollingWatchFile( + fileName: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, + ) { return createSingleWatcherPerName( pollingWatches, useCaseSensitiveFileNames, @@ -1088,7 +1254,15 @@ namespace ts { useCaseSensitiveFileNames, fileOrDirectory, callback, - cb => fsWatchHandlingExistenceOnHost(fileOrDirectory, entryKind, cb, recursive, fallbackPollingInterval, fallbackOptions), + cb => + fsWatchHandlingExistenceOnHost( + fileOrDirectory, + entryKind, + cb, + recursive, + fallbackPollingInterval, + fallbackOptions, + ), ); } @@ -1103,13 +1277,15 @@ namespace ts { let lastDirectoryPartWithDirectorySeparator: string | undefined; let lastDirectoryPart: string | undefined; if (inodeWatching) { - lastDirectoryPartWithDirectorySeparator = fileOrDirectory.substring(fileOrDirectory.lastIndexOf(directorySeparator)); + lastDirectoryPartWithDirectorySeparator = fileOrDirectory.substring( + fileOrDirectory.lastIndexOf(directorySeparator), + ); lastDirectoryPart = lastDirectoryPartWithDirectorySeparator.slice(directorySeparator.length); } /** Watcher for the file system entry depending on whether it is missing or present */ - let watcher: FileWatcher | undefined = !fileSystemEntryExists(fileOrDirectory, entryKind) ? - watchMissingFileSystemEntry() : - watchPresentFileSystemEntry(); + let watcher: FileWatcher | undefined = !fileSystemEntryExists(fileOrDirectory, entryKind) + ? watchMissingFileSystemEntry() + : watchPresentFileSystemEntry(); return { close: () => { // Close the watcher (either existing file system entry watcher or missing file system entry watcher) @@ -1123,7 +1299,11 @@ namespace ts { function updateWatcher(createWatcher: () => FileWatcher) { // If watcher is not closed, update it if (watcher) { - sysLog(`sysLog:: ${fileOrDirectory}:: Changing watcher to ${createWatcher === watchPresentFileSystemEntry ? "Present" : "Missing"}FileSystemEntryWatcher`); + sysLog( + `sysLog:: ${fileOrDirectory}:: Changing watcher to ${ + createWatcher === watchPresentFileSystemEntry ? "Present" : "Missing" + }FileSystemEntryWatcher`, + ); watcher.close(); watcher = createWatcher(); } @@ -1142,9 +1322,9 @@ namespace ts { const presentWatcher = fsWatchWorker( fileOrDirectory, recursive, - inodeWatching ? - callbackChangingToMissingFileSystemEntry : - callback, + inodeWatching + ? callbackChangingToMissingFileSystemEntry + : callback, ); // Watch the missing file or directory or error presentWatcher.on("error", () => { @@ -1163,7 +1343,10 @@ namespace ts { } } - function callbackChangingToMissingFileSystemEntry(event: "rename" | "change", relativeName: string | undefined) { + function callbackChangingToMissingFileSystemEntry( + event: "rename" | "change", + relativeName: string | undefined, + ) { // In some scenarios, file save operation fires event with fileName.ext~ instead of fileName.ext // To ensure we see the file going missing and coming back up (file delete and then recreated) // and watches being updated correctly we are calling back with fileName.ext as well as fileName.ext~ @@ -1177,17 +1360,20 @@ namespace ts { // because relativeName is not guaranteed to be correct we need to check on each rename with few combinations // Eg on ubuntu while watching app/node_modules the relativeName is "node_modules" which is neither relative nor full path if ( - event === "rename" && - (!relativeName || - relativeName === lastDirectoryPart || - endsWith(relativeName, lastDirectoryPartWithDirectorySeparator!)) + event === "rename" + && (!relativeName + || relativeName === lastDirectoryPart + || endsWith(relativeName, lastDirectoryPartWithDirectorySeparator!)) ) { const modifiedTime = getModifiedTime(fileOrDirectory) || missingFileModifiedTime; if (originalRelativeName) callback(event, originalRelativeName, modifiedTime); callback(event, relativeName, modifiedTime); if (inodeWatching) { // If this was rename event, inode has changed means we need to update watcher - updateWatcher(modifiedTime === missingFileModifiedTime ? watchMissingFileSystemEntry : watchPresentFileSystemEntry); + updateWatcher( + modifiedTime === missingFileModifiedTime ? watchMissingFileSystemEntry + : watchPresentFileSystemEntry, + ); } else if (modifiedTime === missingFileModifiedTime) { updateWatcher(watchMissingFileSystemEntry); @@ -1257,7 +1443,17 @@ namespace ts { } /*@internal*/ - export type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex"; + export type BufferEncoding = + | "ascii" + | "utf8" + | "utf-8" + | "utf16le" + | "ucs2" + | "ucs-2" + | "base64" + | "latin1" + | "binary" + | "hex"; /*@internal*/ interface NodeBuffer extends Uint8Array { @@ -1354,8 +1550,18 @@ namespace ts { * @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that * use native OS file watching */ - watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; - watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; + watchFile?( + path: string, + callback: FileWatcherCallback, + pollingInterval?: number, + options?: WatchOptions, + ): FileWatcher; + watchDirectory?( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher; resolvePath(path: string): string; fileExists(path: string): boolean; directoryExists(path: string): boolean; @@ -1363,7 +1569,13 @@ namespace ts { getExecutingFilePath(): string; getCurrentDirectory(): string; getDirectories(path: string): string[]; - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; getModifiedTime?(path: string): Date | undefined; setModifiedTime?(path: string, time: Date): void; deleteFile?(path: string): void; @@ -1461,9 +1673,12 @@ namespace ts { const platform: string = _os.platform(); const useCaseSensitiveFileNames = isFileSystemCaseSensitive(); - const fsRealpath = !!_fs.realpathSync.native ? process.platform === "win32" ? fsRealPathHandlingLongPath : _fs.realpathSync.native : _fs.realpathSync; + const fsRealpath = !!_fs.realpathSync.native + ? process.platform === "win32" ? fsRealPathHandlingLongPath : _fs.realpathSync.native + : _fs.realpathSync; - const fsSupportsRecursiveFsWatch = isNode4OrLater && (process.platform === "win32" || process.platform === "darwin"); + const fsSupportsRecursiveFsWatch = isNode4OrLater + && (process.platform === "win32" || process.platform === "darwin"); const getCurrentDirectory = memoize(() => process.cwd()); const { watchFile, watchDirectory } = createSystemWatchFunctions({ pollingWatchFileWorker: fsWatchFileWorker, @@ -1555,9 +1770,11 @@ namespace ts { }, enableCPUProfiler, disableCPUProfiler, - cpuProfilingEnabled: () => !!activeSession || contains(process.execArgv, "--cpu-prof") || contains(process.execArgv, "--prof"), + cpuProfilingEnabled: () => + !!activeSession || contains(process.execArgv, "--cpu-prof") || contains(process.execArgv, "--prof"), realpath, - debugMode: !!process.env.NODE_INSPECTOR_IPC || !!process.env.VSCODE_INSPECTOR_OPTIONS || some(process.execArgv as string[], arg => /^--(inspect|debug)(-brk)?(=\d+)?$/i.test(arg)), + debugMode: !!process.env.NODE_INSPECTOR_IPC || !!process.env.VSCODE_INSPECTOR_OPTIONS + || some(process.execArgv as string[], arg => /^--(inspect|debug)(-brk)?(=\d+)?$/i.test(arg)), tryEnableSourceMapsForHost() { try { require("source-map-support").install(); @@ -1642,10 +1859,17 @@ namespace ts { if (node.callFrame.url) { const url = normalizeSlashes(node.callFrame.url); if (containsPath(fileUrlRoot, url, useCaseSensitiveFileNames)) { - node.callFrame.url = getRelativePathToDirectoryOrUrl(fileUrlRoot, url, fileUrlRoot, createGetCanonicalFileName(useCaseSensitiveFileNames), /*isAbsolutePathAnUrl*/ true); + node.callFrame.url = getRelativePathToDirectoryOrUrl( + fileUrlRoot, + url, + fileUrlRoot, + createGetCanonicalFileName(useCaseSensitiveFileNames), + /*isAbsolutePathAnUrl*/ true, + ); } else if (!nativePattern.test(url)) { - node.callFrame.url = (remappedPaths.has(url) ? remappedPaths : remappedPaths.set(url, `external${externalFileCounter}.js`)).get(url)!; + node.callFrame.url = (remappedPaths.has(url) ? remappedPaths + : remappedPaths.set(url, `external${externalFileCounter}.js`)).get(url)!; externalFileCounter++; } } @@ -1660,7 +1884,10 @@ namespace ts { if (!err) { try { if (statSync(profilePath)?.isDirectory()) { - profilePath = _path.join(profilePath, `${(new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`); + profilePath = _path.join( + profilePath, + `${(new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`, + ); } } catch { @@ -1711,7 +1938,11 @@ namespace ts { }); } - function fsWatchFileWorker(fileName: string, callback: FileWatcherCallback, pollingInterval: number): FileWatcher { + function fsWatchFileWorker( + fileName: string, + callback: FileWatcherCallback, + pollingInterval: number, + ): FileWatcher { _fs.watchFile(fileName, { persistent: true, interval: pollingInterval }, fileChanged); let eventKind: FileWatcherEventKind; return { @@ -1753,8 +1984,8 @@ namespace ts { // (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643) return _fs.watch( fileOrDirectory, - fsSupportsRecursiveFsWatch ? - { persistent: true, recursive: !!recursive } : { persistent: true }, + fsSupportsRecursiveFsWatch + ? { persistent: true, recursive: !!recursive } : { persistent: true }, callback, ); } @@ -1868,8 +2099,24 @@ namespace ts { } } - function readDirectory(path: string, extensions?: readonly string[], excludes?: readonly string[], includes?: readonly string[], depth?: number): string[] { - return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), depth, getAccessibleFileSystemEntries, realpath); + function readDirectory( + path: string, + extensions?: readonly string[], + excludes?: readonly string[], + includes?: readonly string[], + depth?: number, + ): string[] { + return matchFiles( + path, + extensions, + excludes, + includes, + useCaseSensitiveFileNames, + process.cwd(), + depth, + getAccessibleFileSystemEntries, + realpath, + ); } function fileSystemEntryExists(path: string, entryKind: FileSystemEntryKind): boolean { diff --git a/src/compiler/tracing.ts b/src/compiler/tracing.ts index b77421f927449..32bb8e618110d 100644 --- a/src/compiler/tracing.ts +++ b/src/compiler/tracing.ts @@ -24,7 +24,14 @@ namespace ts { // eslint-disable-line local/one-namespace-per-file // The actual constraint is that JSON.stringify be able to serialize it without throwing. interface Args { - [key: string]: string | number | boolean | null | undefined | Args | readonly (string | number | boolean | null | undefined | Args)[]; + [key: string]: + | string + | number + | boolean + | null + | undefined + | Args + | readonly (string | number | boolean | null | undefined | Args)[]; } /** Starts tracing for the given project. */ @@ -72,7 +79,11 @@ namespace ts { // eslint-disable-line local/one-namespace-per-file fs.writeSync( traceFd, "[\n" - + [{ name: "process_name", args: { name: "tsc" }, ...meta }, { name: "thread_name", args: { name: "Main" }, ...meta }, { name: "TracingStartedInBrowser", ...meta, cat: "disabled-by-default-devtools.timeline" }] + + [{ name: "process_name", args: { name: "tsc" }, ...meta }, { + name: "thread_name", + args: { name: "Main" }, + ...meta, + }, { name: "TracingStartedInBrowser", ...meta, cat: "disabled-by-default-devtools.timeline" }] .map(v => JSON.stringify(v)).join(",\n"), ); } @@ -116,7 +127,8 @@ namespace ts { // eslint-disable-line local/one-namespace-per-file writeEvent("I", phase, name, args, `"s":"g"`); } - const eventStack: { phase: Phase; name: string; args?: Args; time: number; separateBeginAndEnd: boolean; }[] = []; + const eventStack: { phase: Phase; name: string; args?: Args; time: number; separateBeginAndEnd: boolean; }[] = + []; /** * @param separateBeginAndEnd - used for special cases where we need the trace point even if the event @@ -156,12 +168,22 @@ namespace ts { // eslint-disable-line local/one-namespace-per-file } } - function writeEvent(eventType: string, phase: Phase, name: string, args: Args | undefined, extras?: string, time: number = 1000 * timestamp()) { + function writeEvent( + eventType: string, + phase: Phase, + name: string, + args: Args | undefined, + extras?: string, + time: number = 1000 * timestamp(), + ) { // In server mode, there's no easy way to dump type information, so we drop events that would require it. if (mode === "server" && phase === Phase.CheckTypes) return; performance.mark("beginTracing"); - fs.writeSync(traceFd, `,\n{"pid":1,"tid":1,"ph":"${eventType}","cat":"${phase}","ts":${time},"name":"${name}"`); + fs.writeSync( + traceFd, + `,\n{"pid":1,"tid":1,"ph":"${eventType}","cat":"${phase}","ts":${time},"name":"${name}"`, + ); if (extras) fs.writeSync(traceFd, `,${extras}`); if (args) fs.writeSync(traceFd, `,"args":${JSON.stringify(args)}`); fs.writeSync(traceFd, `}`); @@ -292,7 +314,9 @@ namespace ts { // eslint-disable-line local/one-namespace-per-file recursionId: recursionToken, isTuple: objectFlags & ObjectFlags.Tuple ? true : undefined, unionTypes: (type.flags & TypeFlags.Union) ? (type as UnionType).types?.map(t => t.id) : undefined, - intersectionTypes: (type.flags & TypeFlags.Intersection) ? (type as IntersectionType).types.map(t => t.id) : undefined, + intersectionTypes: (type.flags & TypeFlags.Intersection) ? (type as IntersectionType).types.map(t => + t.id + ) : undefined, aliasTypeArguments: type.aliasTypeArguments?.map(t => t.id), keyofType: (type.flags & TypeFlags.Index) ? (type as IndexType).type?.id : undefined, ...indexedAccessProperties, diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 7d888ce28ecd0..c1aa0de1fa6c9 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -29,16 +29,27 @@ namespace ts { EmitNotifications = 1 << 1, } - export const noTransformers: EmitTransformers = { scriptTransformers: emptyArray, declarationTransformers: emptyArray }; + export const noTransformers: EmitTransformers = { + scriptTransformers: emptyArray, + declarationTransformers: emptyArray, + }; - export function getTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnlyDtsFiles?: boolean): EmitTransformers { + export function getTransformers( + compilerOptions: CompilerOptions, + customTransformers?: CustomTransformers, + emitOnlyDtsFiles?: boolean, + ): EmitTransformers { return { scriptTransformers: getScriptTransformers(compilerOptions, customTransformers, emitOnlyDtsFiles), declarationTransformers: getDeclarationTransformers(customTransformers), }; } - function getScriptTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnlyDtsFiles?: boolean) { + function getScriptTransformers( + compilerOptions: CompilerOptions, + customTransformers?: CustomTransformers, + emitOnlyDtsFiles?: boolean, + ) { if (emitOnlyDtsFiles) return emptyArray; const languageVersion = getEmitScriptTarget(compilerOptions); @@ -103,7 +114,10 @@ namespace ts { function getDeclarationTransformers(customTransformers?: CustomTransformers) { const transformers: TransformerFactory[] = []; transformers.push(transformDeclarations); - addRange(transformers, customTransformers && map(customTransformers.afterDeclarations, wrapDeclarationTransformerFactory)); + addRange( + transformers, + customTransformers && map(customTransformers.afterDeclarations, wrapDeclarationTransformerFactory), + ); return transformers; } @@ -117,7 +131,10 @@ namespace ts { /** * Wrap a transformer factory that may return a custom script or declaration transformer object. */ - function wrapCustomTransformerFactory(transformer: TransformerFactory | CustomTransformerFactory, handleDefault: (context: TransformationContext, tx: Transformer) => Transformer): TransformerFactory { + function wrapCustomTransformerFactory( + transformer: TransformerFactory | CustomTransformerFactory, + handleDefault: (context: TransformationContext, tx: Transformer) => Transformer, + ): TransformerFactory { return context => { const customTransformer = transformer(context); return typeof customTransformer === "function" @@ -126,11 +143,15 @@ namespace ts { }; } - function wrapScriptTransformerFactory(transformer: TransformerFactory | CustomTransformerFactory): TransformerFactory { + function wrapScriptTransformerFactory( + transformer: TransformerFactory | CustomTransformerFactory, + ): TransformerFactory { return wrapCustomTransformerFactory(transformer, chainBundle); } - function wrapDeclarationTransformerFactory(transformer: TransformerFactory | CustomTransformerFactory): TransformerFactory { + function wrapDeclarationTransformerFactory( + transformer: TransformerFactory | CustomTransformerFactory, + ): TransformerFactory { return wrapCustomTransformerFactory(transformer, (_, node) => node); } @@ -152,7 +173,15 @@ namespace ts { * @param transforms An array of `TransformerFactory` callbacks. * @param allowDtsFiles A value indicating whether to allow the transformation of .d.ts files. */ - export function transformNodes(resolver: EmitResolver | undefined, host: EmitHost | undefined, factory: NodeFactory, options: CompilerOptions, nodes: readonly T[], transformers: readonly TransformerFactory[], allowDtsFiles: boolean): TransformationResult { + export function transformNodes( + resolver: EmitResolver | undefined, + host: EmitHost | undefined, + factory: NodeFactory, + options: CompilerOptions, + nodes: readonly T[], + transformers: readonly TransformerFactory[], + allowDtsFiles: boolean, + ): TransformationResult { const enabledSyntaxKindFeatures = new Array(SyntaxKind.Count); let lexicalEnvironmentVariableDeclarations: VariableDeclaration[]; let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[]; @@ -203,7 +232,10 @@ namespace ts { return onSubstituteNode; }, set onSubstituteNode(value) { - Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed."); + Debug.assert( + state < TransformationState.Initialized, + "Cannot modify transformation hooks after initialization has completed.", + ); Debug.assert(value !== undefined, "Value must not be 'undefined'"); onSubstituteNode = value; }, @@ -211,7 +243,10 @@ namespace ts { return onEmitNode; }, set onEmitNode(value) { - Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed."); + Debug.assert( + state < TransformationState.Initialized, + "Cannot modify transformation hooks after initialization has completed.", + ); Debug.assert(value !== undefined, "Value must not be 'undefined'"); onEmitNode = value; }, @@ -242,7 +277,12 @@ namespace ts { // Transform each node. const transformed: T[] = []; for (const node of nodes) { - tracing?.push(tracing.Phase.Emit, "transformNodes", node.kind === SyntaxKind.SourceFile ? { path: (node as any as SourceFile).path } : { kind: node.kind, pos: node.pos, end: node.end }); + tracing?.push( + tracing.Phase.Emit, + "transformNodes", + node.kind === SyntaxKind.SourceFile ? { path: (node as any as SourceFile).path } + : { kind: node.kind, pos: node.pos, end: node.end }, + ); transformed.push((allowDtsFiles ? transformation : transformRoot)(node)); tracing?.pop(); } @@ -270,7 +310,10 @@ namespace ts { * Enables expression substitutions in the pretty printer for the provided SyntaxKind. */ function enableSubstitution(kind: SyntaxKind) { - Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the transformation context after transformation has completed.", + ); enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.Substitution; } @@ -290,7 +333,10 @@ namespace ts { * @param emitCallback The callback used to emit the node or its substitute. */ function substituteNode(hint: EmitHint, node: Node) { - Debug.assert(state < TransformationState.Disposed, "Cannot substitute a node after the result is disposed."); + Debug.assert( + state < TransformationState.Disposed, + "Cannot substitute a node after the result is disposed.", + ); return node && isSubstitutionEnabled(node) && onSubstituteNode(hint, node) || node; } @@ -298,7 +344,10 @@ namespace ts { * Enables before/after emit notifications in the pretty printer for the provided SyntaxKind. */ function enableEmitNotification(kind: SyntaxKind) { - Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the transformation context after transformation has completed.", + ); enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.EmitNotifications; } @@ -318,8 +367,15 @@ namespace ts { * @param node The node to emit. * @param emitCallback The callback used to emit the node. */ - function emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) { - Debug.assert(state < TransformationState.Disposed, "Cannot invoke TransformationResult callbacks after the result is disposed."); + function emitNodeWithNotification( + hint: EmitHint, + node: Node, + emitCallback: (hint: EmitHint, node: Node) => void, + ) { + Debug.assert( + state < TransformationState.Disposed, + "Cannot invoke TransformationResult callbacks after the result is disposed.", + ); if (node) { // TODO: Remove check and unconditionally use onEmitNode when API is breakingly changed // (see https://github.com/microsoft/TypeScript/pull/36248/files/5062623f39120171b98870c71344b3242eb03d23#r369766739) @@ -336,8 +392,14 @@ namespace ts { * Records a hoisted variable declaration for the provided name within a lexical environment. */ function hoistVariableDeclaration(name: Identifier): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); const decl = setEmitFlags(factory.createVariableDeclaration(name), EmitFlags.NoNestedSourceMaps); if (!lexicalEnvironmentVariableDeclarations) { lexicalEnvironmentVariableDeclarations = [decl]; @@ -354,8 +416,14 @@ namespace ts { * Records a hoisted function declaration within a lexical environment. */ function hoistFunctionDeclaration(func: FunctionDeclaration): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); setEmitFlags(func, EmitFlags.CustomPrologue); if (!lexicalEnvironmentFunctionDeclarations) { lexicalEnvironmentFunctionDeclarations = [func]; @@ -369,8 +437,14 @@ namespace ts { * Adds an initialization statement to the top of the lexical environment. */ function addInitializationStatement(node: Statement): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); setEmitFlags(node, EmitFlags.CustomPrologue); if (!lexicalEnvironmentStatements) { lexicalEnvironmentStatements = [node]; @@ -385,16 +459,24 @@ namespace ts { * are pushed onto a stack, and the related storage variables are reset. */ function startLexicalEnvironment(): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended."); // Save the current lexical environment. Rather than resizing the array we adjust the // stack size variable. This allows us to reuse existing array slots we've // already allocated between transformations to avoid allocation and GC overhead during // transformation. - lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentVariableDeclarations; - lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFunctionDeclarations; + lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = + lexicalEnvironmentVariableDeclarations; + lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = + lexicalEnvironmentFunctionDeclarations; lexicalEnvironmentStatementsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentStatements; lexicalEnvironmentFlagsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFlags; lexicalEnvironmentStackOffset++; @@ -406,16 +488,28 @@ namespace ts { /** Suspends the current lexical environment, usually after visiting a parameter list. */ function suspendLexicalEnvironment(): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended."); lexicalEnvironmentSuspended = true; } /** Resumes a suspended lexical environment, usually before visiting a function body. */ function resumeLexicalEnvironment(): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); Debug.assert(lexicalEnvironmentSuspended, "Lexical environment is not suspended."); lexicalEnvironmentSuspended = false; } @@ -425,15 +519,21 @@ namespace ts { * any hoisted declarations added in this environment are returned. */ function endLexicalEnvironment(): Statement[] | undefined { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended."); let statements: Statement[] | undefined; if ( - lexicalEnvironmentVariableDeclarations || - lexicalEnvironmentFunctionDeclarations || - lexicalEnvironmentStatements + lexicalEnvironmentVariableDeclarations + || lexicalEnvironmentFunctionDeclarations + || lexicalEnvironmentStatements ) { if (lexicalEnvironmentFunctionDeclarations) { statements = [...lexicalEnvironmentFunctionDeclarations]; @@ -467,8 +567,10 @@ namespace ts { // Restore the previous lexical environment. lexicalEnvironmentStackOffset--; - lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset]; - lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset]; + lexicalEnvironmentVariableDeclarations = + lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset]; + lexicalEnvironmentFunctionDeclarations = + lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset]; lexicalEnvironmentStatements = lexicalEnvironmentStatementsStack[lexicalEnvironmentStackOffset]; lexicalEnvironmentFlags = lexicalEnvironmentFlagsStack[lexicalEnvironmentStackOffset]; if (lexicalEnvironmentStackOffset === 0) { @@ -481,9 +583,9 @@ namespace ts { } function setLexicalEnvironmentFlags(flags: LexicalEnvironmentFlags, value: boolean): void { - lexicalEnvironmentFlags = value ? - lexicalEnvironmentFlags | flags : - lexicalEnvironmentFlags & ~flags; + lexicalEnvironmentFlags = value + ? lexicalEnvironmentFlags | flags + : lexicalEnvironmentFlags & ~flags; } function getLexicalEnvironmentFlags(): LexicalEnvironmentFlags { @@ -494,8 +596,14 @@ namespace ts { * Starts a block scope. Any existing block hoisted variables are pushed onto the stack and the related storage variables are reset. */ function startBlockScope() { - Debug.assert(state > TransformationState.Uninitialized, "Cannot start a block scope during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot start a block scope after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot start a block scope during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot start a block scope after transformation has completed.", + ); blockScopedVariableDeclarationsStack[blockScopeStackOffset] = blockScopedVariableDeclarations; blockScopeStackOffset++; blockScopedVariableDeclarations = undefined!; @@ -506,13 +614,18 @@ namespace ts { */ function endBlockScope() { Debug.assert(state > TransformationState.Uninitialized, "Cannot end a block scope during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot end a block scope after transformation has completed."); - const statements: Statement[] | undefined = some(blockScopedVariableDeclarations) ? - [ + Debug.assert( + state < TransformationState.Completed, + "Cannot end a block scope after transformation has completed.", + ); + const statements: Statement[] | undefined = some(blockScopedVariableDeclarations) + ? [ factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - blockScopedVariableDeclarations.map(identifier => factory.createVariableDeclaration(identifier)), + blockScopedVariableDeclarations.map(identifier => + factory.createVariableDeclaration(identifier) + ), NodeFlags.Let, ), ), @@ -531,8 +644,14 @@ namespace ts { } function requestEmitHelper(helper: EmitHelper): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the transformation context during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the transformation context after transformation has completed.", + ); Debug.assert(!helper.scoped, "Cannot request a scoped emit helper."); if (helper.dependencies) { for (const h of helper.dependencies) { @@ -543,8 +662,14 @@ namespace ts { } function readEmitHelpers(): EmitHelper[] | undefined { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the transformation context during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the transformation context after transformation has completed.", + ); const helpers = emitHelpers; emitHelpers = undefined; return helpers; diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index 73dfdf7cf07ba..b5bc37e694868 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -148,7 +148,8 @@ namespace ts { // Transform field initializers using Define semantics when `useDefineForClassFields: true` and target < ES2022. const shouldTransformInitializersUsingDefine = useDefineForClassFields && languageVersion < ScriptTarget.ES2022; - const shouldTransformInitializers = shouldTransformInitializersUsingSet || shouldTransformInitializersUsingDefine; + const shouldTransformInitializers = shouldTransformInitializersUsingSet + || shouldTransformInitializersUsingDefine; // We need to transform private members and class static blocks when target < ES2022. const shouldTransformPrivateElementsOrClassStaticBlocks = languageVersion < ScriptTarget.ES2022; @@ -162,11 +163,12 @@ namespace ts { // We don't need to transform `super` property access when target <= ES5 because // the es2015 transformation handles those. - const shouldTransformSuperInStaticInitializers = shouldTransformThisInStaticInitializers && languageVersion >= ScriptTarget.ES2015; + const shouldTransformSuperInStaticInitializers = shouldTransformThisInStaticInitializers + && languageVersion >= ScriptTarget.ES2015; - const shouldTransformAnything = shouldTransformInitializers || - shouldTransformPrivateElementsOrClassStaticBlocks || - shouldTransformAutoAccessors; + const shouldTransformAnything = shouldTransformInitializers + || shouldTransformPrivateElementsOrClassStaticBlocks + || shouldTransformAutoAccessors; const previousOnSubstituteNode = context.onSubstituteNode; context.onSubstituteNode = onSubstituteNode; @@ -196,7 +198,10 @@ namespace ts { let currentClassLexicalEnvironment: ClassLexicalEnvironment | undefined; let currentClassContainer: ClassLikeDeclaration | undefined; let currentComputedPropertyNameClassLexicalEnvironment: ClassLexicalEnvironment | undefined; - let currentStaticPropertyDeclarationOrStaticBlock: PropertyDeclaration | ClassStaticBlockDeclaration | undefined; + let currentStaticPropertyDeclarationOrStaticBlock: + | PropertyDeclaration + | ClassStaticBlockDeclaration + | undefined; return chainBundle(context, transformSourceFile); @@ -212,8 +217,8 @@ namespace ts { function visitor(node: Node): VisitResult { if ( - !(node.transformFlags & TransformFlags.ContainsClassFields) && - !(node.transformFlags & TransformFlags.ContainsLexicalThisOrSuper) + !(node.transformFlags & TransformFlags.ContainsClassFields) + && !(node.transformFlags & TransformFlags.ContainsLexicalThisOrSuper) ) { return node; } @@ -239,7 +244,10 @@ namespace ts { return visitElementAccessExpression(node as ElementAccessExpression); case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPreOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, /*valueIsDiscarded*/ false); + return visitPreOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + /*valueIsDiscarded*/ false, + ); case SyntaxKind.BinaryExpression: return visitBinaryExpression(node as BinaryExpression, /*valueIsDiscarded*/ false); case SyntaxKind.CallExpression: @@ -279,7 +287,10 @@ namespace ts { switch (node.kind) { case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPreOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, /*valueIsDiscarded*/ true); + return visitPreOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + /*valueIsDiscarded*/ true, + ); case SyntaxKind.BinaryExpression: return visitBinaryExpression(node as BinaryExpression, /*valueIsDiscarded*/ true); default: @@ -355,7 +366,10 @@ namespace ts { case SyntaxKind.SetAccessor: return classElementVisitor(node); default: - Debug.assertMissingNode(node, "Expected node to either be a PropertyDeclaration, GetAccessorDeclaration, or SetAccessorDeclaration"); + Debug.assertMissingNode( + node, + "Expected node to either be a PropertyDeclaration, GetAccessorDeclaration, or SetAccessorDeclaration", + ); break; } } @@ -376,7 +390,10 @@ namespace ts { return setOriginalNode(factory.createIdentifier(""), node); } - type PrivateIdentifierInExpression = BinaryExpression & { readonly left: PrivateIdentifier; readonly token: InKeyword; }; + type PrivateIdentifierInExpression = BinaryExpression & { + readonly left: PrivateIdentifier; + readonly token: InKeyword; + }; function isPrivateIdentifierInExpression(node: BinaryExpression): node is PrivateIdentifierInExpression { return isPrivateIdentifier(node.left) @@ -406,9 +423,9 @@ namespace ts { pendingStatements = []; const visitedNode = visitEachChild(node, visitor, context); - const statement = some(pendingStatements) ? - [visitedNode, ...pendingStatements] : - visitedNode; + const statement = some(pendingStatements) + ? [visitedNode, ...pendingStatements] + : visitedNode; pendingStatements = savedPendingStatements; return statement; @@ -418,7 +435,10 @@ namespace ts { let expression = visitNode(node.expression, visitor, isExpression); if (some(pendingExpressions)) { if (isParenthesizedExpression(expression)) { - expression = factory.updateParenthesizedExpression(expression, factory.inlineExpressions([...pendingExpressions, expression.expression])); + expression = factory.updateParenthesizedExpression( + expression, + factory.inlineExpressions([...pendingExpressions, expression.expression]), + ); } else { expression = factory.inlineExpressions([...pendingExpressions, expression]); @@ -455,7 +475,10 @@ namespace ts { factory.createAssignment( functionName, factory.createFunctionExpression( - filter(node.modifiers, (m): m is Modifier => isModifier(m) && !isStaticModifier(m) && !isAccessorModifier(m)), + filter( + node.modifiers, + (m): m is Modifier => isModifier(m) && !isStaticModifier(m) && !isAccessorModifier(m), + ), node.asteriskToken, functionName, /* typeParameters */ undefined, @@ -582,7 +605,10 @@ namespace ts { // If it's not inlineable, then we emit an expression after the class which assigns // the property name to the temporary variable. - const expr = getPropertyNameExpressionIfNeeded(node.name, /*shouldHoist*/ !!node.initializer || useDefineForClassFields); + const expr = getPropertyNameExpressionIfNeeded( + node.name, + /*shouldHoist*/ !!node.initializer || useDefineForClassFields, + ); if (expr) { getPendingExpressions().push(expr); } @@ -614,9 +640,9 @@ namespace ts { function transformFieldInitializer(node: PropertyDeclaration) { Debug.assert(!hasDecorators(node), "Decorators should already have been transformed and elided."); - return isPrivateIdentifierClassElementDeclaration(node) ? - transformPrivateFieldInitializer(node) : - transformPublicFieldInitializer(node); + return isPrivateIdentifierClassElementDeclaration(node) + ? transformPrivateFieldInitializer(node) + : transformPublicFieldInitializer(node); } function visitPropertyDeclaration(node: PropertyDeclaration) { @@ -677,11 +703,11 @@ namespace ts { } } if ( - shouldTransformSuperInStaticInitializers && - isSuperProperty(node) && - isIdentifier(node.name) && - currentStaticPropertyDeclarationOrStaticBlock && - currentClassLexicalEnvironment + shouldTransformSuperInStaticInitializers + && isSuperProperty(node) + && isIdentifier(node.name) + && currentStaticPropertyDeclarationOrStaticBlock + && currentClassLexicalEnvironment ) { const { classConstructor, superClassReference, facts } = currentClassLexicalEnvironment; if (facts & ClassFacts.ClassWasDecorated) { @@ -704,10 +730,10 @@ namespace ts { function visitElementAccessExpression(node: ElementAccessExpression) { if ( - shouldTransformSuperInStaticInitializers && - isSuperProperty(node) && - currentStaticPropertyDeclarationOrStaticBlock && - currentClassLexicalEnvironment + shouldTransformSuperInStaticInitializers + && isSuperProperty(node) + && currentStaticPropertyDeclarationOrStaticBlock + && currentClassLexicalEnvironment ) { const { classConstructor, superClassReference, facts } = currentClassLexicalEnvironment; if (facts & ClassFacts.ClassWasDecorated) { @@ -729,15 +755,18 @@ namespace ts { return visitEachChild(node, visitor, context); } - function visitPreOrPostfixUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded: boolean) { + function visitPreOrPostfixUnaryExpression( + node: PrefixUnaryExpression | PostfixUnaryExpression, + valueIsDiscarded: boolean, + ) { if ( - node.operator === SyntaxKind.PlusPlusToken || - node.operator === SyntaxKind.MinusMinusToken + node.operator === SyntaxKind.PlusPlusToken + || node.operator === SyntaxKind.MinusMinusToken ) { const operand = skipParentheses(node.operand); if ( - shouldTransformPrivateElementsOrClassStaticBlocks && - isPrivateIdentifierPropertyAccessExpression(operand) + shouldTransformPrivateElementsOrClassStaticBlocks + && isPrivateIdentifierPropertyAccessExpression(operand) ) { let info: PrivateIdentifierInfo | undefined; if (info = accessPrivateIdentifier(operand.name)) { @@ -745,8 +774,15 @@ namespace ts { const { readExpression, initializeExpression } = createCopiableReceiverExpr(receiver); let expression: Expression = createPrivateIdentifierAccess(info, readExpression); - const temp = isPrefixUnaryExpression(node) || valueIsDiscarded ? undefined : factory.createTempVariable(hoistVariableDeclaration); - expression = expandPreOrPostfixIncrementOrDecrementExpression(factory, node, expression, hoistVariableDeclaration, temp); + const temp = isPrefixUnaryExpression(node) || valueIsDiscarded ? undefined + : factory.createTempVariable(hoistVariableDeclaration); + expression = expandPreOrPostfixIncrementOrDecrementExpression( + factory, + node, + expression, + hoistVariableDeclaration, + temp, + ); expression = createPrivateIdentifierAssignment( info, initializeExpression || readExpression, @@ -763,10 +799,10 @@ namespace ts { } } else if ( - shouldTransformSuperInStaticInitializers && - isSuperProperty(operand) && - currentStaticPropertyDeclarationOrStaticBlock && - currentClassLexicalEnvironment + shouldTransformSuperInStaticInitializers + && isSuperProperty(operand) + && currentStaticPropertyDeclarationOrStaticBlock + && currentClassLexicalEnvironment ) { // converts `++super.a` into `(Reflect.set(_baseTemp, "a", (_a = Reflect.get(_baseTemp, "a", _classTemp), _b = ++_a), _classTemp), _b)` // converts `++super[f()]` into `(Reflect.set(_baseTemp, _a = f(), (_b = Reflect.get(_baseTemp, _a, _classTemp), _c = ++_b), _classTemp), _c)` @@ -779,9 +815,9 @@ namespace ts { const { classConstructor, superClassReference, facts } = currentClassLexicalEnvironment; if (facts & ClassFacts.ClassWasDecorated) { const expression = visitInvalidSuperProperty(operand); - return isPrefixUnaryExpression(node) ? - factory.updatePrefixUnaryExpression(node, expression) : - factory.updatePostfixUnaryExpression(node, expression); + return isPrefixUnaryExpression(node) + ? factory.updatePrefixUnaryExpression(node, expression) + : factory.updatePostfixUnaryExpression(node, expression); } if (classConstructor && superClassReference) { let setterName: Expression | undefined; @@ -797,16 +833,35 @@ namespace ts { } else { getterName = factory.createTempVariable(hoistVariableDeclaration); - setterName = factory.createAssignment(getterName, visitNode(operand.argumentExpression, visitor, isExpression)); + setterName = factory.createAssignment( + getterName, + visitNode(operand.argumentExpression, visitor, isExpression), + ); } } if (setterName && getterName) { - let expression: Expression = factory.createReflectGetCall(superClassReference, getterName, classConstructor); + let expression: Expression = factory.createReflectGetCall( + superClassReference, + getterName, + classConstructor, + ); setTextRange(expression, operand); - const temp = valueIsDiscarded ? undefined : factory.createTempVariable(hoistVariableDeclaration); - expression = expandPreOrPostfixIncrementOrDecrementExpression(factory, node, expression, hoistVariableDeclaration, temp); - expression = factory.createReflectSetCall(superClassReference, setterName, expression, classConstructor); + const temp = valueIsDiscarded ? undefined + : factory.createTempVariable(hoistVariableDeclaration); + expression = expandPreOrPostfixIncrementOrDecrementExpression( + factory, + node, + expression, + hoistVariableDeclaration, + temp, + ); + expression = factory.createReflectSetCall( + superClassReference, + setterName, + expression, + classConstructor, + ); setOriginalNode(expression, node); setTextRange(expression, node); if (temp) { @@ -838,7 +893,9 @@ namespace ts { ); } - function createCopiableReceiverExpr(receiver: Expression): { readExpression: Expression; initializeExpression: Expression | undefined; } { + function createCopiableReceiverExpr( + receiver: Expression, + ): { readExpression: Expression; initializeExpression: Expression | undefined; } { const clone = nodeIsSynthesized(receiver) ? receiver : factory.cloneNode(receiver); if (isSimpleInlineableExpression(receiver)) { return { readExpression: clone, initializeExpression: undefined }; @@ -850,20 +907,27 @@ namespace ts { function visitCallExpression(node: CallExpression) { if ( - shouldTransformPrivateElementsOrClassStaticBlocks && - isPrivateIdentifierPropertyAccessExpression(node.expression) + shouldTransformPrivateElementsOrClassStaticBlocks + && isPrivateIdentifierPropertyAccessExpression(node.expression) ) { // obj.#x() // Transform call expressions of private names to properly bind the `this` parameter. - const { thisArg, target } = factory.createCallBinding(node.expression, hoistVariableDeclaration, languageVersion); + const { thisArg, target } = factory.createCallBinding( + node.expression, + hoistVariableDeclaration, + languageVersion, + ); if (isCallChain(node)) { return factory.updateCallChain( node, factory.createPropertyAccessChain(visitNode(target, visitor), node.questionDotToken, "call"), /*questionDotToken*/ undefined, /*typeArguments*/ undefined, - [visitNode(thisArg, visitor, isExpression), ...visitNodes(node.arguments, visitor, isExpression)], + [ + visitNode(thisArg, visitor, isExpression), + ...visitNodes(node.arguments, visitor, isExpression), + ], ); } return factory.updateCallExpression( @@ -875,10 +939,10 @@ namespace ts { } if ( - shouldTransformSuperInStaticInitializers && - isSuperProperty(node.expression) && - currentStaticPropertyDeclarationOrStaticBlock && - currentClassLexicalEnvironment?.classConstructor + shouldTransformSuperInStaticInitializers + && isSuperProperty(node.expression) + && currentStaticPropertyDeclarationOrStaticBlock + && currentClassLexicalEnvironment?.classConstructor ) { // super.x() // super[x]() @@ -899,11 +963,15 @@ namespace ts { function visitTaggedTemplateExpression(node: TaggedTemplateExpression) { if ( - shouldTransformPrivateElementsOrClassStaticBlocks && - isPrivateIdentifierPropertyAccessExpression(node.tag) + shouldTransformPrivateElementsOrClassStaticBlocks + && isPrivateIdentifierPropertyAccessExpression(node.tag) ) { // Bind the `this` correctly for tagged template literals when the tag is a private identifier property access. - const { thisArg, target } = factory.createCallBinding(node.tag, hoistVariableDeclaration, languageVersion); + const { thisArg, target } = factory.createCallBinding( + node.tag, + hoistVariableDeclaration, + languageVersion, + ); return factory.updateTaggedTemplateExpression( node, factory.createCallExpression( @@ -916,10 +984,10 @@ namespace ts { ); } if ( - shouldTransformSuperInStaticInitializers && - isSuperProperty(node.tag) && - currentStaticPropertyDeclarationOrStaticBlock && - currentClassLexicalEnvironment?.classConstructor + shouldTransformSuperInStaticInitializers + && isSuperProperty(node.tag) + && currentStaticPropertyDeclarationOrStaticBlock + && currentClassLexicalEnvironment?.classConstructor ) { // converts `` super.f`x` `` into `` Reflect.get(_baseTemp, "f", _classTemp).bind(_classTemp)`x` `` const invocation = factory.createFunctionBindCall( @@ -974,23 +1042,28 @@ namespace ts { node.operatorToken, visitNode(node.right, visitor), ); - const expr = some(pendingExpressions) ? - factory.inlineExpressions(compact([...pendingExpressions, node])) : - node; + const expr = some(pendingExpressions) + ? factory.inlineExpressions(compact([...pendingExpressions, node])) + : node; pendingExpressions = savedPendingExpressions; return expr; } if (isAssignmentExpression(node)) { if ( - shouldTransformPrivateElementsOrClassStaticBlocks && - isPrivateIdentifierPropertyAccessExpression(node.left) + shouldTransformPrivateElementsOrClassStaticBlocks + && isPrivateIdentifierPropertyAccessExpression(node.left) ) { // obj.#x = ... const info = accessPrivateIdentifier(node.left.name); if (info) { return setTextRange( setOriginalNode( - createPrivateIdentifierAssignment(info, node.left.expression, node.right, node.operatorToken.kind), + createPrivateIdentifierAssignment( + info, + node.left.expression, + node.right, + node.operatorToken.kind, + ), node, ), node, @@ -998,10 +1071,10 @@ namespace ts { } } else if ( - shouldTransformSuperInStaticInitializers && - isSuperProperty(node.left) && - currentStaticPropertyDeclarationOrStaticBlock && - currentClassLexicalEnvironment + shouldTransformSuperInStaticInitializers + && isSuperProperty(node.left) + && currentStaticPropertyDeclarationOrStaticBlock + && currentClassLexicalEnvironment ) { // super.x = ... // super[x] = ... @@ -1017,9 +1090,10 @@ namespace ts { ); } if (classConstructor && superClassReference) { - let setterName = isElementAccessExpression(node.left) ? visitNode(node.left.argumentExpression, visitor, isExpression) : - isIdentifier(node.left.name) ? factory.createStringLiteralFromNode(node.left.name) : - undefined; + let setterName = isElementAccessExpression(node.left) + ? visitNode(node.left.argumentExpression, visitor, isExpression) + : isIdentifier(node.left.name) ? factory.createStringLiteralFromNode(node.left.name) + : undefined; if (setterName) { // converts `super.x = 1` into `(Reflect.set(_baseTemp, "x", _a = 1, _classTemp), _a)` // converts `super[f()] = 1` into `(Reflect.set(_baseTemp, f(), _a = 1, _classTemp), _a)` @@ -1049,7 +1123,8 @@ namespace ts { setTextRange(expression, node); } - const temp = valueIsDiscarded ? undefined : factory.createTempVariable(hoistVariableDeclaration); + const temp = valueIsDiscarded ? undefined + : factory.createTempVariable(hoistVariableDeclaration); if (temp) { expression = factory.createAssignment(temp, expression); setTextRange(temp, node); @@ -1075,8 +1150,8 @@ namespace ts { } } if ( - shouldTransformPrivateElementsOrClassStaticBlocks && - isPrivateIdentifierInExpression(node) + shouldTransformPrivateElementsOrClassStaticBlocks + && isPrivateIdentifierInExpression(node) ) { // #x in obj return transformPrivateIdentifierInInExpression(node); @@ -1084,7 +1159,12 @@ namespace ts { return visitEachChild(node, visitor, context); } - function createPrivateIdentifierAssignment(info: PrivateIdentifierInfo, receiver: Expression, right: Expression, operator: AssignmentOperator): Expression { + function createPrivateIdentifierAssignment( + info: PrivateIdentifierInfo, + receiver: Expression, + right: Expression, + operator: AssignmentOperator, + ): Expression { receiver = visitNode(receiver, visitor, isExpression); right = visitNode(right, visitor, isExpression); @@ -1142,17 +1222,26 @@ namespace ts { } for (const member of node.members) { if (!isStatic(member)) continue; - if (member.name && (isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) && shouldTransformPrivateElementsOrClassStaticBlocks) { + if ( + member.name && (isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) + && shouldTransformPrivateElementsOrClassStaticBlocks + ) { facts |= ClassFacts.NeedsClassConstructorReference; } if (isPropertyDeclaration(member) || isClassStaticBlockDeclaration(member)) { - if (shouldTransformThisInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalThis) { + if ( + shouldTransformThisInStaticInitializers + && member.transformFlags & TransformFlags.ContainsLexicalThis + ) { facts |= ClassFacts.NeedsSubstitutionForThisInClassStaticField; if (!(facts & ClassFacts.ClassWasDecorated)) { facts |= ClassFacts.NeedsClassConstructorReference; } } - if (shouldTransformSuperInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalSuper) { + if ( + shouldTransformSuperInStaticInitializers + && member.transformFlags & TransformFlags.ContainsLexicalSuper + ) { if (!(facts & ClassFacts.ClassWasDecorated)) { facts |= ClassFacts.NeedsClassConstructorReference | ClassFacts.NeedsClassSuperReference; } @@ -1179,7 +1268,10 @@ namespace ts { return visitEachChild(node, visitor, context); } - function visitInNewClassLexicalEnvironment(node: T, visitor: (node: T, facts: ClassFacts) => U) { + function visitInNewClassLexicalEnvironment( + node: T, + visitor: (node: T, facts: ClassFacts) => U, + ) { const savedCurrentClassContainer = currentClassContainer; const savedPendingExpressions = pendingExpressions; currentClassContainer = node; @@ -1268,7 +1360,11 @@ namespace ts { const staticProperties = getStaticPropertiesAndClassStaticBlock(node); if (some(staticProperties)) { - addPropertyOrClassStaticBlockStatements(statements, staticProperties, factory.getInternalName(node)); + addPropertyOrClassStaticBlockStatements( + statements, + staticProperties, + factory.getInternalName(node), + ); } } @@ -1279,7 +1375,10 @@ namespace ts { return visitInNewClassLexicalEnvironment(node, visitClassExpressionInNewClassLexicalEnvironment); } - function visitClassExpressionInNewClassLexicalEnvironment(node: ClassExpression, facts: ClassFacts): Expression { + function visitClassExpressionInNewClassLexicalEnvironment( + node: ClassExpression, + facts: ClassFacts, + ): Expression { // If this class expression is a transformation of a decorated class declaration, // then we want to output the pendingExpressions as statements, not as inlined // expressions with the class statement. @@ -1291,13 +1390,17 @@ namespace ts { const staticPropertiesOrClassStaticBlocks = getStaticPropertiesAndClassStaticBlock(node); - const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference; + const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) + & NodeCheckFlags.ClassWithConstructorReference; let temp: Identifier | undefined; function createClassTempVar() { const classCheckFlags = resolver.getNodeCheckFlags(node); const isClassWithConstructorReference = classCheckFlags & NodeCheckFlags.ClassWithConstructorReference; const requiresBlockScopedVar = classCheckFlags & NodeCheckFlags.BlockScopedBindingInLoop; - return factory.createTempVariable(requiresBlockScopedVar ? addBlockScopedVariable : hoistVariableDeclaration, !!isClassWithConstructorReference); + return factory.createTempVariable( + requiresBlockScopedVar ? addBlockScopedVariable : hoistVariableDeclaration, + !!isClassWithConstructorReference, + ); } if (facts & ClassFacts.NeedsClassConstructorReference) { @@ -1324,23 +1427,32 @@ namespace ts { // Static initializers are transformed to `static {}` blocks when `useDefineForClassFields: false` // and not also transforming static blocks. - const hasTransformableStatics = shouldTransformPrivateElementsOrClassStaticBlocks && - some(staticPropertiesOrClassStaticBlocks, node => - isClassStaticBlockDeclaration(node) || - isPrivateIdentifierClassElementDeclaration(node) || - shouldTransformInitializers && isInitializedProperty(node)); + const hasTransformableStatics = shouldTransformPrivateElementsOrClassStaticBlocks + && some(staticPropertiesOrClassStaticBlocks, node => + isClassStaticBlockDeclaration(node) + || isPrivateIdentifierClassElementDeclaration(node) + || shouldTransformInitializers && isInitializedProperty(node)); if (hasTransformableStatics || some(pendingExpressions)) { if (isDecoratedClassDeclaration) { - Debug.assertIsDefined(pendingStatements, "Decorated classes transformed by TypeScript are expected to be within a variable declaration."); + Debug.assertIsDefined( + pendingStatements, + "Decorated classes transformed by TypeScript are expected to be within a variable declaration.", + ); // Write any pending expressions from elided or moved computed property names if (pendingStatements && pendingExpressions && some(pendingExpressions)) { - pendingStatements.push(factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))); + pendingStatements.push( + factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions)), + ); } if (pendingStatements && some(staticPropertiesOrClassStaticBlocks)) { - addPropertyOrClassStaticBlockStatements(pendingStatements, staticPropertiesOrClassStaticBlocks, factory.getInternalName(node)); + addPropertyOrClassStaticBlockStatements( + pendingStatements, + staticPropertiesOrClassStaticBlocks, + factory.getInternalName(node), + ); } if (temp) { @@ -1372,7 +1484,13 @@ namespace ts { expressions.push(startOnNewLine(factory.createAssignment(temp, classExpression))); // Add any pending expressions leftover from elided or relocated computed property names addRange(expressions, map(pendingExpressions, startOnNewLine)); - addRange(expressions, generateInitializedPropertyExpressionsOrClassStaticBlock(staticPropertiesOrClassStaticBlocks, temp)); + addRange( + expressions, + generateInitializedPropertyExpressionsOrClassStaticBlock( + staticPropertiesOrClassStaticBlocks, + temp, + ), + ); expressions.push(startOnNewLine(temp)); } } @@ -1399,7 +1517,11 @@ namespace ts { if (shouldTransformPrivateElementsOrClassStaticBlocks) { for (const member of node.members) { if (isPrivateIdentifierClassElementDeclaration(member)) { - addPrivateIdentifierToEnvironment(member, member.name, addPrivateIdentifierClassElementToEnvironment); + addPrivateIdentifierToEnvironment( + member, + member.name, + addPrivateIdentifierClassElementToEnvironment, + ); } } if (some(getPrivateInstanceMethodsAndAccessors(node))) { @@ -1408,8 +1530,16 @@ namespace ts { if (shouldTransformAutoAccessors) { for (const member of node.members) { if (isAutoAccessorPropertyDeclaration(member)) { - const storageName = factory.getGeneratedPrivateNameForNode(member.name, /*prefix*/ undefined, "_accessor_storage"); - addPrivateIdentifierToEnvironment(member, storageName, addPrivateIdentifierPropertyDeclarationToEnvironment); + const storageName = factory.getGeneratedPrivateNameForNode( + member.name, + /*prefix*/ undefined, + "_accessor_storage", + ); + addPrivateIdentifierToEnvironment( + member, + storageName, + addPrivateIdentifierPropertyDeclarationToEnvironment, + ); } } } @@ -1446,7 +1576,9 @@ namespace ts { factory.createBlock([statement]), ); prologue = factory.createAssignment(temp, arrow); - statement = factory.createExpressionStatement(factory.createCallExpression(temp, /*typeArguments*/ undefined, [])); + statement = factory.createExpressionStatement( + factory.createCallExpression(temp, /*typeArguments*/ undefined, []), + ); } const block = factory.createBlock([statement]); @@ -1488,20 +1620,26 @@ namespace ts { return false; } - return shouldTransformInitializersUsingDefine && isPropertyDeclaration(member) || - shouldTransformInitializersUsingSet && isInitializedProperty(member) || - shouldTransformPrivateElementsOrClassStaticBlocks && isPrivateIdentifierClassElementDeclaration(member) || - shouldTransformPrivateElementsOrClassStaticBlocks && shouldTransformAutoAccessors && isAutoAccessorPropertyDeclaration(member); + return shouldTransformInitializersUsingDefine && isPropertyDeclaration(member) + || shouldTransformInitializersUsingSet && isInitializedProperty(member) + || shouldTransformPrivateElementsOrClassStaticBlocks + && isPrivateIdentifierClassElementDeclaration(member) + || shouldTransformPrivateElementsOrClassStaticBlocks && shouldTransformAutoAccessors + && isAutoAccessorPropertyDeclaration(member); } - function transformConstructor(constructor: ConstructorDeclaration | undefined, container: ClassDeclaration | ClassExpression) { + function transformConstructor( + constructor: ConstructorDeclaration | undefined, + container: ClassDeclaration | ClassExpression, + ) { constructor = visitNode(constructor, visitor, isConstructorDeclaration); if (!some(container.members, isClassElementThatRequiresConstructorStatement)) { return constructor; } const extendsClauseElement = getEffectiveBaseTypeNode(container); - const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); + const isDerivedClass = !!(extendsClauseElement + && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); const parameters = visitParameterList(constructor ? constructor.parameters : undefined, visitor, context); const body = transformConstructorBody(container, constructor, isDerivedClass); if (!body) { @@ -1528,10 +1666,18 @@ namespace ts { ); } - function transformConstructorBody(node: ClassDeclaration | ClassExpression, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) { + function transformConstructorBody( + node: ClassDeclaration | ClassExpression, + constructor: ConstructorDeclaration | undefined, + isDerivedClass: boolean, + ) { let properties = getProperties(node, /*requireInitializer*/ false, /*isStatic*/ false); if (!useDefineForClassFields) { - properties = filter(properties, property => !!property.initializer || isPrivateIdentifier(property.name) || hasAccessorModifier(property)); + properties = filter( + properties, + property => + !!property.initializer || isPrivateIdentifier(property.name) || hasAccessorModifier(property), + ); } const privateMethodsAndAccessors = getPrivateInstanceMethodsAndAccessors(node); @@ -1551,7 +1697,12 @@ namespace ts { let statements: Statement[] = []; if (constructor?.body?.statements) { - prologueStatementCount = factory.copyPrologue(constructor.body.statements, statements, /*ensureUseStrict*/ false, visitor); + prologueStatementCount = factory.copyPrologue( + constructor.body.statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); superStatementIndex = findSuperStatementIndex(constructor.body.statements, prologueStatementCount); // If there was a super call, visit existing statements up to and including it @@ -1559,7 +1710,13 @@ namespace ts { indexOfFirstStatementAfterSuperAndPrologue = superStatementIndex + 1; statements = [ ...statements.slice(0, prologueStatementCount), - ...visitNodes(constructor.body.statements, visitor, isStatement, prologueStatementCount, indexOfFirstStatementAfterSuperAndPrologue - prologueStatementCount), + ...visitNodes( + constructor.body.statements, + visitor, + isStatement, + prologueStatementCount, + indexOfFirstStatementAfterSuperAndPrologue - prologueStatementCount, + ), ...statements.slice(prologueStatementCount), ]; } @@ -1599,7 +1756,9 @@ namespace ts { let parameterPropertyDeclarationCount = 0; if (constructor?.body) { if (useDefineForClassFields) { - statements = statements.filter(statement => !isParameterPropertyDeclaration(getOriginalNode(statement), constructor)); + statements = statements.filter(statement => + !isParameterPropertyDeclaration(getOriginalNode(statement), constructor) + ); } else { for (const statement of constructor.body.statements) { @@ -1608,7 +1767,13 @@ namespace ts { } } if (parameterPropertyDeclarationCount > 0) { - const parameterProperties = visitNodes(constructor.body.statements, visitor, isStatement, indexOfFirstStatementAfterSuperAndPrologue, parameterPropertyDeclarationCount); + const parameterProperties = visitNodes( + constructor.body.statements, + visitor, + isStatement, + indexOfFirstStatementAfterSuperAndPrologue, + parameterPropertyDeclarationCount, + ); // If there was a super() call found, add parameter properties immediately after it if (superStatementIndex >= 0) { @@ -1638,7 +1803,15 @@ namespace ts { // Add existing statements after the initial prologues and super call if (constructor) { - addRange(statements, visitNodes(constructor.body!.statements, visitBodyStatement, isStatement, indexOfFirstStatementAfterSuperAndPrologue)); + addRange( + statements, + visitNodes( + constructor.body!.statements, + visitBodyStatement, + isStatement, + indexOfFirstStatementAfterSuperAndPrologue, + ), + ); } statements = factory.mergeLexicalEnvironment(statements, endLexicalEnvironment()); @@ -1647,9 +1820,9 @@ namespace ts { return undefined; } - const multiLine = constructor?.body && constructor.body.statements.length >= statements.length ? - constructor.body.multiLine ?? statements.length > 0 : - statements.length > 0; + const multiLine = constructor?.body && constructor.body.statements.length >= statements.length + ? constructor.body.multiLine ?? statements.length > 0 + : statements.length > 0; return setTextRange( factory.createBlock( @@ -1663,7 +1836,9 @@ namespace ts { ); function visitBodyStatement(statement: Node) { - if (useDefineForClassFields && isParameterPropertyDeclaration(getOriginalNode(statement), constructor!)) { + if ( + useDefineForClassFields && isParameterPropertyDeclaration(getOriginalNode(statement), constructor!) + ) { return undefined; } @@ -1677,9 +1852,15 @@ namespace ts { * @param properties An array of property declarations to transform. * @param receiver The receiver on which each property should be assigned. */ - function addPropertyOrClassStaticBlockStatements(statements: Statement[], properties: readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[], receiver: LeftHandSideExpression) { + function addPropertyOrClassStaticBlockStatements( + statements: Statement[], + properties: readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[], + receiver: LeftHandSideExpression, + ) { for (const property of properties) { - if (isStatic(property) && !shouldTransformPrivateElementsOrClassStaticBlocks && !useDefineForClassFields) { + if ( + isStatic(property) && !shouldTransformPrivateElementsOrClassStaticBlocks && !useDefineForClassFields + ) { continue; } @@ -1692,10 +1873,13 @@ namespace ts { } } - function transformPropertyOrClassStaticBlock(property: PropertyDeclaration | ClassStaticBlockDeclaration, receiver: LeftHandSideExpression) { - const expression = isClassStaticBlockDeclaration(property) ? - transformClassStaticBlockDeclaration(property) : - transformProperty(property, receiver); + function transformPropertyOrClassStaticBlock( + property: PropertyDeclaration | ClassStaticBlockDeclaration, + receiver: LeftHandSideExpression, + ) { + const expression = isClassStaticBlockDeclaration(property) + ? transformClassStaticBlockDeclaration(property) + : transformProperty(property, receiver); if (!expression) { return undefined; } @@ -1721,10 +1905,14 @@ namespace ts { * @param propertiesOrClassStaticBlocks An array of property declarations to transform. * @param receiver The receiver on which each property should be assigned. */ - function generateInitializedPropertyExpressionsOrClassStaticBlock(propertiesOrClassStaticBlocks: readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[], receiver: LeftHandSideExpression) { + function generateInitializedPropertyExpressionsOrClassStaticBlock( + propertiesOrClassStaticBlocks: readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[], + receiver: LeftHandSideExpression, + ) { const expressions: Expression[] = []; for (const property of propertiesOrClassStaticBlocks) { - const expression = isClassStaticBlockDeclaration(property) ? transformClassStaticBlockDeclaration(property) : transformProperty(property, receiver); + const expression = isClassStaticBlockDeclaration(property) + ? transformClassStaticBlockDeclaration(property) : transformProperty(property, receiver); if (!expression) { continue; } @@ -1762,11 +1950,11 @@ namespace ts { // We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name) const emitAssignment = !useDefineForClassFields; - const propertyName = hasAccessorModifier(property) ? - factory.getGeneratedPrivateNameForNode(property.name) : - isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression) ? - factory.updateComputedPropertyName(property.name, factory.getGeneratedNameForNode(property.name)) : - property.name; + const propertyName = hasAccessorModifier(property) + ? factory.getGeneratedPrivateNameForNode(property.name) + : isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression) + ? factory.updateComputedPropertyName(property.name, factory.getGeneratedNameForNode(property.name)) + : property.name; if (hasStaticModifier(property)) { currentStaticPropertyDeclarationOrStaticBlock = property; @@ -1807,19 +1995,32 @@ namespace ts { return undefined; } - const initializer = property.initializer || emitAssignment ? visitNode(property.initializer, visitor, isExpression) ?? factory.createVoidZero() - : isParameterPropertyDeclaration(propertyOriginalNode, propertyOriginalNode.parent) && isIdentifier(propertyName) ? propertyName + const initializer = property.initializer || emitAssignment + ? visitNode(property.initializer, visitor, isExpression) ?? factory.createVoidZero() + : isParameterPropertyDeclaration(propertyOriginalNode, propertyOriginalNode.parent) + && isIdentifier(propertyName) ? propertyName : factory.createVoidZero(); if (emitAssignment || isPrivateIdentifier(propertyName)) { - const memberAccess = createMemberAccessForPropertyName(factory, receiver, propertyName, /*location*/ propertyName); + const memberAccess = createMemberAccessForPropertyName( + factory, + receiver, + propertyName, + /*location*/ propertyName, + ); return factory.createAssignment(memberAccess, initializer); } else { const name = isComputedPropertyName(propertyName) ? propertyName.expression - : isIdentifier(propertyName) ? factory.createStringLiteral(unescapeLeadingUnderscores(propertyName.escapedText)) + : isIdentifier(propertyName) + ? factory.createStringLiteral(unescapeLeadingUnderscores(propertyName.escapedText)) : propertyName; - const descriptor = factory.createPropertyDescriptor({ value: initializer, configurable: true, writable: true, enumerable: true }); + const descriptor = factory.createPropertyDescriptor({ + value: initializer, + configurable: true, + writable: true, + enumerable: true, + }); return factory.createObjectDefinePropertyCall(receiver, name, descriptor); } } @@ -1868,7 +2069,11 @@ namespace ts { * @param methods An array of method declarations. * @param receiver The receiver on which each method should be assigned. */ - function addMethodStatements(statements: Statement[], methods: readonly (MethodDeclaration | AccessorDeclaration | AutoAccessorPropertyDeclaration)[], receiver: LeftHandSideExpression) { + function addMethodStatements( + statements: Statement[], + methods: readonly (MethodDeclaration | AccessorDeclaration | AutoAccessorPropertyDeclaration)[], + receiver: LeftHandSideExpression, + ) { if (!shouldTransformPrivateElementsOrClassStaticBlocks || !some(methods)) { return; } @@ -1883,13 +2088,13 @@ namespace ts { } function visitInvalidSuperProperty(node: SuperProperty) { - return isPropertyAccessExpression(node) ? - factory.updatePropertyAccessExpression( + return isPropertyAccessExpression(node) + ? factory.updatePropertyAccessExpression( node, factory.createVoidZero(), node.name, - ) : - factory.updateElementAccessExpression( + ) + : factory.updateElementAccessExpression( node, factory.createVoidZero(), visitNode(node.argumentExpression, visitor, isExpression), @@ -1902,12 +2107,14 @@ namespace ts { const classLexicalEnvironment = classLexicalEnvironmentMap.get(original.id); if (classLexicalEnvironment) { const savedClassLexicalEnvironment = currentClassLexicalEnvironment; - const savedCurrentComputedPropertyNameClassLexicalEnvironment = currentComputedPropertyNameClassLexicalEnvironment; + const savedCurrentComputedPropertyNameClassLexicalEnvironment = + currentComputedPropertyNameClassLexicalEnvironment; currentClassLexicalEnvironment = classLexicalEnvironment; currentComputedPropertyNameClassLexicalEnvironment = classLexicalEnvironment; previousOnEmitNode(hint, node, emitCallback); currentClassLexicalEnvironment = savedClassLexicalEnvironment; - currentComputedPropertyNameClassLexicalEnvironment = savedCurrentComputedPropertyNameClassLexicalEnvironment; + currentComputedPropertyNameClassLexicalEnvironment = + savedCurrentComputedPropertyNameClassLexicalEnvironment; return; } } @@ -1922,12 +2129,14 @@ namespace ts { case SyntaxKind.FunctionDeclaration: case SyntaxKind.Constructor: { const savedClassLexicalEnvironment = currentClassLexicalEnvironment; - const savedCurrentComputedPropertyNameClassLexicalEnvironment = currentComputedPropertyNameClassLexicalEnvironment; + const savedCurrentComputedPropertyNameClassLexicalEnvironment = + currentComputedPropertyNameClassLexicalEnvironment; currentClassLexicalEnvironment = undefined; currentComputedPropertyNameClassLexicalEnvironment = undefined; previousOnEmitNode(hint, node, emitCallback); currentClassLexicalEnvironment = savedClassLexicalEnvironment; - currentComputedPropertyNameClassLexicalEnvironment = savedCurrentComputedPropertyNameClassLexicalEnvironment; + currentComputedPropertyNameClassLexicalEnvironment = + savedCurrentComputedPropertyNameClassLexicalEnvironment; return; } @@ -1936,22 +2145,26 @@ namespace ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.PropertyDeclaration: { const savedClassLexicalEnvironment = currentClassLexicalEnvironment; - const savedCurrentComputedPropertyNameClassLexicalEnvironment = currentComputedPropertyNameClassLexicalEnvironment; + const savedCurrentComputedPropertyNameClassLexicalEnvironment = + currentComputedPropertyNameClassLexicalEnvironment; currentComputedPropertyNameClassLexicalEnvironment = currentClassLexicalEnvironment; currentClassLexicalEnvironment = undefined; previousOnEmitNode(hint, node, emitCallback); currentClassLexicalEnvironment = savedClassLexicalEnvironment; - currentComputedPropertyNameClassLexicalEnvironment = savedCurrentComputedPropertyNameClassLexicalEnvironment; + currentComputedPropertyNameClassLexicalEnvironment = + savedCurrentComputedPropertyNameClassLexicalEnvironment; return; } case SyntaxKind.ComputedPropertyName: { const savedClassLexicalEnvironment = currentClassLexicalEnvironment; - const savedCurrentComputedPropertyNameClassLexicalEnvironment = currentComputedPropertyNameClassLexicalEnvironment; + const savedCurrentComputedPropertyNameClassLexicalEnvironment = + currentComputedPropertyNameClassLexicalEnvironment; currentClassLexicalEnvironment = currentComputedPropertyNameClassLexicalEnvironment; currentComputedPropertyNameClassLexicalEnvironment = undefined; previousOnEmitNode(hint, node, emitCallback); currentClassLexicalEnvironment = savedClassLexicalEnvironment; - currentComputedPropertyNameClassLexicalEnvironment = savedCurrentComputedPropertyNameClassLexicalEnvironment; + currentComputedPropertyNameClassLexicalEnvironment = + savedCurrentComputedPropertyNameClassLexicalEnvironment; return; } } @@ -1983,7 +2196,10 @@ namespace ts { } function substituteThisExpression(node: ThisExpression) { - if (enabledSubstitutions & ClassPropertySubstitutionFlags.ClassStaticThisOrSuperReference && currentClassLexicalEnvironment) { + if ( + enabledSubstitutions & ClassPropertySubstitutionFlags.ClassStaticThisOrSuperReference + && currentClassLexicalEnvironment + ) { const { facts, classConstructor } = currentClassLexicalEnvironment; if (facts & ClassFacts.ClassWasDecorated) { return factory.createParenthesizedExpression(factory.createVoidZero()); @@ -2039,7 +2255,8 @@ namespace ts { const expression = visitNode(name.expression, visitor, isExpression); const innerExpression = skipPartiallyEmittedExpressions(expression); const inlinable = isSimpleInlineableExpression(innerExpression); - const alreadyTransformed = isAssignmentExpression(innerExpression) && isGeneratedIdentifier(innerExpression.left); + const alreadyTransformed = isAssignmentExpression(innerExpression) + && isGeneratedIdentifier(innerExpression.left); if (!alreadyTransformed && !inlinable && shouldHoist) { const generatedName = factory.getGeneratedNameForNode(name); if (resolver.getNodeCheckFlags(name) & NodeCheckFlags.BlockScopedBindingInLoop) { @@ -2097,19 +2314,59 @@ namespace ts { previousInfo: PrivateIdentifierInfo | undefined, ) { if (isAutoAccessorPropertyDeclaration(node)) { - addPrivateIdentifierAutoAccessorPropertyDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierAutoAccessorPropertyDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } else if (isPropertyDeclaration(node)) { - addPrivateIdentifierPropertyDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierPropertyDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } else if (isMethodDeclaration(node)) { - addPrivateIdentifierMethodDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierMethodDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } else if (isGetAccessorDeclaration(node)) { - addPrivateIdentifierGetAccessorDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierGetAccessorDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } else if (isSetAccessorDeclaration(node)) { - addPrivateIdentifierSetAccessorDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierSetAccessorDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } } @@ -2166,9 +2423,15 @@ namespace ts { _previousInfo: PrivateIdentifierInfo | undefined, ) { const methodName = createHoistedVariableForPrivateName(name); - const brandCheckIdentifier = isStatic ? - Debug.checkDefined(lex.classConstructor, "classConstructor should be set in private identifier environment") : - Debug.checkDefined(privateEnv.weakSetName, "weakSetName should be set in private identifier environment"); + const brandCheckIdentifier = isStatic + ? Debug.checkDefined( + lex.classConstructor, + "classConstructor should be set in private identifier environment", + ) + : Debug.checkDefined( + privateEnv.weakSetName, + "weakSetName should be set in private identifier environment", + ); setPrivateIdentifier(privateEnv, name, { kind: PrivateIdentifierKind.Method, @@ -2189,11 +2452,20 @@ namespace ts { previousInfo: PrivateIdentifierInfo | undefined, ) { const getterName = createHoistedVariableForPrivateName(name, "_get"); - const brandCheckIdentifier = isStatic ? - Debug.checkDefined(lex.classConstructor, "classConstructor should be set in private identifier environment") : - Debug.checkDefined(privateEnv.weakSetName, "weakSetName should be set in private identifier environment"); + const brandCheckIdentifier = isStatic + ? Debug.checkDefined( + lex.classConstructor, + "classConstructor should be set in private identifier environment", + ) + : Debug.checkDefined( + privateEnv.weakSetName, + "weakSetName should be set in private identifier environment", + ); - if (previousInfo?.kind === PrivateIdentifierKind.Accessor && previousInfo.isStatic === isStatic && !previousInfo.getterName) { + if ( + previousInfo?.kind === PrivateIdentifierKind.Accessor && previousInfo.isStatic === isStatic + && !previousInfo.getterName + ) { previousInfo.getterName = getterName; } else { @@ -2218,11 +2490,20 @@ namespace ts { previousInfo: PrivateIdentifierInfo | undefined, ) { const setterName = createHoistedVariableForPrivateName(name, "_set"); - const brandCheckIdentifier = isStatic ? - Debug.checkDefined(lex.classConstructor, "classConstructor should be set in private identifier environment") : - Debug.checkDefined(privateEnv.weakSetName, "weakSetName should be set in private identifier environment"); + const brandCheckIdentifier = isStatic + ? Debug.checkDefined( + lex.classConstructor, + "classConstructor should be set in private identifier environment", + ) + : Debug.checkDefined( + privateEnv.weakSetName, + "weakSetName should be set in private identifier environment", + ); - if (previousInfo?.kind === PrivateIdentifierKind.Accessor && previousInfo.isStatic === isStatic && !previousInfo.setterName) { + if ( + previousInfo?.kind === PrivateIdentifierKind.Accessor && previousInfo.isStatic === isStatic + && !previousInfo.setterName + ) { previousInfo.setterName = setterName; } else { @@ -2248,9 +2529,15 @@ namespace ts { ) { const getterName = createHoistedVariableForPrivateName(name, "_get"); const setterName = createHoistedVariableForPrivateName(name, "_set"); - const brandCheckIdentifier = isStatic ? - Debug.checkDefined(lex.classConstructor, "classConstructor should be set in private identifier environment") : - Debug.checkDefined(privateEnv.weakSetName, "weakSetName should be set in private identifier environment"); + const brandCheckIdentifier = isStatic + ? Debug.checkDefined( + lex.classConstructor, + "classConstructor should be set in private identifier environment", + ) + : Debug.checkDefined( + privateEnv.weakSetName, + "weakSetName should be set in private identifier environment", + ); setPrivateIdentifier(privateEnv, name, { kind: PrivateIdentifierKind.Accessor, @@ -2262,7 +2549,9 @@ namespace ts { }); } - function addPrivateIdentifierToEnvironment( + function addPrivateIdentifierToEnvironment< + T extends PropertyDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration, + >( node: T, name: PrivateIdentifier, addDeclaration: ( @@ -2283,12 +2572,28 @@ namespace ts { addDeclaration(node, name, lex, privateEnv, isStatic, isValid, previousInfo); } - function createHoistedVariableForClass(name: string | PrivateIdentifier | undefined, node: PrivateIdentifier | ClassStaticBlockDeclaration, suffix?: string): Identifier { + function createHoistedVariableForClass( + name: string | PrivateIdentifier | undefined, + node: PrivateIdentifier | ClassStaticBlockDeclaration, + suffix?: string, + ): Identifier { const { className } = getPrivateIdentifierEnvironment(); const prefix: GeneratedNamePart | string = className ? { prefix: "_", node: className, suffix: "_" } : "_"; - const identifier = typeof name === "object" ? factory.getGeneratedNameForNode(name, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes, prefix, suffix) : - typeof name === "string" ? factory.createUniqueName(name, GeneratedIdentifierFlags.Optimistic, prefix, suffix) : - factory.createTempVariable(/*recordTempVariable*/ undefined, /*reserveInNestedScopes*/ true, prefix, suffix); + const identifier = typeof name === "object" + ? factory.getGeneratedNameForNode( + name, + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes, + prefix, + suffix, + ) + : typeof name === "string" + ? factory.createUniqueName(name, GeneratedIdentifierFlags.Optimistic, prefix, suffix) + : factory.createTempVariable( + /*recordTempVariable*/ undefined, + /*reserveInNestedScopes*/ true, + prefix, + suffix, + ); if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.BlockScopedBindingInLoop) { addBlockScopedVariable(identifier); @@ -2328,11 +2633,17 @@ namespace ts { } function accessPrivateIdentifierWorker( - getPrivateIdentifierInfo: (privateEnv: PrivateIdentifierEnvironment, key: K) => PrivateIdentifierInfo | undefined, + getPrivateIdentifierInfo: ( + privateEnv: PrivateIdentifierEnvironment, + key: K, + ) => PrivateIdentifierInfo | undefined, privateIdentifierKey: K, ) { if (currentClassLexicalEnvironment?.privateIdentifierEnvironment) { - const info = getPrivateIdentifierInfo(currentClassLexicalEnvironment.privateIdentifierEnvironment, privateIdentifierKey); + const info = getPrivateIdentifierInfo( + currentClassLexicalEnvironment.privateIdentifierEnvironment, + privateIdentifierKey, + ); if (info) { return info; } @@ -2363,7 +2674,13 @@ namespace ts { // differently inside the function. if (isThisProperty(node) || isSuperProperty(node) || !isSimpleCopiableExpression(node.expression)) { receiver = factory.createTempVariable(hoistVariableDeclaration, /*reservedInNestedScopes*/ true); - getPendingExpressions().push(factory.createBinaryExpression(receiver, SyntaxKind.EqualsToken, visitNode(node.expression, visitor, isExpression))); + getPendingExpressions().push( + factory.createBinaryExpression( + receiver, + SyntaxKind.EqualsToken, + visitNode(node.expression, visitor, isExpression), + ), + ); } return factory.createAssignmentTargetWrapper( parameter, @@ -2384,19 +2701,20 @@ namespace ts { wrapped = wrapPrivateIdentifierForDestructuringTarget(target); } else if ( - shouldTransformSuperInStaticInitializers && - isSuperProperty(target) && - currentStaticPropertyDeclarationOrStaticBlock && - currentClassLexicalEnvironment + shouldTransformSuperInStaticInitializers + && isSuperProperty(target) + && currentStaticPropertyDeclarationOrStaticBlock + && currentClassLexicalEnvironment ) { const { classConstructor, superClassReference, facts } = currentClassLexicalEnvironment; if (facts & ClassFacts.ClassWasDecorated) { wrapped = visitInvalidSuperProperty(target); } else if (classConstructor && superClassReference) { - const name = isElementAccessExpression(target) ? visitNode(target.argumentExpression, visitor, isExpression) : - isIdentifier(target.name) ? factory.createStringLiteralFromNode(target.name) : - undefined; + const name = isElementAccessExpression(target) + ? visitNode(target.argumentExpression, visitor, isExpression) + : isIdentifier(target.name) ? factory.createStringLiteralFromNode(target.name) + : undefined; if (name) { const temp = factory.createTempVariable(/*recordTempVariable*/ undefined); wrapped = factory.createAssignmentTargetWrapper( @@ -2440,19 +2758,20 @@ namespace ts { wrapped = wrapPrivateIdentifierForDestructuringTarget(target); } else if ( - shouldTransformSuperInStaticInitializers && - isSuperProperty(target) && - currentStaticPropertyDeclarationOrStaticBlock && - currentClassLexicalEnvironment + shouldTransformSuperInStaticInitializers + && isSuperProperty(target) + && currentStaticPropertyDeclarationOrStaticBlock + && currentClassLexicalEnvironment ) { const { classConstructor, superClassReference, facts } = currentClassLexicalEnvironment; if (facts & ClassFacts.ClassWasDecorated) { wrapped = visitInvalidSuperProperty(target); } else if (classConstructor && superClassReference) { - const name = isElementAccessExpression(target) ? visitNode(target.argumentExpression, visitor, isExpression) : - isIdentifier(target.name) ? factory.createStringLiteralFromNode(target.name) : - undefined; + const name = isElementAccessExpression(target) + ? visitNode(target.argumentExpression, visitor, isExpression) + : isIdentifier(target.name) ? factory.createStringLiteralFromNode(target.name) + : undefined; if (name) { const temp = factory.createTempVariable(/*recordTempVariable*/ undefined); wrapped = factory.createAssignmentTargetWrapper( @@ -2473,9 +2792,9 @@ namespace ts { return factory.updatePropertyAssignment( node, visitNode(node.name, visitor, isPropertyName), - wrapped ? - initializer ? factory.createAssignment(wrapped, visitNode(initializer, visitor)) : wrapped : - visitNode(node.initializer, assignmentTargetVisitor, isExpression), + wrapped + ? initializer ? factory.createAssignment(wrapped, visitNode(initializer, visitor)) : wrapped + : visitNode(node.initializer, assignmentTargetVisitor, isExpression), ); } if (isSpreadAssignment(node)) { @@ -2530,7 +2849,11 @@ namespace ts { ); } - function createPrivateInstanceFieldInitializer(receiver: LeftHandSideExpression, initializer: Expression | undefined, weakMapName: Identifier) { + function createPrivateInstanceFieldInitializer( + receiver: LeftHandSideExpression, + initializer: Expression | undefined, + weakMapName: Identifier, + ) { return factory.createCallExpression( factory.createPropertyAccessExpression(weakMapName, "set"), /*typeArguments*/ undefined, @@ -2551,12 +2874,16 @@ namespace ts { } function getPrivateIdentifier(privateEnv: PrivateIdentifierEnvironment, name: PrivateIdentifier) { - return isGeneratedPrivateIdentifier(name) ? - getGeneratedPrivateIdentifierInfo(privateEnv, getNodeForGeneratedName(name)) : - getPrivateIdentifierInfo(privateEnv, name.escapedText); + return isGeneratedPrivateIdentifier(name) + ? getGeneratedPrivateIdentifierInfo(privateEnv, getNodeForGeneratedName(name)) + : getPrivateIdentifierInfo(privateEnv, name.escapedText); } - function setPrivateIdentifier(privateEnv: PrivateIdentifierEnvironment, name: PrivateIdentifier, info: PrivateIdentifierInfo) { + function setPrivateIdentifier( + privateEnv: PrivateIdentifierEnvironment, + name: PrivateIdentifier, + info: PrivateIdentifierInfo, + ) { if (isGeneratedPrivateIdentifier(name)) { privateEnv.generatedIdentifiers ??= new Map(); privateEnv.generatedIdentifiers.set(getNodeForGeneratedName(name), info); diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 6829905fd75f5..67e610d4551d6 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -1,8 +1,20 @@ /*@internal*/ namespace ts { - export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] | undefined { + export function getDeclarationDiagnostics( + host: EmitHost, + resolver: EmitResolver, + file: SourceFile | undefined, + ): DiagnosticWithLocation[] | undefined { const compilerOptions = host.getCompilerOptions(); - const result = transformNodes(resolver, host, factory, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJson), [transformDeclarations], /*allowDtsFiles*/ false); + const result = transformNodes( + resolver, + host, + factory, + compilerOptions, + file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJson), + [transformDeclarations], + /*allowDtsFiles*/ false, + ); return result.diagnostics; } @@ -14,19 +26,34 @@ namespace ts { export function isInternalDeclaration(node: Node, currentSourceFile: SourceFile) { const parseTreeNode = getParseTreeNode(node); if (parseTreeNode && parseTreeNode.kind === SyntaxKind.Parameter) { - const paramIdx = (parseTreeNode.parent as SignatureDeclaration).parameters.indexOf(parseTreeNode as ParameterDeclaration); - const previousSibling = paramIdx > 0 ? (parseTreeNode.parent as SignatureDeclaration).parameters[paramIdx - 1] : undefined; + const paramIdx = (parseTreeNode.parent as SignatureDeclaration).parameters.indexOf( + parseTreeNode as ParameterDeclaration, + ); + const previousSibling = paramIdx > 0 + ? (parseTreeNode.parent as SignatureDeclaration).parameters[paramIdx - 1] : undefined; const text = currentSourceFile.text; const commentRanges = previousSibling ? concatenate( // to handle // ... parameters, /* @internal */ // public param: string - getTrailingCommentRanges(text, skipTrivia(text, previousSibling.end + 1, /* stopAfterLineBreak */ false, /* stopAtComments */ true)), + getTrailingCommentRanges( + text, + skipTrivia( + text, + previousSibling.end + 1, + /* stopAfterLineBreak */ false, + /* stopAtComments */ true, + ), + ), getLeadingCommentRanges(text, node.pos), ) - : getTrailingCommentRanges(text, skipTrivia(text, node.pos, /* stopAfterLineBreak */ false, /* stopAtComments */ true)); - return commentRanges && commentRanges.length && hasInternalAnnotation(last(commentRanges), currentSourceFile); + : getTrailingCommentRanges( + text, + skipTrivia(text, node.pos, /* stopAfterLineBreak */ false, /* stopAtComments */ true), + ); + return commentRanges && commentRanges.length + && hasInternalAnnotation(last(commentRanges), currentSourceFile); } const leadingCommentRanges = parseTreeNode && getLeadingCommentRangesOfNode(parseTreeNode, currentSourceFile); return !!forEach(leadingCommentRanges, range => { @@ -34,13 +61,13 @@ namespace ts { }); } - const declarationEmitNodeBuilderFlags = NodeBuilderFlags.MultilineObjectLiterals | - NodeBuilderFlags.WriteClassExpressionAsTypeLiteral | - NodeBuilderFlags.UseTypeOfFunction | - NodeBuilderFlags.UseStructuralFallback | - NodeBuilderFlags.AllowEmptyTuple | - NodeBuilderFlags.GenerateNamesForShadowedTypeParams | - NodeBuilderFlags.NoTruncation; + const declarationEmitNodeBuilderFlags = NodeBuilderFlags.MultilineObjectLiterals + | NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + | NodeBuilderFlags.UseTypeOfFunction + | NodeBuilderFlags.UseStructuralFallback + | NodeBuilderFlags.AllowEmptyTuple + | NodeBuilderFlags.GenerateNamesForShadowedTypeParams + | NodeBuilderFlags.NoTruncation; /** * Transforms a ts file into a .d.ts file @@ -57,7 +84,9 @@ namespace ts { let needsScopeFixMarker = false; let resultHasScopeMarker = false; let enclosingDeclaration: Node; - let necessaryTypeReferences: Set<[specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined]> | undefined; + let necessaryTypeReferences: + | Set<[specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined]> + | undefined; let lateMarkedStatements: LateVisibilityPaintedStatement[] | undefined; let lateStatementReplacementMap: ESMap>; let suppressNewDiagnosticContexts: boolean; @@ -92,7 +121,11 @@ namespace ts { const { noResolve, stripInternal } = options; return transformRoot; - function recordTypeReferenceDirectivesIfNecessary(typeReferenceDirectives: readonly [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined): void { + function recordTypeReferenceDirectivesIfNecessary( + typeReferenceDirectives: + | readonly [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] + | undefined, + ): void { if (!typeReferenceDirectives) { return; } @@ -134,10 +167,25 @@ namespace ts { const errorInfo = getSymbolAccessibilityDiagnostic(symbolAccessibilityResult); if (errorInfo) { if (errorInfo.typeName) { - context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode, errorInfo.diagnosticMessage, getTextOfNode(errorInfo.typeName), symbolAccessibilityResult.errorSymbolName, symbolAccessibilityResult.errorModuleName)); + context.addDiagnostic( + createDiagnosticForNode( + symbolAccessibilityResult.errorNode || errorInfo.errorNode, + errorInfo.diagnosticMessage, + getTextOfNode(errorInfo.typeName), + symbolAccessibilityResult.errorSymbolName, + symbolAccessibilityResult.errorModuleName, + ), + ); } else { - context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode, errorInfo.diagnosticMessage, symbolAccessibilityResult.errorSymbolName, symbolAccessibilityResult.errorModuleName)); + context.addDiagnostic( + createDiagnosticForNode( + symbolAccessibilityResult.errorNode || errorInfo.errorNode, + errorInfo.diagnosticMessage, + symbolAccessibilityResult.errorSymbolName, + symbolAccessibilityResult.errorModuleName, + ), + ); } return true; } @@ -153,7 +201,14 @@ namespace ts { function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { if (symbol.flags & SymbolFlags.TypeParameter) return false; - const issuedDiagnostic = handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ true)); + const issuedDiagnostic = handleSymbolAccessibilityError( + resolver.isSymbolAccessible( + symbol, + enclosingDeclaration, + meaning, + /*shouldComputeAliasesToMakeVisible*/ true, + ), + ); recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning)); return issuedDiagnostic; } @@ -161,45 +216,88 @@ namespace ts { function reportPrivateInBaseOfClassExpression(propertyName: string) { if (errorNameNode || errorFallbackNode) { context.addDiagnostic( - createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.Property_0_of_exported_class_expression_may_not_be_private_or_protected, propertyName), + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics.Property_0_of_exported_class_expression_may_not_be_private_or_protected, + propertyName, + ), ); } } function errorDeclarationNameWithFallback() { - return errorNameNode ? declarationNameToString(errorNameNode) : - errorFallbackNode && getNameOfDeclaration(errorFallbackNode) ? declarationNameToString(getNameOfDeclaration(errorFallbackNode)) : - errorFallbackNode && isExportAssignment(errorFallbackNode) ? errorFallbackNode.isExportEquals ? "export=" : "default" : - "(Missing)"; // same fallback declarationNameToString uses when node is zero-width (ie, nameless) + return errorNameNode ? declarationNameToString(errorNameNode) + : errorFallbackNode && getNameOfDeclaration(errorFallbackNode) + ? declarationNameToString(getNameOfDeclaration(errorFallbackNode)) + : errorFallbackNode && isExportAssignment(errorFallbackNode) + ? errorFallbackNode.isExportEquals ? "export=" : "default" + : "(Missing)"; // same fallback declarationNameToString uses when node is zero-width (ie, nameless) } function reportInaccessibleUniqueSymbolError() { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, errorDeclarationNameWithFallback(), "unique symbol")); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, + errorDeclarationNameWithFallback(), + "unique symbol", + ), + ); } } function reportCyclicStructureError() { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_references_a_type_with_a_cyclic_structure_which_cannot_be_trivially_serialized_A_type_annotation_is_necessary, errorDeclarationNameWithFallback())); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_inferred_type_of_0_references_a_type_with_a_cyclic_structure_which_cannot_be_trivially_serialized_A_type_annotation_is_necessary, + errorDeclarationNameWithFallback(), + ), + ); } } function reportInaccessibleThisError() { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, errorDeclarationNameWithFallback(), "this")); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, + errorDeclarationNameWithFallback(), + "this", + ), + ); } } function reportLikelyUnsafeImportRequiredError(specifier: string) { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_cannot_be_named_without_a_reference_to_1_This_is_likely_not_portable_A_type_annotation_is_necessary, errorDeclarationNameWithFallback(), specifier)); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_inferred_type_of_0_cannot_be_named_without_a_reference_to_1_This_is_likely_not_portable_A_type_annotation_is_necessary, + errorDeclarationNameWithFallback(), + specifier, + ), + ); } } function reportTruncationError() { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_this_node_exceeds_the_maximum_length_the_compiler_will_serialize_An_explicit_type_annotation_is_needed)); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_inferred_type_of_this_node_exceeds_the_maximum_length_the_compiler_will_serialize_An_explicit_type_annotation_is_needed, + ), + ); } } @@ -209,8 +307,15 @@ namespace ts { if (primaryDeclaration && augmentingDeclarations) { for (const augmentations of augmentingDeclarations) { context.addDiagnostic(addRelatedInfo( - createDiagnosticForNode(augmentations, Diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized), - createDiagnosticForNode(primaryDeclaration, Diagnostics.This_is_the_declaration_being_augmented_Consider_moving_the_augmenting_declaration_into_the_same_file), + createDiagnosticForNode( + augmentations, + Diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized, + ), + createDiagnosticForNode( + primaryDeclaration, + Diagnostics + .This_is_the_declaration_being_augmented_Consider_moving_the_augmenting_declaration_into_the_same_file, + ), )); } } @@ -218,25 +323,46 @@ namespace ts { function reportNonSerializableProperty(propertyName: string) { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_type_of_this_node_cannot_be_serialized_because_its_property_0_cannot_be_serialized, propertyName)); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_type_of_this_node_cannot_be_serialized_because_its_property_0_cannot_be_serialized, + propertyName, + ), + ); } } function reportImportTypeNodeResolutionModeOverride() { if (!isNightly() && (errorNameNode || errorFallbackNode)) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_type_of_this_expression_cannot_be_named_without_a_resolution_mode_assertion_which_is_an_unstable_feature_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next)); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_type_of_this_expression_cannot_be_named_without_a_resolution_mode_assertion_which_is_an_unstable_feature_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next, + ), + ); } } function transformDeclarationsForJS(sourceFile: SourceFile, bundled?: boolean) { const oldDiag = getSymbolAccessibilityDiagnostic; - getSymbolAccessibilityDiagnostic = s => (s.errorNode && canProduceDiagnostics(s.errorNode) ? createGetSymbolAccessibilityDiagnosticForNode(s.errorNode)(s) : ({ - diagnosticMessage: s.errorModuleName - ? Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotation_may_unblock_declaration_emit - : Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_declaration_emit, - errorNode: s.errorNode || sourceFile, - })); - const result = resolver.getDeclarationStatementsForSourceFile(sourceFile, declarationEmitNodeBuilderFlags, symbolTracker, bundled); + getSymbolAccessibilityDiagnostic = s => (s.errorNode && canProduceDiagnostics(s.errorNode) + ? createGetSymbolAccessibilityDiagnosticForNode(s.errorNode)(s) : ({ + diagnosticMessage: s.errorModuleName + ? Diagnostics + .Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotation_may_unblock_declaration_emit + : Diagnostics + .Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_declaration_emit, + errorNode: s.errorNode || sourceFile, + })); + const result = resolver.getDeclarationStatementsForSourceFile( + sourceFile, + declarationEmitNodeBuilderFlags, + symbolTracker, + bundled, + ); getSymbolAccessibilityDiagnostic = oldDiag; return result; } @@ -271,13 +397,24 @@ namespace ts { if (isExternalOrCommonJsModule(sourceFile) || isJsonSourceFile(sourceFile)) { resultHasExternalModuleIndicator = false; // unused in external module bundle emit (all external modules are within module blocks, therefore are known to be modules) needsDeclare = false; - const statements = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile, /*bundled*/ true)) : visitNodes(sourceFile.statements, visitDeclarationStatements); + const statements = isSourceFileJS(sourceFile) + ? factory.createNodeArray(transformDeclarationsForJS(sourceFile, /*bundled*/ true)) + : visitNodes(sourceFile.statements, visitDeclarationStatements); const newFile = factory.updateSourceFile( sourceFile, [factory.createModuleDeclaration( [factory.createModifier(SyntaxKind.DeclareKeyword)], - factory.createStringLiteral(getResolvedExternalModuleName(context.getEmitHost(), sourceFile)), - factory.createModuleBlock(setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), sourceFile.statements)), + factory.createStringLiteral( + getResolvedExternalModuleName(context.getEmitHost(), sourceFile), + ), + factory.createModuleBlock( + setTextRange( + factory.createNodeArray( + transformAndReplaceLatePaintedStatements(statements), + ), + sourceFile.statements, + ), + ), )], /*isDeclarationFile*/ true, /*referencedFiles*/ [], @@ -288,15 +425,27 @@ namespace ts { return newFile; } needsDeclare = true; - const updated = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile)) : visitNodes(sourceFile.statements, visitDeclarationStatements); - return factory.updateSourceFile(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []); + const updated = isSourceFileJS(sourceFile) + ? factory.createNodeArray(transformDeclarationsForJS(sourceFile)) + : visitNodes(sourceFile.statements, visitDeclarationStatements); + return factory.updateSourceFile( + sourceFile, + transformAndReplaceLatePaintedStatements(updated), + /*isDeclarationFile*/ true, + /*referencedFiles*/ [], + /*typeReferences*/ [], + /*hasNoDefaultLib*/ false, + /*libReferences*/ [], + ); }), mapDefined(node.prepends, prepend => { if (prepend.kind === SyntaxKind.InputFiles) { const sourceFile = createUnparsedSourceFile(prepend, "dts", stripInternal); hasNoDefaultLib = hasNoDefaultLib || !!sourceFile.hasNoDefaultLib; collectReferences(sourceFile, refs); - recordTypeReferenceDirectivesIfNecessary(map(sourceFile.typeReferenceDirectives, ref => [ref.fileName, ref.resolutionMode])); + recordTypeReferenceDirectivesIfNecessary( + map(sourceFile.typeReferenceDirectives, ref => [ref.fileName, ref.resolutionMode]), + ); collectLibs(sourceFile, libs); return sourceFile; } @@ -307,8 +456,13 @@ namespace ts { bundle.syntheticTypeReferences = getFileReferencesForUsedTypeReferences(); bundle.syntheticLibReferences = getLibReferences(); bundle.hasNoDefaultLib = hasNoDefaultLib; - const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!)); - const referenceVisitor = mapReferencesIntoArray(bundle.syntheticFileReferences as FileReference[], outputFilePath); + const outputFilePath = getDirectoryPath( + normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!), + ); + const referenceVisitor = mapReferencesIntoArray( + bundle.syntheticFileReferences as FileReference[], + outputFilePath, + ); refs.forEach(referenceVisitor); return bundle; } @@ -329,7 +483,9 @@ namespace ts { refs = collectReferences(currentSourceFile, new Map()); libs = collectLibs(currentSourceFile, new Map()); const references: FileReference[] = []; - const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!)); + const outputFilePath = getDirectoryPath( + normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!), + ); const referenceVisitor = mapReferencesIntoArray(references, outputFilePath); let combinedStatements: NodeArray; if (isSourceFileJS(currentSourceFile)) { @@ -339,14 +495,31 @@ namespace ts { } else { const statements = visitNodes(node.statements, visitDeclarationStatements); - combinedStatements = setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), node.statements); + combinedStatements = setTextRange( + factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), + node.statements, + ); refs.forEach(referenceVisitor); emittedImports = filter(combinedStatements, isAnyImportSyntax); - if (isExternalModule(node) && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker))) { - combinedStatements = setTextRange(factory.createNodeArray([...combinedStatements, createEmptyExports(factory)]), combinedStatements); + if ( + isExternalModule(node) + && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker)) + ) { + combinedStatements = setTextRange( + factory.createNodeArray([...combinedStatements, createEmptyExports(factory)]), + combinedStatements, + ); } } - const updated = factory.updateSourceFile(node, combinedStatements, /*isDeclarationFile*/ true, references, getFileReferencesForUsedTypeReferences(), node.hasNoDefaultLib, getLibReferences()); + const updated = factory.updateSourceFile( + node, + combinedStatements, + /*isDeclarationFile*/ true, + references, + getFileReferencesForUsedTypeReferences(), + node.hasNoDefaultLib, + getLibReferences(), + ); updated.exportedModulesFromDeclarationEmit = exportedModulesFromDeclarationEmit; return updated; @@ -355,20 +528,29 @@ namespace ts { } function getFileReferencesForUsedTypeReferences() { - return necessaryTypeReferences ? mapDefined(arrayFrom(necessaryTypeReferences.keys()), getFileReferenceForSpecifierModeTuple) : []; + return necessaryTypeReferences + ? mapDefined(arrayFrom(necessaryTypeReferences.keys()), getFileReferenceForSpecifierModeTuple) : []; } - function getFileReferenceForSpecifierModeTuple([typeName, mode]: [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined]): FileReference | undefined { + function getFileReferenceForSpecifierModeTuple( + [typeName, mode]: [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined], + ): FileReference | undefined { // Elide type references for which we have imports if (emittedImports) { for (const importStatement of emittedImports) { - if (isImportEqualsDeclaration(importStatement) && isExternalModuleReference(importStatement.moduleReference)) { + if ( + isImportEqualsDeclaration(importStatement) + && isExternalModuleReference(importStatement.moduleReference) + ) { const expr = importStatement.moduleReference.expression; if (isStringLiteralLike(expr) && expr.text === typeName) { return undefined; } } - else if (isImportDeclaration(importStatement) && isStringLiteral(importStatement.moduleSpecifier) && importStatement.moduleSpecifier.text === typeName) { + else if ( + isImportDeclaration(importStatement) && isStringLiteral(importStatement.moduleSpecifier) + && importStatement.moduleSpecifier.text === typeName + ) { return undefined; } } @@ -376,7 +558,10 @@ namespace ts { return { fileName: typeName, pos: -1, end: -1, ...(mode ? { resolutionMode: mode } : undefined) }; } - function mapReferencesIntoArray(references: FileReference[], outputFilePath: string): (file: SourceFile) => void { + function mapReferencesIntoArray( + references: FileReference[], + outputFilePath: string, + ): (file: SourceFile) => void { return file => { let declFileName: string; if (file.isDeclarationFile) { // Neither decl files or js should have their refs changed @@ -466,7 +651,10 @@ namespace ts { if (elem.kind === SyntaxKind.OmittedExpression) { return elem; } - if (elem.propertyName && isIdentifier(elem.propertyName) && isIdentifier(elem.name) && !elem.symbol.isReferenced) { + if ( + elem.propertyName && isIdentifier(elem.propertyName) && isIdentifier(elem.name) + && !elem.symbol.isReferenced + ) { // Unnecessary property renaming is forbidden in types, so remove renaming return factory.updateBindingElement( elem, @@ -486,7 +674,11 @@ namespace ts { } } - function ensureParameter(p: ParameterDeclaration, modifierMask?: ModifierFlags, type?: TypeNode): ParameterDeclaration { + function ensureParameter( + p: ParameterDeclaration, + modifierMask?: ModifierFlags, + type?: TypeNode, + ): ParameterDeclaration { let oldDiag: typeof getSymbolAccessibilityDiagnostic | undefined; if (!suppressNewDiagnosticContexts) { oldDiag = getSymbolAccessibilityDiagnostic; @@ -497,7 +689,8 @@ namespace ts { maskModifiers(p, modifierMask), p.dotDotDotToken, filterBindingPatternInitializersAndRenamings(p.name), - resolver.isOptionalParameter(p) ? (p.questionToken || factory.createToken(SyntaxKind.QuestionToken)) : undefined, + resolver.isOptionalParameter(p) ? (p.questionToken || factory.createToken(SyntaxKind.QuestionToken)) + : undefined, ensureType(p, type || p.type, /*ignorePrivate*/ true), // Ignore private param props, since this type is going straight back into a param ensureNoInitializer(p), ); @@ -508,12 +701,16 @@ namespace ts { } function shouldPrintWithInitializer(node: Node) { - return canHaveLiteralInitializer(node) && resolver.isLiteralConstDeclaration(getParseTreeNode(node) as CanHaveLiteralInitializer); // TODO: Make safe + return canHaveLiteralInitializer(node) + && resolver.isLiteralConstDeclaration(getParseTreeNode(node) as CanHaveLiteralInitializer); // TODO: Make safe } function ensureNoInitializer(node: CanHaveLiteralInitializer) { if (shouldPrintWithInitializer(node)) { - return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, symbolTracker); // TODO: Make safe + return resolver.createLiteralConstValue( + getParseTreeNode(node) as CanHaveLiteralInitializer, + symbolTracker, + ); // TODO: Make safe } return undefined; } @@ -532,7 +729,11 @@ namespace ts { | PropertyDeclaration | PropertySignature; - function ensureType(node: HasInferredType, type: TypeNode | undefined, ignorePrivate?: boolean): TypeNode | undefined { + function ensureType( + node: HasInferredType, + type: TypeNode | undefined, + ignorePrivate?: boolean, + ): TypeNode | undefined { if (!ignorePrivate && hasEffectiveModifier(node, ModifierFlags.Private)) { // Private nodes emit no types (except private parameter properties, whose parameter types are actually visible) return; @@ -541,14 +742,15 @@ namespace ts { // Literal const declarations will have an initializer ensured rather than a type return; } - const shouldUseResolverType = node.kind === SyntaxKind.Parameter && - (resolver.isRequiredInitializedParameter(node) || - resolver.isOptionalUninitializedParameterProperty(node)); + const shouldUseResolverType = node.kind === SyntaxKind.Parameter + && (resolver.isRequiredInitializedParameter(node) + || resolver.isOptionalUninitializedParameterProperty(node)); if (type && !shouldUseResolverType) { return visitNode(type, visitDeclarationSubtree); } if (!getParseTreeNode(node)) { - return type ? visitNode(type, visitDeclarationSubtree) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + return type ? visitNode(type, visitDeclarationSubtree) + : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); } if (node.kind === SyntaxKind.SetAccessor) { // Set accessors with no associated type node (from it's param or get accessor return) are `any` since they are never contextually typed right now @@ -562,17 +764,55 @@ namespace ts { getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node); } if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { - return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker)); + return cleanup( + resolver.createTypeOfDeclaration( + node, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + ); } if ( node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature ) { - if (isPropertySignature(node) || !node.initializer) return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType)); - return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType) || resolver.createTypeOfExpression(node.initializer, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker)); + if (isPropertySignature(node) || !node.initializer) { + return cleanup( + resolver.createTypeOfDeclaration( + node, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + shouldUseResolverType, + ), + ); + } + return cleanup( + resolver.createTypeOfDeclaration( + node, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + shouldUseResolverType, + ) + || resolver.createTypeOfExpression( + node.initializer, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + ); } - return cleanup(resolver.createReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker)); + return cleanup( + resolver.createReturnTypeOfSignatureDeclaration( + node, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + ); function cleanup(returnValue: TypeNode | undefined) { errorNameNode = undefined; @@ -613,7 +853,9 @@ namespace ts { return true; } - const overloadSignatures = input.symbol.declarations?.filter(decl => isFunctionDeclaration(decl) && !decl.body); + const overloadSignatures = input.symbol.declarations?.filter(decl => + isFunctionDeclaration(decl) && !decl.body + ); return !overloadSignatures || overloadSignatures.indexOf(input) === overloadSignatures.length - 1; } @@ -654,7 +896,10 @@ namespace ts { if (!isPrivate) { const valueParameter = getSetAccessorValueParameter(input); if (valueParameter) { - const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input)); + const accessorType = getTypeAnnotationFromAllAccessorDeclarations( + input, + resolver.getAllAccessorDeclarations(input), + ); newValueParameter = ensureParameter(valueParameter, /*modifierMask*/ undefined, accessorType); } } @@ -671,7 +916,8 @@ namespace ts { } function ensureTypeParams(node: Node, params: NodeArray | undefined) { - return hasEffectiveModifier(node, ModifierFlags.Private) ? undefined : visitNodes(params, visitDeclarationSubtree); + return hasEffectiveModifier(node, ModifierFlags.Private) ? undefined + : visitNodes(params, visitDeclarationSubtree); } function isEnclosingDeclaration(node: Node) { @@ -698,9 +944,18 @@ namespace ts { return setCommentRange(updated, getCommentRange(original)); } - function rewriteModuleSpecifier(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode, input: T | undefined): T | StringLiteral { + function rewriteModuleSpecifier( + parent: + | ImportEqualsDeclaration + | ImportDeclaration + | ExportDeclaration + | ModuleDeclaration + | ImportTypeNode, + input: T | undefined, + ): T | StringLiteral { if (!input) return undefined!; // TODO: GH#18217 - resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || (parent.kind !== SyntaxKind.ModuleDeclaration && parent.kind !== SyntaxKind.ImportType); + resultHasExternalModuleIndicator = resultHasExternalModuleIndicator + || (parent.kind !== SyntaxKind.ModuleDeclaration && parent.kind !== SyntaxKind.ImportType); if (isStringLiteralLike(input)) { if (isBundledEmit) { const newName = getExternalModuleNameFromDeclaration(context.getEmitHost(), resolver, parent); @@ -728,7 +983,10 @@ namespace ts { decl.modifiers, decl.isTypeOnly, decl.name, - factory.updateExternalModuleReference(decl.moduleReference, rewriteModuleSpecifier(decl, specifier)), + factory.updateExternalModuleReference( + decl.moduleReference, + rewriteModuleSpecifier(decl, specifier), + ), ); } else { @@ -752,7 +1010,9 @@ namespace ts { ); } // The `importClause` visibility corresponds to the default's visibility. - const visibleDefaultBinding = decl.importClause && decl.importClause.name && resolver.isDeclarationVisible(decl.importClause) ? decl.importClause.name : undefined; + const visibleDefaultBinding = + decl.importClause && decl.importClause.name && resolver.isDeclarationVisible(decl.importClause) + ? decl.importClause.name : undefined; if (!decl.importClause.namedBindings) { // No named bindings (either namespace or list), meaning the import is just default or should be elided return visibleDefaultBinding && factory.updateImportDeclaration( @@ -770,7 +1030,8 @@ namespace ts { } if (decl.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { // Namespace import (optionally with visible default) - const namedBindings = resolver.isDeclarationVisible(decl.importClause.namedBindings) ? decl.importClause.namedBindings : /*namedBindings*/ undefined; + const namedBindings = resolver.isDeclarationVisible(decl.importClause.namedBindings) + ? decl.importClause.namedBindings : /*namedBindings*/ undefined; return visibleDefaultBinding || namedBindings ? factory.updateImportDeclaration( decl, decl.modifiers, @@ -785,7 +1046,10 @@ namespace ts { ) : undefined; } // Named imports (optionally with visible default) - const bindingList = mapDefined(decl.importClause.namedBindings.elements, b => resolver.isDeclarationVisible(b) ? b : undefined); + const bindingList = mapDefined( + decl.importClause.namedBindings.elements, + b => resolver.isDeclarationVisible(b) ? b : undefined, + ); if ((bindingList && bindingList.length) || visibleDefaultBinding) { return factory.updateImportDeclaration( decl, @@ -794,7 +1058,8 @@ namespace ts { decl.importClause, decl.importClause.isTypeOnly, visibleDefaultBinding, - bindingList && bindingList.length ? factory.updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined, + bindingList && bindingList.length + ? factory.updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined, ), rewriteModuleSpecifier(decl, decl.moduleSpecifier), getResolutionModeOverrideForClauseInNightly(decl.assertClause), @@ -817,7 +1082,13 @@ namespace ts { const mode = getResolutionModeOverrideForClause(assertClause); if (mode !== undefined) { if (!isNightly()) { - context.addDiagnostic(createDiagnosticForNode(assertClause!, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next)); + context.addDiagnostic( + createDiagnosticForNode( + assertClause!, + Diagnostics + .resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next, + ), + ); } return assertClause; } @@ -842,7 +1113,11 @@ namespace ts { while (length(lateMarkedStatements)) { const i = lateMarkedStatements!.shift()!; if (!isLateVisibilityPaintedStatement(i)) { - return Debug.fail(`Late replaced statement was found which is not handled by the declaration transformer!: ${Debug.formatSyntaxKind((i as Node).kind)}`); + return Debug.fail( + `Late replaced statement was found which is not handled by the declaration transformer!: ${ + Debug.formatSyntaxKind((i as Node).kind) + }`, + ); } const priorNeedsDeclare = needsDeclare; needsDeclare = i.parent && isSourceFile(i.parent) && !(isExternalModule(i.parent) && isBundledEmit); @@ -866,7 +1141,11 @@ namespace ts { // Top-level declarations in .d.ts files are always considered exported even without a modifier unless there's an export assignment or specifier needsScopeFixMarker = true; } - if (isSourceFile(statement.parent) && (isArray(result) ? some(result, isExternalModuleIndicator) : isExternalModuleIndicator(result))) { + if ( + isSourceFile(statement.parent) + && (isArray(result) ? some(result, isExternalModuleIndicator) + : isExternalModuleIndicator(result)) + ) { resultHasExternalModuleIndicator = true; } } @@ -903,13 +1182,23 @@ namespace ts { // We'd see a TDZ violation at runtime const canProduceDiagnostic = canProduceDiagnostics(input); const oldWithinObjectLiteralType = suppressNewDiagnosticContexts; - let shouldEnterSuppressNewDiagnosticsContextContext = ((input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) && input.parent.kind !== SyntaxKind.TypeAliasDeclaration); + let shouldEnterSuppressNewDiagnosticsContextContext = + ((input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) + && input.parent.kind !== SyntaxKind.TypeAliasDeclaration); // Emit methods which are private as properties with no type information if (isMethodDeclaration(input) || isMethodSignature(input)) { if (hasEffectiveModifier(input, ModifierFlags.Private)) { if (input.symbol && input.symbol.declarations && input.symbol.declarations[0] !== input) return; // Elide all but the first overload - return cleanup(factory.createPropertyDeclaration(ensureModifiers(input), input.name, /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined)); + return cleanup( + factory.createPropertyDeclaration( + ensureModifiers(input), + input.name, + /*questionToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined, + ), + ); } } @@ -933,7 +1222,9 @@ namespace ts { checkEntityNameVisibility(input.expression, enclosingDeclaration); } const node = visitEachChild(input, visitDeclarationSubtree, context); - return cleanup(factory.updateExpressionWithTypeArguments(node, node.expression, node.typeArguments)); + return cleanup( + factory.updateExpressionWithTypeArguments(node, node.expression, node.typeArguments), + ); } case SyntaxKind.TypeReference: { checkEntityNameVisibility(input.typeName, enclosingDeclaration); @@ -976,7 +1267,10 @@ namespace ts { if (isPrivateIdentifier(input.name)) { return cleanup(/*returnValue*/ undefined); } - const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input)); + const accessorType = getTypeAnnotationFromAllAccessorDeclarations( + input, + resolver.getAllAccessorDeclarations(input), + ); return cleanup(factory.updateGetAccessorDeclaration( input, ensureModifiers(input), @@ -1048,7 +1342,8 @@ namespace ts { input, ensureModifiers(input), updateParamsList(input, input.parameters), - visitNode(input.type, visitDeclarationSubtree) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + visitNode(input.type, visitDeclarationSubtree) + || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), )); } case SyntaxKind.VariableDeclaration: { @@ -1057,11 +1352,27 @@ namespace ts { } shouldEnterSuppressNewDiagnosticsContextContext = true; suppressNewDiagnosticContexts = true; // Variable declaration types also suppress new diagnostic contexts, provided the contexts wouldn't be made for binding pattern types - return cleanup(factory.updateVariableDeclaration(input, input.name, /*exclamationToken*/ undefined, ensureType(input, input.type), ensureNoInitializer(input))); + return cleanup( + factory.updateVariableDeclaration( + input, + input.name, + /*exclamationToken*/ undefined, + ensureType(input, input.type), + ensureNoInitializer(input), + ), + ); } case SyntaxKind.TypeParameter: { if (isPrivateMethodTypeParameter(input) && (input.default || input.constraint)) { - return cleanup(factory.updateTypeParameterDeclaration(input, input.modifiers, input.name, /*constraint*/ undefined, /*defaultType*/ undefined)); + return cleanup( + factory.updateTypeParameterDeclaration( + input, + input.modifiers, + input.name, + /*constraint*/ undefined, + /*defaultType*/ undefined, + ), + ); } return cleanup(visitEachChild(input, visitDeclarationSubtree, context)); } @@ -1075,19 +1386,39 @@ namespace ts { const trueType = visitNode(input.trueType, visitDeclarationSubtree); enclosingDeclaration = oldEnclosingDecl; const falseType = visitNode(input.falseType, visitDeclarationSubtree); - return cleanup(factory.updateConditionalTypeNode(input, checkType, extendsType, trueType, falseType)); + return cleanup( + factory.updateConditionalTypeNode(input, checkType, extendsType, trueType, falseType), + ); } case SyntaxKind.FunctionType: { - return cleanup(factory.updateFunctionTypeNode(input, visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree))); + return cleanup( + factory.updateFunctionTypeNode( + input, + visitNodes(input.typeParameters, visitDeclarationSubtree), + updateParamsList(input, input.parameters), + visitNode(input.type, visitDeclarationSubtree), + ), + ); } case SyntaxKind.ConstructorType: { - return cleanup(factory.updateConstructorTypeNode(input, ensureModifiers(input), visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree))); + return cleanup( + factory.updateConstructorTypeNode( + input, + ensureModifiers(input), + visitNodes(input.typeParameters, visitDeclarationSubtree), + updateParamsList(input, input.parameters), + visitNode(input.type, visitDeclarationSubtree), + ), + ); } case SyntaxKind.ImportType: { if (!isLiteralImportTypeNode(input)) return cleanup(input); return cleanup(factory.updateImportTypeNode( input, - factory.updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)), + factory.updateLiteralTypeNode( + input.argument, + rewriteModuleSpecifier(input, input.argument.literal), + ), input.assertions, input.qualifier, visitNodes(input.typeArguments, visitDeclarationSubtree, isTypeNode), @@ -1095,11 +1426,18 @@ namespace ts { )); } default: - Debug.assertNever(input, `Attempted to process unhandled node kind: ${Debug.formatSyntaxKind((input as Node).kind)}`); + Debug.assertNever( + input, + `Attempted to process unhandled node kind: ${Debug.formatSyntaxKind((input as Node).kind)}`, + ); } } - if (isTupleTypeNode(input) && (getLineAndCharacterOfPosition(currentSourceFile, input.pos).line === getLineAndCharacterOfPosition(currentSourceFile, input.end).line)) { + if ( + isTupleTypeNode(input) + && (getLineAndCharacterOfPosition(currentSourceFile, input.pos).line + === getLineAndCharacterOfPosition(currentSourceFile, input.end).line) + ) { setEmitFlags(input, EmitFlags.SingleLine); } @@ -1126,7 +1464,8 @@ namespace ts { } function isPrivateMethodTypeParameter(node: TypeParameterDeclaration) { - return node.parent.kind === SyntaxKind.MethodDeclaration && hasEffectiveModifier(node.parent, ModifierFlags.Private); + return node.parent.kind === SyntaxKind.MethodDeclaration + && hasEffectiveModifier(node.parent, ModifierFlags.Private); } function visitDeclarationStatements(input: Node): VisitResult { @@ -1169,9 +1508,22 @@ namespace ts { errorNode: input, }); errorFallbackNode = input; - const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(input.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined); + const varDecl = factory.createVariableDeclaration( + newId, + /*exclamationToken*/ undefined, + resolver.createTypeOfExpression( + input.expression, + input, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + /*initializer*/ undefined, + ); errorFallbackNode = undefined; - const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const)); + const statement = factory.createVariableStatement( + needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], + factory.createVariableDeclarationList([varDecl], NodeFlags.Const), + ); preserveJsDoc(statement, input); removeAllComments(input); @@ -1187,13 +1539,18 @@ namespace ts { } function stripExportModifiers(statement: Statement): Statement { - if (isImportEqualsDeclaration(statement) || hasEffectiveModifier(statement, ModifierFlags.Default) || !canHaveModifiers(statement)) { + if ( + isImportEqualsDeclaration(statement) || hasEffectiveModifier(statement, ModifierFlags.Default) + || !canHaveModifiers(statement) + ) { // `export import` statements should remain as-is, as imports are _not_ implicitly exported in an ambient namespace // Likewise, `export default` classes and the like and just be `default`, so we preserve their `export` modifiers, too return statement; } - const modifiers = factory.createModifiersFromModifierFlags(getEffectiveModifierFlags(statement) & (ModifierFlags.All ^ ModifierFlags.Export)); + const modifiers = factory.createModifiersFromModifierFlags( + getEffectiveModifierFlags(statement) & (ModifierFlags.All ^ ModifierFlags.Export), + ); return factory.updateModifiers(statement, modifiers); } @@ -1224,7 +1581,9 @@ namespace ts { const canProdiceDiagnostic = canProduceDiagnostics(input); const oldDiag = getSymbolAccessibilityDiagnostic; if (canProdiceDiagnostic) { - getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input as DeclarationDiagnosticProducing); + getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode( + input as DeclarationDiagnosticProducing, + ); } const previousNeedsDeclare = needsDeclare; @@ -1266,7 +1625,12 @@ namespace ts { if (clean && resolver.isExpandoFunctionDeclaration(input) && shouldEmitFunctionProperties(input)) { const props = resolver.getPropertiesOfContainerFunction(input); // Use parseNodeFactory so it is usable as an enclosing declaration - const fakespace = parseNodeFactory.createModuleDeclaration(/*modifiers*/ undefined, clean.name || factory.createIdentifier("_default"), factory.createModuleBlock([]), NodeFlags.Namespace); + const fakespace = parseNodeFactory.createModuleDeclaration( + /*modifiers*/ undefined, + clean.name || factory.createIdentifier("_default"), + factory.createModuleBlock([]), + NodeFlags.Namespace, + ); setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration); fakespace.locals = createSymbolTable(props); fakespace.symbol = props[0].parent!; @@ -1275,20 +1639,41 @@ namespace ts { if (!p.valueDeclaration || !isPropertyAccessExpression(p.valueDeclaration)) { return undefined; // TODO GH#33569: Handle element access expressions that created late bound names (rather than silently omitting them) } - getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration); - const type = resolver.createTypeOfDeclaration(p.valueDeclaration, fakespace, declarationEmitNodeBuilderFlags, symbolTracker); + getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode( + p.valueDeclaration, + ); + const type = resolver.createTypeOfDeclaration( + p.valueDeclaration, + fakespace, + declarationEmitNodeBuilderFlags, + symbolTracker, + ); getSymbolAccessibilityDiagnostic = oldDiag; const nameStr = unescapeLeadingUnderscores(p.escapedName); const isNonContextualKeywordName = isStringANonContextualKeyword(nameStr); - const name = isNonContextualKeywordName ? factory.getGeneratedNameForNode(p.valueDeclaration) : factory.createIdentifier(nameStr); + const name = isNonContextualKeywordName + ? factory.getGeneratedNameForNode(p.valueDeclaration) + : factory.createIdentifier(nameStr); if (isNonContextualKeywordName) { exportMappings.push([name, nameStr]); } - const varDecl = factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, /*initializer*/ undefined); - return factory.createVariableStatement(isNonContextualKeywordName ? undefined : [factory.createToken(SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([varDecl])); + const varDecl = factory.createVariableDeclaration( + name, + /*exclamationToken*/ undefined, + type, + /*initializer*/ undefined, + ); + return factory.createVariableStatement( + isNonContextualKeywordName ? undefined + : [factory.createToken(SyntaxKind.ExportKeyword)], + factory.createVariableDeclarationList([varDecl]), + ); }); if (!exportMappings.length) { - declarations = mapDefined(declarations, declaration => factory.updateModifiers(declaration, ModifierFlags.None)); + declarations = mapDefined( + declarations, + declaration => factory.updateModifiers(declaration, ModifierFlags.None), + ); } else { declarations.push(factory.createExportDeclaration( @@ -1299,12 +1684,19 @@ namespace ts { })), )); } - const namespaceDecl = factory.createModuleDeclaration(ensureModifiers(input), input.name!, factory.createModuleBlock(declarations), NodeFlags.Namespace); + const namespaceDecl = factory.createModuleDeclaration( + ensureModifiers(input), + input.name!, + factory.createModuleBlock(declarations), + NodeFlags.Namespace, + ); if (!hasEffectiveModifier(clean, ModifierFlags.Default)) { return [clean, namespaceDecl]; } - const modifiers = factory.createModifiersFromModifierFlags((getEffectiveModifierFlags(clean) & ~ModifierFlags.ExportDefault) | ModifierFlags.Ambient); + const modifiers = factory.createModifiersFromModifierFlags( + (getEffectiveModifierFlags(clean) & ~ModifierFlags.ExportDefault) | ModifierFlags.Ambient, + ); const cleanDeclaration = factory.updateFunctionDeclaration( clean, modifiers, @@ -1357,9 +1749,15 @@ namespace ts { // 1. There's an export assignment or export declaration in the namespace - do nothing // 2. Everything is exported and there are no export assignments or export declarations - strip all export modifiers // 3. Some things are exported, some are not, and there's no marker - add an empty marker - if (!isGlobalScopeAugmentation(input) && !hasScopeMarker(lateStatements) && !resultHasScopeMarker) { + if ( + !isGlobalScopeAugmentation(input) && !hasScopeMarker(lateStatements) + && !resultHasScopeMarker + ) { if (needsScopeFixMarker) { - lateStatements = factory.createNodeArray([...lateStatements, createEmptyExports(factory)]); + lateStatements = factory.createNodeArray([ + ...lateStatements, + createEmptyExports(factory), + ]); } else { lateStatements = visitNodes(lateStatements, stripExportModifiers); @@ -1373,7 +1771,8 @@ namespace ts { return cleanup(factory.updateModuleDeclaration( input, mods, - isExternalModuleAugmentation(input) ? rewriteModuleSpecifier(input, input.name) : input.name, + isExternalModuleAugmentation(input) ? rewriteModuleSpecifier(input, input.name) + : input.name, body, )); } @@ -1404,7 +1803,10 @@ namespace ts { if (ctor) { const oldDiag = getSymbolAccessibilityDiagnostic; parameterProperties = compact(flatMap(ctor.parameters, param => { - if (!hasSyntacticModifier(param, ModifierFlags.ParameterPropertyModifier) || shouldStripInternal(param)) return; + if ( + !hasSyntacticModifier(param, ModifierFlags.ParameterPropertyModifier) + || shouldStripInternal(param) + ) return; getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(param); if (param.name.kind === SyntaxKind.Identifier) { return preserveJsDoc( @@ -1445,7 +1847,10 @@ namespace ts { getSymbolAccessibilityDiagnostic = oldDiag; } - const hasPrivateIdentifier = some(input.members, member => !!member.name && isPrivateIdentifier(member.name)); + const hasPrivateIdentifier = some( + input.members, + member => !!member.name && isPrivateIdentifier(member.name), + ); // When the class has at least one private identifier, create a unique constant identifier to retain the nominal typing behavior // Prevents other classes with the same public members from being used in place of the current class const privateIdentifier = hasPrivateIdentifier ? [ @@ -1457,31 +1862,71 @@ namespace ts { /*initializer*/ undefined, ), ] : undefined; - const memberNodes = concatenate(concatenate(privateIdentifier, parameterProperties), visitNodes(input.members, visitDeclarationSubtree)); + const memberNodes = concatenate( + concatenate(privateIdentifier, parameterProperties), + visitNodes(input.members, visitDeclarationSubtree), + ); const members = factory.createNodeArray(memberNodes); const extendsClause = getEffectiveBaseTypeNode(input); - if (extendsClause && !isEntityNameExpression(extendsClause.expression) && extendsClause.expression.kind !== SyntaxKind.NullKeyword) { + if ( + extendsClause && !isEntityNameExpression(extendsClause.expression) + && extendsClause.expression.kind !== SyntaxKind.NullKeyword + ) { // We must add a temporary declaration for the extends clause expression const oldId = input.name ? unescapeLeadingUnderscores(input.name.escapedText) : "default"; const newId = factory.createUniqueName(`${oldId}_base`, GeneratedIdentifierFlags.Optimistic); getSymbolAccessibilityDiagnostic = () => ({ - diagnosticMessage: Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1, + diagnosticMessage: + Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1, errorNode: extendsClause, typeName: input.name, }); - const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(extendsClause.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined); - const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const)); + const varDecl = factory.createVariableDeclaration( + newId, + /*exclamationToken*/ undefined, + resolver.createTypeOfExpression( + extendsClause.expression, + input, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + /*initializer*/ undefined, + ); + const statement = factory.createVariableStatement( + needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], + factory.createVariableDeclarationList([varDecl], NodeFlags.Const), + ); const heritageClauses = factory.createNodeArray(map(input.heritageClauses, clause => { if (clause.token === SyntaxKind.ExtendsKeyword) { const oldDiag = getSymbolAccessibilityDiagnostic; - getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(clause.types[0]); - const newClause = factory.updateHeritageClause(clause, map(clause.types, t => factory.updateExpressionWithTypeArguments(t, newId, visitNodes(t.typeArguments, visitDeclarationSubtree)))); + getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode( + clause.types[0], + ); + const newClause = factory.updateHeritageClause( + clause, + map(clause.types, t => + factory.updateExpressionWithTypeArguments( + t, + newId, + visitNodes(t.typeArguments, visitDeclarationSubtree), + )), + ); getSymbolAccessibilityDiagnostic = oldDiag; return newClause; } - return factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => isEntityNameExpression(t.expression) || t.expression.kind === SyntaxKind.NullKeyword)), visitDeclarationSubtree)); + return factory.updateHeritageClause( + clause, + visitNodes( + factory.createNodeArray( + filter(clause.types, t => + isEntityNameExpression(t.expression) + || t.expression.kind === SyntaxKind.NullKeyword), + ), + visitDeclarationSubtree, + ), + ); })); return [ statement, @@ -1519,13 +1964,25 @@ namespace ts { if (shouldStripInternal(m)) return; // Rewrite enum values to their constants, if available const constValue = resolver.getConstantValue(m); - return preserveJsDoc(factory.updateEnumMember(m, m.name, constValue !== undefined ? typeof constValue === "string" ? factory.createStringLiteral(constValue) : factory.createNumericLiteral(constValue) : undefined), m); + return preserveJsDoc( + factory.updateEnumMember( + m, + m.name, + constValue !== undefined + ? typeof constValue === "string" ? factory.createStringLiteral(constValue) + : factory.createNumericLiteral(constValue) : undefined, + ), + m, + ); })), )); } } // Anything left unhandled is an error, so this should be unreachable - return Debug.assertNever(input, `Unhandled top-level node in declaration emit: ${Debug.formatSyntaxKind((input as Node).kind)}`); + return Debug.assertNever( + input, + `Unhandled top-level node in declaration emit: ${Debug.formatSyntaxKind((input as Node).kind)}`, + ); function cleanup(node: T | undefined): T | undefined { if (isEnclosingDeclaration(input)) { @@ -1550,7 +2007,11 @@ namespace ts { if (!forEach(input.declarationList.declarations, getBindingNameVisible)) return; const nodes = visitNodes(input.declarationList.declarations, visitDeclarationSubtree); if (!length(nodes)) return; - return factory.updateVariableStatement(input, factory.createNodeArray(ensureModifiers(input)), factory.updateVariableDeclarationList(input.declarationList, nodes)); + return factory.updateVariableStatement( + input, + factory.createNodeArray(ensureModifiers(input)), + factory.updateVariableDeclarationList(input.declarationList, nodes), + ); } function recreateBindingPattern(d: BindingPattern): VariableDeclaration[] { @@ -1567,7 +2028,12 @@ namespace ts { return recreateBindingPattern(e.name); } else { - return factory.createVariableDeclaration(e.name, /*exclamationToken*/ undefined, ensureType(e, /*type*/ undefined), /*initializer*/ undefined); + return factory.createVariableDeclaration( + e.name, + /*exclamationToken*/ undefined, + ensureType(e, /*type*/ undefined), + /*initializer*/ undefined, + ); } } } @@ -1621,17 +2087,24 @@ namespace ts { return maskModifierFlags(node, mask, additions); } - function getTypeAnnotationFromAllAccessorDeclarations(node: AccessorDeclaration, accessors: AllAccessorDeclarations) { + function getTypeAnnotationFromAllAccessorDeclarations( + node: AccessorDeclaration, + accessors: AllAccessorDeclarations, + ) { let accessorType = getTypeAnnotationFromAccessor(node); if (!accessorType && node !== accessors.firstAccessor) { accessorType = getTypeAnnotationFromAccessor(accessors.firstAccessor); // If we end up pulling the type from the second accessor, we also need to change the diagnostic context to get the expected error message - getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.firstAccessor); + getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode( + accessors.firstAccessor, + ); } if (!accessorType && accessors.secondAccessor && node !== accessors.secondAccessor) { accessorType = getTypeAnnotationFromAccessor(accessors.secondAccessor); // If we end up pulling the type from the second accessor, we also need to change the diagnostic context to get the expected error message - getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.secondAccessor); + getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode( + accessors.secondAccessor, + ); } return accessorType; } @@ -1643,7 +2116,9 @@ namespace ts { clause, visitNodes( factory.createNodeArray(filter(clause.types, t => { - return isEntityNameExpression(t.expression) || (clause.token === SyntaxKind.ExtendsKeyword && t.expression.kind === SyntaxKind.NullKeyword); + return isEntityNameExpression(t.expression) + || (clause.token === SyntaxKind.ExtendsKeyword + && t.expression.kind === SyntaxKind.NullKeyword); })), visitDeclarationSubtree, ), @@ -1661,11 +2136,19 @@ namespace ts { } // Elide "public" modifier, as it is the default - function maskModifiers(node: Node, modifierMask?: ModifierFlags, modifierAdditions?: ModifierFlags): Modifier[] | undefined { + function maskModifiers( + node: Node, + modifierMask?: ModifierFlags, + modifierAdditions?: ModifierFlags, + ): Modifier[] | undefined { return factory.createModifiersFromModifierFlags(maskModifierFlags(node, modifierMask, modifierAdditions)); } - function maskModifierFlags(node: Node, modifierMask: ModifierFlags = ModifierFlags.All ^ ModifierFlags.Public, modifierAdditions: ModifierFlags = ModifierFlags.None): ModifierFlags { + function maskModifierFlags( + node: Node, + modifierMask: ModifierFlags = ModifierFlags.All ^ ModifierFlags.Public, + modifierAdditions: ModifierFlags = ModifierFlags.None, + ): ModifierFlags { let flags = (getEffectiveModifierFlags(node) & modifierMask) | modifierAdditions; if (flags & ModifierFlags.Default && !(flags & ModifierFlags.Export)) { // A non-exported default is a nonsequitor - we usually try to remove all export modifiers @@ -1688,7 +2171,11 @@ namespace ts { } } - type CanHaveLiteralInitializer = VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration; + type CanHaveLiteralInitializer = + | VariableDeclaration + | PropertyDeclaration + | PropertySignature + | ParameterDeclaration; function canHaveLiteralInitializer(node: Node): boolean { switch (node.kind) { case SyntaxKind.PropertyDeclaration: diff --git a/src/compiler/transformers/declarations/diagnostics.ts b/src/compiler/transformers/declarations/diagnostics.ts index 0ca15641396be..e4a7431485c26 100644 --- a/src/compiler/transformers/declarations/diagnostics.ts +++ b/src/compiler/transformers/declarations/diagnostics.ts @@ -1,6 +1,8 @@ /* @internal */ namespace ts { - export type GetSymbolAccessibilityDiagnostic = (symbolAccessibilityResult: SymbolAccessibilityResult) => SymbolAccessibilityDiagnostic | undefined; + export type GetSymbolAccessibilityDiagnostic = ( + symbolAccessibilityResult: SymbolAccessibilityResult, + ) => SymbolAccessibilityDiagnostic | undefined; export interface SymbolAccessibilityDiagnostic { errorNode: Node; @@ -33,26 +35,26 @@ namespace ts { | JSDocEnumTag; export function canProduceDiagnostics(node: Node): node is DeclarationDiagnosticProducing { - return isVariableDeclaration(node) || - isPropertyDeclaration(node) || - isPropertySignature(node) || - isBindingElement(node) || - isSetAccessor(node) || - isGetAccessor(node) || - isConstructSignatureDeclaration(node) || - isCallSignatureDeclaration(node) || - isMethodDeclaration(node) || - isMethodSignature(node) || - isFunctionDeclaration(node) || - isParameter(node) || - isTypeParameterDeclaration(node) || - isExpressionWithTypeArguments(node) || - isImportEqualsDeclaration(node) || - isTypeAliasDeclaration(node) || - isConstructorDeclaration(node) || - isIndexSignatureDeclaration(node) || - isPropertyAccessExpression(node) || - isJSDocTypeAlias(node); + return isVariableDeclaration(node) + || isPropertyDeclaration(node) + || isPropertySignature(node) + || isBindingElement(node) + || isSetAccessor(node) + || isGetAccessor(node) + || isConstructSignatureDeclaration(node) + || isCallSignatureDeclaration(node) + || isMethodDeclaration(node) + || isMethodSignature(node) + || isFunctionDeclaration(node) + || isParameter(node) + || isTypeParameterDeclaration(node) + || isExpressionWithTypeArguments(node) + || isImportEqualsDeclaration(node) + || isTypeAliasDeclaration(node) + || isConstructorDeclaration(node) + || isIndexSignatureDeclaration(node) + || isPropertyAccessExpression(node) + || isJSDocTypeAlias(node); } export function createGetSymbolAccessibilityDiagnosticForNodeName(node: DeclarationDiagnosticProducing) { @@ -76,27 +78,32 @@ namespace ts { function getAccessorNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) { if (isStatic(node)) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; } else { - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; } } - function getMethodNameVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined { + function getMethodNameVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic | undefined { const diagnosticMessage = getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult); return diagnosticMessage !== undefined ? { diagnosticMessage, @@ -107,39 +114,53 @@ namespace ts { function getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) { if (isStatic(node)) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_method_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_method_0_of_exported_class_has_or_is_using_private_name_1; } else { - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Method_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Method_0_of_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics.Method_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Method_0_of_exported_interface_has_or_is_using_private_name_1; } } } - export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationDiagnosticProducing): GetSymbolAccessibilityDiagnostic { - if (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isPropertyAccessExpression(node) || isBindingElement(node) || isConstructorDeclaration(node)) { + export function createGetSymbolAccessibilityDiagnosticForNode( + node: DeclarationDiagnosticProducing, + ): GetSymbolAccessibilityDiagnostic { + if ( + isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) + || isPropertyAccessExpression(node) || isBindingElement(node) || isConstructorDeclaration(node) + ) { return getVariableDeclarationTypeVisibilityError; } else if (isSetAccessor(node) || isGetAccessor(node)) { return getAccessorDeclarationTypeVisibilityError; } - else if (isConstructSignatureDeclaration(node) || isCallSignatureDeclaration(node) || isMethodDeclaration(node) || isMethodSignature(node) || isFunctionDeclaration(node) || isIndexSignatureDeclaration(node)) { + else if ( + isConstructSignatureDeclaration(node) || isCallSignatureDeclaration(node) || isMethodDeclaration(node) + || isMethodSignature(node) || isFunctionDeclaration(node) || isIndexSignatureDeclaration(node) + ) { return getReturnTypeVisibilityError; } else if (isParameter(node)) { - if (isParameterPropertyDeclaration(node, node.parent) && hasSyntacticModifier(node.parent, ModifierFlags.Private)) { + if ( + isParameterPropertyDeclaration(node, node.parent) + && hasSyntacticModifier(node.parent, ModifierFlags.Private) + ) { return getVariableDeclarationTypeVisibilityError; } return getParameterDeclarationTypeVisibilityError; @@ -157,48 +178,63 @@ namespace ts { return getTypeAliasDeclarationVisibilityError; } else { - return Debug.assertNever(node, `Attempted to set a declaration diagnostic context for unhandled node kind: ${Debug.formatSyntaxKind((node as Node).kind)}`); + return Debug.assertNever( + node, + `Attempted to set a declaration diagnostic context for unhandled node kind: ${ + Debug.formatSyntaxKind((node as Node).kind) + }`, + ); } - function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) { + function getVariableDeclarationTypeVisibilityDiagnosticMessage( + symbolAccessibilityResult: SymbolAccessibilityResult, + ) { if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Exported_variable_0_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Exported_variable_0_has_or_is_using_private_name_1; } // This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit // The only exception here is if the constructor was marked as private. we are not emitting the constructor parameters at all. else if ( - node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.PropertySignature || - (node.kind === SyntaxKind.Parameter && hasSyntacticModifier(node.parent, ModifierFlags.Private)) + node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression + || node.kind === SyntaxKind.PropertySignature + || (node.kind === SyntaxKind.Parameter && hasSyntacticModifier(node.parent, ModifierFlags.Private)) ) { // TODO(jfreeman): Deal with computed properties in error reporting. if (isStatic(node)) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; } else if (node.parent.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.Parameter) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; } else { // Interfaces cannot have types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; } } } - function getVariableDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined { + function getVariableDeclarationTypeVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic | undefined { const diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult); return diagnosticMessage !== undefined ? { diagnosticMessage, @@ -207,36 +243,47 @@ namespace ts { } : undefined; } - function getAccessorDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { + function getAccessorDeclarationTypeVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic { let diagnosticMessage: DiagnosticMessage; if (node.kind === SyntaxKind.SetAccessor) { // Getters can infer the return type from the returned expression, but setters cannot, so the // "_from_external_module_1_but_cannot_be_named" case cannot occur. if (isStatic(node)) { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_private_name_1; } else { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_private_name_1; } } else { if (isStatic(node)) { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_private_name_1; } else { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_private_name_1; } } return { @@ -246,60 +293,76 @@ namespace ts { }; } - function getReturnTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { + function getReturnTypeVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic { let diagnosticMessage: DiagnosticMessage; switch (node.kind) { case SyntaxKind.ConstructSignature: // Interfaces cannot have return types that cannot be named - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 + : Diagnostics + .Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0; break; case SyntaxKind.CallSignature: // Interfaces cannot have return types that cannot be named - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 + : Diagnostics + .Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0; break; case SyntaxKind.IndexSignature: // Interfaces cannot have return types that cannot be named - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 + : Diagnostics + .Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0; break; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: if (isStatic(node)) { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : - Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named + : Diagnostics + .Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 + : Diagnostics + .Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : - Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named + : Diagnostics + .Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 + : Diagnostics + .Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0; } else { // Interfaces cannot have return types that cannot be named - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 + : Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0; } break; case SyntaxKind.FunctionDeclaration: - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : - Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named + : Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 + : Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0; break; default: @@ -312,8 +375,12 @@ namespace ts { }; } - function getParameterDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined { - const diagnosticMessage: DiagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult); + function getParameterDeclarationTypeVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic | undefined { + const diagnosticMessage: DiagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage( + symbolAccessibilityResult, + ); return diagnosticMessage !== undefined ? { diagnosticMessage, errorNode: node, @@ -321,71 +388,90 @@ namespace ts { } : undefined; } - function getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult): DiagnosticMessage { + function getParameterDeclarationTypeVisibilityDiagnosticMessage( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): DiagnosticMessage { switch (node.parent.kind) { case SyntaxKind.Constructor: - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1; case SyntaxKind.ConstructSignature: case SyntaxKind.ConstructorType: // Interfaces cannot have parameter types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; case SyntaxKind.CallSignature: // Interfaces cannot have parameter types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; case SyntaxKind.IndexSignature: // Interfaces cannot have parameter types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_private_name_1; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: if (isStatic(node.parent)) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; } else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; } else { // Interfaces cannot have parameter types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; } case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionType: - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1; case SyntaxKind.SetAccessor: case SyntaxKind.GetAccessor: - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_accessor_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_accessor_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_accessor_has_or_is_using_private_name_1; default: return Debug.fail(`Unknown parent for parameter: ${Debug.formatSyntaxKind(node.parent.kind)}`); @@ -401,42 +487,51 @@ namespace ts { break; case SyntaxKind.InterfaceDeclaration: - diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1; + diagnosticMessage = + Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1; break; case SyntaxKind.MappedType: - diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_mapped_object_type_is_using_private_name_1; + diagnosticMessage = + Diagnostics.Type_parameter_0_of_exported_mapped_object_type_is_using_private_name_1; break; case SyntaxKind.ConstructorType: case SyntaxKind.ConstructSignature: - diagnosticMessage = Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; + diagnosticMessage = Diagnostics + .Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; break; case SyntaxKind.CallSignature: - diagnosticMessage = Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; + diagnosticMessage = Diagnostics + .Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; break; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: if (isStatic(node.parent)) { - diagnosticMessage = Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = Diagnostics + .Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; } else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { - diagnosticMessage = Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = Diagnostics + .Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; } else { - diagnosticMessage = Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; + diagnosticMessage = Diagnostics + .Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; } break; case SyntaxKind.FunctionType: case SyntaxKind.FunctionDeclaration: - diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1; + diagnosticMessage = + Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1; break; case SyntaxKind.TypeAliasDeclaration: - diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_type_alias_has_or_is_using_private_name_1; + diagnosticMessage = + Diagnostics.Type_parameter_0_of_exported_type_alias_has_or_is_using_private_name_1; break; default: @@ -455,10 +550,11 @@ namespace ts { // Heritage clause is written by user so it can always be named if (isClassDeclaration(node.parent.parent)) { // Class or Interface implemented/extended is inaccessible - diagnosticMessage = isHeritageClause(node.parent) && node.parent.token === SyntaxKind.ImplementsKeyword ? - Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 : - node.parent.parent.name ? Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1 : - Diagnostics.extends_clause_of_exported_class_has_or_is_using_private_name_0; + diagnosticMessage = isHeritageClause(node.parent) && node.parent.token === SyntaxKind.ImplementsKeyword + ? Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 + : node.parent.parent.name + ? Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1 + : Diagnostics.extends_clause_of_exported_class_has_or_is_using_private_name_0; } else { // interface is inaccessible @@ -480,12 +576,15 @@ namespace ts { }; } - function getTypeAliasDeclarationVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { + function getTypeAliasDeclarationVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic { return { diagnosticMessage: symbolAccessibilityResult.errorModuleName ? Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1_from_module_2 : Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1, - errorNode: isJSDocTypeAlias(node) ? Debug.checkDefined(node.typeExpression) : (node as TypeAliasDeclaration).type, + errorNode: isJSDocTypeAlias(node) ? Debug.checkDefined(node.typeExpression) + : (node as TypeAliasDeclaration).type, typeName: isJSDocTypeAlias(node) ? getNameOfDeclaration(node) : (node as TypeAliasDeclaration).name, }; } diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index ec5dc75d7cb37..501c979f276b4 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -7,9 +7,18 @@ namespace ts { hoistTempVariables: boolean; hasTransformedPriorElement?: boolean; // indicates whether we've transformed a prior declaration emitExpression: (value: Expression) => void; - emitBindingOrAssignment: (target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node | undefined) => void; - createArrayBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ArrayBindingOrAssignmentPattern; - createObjectBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ObjectBindingOrAssignmentPattern; + emitBindingOrAssignment: ( + target: BindingOrAssignmentElementTarget, + value: Expression, + location: TextRange, + original: Node | undefined, + ) => void; + createArrayBindingOrAssignmentPattern: ( + elements: BindingOrAssignmentElement[], + ) => ArrayBindingOrAssignmentPattern; + createObjectBindingOrAssignmentPattern: ( + elements: BindingOrAssignmentElement[], + ) => ObjectBindingOrAssignmentPattern; createArrayBindingOrAssignmentElement: (node: Identifier) => BindingOrAssignmentElement; visitor?: (node: Node) => VisitResult; } @@ -71,8 +80,8 @@ namespace ts { value = visitNode(value, visitor, isExpression); if ( - isIdentifier(value) && bindingOrAssignmentElementAssignsToName(node, value.escapedText) || - bindingOrAssignmentElementContainsNonLiteralComputedName(node) + isIdentifier(value) && bindingOrAssignmentElementAssignsToName(node, value.escapedText) + || bindingOrAssignmentElementContainsNonLiteralComputedName(node) ) { // If the right-hand value of the assignment is also an assignment target then // we need to cache the right-hand value. @@ -98,7 +107,13 @@ namespace ts { } } - flattenBindingOrAssignmentElement(flattenContext, node, value, location, /*skipInitializer*/ isDestructuringAssignment(node)); + flattenBindingOrAssignmentElement( + flattenContext, + node, + value, + location, + /*skipInitializer*/ isDestructuringAssignment(node), + ); if (value && needsValue) { if (!some(expressions)) { @@ -114,7 +129,12 @@ namespace ts { expressions = append(expressions, expression); } - function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node) { + function emitBindingOrAssignment( + target: BindingOrAssignmentElementTarget, + value: Expression, + location: TextRange, + original: Node, + ) { Debug.assertNode(target, createAssignmentCallback ? isIdentifier : isExpression); const expression = createAssignmentCallback ? createAssignmentCallback(target as Identifier, value, location) @@ -127,7 +147,10 @@ namespace ts { } } - function bindingOrAssignmentElementAssignsToName(element: BindingOrAssignmentElement, escapedName: __String): boolean { + function bindingOrAssignmentElementAssignsToName( + element: BindingOrAssignmentElement, + escapedName: __String, + ): boolean { const target = getTargetOfBindingOrAssignmentElement(element)!; // TODO: GH#18217 if (isBindingOrAssignmentPattern(target)) { return bindingOrAssignmentPatternAssignsToName(target, escapedName); @@ -138,7 +161,10 @@ namespace ts { return false; } - function bindingOrAssignmentPatternAssignsToName(pattern: BindingOrAssignmentPattern, escapedName: __String): boolean { + function bindingOrAssignmentPatternAssignsToName( + pattern: BindingOrAssignmentPattern, + escapedName: __String, + ): boolean { const elements = getElementsOfBindingOrAssignmentPattern(pattern); for (const element of elements) { if (bindingOrAssignmentElementAssignsToName(element, escapedName)) { @@ -154,11 +180,15 @@ namespace ts { return true; } const target = getTargetOfBindingOrAssignmentElement(element); - return !!target && isBindingOrAssignmentPattern(target) && bindingOrAssignmentPatternContainsNonLiteralComputedName(target); + return !!target && isBindingOrAssignmentPattern(target) + && bindingOrAssignmentPatternContainsNonLiteralComputedName(target); } function bindingOrAssignmentPatternContainsNonLiteralComputedName(pattern: BindingOrAssignmentPattern): boolean { - return !!forEach(getElementsOfBindingOrAssignmentPattern(pattern), bindingOrAssignmentElementContainsNonLiteralComputedName); + return !!forEach( + getElementsOfBindingOrAssignmentPattern(pattern), + bindingOrAssignmentElementContainsNonLiteralComputedName, + ); } /** @@ -182,7 +212,13 @@ namespace ts { skipInitializer?: boolean, ): VariableDeclaration[] { let pendingExpressions: Expression[] | undefined; - const pendingDeclarations: { pendingExpressions?: Expression[]; name: BindingName; value: Expression; location?: TextRange; original?: Node; }[] = []; + const pendingDeclarations: { + pendingExpressions?: Expression[]; + name: BindingName; + value: Expression; + location?: TextRange; + original?: Node; + }[] = []; const declarations: VariableDeclaration[] = []; const flattenContext: FlattenContext = { context, @@ -200,13 +236,25 @@ namespace ts { if (isVariableDeclaration(node)) { let initializer = getInitializerOfBindingOrAssignmentElement(node); if ( - initializer && (isIdentifier(initializer) && bindingOrAssignmentElementAssignsToName(node, initializer.escapedText) || - bindingOrAssignmentElementContainsNonLiteralComputedName(node)) + initializer + && (isIdentifier(initializer) && bindingOrAssignmentElementAssignsToName(node, initializer.escapedText) + || bindingOrAssignmentElementContainsNonLiteralComputedName(node)) ) { // If the right-hand value of the assignment is also an assignment target then // we need to cache the right-hand value. - initializer = ensureIdentifier(flattenContext, visitNode(initializer, flattenContext.visitor), /*reuseIdentifierExpressions*/ false, initializer); - node = context.factory.updateVariableDeclaration(node, node.name, /*exclamationToken*/ undefined, /*type*/ undefined, initializer); + initializer = ensureIdentifier( + flattenContext, + visitNode(initializer, flattenContext.visitor), + /*reuseIdentifierExpressions*/ false, + initializer, + ); + node = context.factory.updateVariableDeclaration( + node, + node.name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + initializer, + ); } } @@ -246,7 +294,12 @@ namespace ts { pendingExpressions = append(pendingExpressions, value); } - function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange | undefined, original: Node | undefined) { + function emitBindingOrAssignment( + target: BindingOrAssignmentElementTarget, + value: Expression, + location: TextRange | undefined, + original: Node | undefined, + ) { Debug.assertNode(target, isBindingName); if (pendingExpressions) { value = context.factory.inlineExpressions(append(pendingExpressions, value)); @@ -275,7 +328,11 @@ namespace ts { ) { const bindingTarget = getTargetOfBindingOrAssignmentElement(element)!; // TODO: GH#18217 if (!skipInitializer) { - const initializer = visitNode(getInitializerOfBindingOrAssignmentElement(element), flattenContext.visitor, isExpression); + const initializer = visitNode( + getInitializerOfBindingOrAssignmentElement(element), + flattenContext.visitor, + isExpression, + ); if (initializer) { // Combine value and initializer if (value) { @@ -314,7 +371,13 @@ namespace ts { * @param value The current RHS value to assign to the element. * @param location The location to use for source maps and comments. */ - function flattenObjectBindingOrAssignmentPattern(flattenContext: FlattenContext, parent: BindingOrAssignmentElement, pattern: ObjectBindingOrAssignmentPattern, value: Expression, location: TextRange) { + function flattenObjectBindingOrAssignmentPattern( + flattenContext: FlattenContext, + parent: BindingOrAssignmentElement, + pattern: ObjectBindingOrAssignmentPattern, + value: Expression, + location: TextRange, + ) { const elements = getElementsOfBindingOrAssignmentPattern(pattern); const numElements = elements.length; if (numElements !== 1) { @@ -333,35 +396,60 @@ namespace ts { const propertyName = getPropertyNameOfBindingOrAssignmentElement(element)!; if ( flattenContext.level >= FlattenLevel.ObjectRest - && !(element.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) - && !(getTargetOfBindingOrAssignmentElement(element)!.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) + && !(element.transformFlags + & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) + && !(getTargetOfBindingOrAssignmentElement(element)!.transformFlags + & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) && !isComputedPropertyName(propertyName) ) { bindingElements = append(bindingElements, visitNode(element, flattenContext.visitor)); } else { if (bindingElements) { - flattenContext.emitBindingOrAssignment(flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), value, location, pattern); + flattenContext.emitBindingOrAssignment( + flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), + value, + location, + pattern, + ); bindingElements = undefined; } const rhsValue = createDestructuringPropertyAccess(flattenContext, value, propertyName); if (isComputedPropertyName(propertyName)) { - computedTempVariables = append(computedTempVariables, (rhsValue as ElementAccessExpression).argumentExpression); + computedTempVariables = append( + computedTempVariables, + (rhsValue as ElementAccessExpression).argumentExpression, + ); } flattenBindingOrAssignmentElement(flattenContext, element, rhsValue, /*location*/ element); } } else if (i === numElements - 1) { if (bindingElements) { - flattenContext.emitBindingOrAssignment(flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), value, location, pattern); + flattenContext.emitBindingOrAssignment( + flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), + value, + location, + pattern, + ); bindingElements = undefined; } - const rhsValue = flattenContext.context.getEmitHelperFactory().createRestHelper(value, elements, computedTempVariables, pattern); + const rhsValue = flattenContext.context.getEmitHelperFactory().createRestHelper( + value, + elements, + computedTempVariables, + pattern, + ); flattenBindingOrAssignmentElement(flattenContext, element, rhsValue, element); } } if (bindingElements) { - flattenContext.emitBindingOrAssignment(flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), value, location, pattern); + flattenContext.emitBindingOrAssignment( + flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), + value, + location, + pattern, + ); } } @@ -374,7 +462,13 @@ namespace ts { * @param value The current RHS value to assign to the element. * @param location The location to use for source maps and comments. */ - function flattenArrayBindingOrAssignmentPattern(flattenContext: FlattenContext, parent: BindingOrAssignmentElement, pattern: ArrayBindingOrAssignmentPattern, value: Expression, location: TextRange) { + function flattenArrayBindingOrAssignmentPattern( + flattenContext: FlattenContext, + parent: BindingOrAssignmentElement, + pattern: ArrayBindingOrAssignmentPattern, + value: Expression, + location: TextRange, + ) { const elements = getElementsOfBindingOrAssignmentPattern(pattern); const numElements = elements.length; if (flattenContext.level < FlattenLevel.ObjectRest && flattenContext.downlevelIteration) { @@ -414,15 +508,24 @@ namespace ts { if (flattenContext.level >= FlattenLevel.ObjectRest) { // If an array pattern contains an ObjectRest, we must cache the result so that we // can perform the ObjectRest destructuring in a different declaration - if (element.transformFlags & TransformFlags.ContainsObjectRestOrSpread || flattenContext.hasTransformedPriorElement && !isSimpleBindingOrAssignmentElement(element)) { + if ( + element.transformFlags & TransformFlags.ContainsObjectRestOrSpread + || flattenContext.hasTransformedPriorElement && !isSimpleBindingOrAssignmentElement(element) + ) { flattenContext.hasTransformedPriorElement = true; const temp = flattenContext.context.factory.createTempVariable(/*recordTempVariable*/ undefined); if (flattenContext.hoistTempVariables) { flattenContext.context.hoistVariableDeclaration(temp); } - restContainingElements = append(restContainingElements, [temp, element] as [Identifier, BindingOrAssignmentElement]); - bindingElements = append(bindingElements, flattenContext.createArrayBindingOrAssignmentElement(temp)); + restContainingElements = append( + restContainingElements, + [temp, element] as [Identifier, BindingOrAssignmentElement], + ); + bindingElements = append( + bindingElements, + flattenContext.createArrayBindingOrAssignmentElement(temp), + ); } else { bindingElements = append(bindingElements, element); @@ -441,7 +544,12 @@ namespace ts { } } if (bindingElements) { - flattenContext.emitBindingOrAssignment(flattenContext.createArrayBindingOrAssignmentPattern(bindingElements), value, location, pattern); + flattenContext.emitBindingOrAssignment( + flattenContext.createArrayBindingOrAssignmentPattern(bindingElements), + value, + location, + pattern, + ); } if (restContainingElements) { for (const [id, element] of restContainingElements) { @@ -457,7 +565,9 @@ namespace ts { if (propertyName && !isPropertyNameLiteral(propertyName)) return false; const initializer = getInitializerOfBindingOrAssignmentElement(element); if (initializer && !isSimpleInlineableExpression(initializer)) return false; - if (isBindingOrAssignmentPattern(target)) return every(getElementsOfBindingOrAssignmentPattern(target), isSimpleBindingOrAssignmentElement); + if (isBindingOrAssignmentPattern(target)) { + return every(getElementsOfBindingOrAssignmentPattern(target), isSimpleBindingOrAssignmentElement); + } return isIdentifier(target); } @@ -469,9 +579,20 @@ namespace ts { * @param defaultValue The default value to use if `value` is `undefined` at runtime. * @param location The location to use for source maps and comments. */ - function createDefaultValueCheck(flattenContext: FlattenContext, value: Expression, defaultValue: Expression, location: TextRange): Expression { + function createDefaultValueCheck( + flattenContext: FlattenContext, + value: Expression, + defaultValue: Expression, + location: TextRange, + ): Expression { value = ensureIdentifier(flattenContext, value, /*reuseIdentifierExpressions*/ true, location); - return flattenContext.context.factory.createConditionalExpression(flattenContext.context.factory.createTypeCheck(value, "undefined"), /*questionToken*/ undefined, defaultValue, /*colonToken*/ undefined, value); + return flattenContext.context.factory.createConditionalExpression( + flattenContext.context.factory.createTypeCheck(value, "undefined"), + /*questionToken*/ undefined, + defaultValue, + /*colonToken*/ undefined, + value, + ); } /** @@ -484,9 +605,18 @@ namespace ts { * @param value The RHS value that is the source of the property. * @param propertyName The destructuring property name. */ - function createDestructuringPropertyAccess(flattenContext: FlattenContext, value: Expression, propertyName: PropertyName): LeftHandSideExpression { + function createDestructuringPropertyAccess( + flattenContext: FlattenContext, + value: Expression, + propertyName: PropertyName, + ): LeftHandSideExpression { if (isComputedPropertyName(propertyName)) { - const argumentExpression = ensureIdentifier(flattenContext, visitNode(propertyName.expression, flattenContext.visitor), /*reuseIdentifierExpressions*/ false, /*location*/ propertyName); + const argumentExpression = ensureIdentifier( + flattenContext, + visitNode(propertyName.expression, flattenContext.visitor), + /*reuseIdentifierExpressions*/ false, + /*location*/ propertyName, + ); return flattenContext.context.factory.createElementAccessExpression(value, argumentExpression); } else if (isStringOrNumericLiteralLike(propertyName)) { @@ -510,7 +640,12 @@ namespace ts { * false if it is necessary to always emit an identifier. * @param location The location to use for source maps and comments. */ - function ensureIdentifier(flattenContext: FlattenContext, value: Expression, reuseIdentifierExpressions: boolean, location: TextRange) { + function ensureIdentifier( + flattenContext: FlattenContext, + value: Expression, + reuseIdentifierExpressions: boolean, + location: TextRange, + ) { if (isIdentifier(value) && reuseIdentifierExpressions) { return value; } @@ -518,7 +653,9 @@ namespace ts { const temp = flattenContext.context.factory.createTempVariable(/*recordTempVariable*/ undefined); if (flattenContext.hoistTempVariables) { flattenContext.context.hoistVariableDeclaration(temp); - flattenContext.emitExpression(setTextRange(flattenContext.context.factory.createAssignment(temp, value), location)); + flattenContext.emitExpression( + setTextRange(flattenContext.context.factory.createAssignment(temp, value), location), + ); } else { flattenContext.emitBindingOrAssignment(temp, value, location, /*original*/ undefined); @@ -542,7 +679,9 @@ namespace ts { } function makeObjectAssignmentPattern(factory: NodeFactory, elements: BindingOrAssignmentElement[]) { - return factory.createObjectLiteralExpression(map(elements, factory.converters.convertToObjectAssignmentElement)); + return factory.createObjectLiteralExpression( + map(elements, factory.converters.convertToObjectAssignmentElement), + ); } function makeBindingElement(factory: NodeFactory, name: Identifier) { diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 08df37fa8e5c8..bdc1ec22298be 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -145,7 +145,12 @@ namespace ts { loopOutParameters: LoopOutParameter[]; } - type LoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts) => Statement; + type LoopConverter = ( + node: IterationStatement, + outermostLabeledStatement: LabeledStatement | undefined, + convertedLoopBodyStatements: Statement[] | undefined, + ancestorFacts: HierarchyFacts, + ) => Statement; // Facts we track as we traverse the tree const enum HierarchyFacts { @@ -183,7 +188,8 @@ namespace ts { // We are always in *some* kind of block scope, but only specific block-scope containers are // top-level or Blocks. BlockScopeIncludes = None, - BlockScopeExcludes = TopLevel | Block | IterationStatement | IterationStatementBlock | ForStatement | ForInOrForOfStatement, + BlockScopeExcludes = TopLevel | Block | IterationStatement | IterationStatementBlock | ForStatement + | ForInOrForOfStatement, // A source file is a top-level block scope. SourceFileIncludes = TopLevel, @@ -191,7 +197,8 @@ namespace ts { // Functions, methods, and accessors are both new lexical scopes and new block scopes. FunctionIncludes = Function | TopLevel, - FunctionExcludes = BlockScopeExcludes & ~TopLevel | ArrowFunction | AsyncFunctionBody | CapturesThis | NonStaticClassElement | ConstructorWithCapturedSuper | IterationContainer | StaticInitializer, + FunctionExcludes = BlockScopeExcludes & ~TopLevel | ArrowFunction | AsyncFunctionBody | CapturesThis + | NonStaticClassElement | ConstructorWithCapturedSuper | IterationContainer | StaticInitializer, AsyncFunctionBodyIncludes = FunctionIncludes | AsyncFunctionBody, AsyncFunctionBodyExcludes = FunctionExcludes & ~NonStaticClassElement, @@ -341,8 +348,13 @@ namespace ts { * @param excludeFacts The existing `HierarchyFacts` of the subtree that should not be propagated. * @param includeFacts The new `HierarchyFacts` of the subtree that should be propagated. */ - function exitSubtree(ancestorFacts: HierarchyFacts, excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) { - hierarchyFacts = (hierarchyFacts & ~excludeFacts | includeFacts) & HierarchyFacts.SubtreeFactsMask | ancestorFacts; + function exitSubtree( + ancestorFacts: HierarchyFacts, + excludeFacts: HierarchyFacts, + includeFacts: HierarchyFacts, + ) { + hierarchyFacts = (hierarchyFacts & ~excludeFacts | includeFacts) & HierarchyFacts.SubtreeFactsMask + | ancestorFacts; } function isReturnVoidStatementInConstructorWithCapturedSuper(node: Node): boolean { @@ -370,8 +382,10 @@ namespace ts { function shouldVisitNode(node: Node): boolean { return (node.transformFlags & TransformFlags.ContainsES2015) !== 0 || convertedLoopState !== undefined - || (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && isOrMayContainReturnCompletion(node)) - || (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatement(node)) + || (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper + && isOrMayContainReturnCompletion(node)) + || (isIterationStatement(node, /*lookInLabeledStatements*/ false) + && shouldConvertIterationStatement(node)) || (getEmitFlags(node) & EmitFlags.TypeScriptClassWrapper) !== 0; } @@ -457,7 +471,10 @@ namespace ts { case SyntaxKind.DoStatement: case SyntaxKind.WhileStatement: - return visitDoOrWhileStatement(node as DoStatement | WhileStatement, /*outermostLabeledStatement*/ undefined); + return visitDoOrWhileStatement( + node as DoStatement | WhileStatement, + /*outermostLabeledStatement*/ undefined, + ); case SyntaxKind.ForStatement: return visitForStatement(node as ForStatement, /*outermostLabeledStatement*/ undefined); @@ -564,7 +581,10 @@ namespace ts { addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset)); if (taggedTemplateStringDeclarations) { statements.push( - factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList(taggedTemplateStringDeclarations)), + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList(taggedTemplateStringDeclarations), + ), ); } factory.mergeLexicalEnvironment(prologue, endLexicalEnvironment()); @@ -596,7 +616,15 @@ namespace ts { } function returnCapturedThis(node: Node): ReturnStatement { - return setOriginalNode(factory.createReturnStatement(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)), node); + return setOriginalNode( + factory.createReturnStatement( + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + ), + node, + ); } function visitReturnStatement(node: ReturnStatement): Statement { @@ -646,7 +674,8 @@ namespace ts { function visitIdentifier(node: Identifier): Identifier { if (convertedLoopState) { if (resolver.isArgumentsLocalBinding(node)) { - return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = factory.createUniqueName("arguments")); + return convertedLoopState.argumentsName + || (convertedLoopState.argumentsName = factory.createUniqueName("arguments")); } } if (node.hasExtendedUnicodeEscape) { @@ -668,8 +697,9 @@ namespace ts { // - break/continue is labeled and label is located inside the converted loop // - break/continue is non-labeled and located in non-converted loop/switch statement const jump = node.kind === SyntaxKind.BreakStatement ? Jump.Break : Jump.Continue; - const canUseBreakOrContinue = (node.label && convertedLoopState.labels && convertedLoopState.labels.get(idText(node.label))) || - (!node.label && (convertedLoopState.allowedNonLabeledJumps! & jump)); + const canUseBreakOrContinue = + (node.label && convertedLoopState.labels && convertedLoopState.labels.get(idText(node.label))) + || (!node.label && (convertedLoopState.allowedNonLabeledJumps! & jump)); if (!canUseBreakOrContinue) { let labelMarker: string; @@ -708,7 +738,11 @@ namespace ts { expr = factory.createBinaryExpression(expr!, SyntaxKind.CommaToken, copyExpr); } } - returnExpression = factory.createBinaryExpression(expr!, SyntaxKind.CommaToken, returnExpression); + returnExpression = factory.createBinaryExpression( + expr!, + SyntaxKind.CommaToken, + returnExpression, + ); } return factory.createReturnStatement(returnExpression); } @@ -742,7 +776,10 @@ namespace ts { setOriginalNode(variable, node); const statements: Statement[] = []; - const statement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([variable])); + const statement = factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([variable]), + ); setOriginalNode(statement, node); setTextRange(statement, node); @@ -827,7 +864,15 @@ namespace ts { /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, - extendsClauseElement ? [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel))] : [], + extendsClauseElement + ? [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + )] : [], /*type*/ undefined, transformClassBody(node, extendsClauseElement), ); @@ -866,17 +911,24 @@ namespace ts { * @param node A ClassExpression or ClassDeclaration node. * @param extendsClauseElement The expression for the class `extends` clause. */ - function transformClassBody(node: ClassExpression | ClassDeclaration, extendsClauseElement: ExpressionWithTypeArguments | undefined): Block { + function transformClassBody( + node: ClassExpression | ClassDeclaration, + extendsClauseElement: ExpressionWithTypeArguments | undefined, + ): Block { const statements: Statement[] = []; const name = factory.getInternalName(node); - const constructorLikeName = isIdentifierANonContextualKeyword(name) ? factory.getGeneratedNameForNode(name) : name; + const constructorLikeName = isIdentifierANonContextualKeyword(name) ? factory.getGeneratedNameForNode(name) + : name; startLexicalEnvironment(); addExtendsHelperIfNeeded(statements, node, extendsClauseElement); addConstructor(statements, node, constructorLikeName, extendsClauseElement); addClassMembers(statements, node); // Create a synthetic text range for the return statement. - const closingBraceLocation = createTokenRange(skipTrivia(currentText, node.members.end), SyntaxKind.CloseBraceToken); + const closingBraceLocation = createTokenRange( + skipTrivia(currentText, node.members.end), + SyntaxKind.CloseBraceToken, + ); // The following partially-emitted expression exists purely to align our sourcemap // emit with the original emitter. @@ -891,7 +943,10 @@ namespace ts { insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); - const block = factory.createBlock(setTextRange(factory.createNodeArray(statements), /*location*/ node.members), /*multiLine*/ true); + const block = factory.createBlock( + setTextRange(factory.createNodeArray(statements), /*location*/ node.members), + /*multiLine*/ true, + ); setEmitFlags(block, EmitFlags.NoComments); return block; } @@ -903,7 +958,11 @@ namespace ts { * @param node The ClassExpression or ClassDeclaration node. * @param extendsClauseElement The expression for the class `extends` clause. */ - function addExtendsHelperIfNeeded(statements: Statement[], node: ClassExpression | ClassDeclaration, extendsClauseElement: ExpressionWithTypeArguments | undefined): void { + function addExtendsHelperIfNeeded( + statements: Statement[], + node: ClassExpression | ClassDeclaration, + extendsClauseElement: ExpressionWithTypeArguments | undefined, + ): void { if (extendsClauseElement) { statements.push( setTextRange( @@ -923,7 +982,12 @@ namespace ts { * @param node The ClassExpression or ClassDeclaration node. * @param extendsClauseElement The expression for the class `extends` clause. */ - function addConstructor(statements: Statement[], node: ClassExpression | ClassDeclaration, name: Identifier, extendsClauseElement: ExpressionWithTypeArguments | undefined): void { + function addConstructor( + statements: Statement[], + node: ClassExpression | ClassDeclaration, + name: Identifier, + extendsClauseElement: ExpressionWithTypeArguments | undefined, + ): void { const savedConvertedLoopState = convertedLoopState; convertedLoopState = undefined; const ancestorFacts = enterSubtree(HierarchyFacts.ConstructorExcludes, HierarchyFacts.ConstructorIncludes); @@ -956,13 +1020,20 @@ namespace ts { * @param hasSynthesizedSuper A value indicating whether the constructor starts with a * synthesized `super` call. */ - function transformConstructorParameters(constructor: ConstructorDeclaration | undefined, hasSynthesizedSuper: boolean) { + function transformConstructorParameters( + constructor: ConstructorDeclaration | undefined, + hasSynthesizedSuper: boolean, + ) { // If the TypeScript transformer needed to synthesize a constructor for property // initializers, it would have also added a synthetic `...args` parameter and // `super` call. // If this is the case, we do not include the synthetic `...args` parameter and // will instead use the `arguments` object in ES5/3. - return visitParameterList(constructor && !hasSynthesizedSuper ? constructor.parameters : undefined, visitor, context) + return visitParameterList( + constructor && !hasSynthesizedSuper ? constructor.parameters : undefined, + visitor, + context, + ) || [] as ParameterDeclaration[]; } @@ -997,10 +1068,16 @@ namespace ts { * @param hasSynthesizedSuper A value indicating whether the constructor starts with a * synthesized `super` call. */ - function transformConstructorBody(constructor: ConstructorDeclaration & { body: FunctionBody; } | undefined, node: ClassDeclaration | ClassExpression, extendsClauseElement: ExpressionWithTypeArguments | undefined, hasSynthesizedSuper: boolean) { + function transformConstructorBody( + constructor: ConstructorDeclaration & { body: FunctionBody; } | undefined, + node: ClassDeclaration | ClassExpression, + extendsClauseElement: ExpressionWithTypeArguments | undefined, + hasSynthesizedSuper: boolean, + ) { // determine whether the class is known syntactically to be a derived class (e.g. a // class that extends a value that is not syntactically known to be `null`). - const isDerivedClass = !!extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword; + const isDerivedClass = !!extendsClauseElement + && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword; // When the subclass does not have a constructor, we synthesize a *default* constructor using the following // representation: @@ -1027,15 +1104,34 @@ namespace ts { // In derived classes, there may be code before the necessary super() call // We'll remove pre-super statements to be tacked on after the rest of the body const existingPrologue = takeWhile(constructor.body.statements, isPrologueDirective); - const { superCall, superStatementIndex } = findSuperCallAndStatementIndex(constructor.body.statements, existingPrologue); - const postSuperStatementsStart = superStatementIndex === -1 ? existingPrologue.length : superStatementIndex + 1; + const { superCall, superStatementIndex } = findSuperCallAndStatementIndex( + constructor.body.statements, + existingPrologue, + ); + const postSuperStatementsStart = superStatementIndex === -1 ? existingPrologue.length + : superStatementIndex + 1; // If a super call has already been synthesized, // we're going to assume that we should just transform everything after that. // The assumption is that no prior step in the pipeline has added any prologue directives. let statementOffset = postSuperStatementsStart; - if (!hasSynthesizedSuper) statementOffset = factory.copyStandardPrologue(constructor.body.statements, prologue, statementOffset, /*ensureUseStrict*/ false); - if (!hasSynthesizedSuper) statementOffset = factory.copyCustomPrologue(constructor.body.statements, statements, statementOffset, visitor, /*filter*/ undefined); + if (!hasSynthesizedSuper) { + statementOffset = factory.copyStandardPrologue( + constructor.body.statements, + prologue, + statementOffset, + /*ensureUseStrict*/ false, + ); + } + if (!hasSynthesizedSuper) { + statementOffset = factory.copyCustomPrologue( + constructor.body.statements, + statements, + statementOffset, + visitor, + /*filter*/ undefined, + ); + } // If there already exists a call to `super()`, visit the statement directly let superCallExpression: Expression | undefined; @@ -1055,13 +1151,19 @@ namespace ts { addRestParameterIfNeeded(prologue, constructor, hasSynthesizedSuper); // visit the remaining statements - addRange(statements, visitNodes(constructor.body.statements, visitor, isStatement, /*start*/ statementOffset)); + addRange( + statements, + visitNodes(constructor.body.statements, visitor, isStatement, /*start*/ statementOffset), + ); factory.mergeLexicalEnvironment(prologue, endLexicalEnvironment()); insertCaptureNewTargetIfNeeded(prologue, constructor, /*copyOnWrite*/ false); if (isDerivedClass || superCallExpression) { - if (superCallExpression && postSuperStatementsStart === constructor.body.statements.length && !(constructor.body.transformFlags & TransformFlags.ContainsLexicalThis)) { + if ( + superCallExpression && postSuperStatementsStart === constructor.body.statements.length + && !(constructor.body.transformFlags & TransformFlags.ContainsLexicalThis) + ) { // If the subclass constructor does *not* contain `this` and *ends* with a `super()` call, we will use the // following representation: // @@ -1125,7 +1227,14 @@ namespace ts { } if (!isSufficientlyCoveredByReturnStatements(constructor.body)) { - statements.push(factory.createReturnStatement(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel))); + statements.push( + factory.createReturnStatement( + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + ), + ); } } } @@ -1153,7 +1262,14 @@ namespace ts { [ ...existingPrologue, ...prologue, - ...(superStatementIndex <= existingPrologue.length ? emptyArray : visitNodes(constructor.body.statements, visitor, isStatement, existingPrologue.length, superStatementIndex - existingPrologue.length)), + ...(superStatementIndex <= existingPrologue.length ? emptyArray + : visitNodes( + constructor.body.statements, + visitor, + isStatement, + existingPrologue.length, + superStatementIndex - existingPrologue.length, + )), ...statements, ], ), @@ -1166,7 +1282,10 @@ namespace ts { return body; } - function findSuperCallAndStatementIndex(originalBodyStatements: NodeArray, existingPrologue: Statement[]) { + function findSuperCallAndStatementIndex( + originalBodyStatements: NodeArray, + existingPrologue: Statement[], + ) { for (let i = existingPrologue.length; i < originalBodyStatements.length; i += 1) { const superCall = getSuperCallFromStatement(originalBodyStatements[i]); if (superCall) { @@ -1198,8 +1317,8 @@ namespace ts { else if (statement.kind === SyntaxKind.IfStatement) { const ifStatement = statement as IfStatement; if (ifStatement.elseStatement) { - return isSufficientlyCoveredByReturnStatements(ifStatement.thenStatement) && - isSufficientlyCoveredByReturnStatements(ifStatement.elseStatement); + return isSufficientlyCoveredByReturnStatements(ifStatement.thenStatement) + && isSufficientlyCoveredByReturnStatements(ifStatement.elseStatement); } } // A block is covered if it has a last statement which is covered. @@ -1221,11 +1340,17 @@ namespace ts { return factory.createLogicalOr( factory.createLogicalAnd( factory.createStrictInequality( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), factory.createNull(), ), factory.createFunctionApplyCall( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), createActualThis(), factory.createIdentifier("arguments"), ), @@ -1312,7 +1437,8 @@ namespace ts { } if (isBindingPattern(name)) { - added = insertDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer) || added; + added = insertDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer) + || added; } else if (initializer) { insertDefaultValueAssignmentForInitializer(statements, parameter, name, initializer); @@ -1330,7 +1456,12 @@ namespace ts { * @param name The name of the parameter. * @param initializer The initializer for the parameter. */ - function insertDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration, name: BindingPattern, initializer: Expression | undefined): boolean { + function insertDefaultValueAssignmentForBindingPattern( + statements: Statement[], + parameter: ParameterDeclaration, + name: BindingPattern, + initializer: Expression | undefined, + ): boolean { // In cases where a binding pattern is simply '[]' or '{}', // we usually don't want to emit a var declaration; however, in the presence // of an initializer, we must emit that expression to preserve side effects. @@ -1381,7 +1512,12 @@ namespace ts { * @param name The name of the parameter. * @param initializer The initializer for the parameter. */ - function insertDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void { + function insertDefaultValueAssignmentForInitializer( + statements: Statement[], + parameter: ParameterDeclaration, + name: Identifier, + initializer: Expression, + ): void { initializer = visitNode(initializer, visitor, isExpression); const statement = factory.createIfStatement( factory.createTypeCheck(factory.cloneNode(name), "undefined"), @@ -1393,8 +1529,15 @@ namespace ts { setTextRange( factory.createAssignment( // TODO(rbuckton): Does this need to be parented? - setEmitFlags(setParent(setTextRange(factory.cloneNode(name), name), name.parent), EmitFlags.NoSourceMap), - setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer) | EmitFlags.NoComments), + setEmitFlags( + setParent(setTextRange(factory.cloneNode(name), name), name.parent), + EmitFlags.NoSourceMap, + ), + setEmitFlags( + initializer, + EmitFlags.NoSourceMap | getEmitFlags(initializer) + | EmitFlags.NoComments, + ), ), parameter, ), @@ -1404,13 +1547,18 @@ namespace ts { ]), parameter, ), - EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments, + EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps + | EmitFlags.NoComments, ), ); startOnNewLine(statement); setTextRange(statement, parameter); - setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue | EmitFlags.NoComments); + setEmitFlags( + statement, + EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue + | EmitFlags.NoComments, + ); insertStatementAfterCustomPrologue(statements, statement); } @@ -1422,7 +1570,10 @@ namespace ts { * part of a constructor declaration with a * synthesized call to `super` */ - function shouldAddRestParameter(node: ParameterDeclaration | undefined, inConstructorWithSynthesizedSuper: boolean): node is ParameterDeclaration { + function shouldAddRestParameter( + node: ParameterDeclaration | undefined, + inConstructorWithSynthesizedSuper: boolean, + ): node is ParameterDeclaration { return !!(node && node.dotDotDotToken && !inConstructorWithSynthesizedSuper); } @@ -1435,7 +1586,11 @@ namespace ts { * part of a constructor declaration with a * synthesized call to `super` */ - function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): boolean { + function addRestParameterIfNeeded( + statements: Statement[], + node: FunctionLikeDeclaration, + inConstructorWithSynthesizedSuper: boolean, + ): boolean { const prologueStatements: Statement[] = []; const parameter = lastOrUndefined(node.parameters); if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) { @@ -1444,11 +1599,14 @@ namespace ts { // `declarationName` is the name of the local declaration for the parameter. // TODO(rbuckton): Does this need to be parented? - const declarationName = parameter.name.kind === SyntaxKind.Identifier ? setParent(setTextRange(factory.cloneNode(parameter.name), parameter.name), parameter.name.parent) : factory.createTempVariable(/*recordTempVariable*/ undefined); + const declarationName = parameter.name.kind === SyntaxKind.Identifier + ? setParent(setTextRange(factory.cloneNode(parameter.name), parameter.name), parameter.name.parent) + : factory.createTempVariable(/*recordTempVariable*/ undefined); setEmitFlags(declarationName, EmitFlags.NoSourceMap); // `expressionName` is the name of the parameter used in expressions. - const expressionName = parameter.name.kind === SyntaxKind.Identifier ? factory.cloneNode(parameter.name) : declarationName; + const expressionName = parameter.name.kind === SyntaxKind.Identifier ? factory.cloneNode(parameter.name) + : declarationName; const restIndex = node.parameters.length - 1; const temp = factory.createLoopVariable(); @@ -1479,7 +1637,12 @@ namespace ts { const forStatement = factory.createForStatement( setTextRange( factory.createVariableDeclarationList([ - factory.createVariableDeclaration(temp, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(restIndex)), + factory.createVariableDeclaration( + temp, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(restIndex), + ), ]), parameter, ), @@ -1523,7 +1686,13 @@ namespace ts { factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - flattenDestructuringBinding(parameter, visitor, context, FlattenLevel.All, expressionName), + flattenDestructuringBinding( + parameter, + visitor, + context, + FlattenLevel.All, + expressionName, + ), ), ), parameter, @@ -1571,13 +1740,20 @@ namespace ts { setCommentRange(assignSuperExpression, getOriginalNode(superExpression).parent); } - function insertCaptureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined): void { + function insertCaptureThisForNode( + statements: Statement[], + node: Node, + initializer: Expression | undefined, + ): void { enableSubstitutionsForCapturedThis(); const captureThisStatement = factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList([ factory.createVariableDeclaration( - factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*exclamationToken*/ undefined, /*type*/ undefined, initializer, @@ -1589,7 +1765,11 @@ namespace ts { insertStatementAfterCustomPrologue(statements, captureThisStatement); } - function insertCaptureNewTargetIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, copyOnWrite: boolean): Statement[] { + function insertCaptureNewTargetIfNeeded( + statements: Statement[], + node: FunctionLikeDeclaration, + copyOnWrite: boolean, + ): Statement[] { if (hierarchyFacts & HierarchyFacts.NewTarget) { let newTarget: Expression; switch (node.kind) { @@ -1644,7 +1824,10 @@ namespace ts { /*modifiers*/ undefined, factory.createVariableDeclarationList([ factory.createVariableDeclaration( - factory.createUniqueName("_newTarget", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_newTarget", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*exclamationToken*/ undefined, /*type*/ undefined, newTarget, @@ -1679,14 +1862,22 @@ namespace ts { break; case SyntaxKind.MethodDeclaration: - statements.push(transformClassMethodDeclarationToStatement(getClassMemberPrefix(node, member), member as MethodDeclaration, node)); + statements.push( + transformClassMethodDeclarationToStatement( + getClassMemberPrefix(node, member), + member as MethodDeclaration, + node, + ), + ); break; case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: const accessors = getAllAccessorDeclarations(node.members, member as AccessorDeclaration); if (member === accessors.firstAccessor) { - statements.push(transformAccessorsToStatement(getClassMemberPrefix(node, member), accessors, node)); + statements.push( + transformAccessorsToStatement(getClassMemberPrefix(node, member), accessors, node), + ); } break; @@ -1718,20 +1909,44 @@ namespace ts { * @param receiver The receiver for the member. * @param member The MethodDeclaration node. */ - function transformClassMethodDeclarationToStatement(receiver: LeftHandSideExpression, member: MethodDeclaration, container: Node) { + function transformClassMethodDeclarationToStatement( + receiver: LeftHandSideExpression, + member: MethodDeclaration, + container: Node, + ) { const commentRange = getCommentRange(member); const sourceMapRange = getSourceMapRange(member); - const memberFunction = transformFunctionLikeToExpression(member, /*location*/ member, /*name*/ undefined, container); + const memberFunction = transformFunctionLikeToExpression( + member, + /*location*/ member, + /*name*/ undefined, + container, + ); const propertyName = visitNode(member.name, visitor, isPropertyName); let e: Expression; if (!isPrivateIdentifier(propertyName) && getUseDefineForClassFields(context.getCompilerOptions())) { const name = isComputedPropertyName(propertyName) ? propertyName.expression - : isIdentifier(propertyName) ? factory.createStringLiteral(unescapeLeadingUnderscores(propertyName.escapedText)) + : isIdentifier(propertyName) + ? factory.createStringLiteral(unescapeLeadingUnderscores(propertyName.escapedText)) : propertyName; - e = factory.createObjectDefinePropertyCall(receiver, name, factory.createPropertyDescriptor({ value: memberFunction, enumerable: false, writable: true, configurable: true })); + e = factory.createObjectDefinePropertyCall( + receiver, + name, + factory.createPropertyDescriptor({ + value: memberFunction, + enumerable: false, + writable: true, + configurable: true, + }), + ); } else { - const memberName = createMemberAccessForPropertyName(factory, receiver, propertyName, /*location*/ member.name); + const memberName = createMemberAccessForPropertyName( + factory, + receiver, + propertyName, + /*location*/ member.name, + ); e = factory.createAssignment(memberName, memberFunction); } setEmitFlags(memberFunction, EmitFlags.NoComments); @@ -1754,8 +1969,14 @@ namespace ts { * @param receiver The receiver for the member. * @param accessors The set of related get/set accessors. */ - function transformAccessorsToStatement(receiver: LeftHandSideExpression, accessors: AllAccessorDeclarations, container: Node): Statement { - const statement = factory.createExpressionStatement(transformAccessorsToExpression(receiver, accessors, container, /*startsOnNewLine*/ false)); + function transformAccessorsToStatement( + receiver: LeftHandSideExpression, + accessors: AllAccessorDeclarations, + container: Node, + ): Statement { + const statement = factory.createExpressionStatement( + transformAccessorsToExpression(receiver, accessors, container, /*startsOnNewLine*/ false), + ); // The location for the statement is used to emit source maps only. // No comments should be emitted for this statement to align with the // old emitter. @@ -1770,7 +1991,12 @@ namespace ts { * * @param receiver The receiver for the member. */ - function transformAccessorsToExpression(receiver: LeftHandSideExpression, { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations, container: Node, startsOnNewLine: boolean): Expression { + function transformAccessorsToExpression( + receiver: LeftHandSideExpression, + { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations, + container: Node, + startsOnNewLine: boolean, + ): Expression { // To align with source maps in the old emitter, the receiver and property name // arguments are both mapped contiguously to the accessor name. // TODO(rbuckton): Does this need to be parented? @@ -1780,7 +2006,10 @@ namespace ts { const visitedAccessorName = visitNode(firstAccessor.name, visitor, isPropertyName); if (isPrivateIdentifier(visitedAccessorName)) { - return Debug.failBadSyntaxKind(visitedAccessorName, "Encountered unhandled private identifier while transforming ES2015."); + return Debug.failBadSyntaxKind( + visitedAccessorName, + "Encountered unhandled private identifier while transforming ES2015.", + ); } const propertyName = createExpressionForPropertyName(factory, visitedAccessorName); setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoLeadingSourceMap); @@ -1788,7 +2017,12 @@ namespace ts { const properties: ObjectLiteralElementLike[] = []; if (getAccessor) { - const getterFunction = transformFunctionLikeToExpression(getAccessor, /*location*/ undefined, /*name*/ undefined, container); + const getterFunction = transformFunctionLikeToExpression( + getAccessor, + /*location*/ undefined, + /*name*/ undefined, + container, + ); setSourceMapRange(getterFunction, getSourceMapRange(getAccessor)); setEmitFlags(getterFunction, EmitFlags.NoLeadingComments); const getter = factory.createPropertyAssignment("get", getterFunction); @@ -1797,7 +2031,12 @@ namespace ts { } if (setAccessor) { - const setterFunction = transformFunctionLikeToExpression(setAccessor, /*location*/ undefined, /*name*/ undefined, container); + const setterFunction = transformFunctionLikeToExpression( + setAccessor, + /*location*/ undefined, + /*name*/ undefined, + container, + ); setSourceMapRange(setterFunction, getSourceMapRange(setAccessor)); setEmitFlags(setterFunction, EmitFlags.NoLeadingComments); const setter = factory.createPropertyAssignment("set", setterFunction); @@ -1806,7 +2045,10 @@ namespace ts { } properties.push( - factory.createPropertyAssignment("enumerable", getAccessor || setAccessor ? factory.createFalse() : factory.createTrue()), + factory.createPropertyAssignment( + "enumerable", + getAccessor || setAccessor ? factory.createFalse() : factory.createTrue(), + ), factory.createPropertyAssignment("configurable", factory.createTrue()), ); @@ -1832,13 +2074,19 @@ namespace ts { * @param node An ArrowFunction node. */ function visitArrowFunction(node: ArrowFunction) { - if (node.transformFlags & TransformFlags.ContainsLexicalThis && !(hierarchyFacts & HierarchyFacts.StaticInitializer)) { + if ( + node.transformFlags & TransformFlags.ContainsLexicalThis + && !(hierarchyFacts & HierarchyFacts.StaticInitializer) + ) { hierarchyFacts |= HierarchyFacts.CapturedLexicalThis; } const savedConvertedLoopState = convertedLoopState; convertedLoopState = undefined; - const ancestorFacts = enterSubtree(HierarchyFacts.ArrowFunctionExcludes, HierarchyFacts.ArrowFunctionIncludes); + const ancestorFacts = enterSubtree( + HierarchyFacts.ArrowFunctionExcludes, + HierarchyFacts.ArrowFunctionIncludes, + ); const func = factory.createFunctionExpression( /*modifiers*/ undefined, /*asteriskToken*/ undefined, @@ -1927,15 +2175,26 @@ namespace ts { * @param location The source-map location for the new FunctionExpression. * @param name The name of the new FunctionExpression. */ - function transformFunctionLikeToExpression(node: FunctionLikeDeclaration, location: TextRange | undefined, name: Identifier | undefined, container: Node | undefined): FunctionExpression { + function transformFunctionLikeToExpression( + node: FunctionLikeDeclaration, + location: TextRange | undefined, + name: Identifier | undefined, + container: Node | undefined, + ): FunctionExpression { const savedConvertedLoopState = convertedLoopState; convertedLoopState = undefined; const ancestorFacts = container && isClassLike(container) && !isStatic(node) - ? enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes | HierarchyFacts.NonStaticClassElement) + ? enterSubtree( + HierarchyFacts.FunctionExcludes, + HierarchyFacts.FunctionIncludes | HierarchyFacts.NonStaticClassElement, + ) : enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes); const parameters = visitParameterList(node.parameters, visitor, context); const body = transformFunctionBody(node); - if (hierarchyFacts & HierarchyFacts.NewTarget && !name && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) { + if ( + hierarchyFacts & HierarchyFacts.NewTarget && !name + && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression) + ) { name = factory.getGeneratedNameForNode(node); } @@ -1979,12 +2238,25 @@ namespace ts { // ensureUseStrict is false because no new prologue-directive should be added. // addStandardPrologue will put already-existing directives at the beginning of the target statement-array statementOffset = factory.copyStandardPrologue(body.statements, prologue, 0, /*ensureUseStrict*/ false); - statementOffset = factory.copyCustomPrologue(body.statements, statements, statementOffset, visitor, isHoistedFunction); - statementOffset = factory.copyCustomPrologue(body.statements, statements, statementOffset, visitor, isHoistedVariableStatement); + statementOffset = factory.copyCustomPrologue( + body.statements, + statements, + statementOffset, + visitor, + isHoistedFunction, + ); + statementOffset = factory.copyCustomPrologue( + body.statements, + statements, + statementOffset, + visitor, + isHoistedVariableStatement, + ); } multiLine = addDefaultValueAssignmentsIfNeeded(statements, node) || multiLine; - multiLine = addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false) || multiLine; + multiLine = addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false) + || multiLine; if (isBlock(body)) { // addCustomPrologue puts already-existing directives at the beginning of the target statement-array @@ -2021,7 +2293,10 @@ namespace ts { const returnStatement = factory.createReturnStatement(expression); setTextRange(returnStatement, body); moveSyntheticComments(returnStatement, body); - setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments); + setEmitFlags( + returnStatement, + EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments, + ); statements.push(returnStatement); // To align with the source map emit for the old emitter, we set a custom @@ -2044,7 +2319,10 @@ namespace ts { return body; } - const block = factory.createBlock(setTextRange(factory.createNodeArray(statements), statementsLocation), multiLine); + const block = factory.createBlock( + setTextRange(factory.createNodeArray(statements), statementsLocation), + multiLine, + ); setTextRange(block, node.body); if (!multiLine && singleLine) { setEmitFlags(block, EmitFlags.SingleLine); @@ -2064,7 +2342,10 @@ namespace ts { return visitEachChild(node, visitor, context); } const ancestorFacts = hierarchyFacts & HierarchyFacts.IterationStatement - ? enterSubtree(HierarchyFacts.IterationStatementBlockExcludes, HierarchyFacts.IterationStatementBlockIncludes) + ? enterSubtree( + HierarchyFacts.IterationStatementBlockExcludes, + HierarchyFacts.IterationStatementBlockIncludes, + ) : enterSubtree(HierarchyFacts.BlockExcludes, HierarchyFacts.BlockIncludes); const updated = visitEachChild(node, visitor, context); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); @@ -2087,8 +2368,15 @@ namespace ts { * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the * expression of an `ExpressionStatement`). */ - function visitParenthesizedExpression(node: ParenthesizedExpression, expressionResultIsUnused: boolean): ParenthesizedExpression { - return visitEachChild(node, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, context); + function visitParenthesizedExpression( + node: ParenthesizedExpression, + expressionResultIsUnused: boolean, + ): ParenthesizedExpression { + return visitEachChild( + node, + expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, + context, + ); } /** @@ -2114,7 +2402,11 @@ namespace ts { node, visitNode(node.left, visitorWithUnusedExpressionResult, isExpression), node.operatorToken, - visitNode(node.right, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, isExpression), + visitNode( + node.right, + expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, + isExpression, + ), ); } return visitEachChild(node, visitor, context); @@ -2131,7 +2423,11 @@ namespace ts { let result: Expression[] | undefined; for (let i = 0; i < node.elements.length; i++) { const element = node.elements[i]; - const visited = visitNode(element, i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, isExpression); + const visited = visitNode( + element, + i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, + isExpression, + ); if (result || visited !== element) { result ||= node.elements.slice(0, i); result.push(visited); @@ -2144,13 +2440,21 @@ namespace ts { function isVariableStatementOfTypeScriptClassWrapper(node: VariableStatement) { return node.declarationList.declarations.length === 1 && !!node.declarationList.declarations[0].initializer - && !!(getEmitFlags(node.declarationList.declarations[0].initializer) & EmitFlags.TypeScriptClassWrapper); + && !!(getEmitFlags(node.declarationList.declarations[0].initializer) + & EmitFlags.TypeScriptClassWrapper); } function visitVariableStatement(node: VariableStatement): Statement | undefined { - const ancestorFacts = enterSubtree(HierarchyFacts.None, hasSyntacticModifier(node, ModifierFlags.Export) ? HierarchyFacts.ExportedVariableStatement : HierarchyFacts.None); + const ancestorFacts = enterSubtree( + HierarchyFacts.None, + hasSyntacticModifier(node, ModifierFlags.Export) ? HierarchyFacts.ExportedVariableStatement + : HierarchyFacts.None, + ); let updated: Statement | undefined; - if (convertedLoopState && (node.declarationList.flags & NodeFlags.BlockScoped) === 0 && !isVariableStatementOfTypeScriptClassWrapper(node)) { + if ( + convertedLoopState && (node.declarationList.flags & NodeFlags.BlockScoped) === 0 + && !isVariableStatementOfTypeScriptClassWrapper(node) + ) { // we are inside a converted loop - hoist variable declarations let assignments: Expression[] | undefined; for (const decl of node.declarationList.declarations) { @@ -2166,7 +2470,11 @@ namespace ts { ); } else { - assignment = factory.createBinaryExpression(decl.name, SyntaxKind.EqualsToken, visitNode(decl.initializer, visitor, isExpression)); + assignment = factory.createBinaryExpression( + decl.name, + SyntaxKind.EqualsToken, + visitNode(decl.initializer, visitor, isExpression), + ); setTextRange(assignment, decl); } @@ -2174,7 +2482,10 @@ namespace ts { } } if (assignments) { - updated = setTextRange(factory.createExpressionStatement(factory.inlineExpressions(assignments)), node); + updated = setTextRange( + factory.createExpressionStatement(factory.inlineExpressions(assignments)), + node, + ); } else { // none of declarations has initializer - the entire variable statement can be deleted @@ -2297,7 +2608,8 @@ namespace ts { && (!resolver.isDeclarationWithCollidingName(node) || (isDeclaredInLoop && !isCapturedInFunction - && (hierarchyFacts & (HierarchyFacts.ForStatement | HierarchyFacts.ForInOrForOfStatement)) === 0)); + && (hierarchyFacts & (HierarchyFacts.ForStatement | HierarchyFacts.ForInOrForOfStatement)) + === 0)); return emitExplicitInitializer; } @@ -2317,7 +2629,13 @@ namespace ts { } if (!node.initializer && shouldEmitExplicitInitializerForLetDeclaration(node)) { - return factory.updateVariableDeclaration(node, node.name, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createVoidZero()); + return factory.updateVariableDeclaration( + node, + node.name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createVoidZero(), + ); } return visitEachChild(node, visitor, context); @@ -2364,7 +2682,11 @@ namespace ts { const statement = unwrapInnermostStatementOfLabel(node, convertedLoopState && recordLabel); return isIterationStatement(statement, /*lookInLabeledStatements*/ false) ? visitIterationStatement(statement, /*outermostLabeledStatement*/ node) - : factory.restoreEnclosingLabel(visitNode(statement, visitor, isStatement, factory.liftToBlock), node, convertedLoopState && resetLabel); + : factory.restoreEnclosingLabel( + visitNode(statement, visitor, isStatement, factory.liftToBlock), + node, + convertedLoopState && resetLabel, + ); } function visitIterationStatement(node: IterationStatement, outermostLabeledStatement: LabeledStatement) { @@ -2381,14 +2703,28 @@ namespace ts { } } - function visitIterationStatementWithFacts(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts, node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter) { + function visitIterationStatementWithFacts( + excludeFacts: HierarchyFacts, + includeFacts: HierarchyFacts, + node: IterationStatement, + outermostLabeledStatement: LabeledStatement | undefined, + convert?: LoopConverter, + ) { const ancestorFacts = enterSubtree(excludeFacts, includeFacts); - const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, ancestorFacts, convert); + const updated = convertIterationStatementBodyIfNecessary( + node, + outermostLabeledStatement, + ancestorFacts, + convert, + ); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); return updated; } - function visitDoOrWhileStatement(node: DoStatement | WhileStatement, outermostLabeledStatement: LabeledStatement | undefined) { + function visitDoOrWhileStatement( + node: DoStatement | WhileStatement, + outermostLabeledStatement: LabeledStatement | undefined, + ) { return visitIterationStatementWithFacts( HierarchyFacts.DoOrWhileStatementExcludes, HierarchyFacts.DoOrWhileStatementIncludes, @@ -2425,7 +2761,10 @@ namespace ts { ); } - function visitForOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined): VisitResult { + function visitForOfStatement( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement | undefined, + ): VisitResult { return visitIterationStatementWithFacts( HierarchyFacts.ForInOrForOfStatementExcludes, HierarchyFacts.ForInOrForOfStatementIncludes, @@ -2435,7 +2774,11 @@ namespace ts { ); } - function convertForOfStatementHead(node: ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[]) { + function convertForOfStatementHead( + node: ForOfStatement, + boundValue: Expression, + convertedLoopBodyStatements: Statement[], + ) { const statements: Statement[] = []; const initializer = node.initializer; if (isVariableDeclarationList(initializer)) { @@ -2455,7 +2798,10 @@ namespace ts { boundValue, ); - const declarationList = setTextRange(factory.createVariableDeclarationList(declarations), node.initializer); + const declarationList = setTextRange( + factory.createVariableDeclarationList(declarations), + node.initializer, + ); setOriginalNode(declarationList, node.initializer); // Adjust the source map range for the first declaration to align with the old @@ -2480,7 +2826,8 @@ namespace ts { setTextRange( factory.createVariableDeclarationList([ factory.createVariableDeclaration( - firstOriginalDeclaration ? firstOriginalDeclaration.name : factory.createTempVariable(/*recordTempVariable*/ undefined), + firstOriginalDeclaration ? firstOriginalDeclaration.name + : factory.createTempVariable(/*recordTempVariable*/ undefined), /*exclamationToken*/ undefined, /*type*/ undefined, boundValue, @@ -2501,11 +2848,20 @@ namespace ts { // evaluated on every iteration. const assignment = factory.createAssignment(initializer, boundValue); if (isDestructuringAssignment(assignment)) { - statements.push(factory.createExpressionStatement(visitBinaryExpression(assignment, /*expressionResultIsUnused*/ true))); + statements.push( + factory.createExpressionStatement( + visitBinaryExpression(assignment, /*expressionResultIsUnused*/ true), + ), + ); } else { setTextRangeEnd(assignment, initializer.end); - statements.push(setTextRange(factory.createExpressionStatement(visitNode(assignment, visitor, isExpression)), moveRangeEnd(initializer, -1))); + statements.push( + setTextRange( + factory.createExpressionStatement(visitNode(assignment, visitor, isExpression)), + moveRangeEnd(initializer, -1), + ), + ); } } @@ -2515,7 +2871,13 @@ namespace ts { else { const statement = visitNode(node.statement, visitor, isStatement, factory.liftToBlock); if (isBlock(statement)) { - return factory.updateBlock(statement, setTextRange(factory.createNodeArray(concatenate(statements, statement.statements)), statement.statements)); + return factory.updateBlock( + statement, + setTextRange( + factory.createNodeArray(concatenate(statements, statement.statements)), + statement.statements, + ), + ); } else { statements.push(statement); @@ -2534,7 +2896,11 @@ namespace ts { ); } - function convertForOfStatementForArray(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[]): Statement { + function convertForOfStatementForArray( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement, + convertedLoopBodyStatements: Statement[], + ): Statement { // The following ES6 code: // // for (let v of expr) { } @@ -2564,7 +2930,8 @@ namespace ts { // // we don't want to emit a temporary variable for the RHS, just use it directly. const counter = factory.createLoopVariable(); - const rhsReference = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined); + const rhsReference = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) + : factory.createTempVariable(/*recordTempVariable*/ undefined); // The old emitter does not emit source maps for the expression setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression)); @@ -2574,8 +2941,24 @@ namespace ts { /*initializer*/ setEmitFlags( setTextRange( factory.createVariableDeclarationList([ - setTextRange(factory.createVariableDeclaration(counter, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(0)), moveRangePos(node.expression, -1)), - setTextRange(factory.createVariableDeclaration(rhsReference, /*exclamationToken*/ undefined, /*type*/ undefined, expression), node.expression), + setTextRange( + factory.createVariableDeclaration( + counter, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(0), + ), + moveRangePos(node.expression, -1), + ), + setTextRange( + factory.createVariableDeclaration( + rhsReference, + /*exclamationToken*/ undefined, + /*type*/ undefined, + expression, + ), + node.expression, + ), ]), node.expression, ), @@ -2601,18 +2984,33 @@ namespace ts { // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps); setTextRange(forStatement, node); - return factory.restoreEnclosingLabel(forStatement, outermostLabeledStatement, convertedLoopState && resetLabel); + return factory.restoreEnclosingLabel( + forStatement, + outermostLabeledStatement, + convertedLoopState && resetLabel, + ); } - function convertForOfStatementForIterable(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[], ancestorFacts: HierarchyFacts): Statement { + function convertForOfStatementForIterable( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement, + convertedLoopBodyStatements: Statement[], + ancestorFacts: HierarchyFacts, + ): Statement { const expression = visitNode(node.expression, visitor, isExpression); - const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined); - const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) : factory.createTempVariable(/*recordTempVariable*/ undefined); + const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) + : factory.createTempVariable(/*recordTempVariable*/ undefined); + const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) + : factory.createTempVariable(/*recordTempVariable*/ undefined); const errorRecord = factory.createUniqueName("e"); const catchVariable = factory.getGeneratedNameForNode(errorRecord); const returnMethod = factory.createTempVariable(/*recordTempVariable*/ undefined); const values = setTextRange(emitHelpers().createValuesHelper(expression), node.expression); - const next = factory.createCallExpression(factory.createPropertyAccessExpression(iterator, "next"), /*typeArguments*/ undefined, []); + const next = factory.createCallExpression( + factory.createPropertyAccessExpression(iterator, "next"), + /*typeArguments*/ undefined, + [], + ); hoistVariableDeclaration(errorRecord); hoistVariableDeclaration(returnMethod); @@ -2628,8 +3026,21 @@ namespace ts { /*initializer*/ setEmitFlags( setTextRange( factory.createVariableDeclarationList([ - setTextRange(factory.createVariableDeclaration(iterator, /*exclamationToken*/ undefined, /*type*/ undefined, initializer), node.expression), - factory.createVariableDeclaration(result, /*exclamationToken*/ undefined, /*type*/ undefined, next), + setTextRange( + factory.createVariableDeclaration( + iterator, + /*exclamationToken*/ undefined, + /*type*/ undefined, + initializer, + ), + node.expression, + ), + factory.createVariableDeclaration( + result, + /*exclamationToken*/ undefined, + /*type*/ undefined, + next, + ), ]), node.expression, ), @@ -2730,8 +3141,8 @@ namespace ts { for (let i = 0; i < properties.length; i++) { const property = properties[i]; if ( - (property.transformFlags & TransformFlags.ContainsYield && - hierarchyFacts & HierarchyFacts.AsyncFunctionBody) + (property.transformFlags & TransformFlags.ContainsYield + && hierarchyFacts & HierarchyFacts.AsyncFunctionBody) || (hasComputed = Debug.checkDefined(property.name).kind === SyntaxKind.ComputedPropertyName) ) { numInitialProperties = i; @@ -2770,7 +3181,10 @@ namespace ts { // We need to clone the temporary identifier so that we can write it on a // new line - expressions.push(node.multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp); + expressions.push( + node.multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) + : temp, + ); return factory.inlineExpressions(expressions); } @@ -2790,16 +3204,24 @@ namespace ts { return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsCapturedBlockScopeBinding) !== 0; } - function shouldConvertInitializerOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleInitializer { - return isForStatement(node) && !!node.initializer && shouldConvertPartOfIterationStatement(node.initializer); + function shouldConvertInitializerOfForStatement( + node: IterationStatement, + ): node is ForStatementWithConvertibleInitializer { + return isForStatement(node) && !!node.initializer + && shouldConvertPartOfIterationStatement(node.initializer); } - function shouldConvertConditionOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleCondition { + function shouldConvertConditionOfForStatement( + node: IterationStatement, + ): node is ForStatementWithConvertibleCondition { return isForStatement(node) && !!node.condition && shouldConvertPartOfIterationStatement(node.condition); } - function shouldConvertIncrementorOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleIncrementor { - return isForStatement(node) && !!node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor); + function shouldConvertIncrementorOfForStatement( + node: IterationStatement, + ): node is ForStatementWithConvertibleIncrementor { + return isForStatement(node) && !!node.incrementor + && shouldConvertPartOfIterationStatement(node.incrementor); } function shouldConvertIterationStatement(node: IterationStatement) { @@ -2814,7 +3236,10 @@ namespace ts { /** * Records constituents of name for the given variable to be hoisted in the outer scope. */ - function hoistVariableDeclarationDeclaredInConvertedLoop(state: ConvertedLoopState, node: VariableDeclaration): void { + function hoistVariableDeclarationDeclaredInConvertedLoop( + state: ConvertedLoopState, + node: VariableDeclaration, + ): void { if (!state.hoistedLocalVariables) { state.hoistedLocalVariables = []; } @@ -2835,7 +3260,12 @@ namespace ts { } } - function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts, convert?: LoopConverter): VisitResult { + function convertIterationStatementBodyIfNecessary( + node: IterationStatement, + outermostLabeledStatement: LabeledStatement | undefined, + ancestorFacts: HierarchyFacts, + convert?: LoopConverter, + ): VisitResult { if (!shouldConvertIterationStatement(node)) { let saveAllowedNonLabeledJumps: Jump | undefined; if (convertedLoopState) { @@ -2848,7 +3278,8 @@ namespace ts { const result = convert ? convert(node, outermostLabeledStatement, /*convertedLoopBodyStatements*/ undefined, ancestorFacts) : factory.restoreEnclosingLabel( - isForStatement(node) ? visitEachChildOfForStatement(node) : visitEachChild(node, visitor, context), + isForStatement(node) ? visitEachChildOfForStatement(node) + : visitEachChild(node, visitor, context), outermostLabeledStatement, convertedLoopState && resetLabel, ); @@ -2865,8 +3296,10 @@ namespace ts { const outerConvertedLoopState = convertedLoopState; convertedLoopState = currentState; - const initializerFunction = shouldConvertInitializerOfForStatement(node) ? createFunctionForInitializerOfForStatement(node, currentState) : undefined; - const bodyFunction = shouldConvertBodyOfIterationStatement(node) ? createFunctionForBodyOfIterationStatement(node, currentState, outerConvertedLoopState) : undefined; + const initializerFunction = shouldConvertInitializerOfForStatement(node) + ? createFunctionForInitializerOfForStatement(node, currentState) : undefined; + const bodyFunction = shouldConvertBodyOfIterationStatement(node) + ? createFunctionForBodyOfIterationStatement(node, currentState, outerConvertedLoopState) : undefined; convertedLoopState = outerConvertedLoopState; @@ -2876,7 +3309,12 @@ namespace ts { addExtraDeclarationsForConvertedLoop(statements, currentState, outerConvertedLoopState); if (initializerFunction) { - statements.push(generateCallToConvertedLoopInitializer(initializerFunction.functionName, initializerFunction.containsYield)); + statements.push( + generateCallToConvertedLoopInitializer( + initializerFunction.functionName, + initializerFunction.containsYield, + ), + ); } let loop: Statement; @@ -2885,20 +3323,40 @@ namespace ts { loop = convert(node, outermostLabeledStatement, bodyFunction.part, ancestorFacts); } else { - const clone = convertIterationStatementCore(node, initializerFunction, factory.createBlock(bodyFunction.part, /*multiLine*/ true)); - loop = factory.restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel); + const clone = convertIterationStatementCore( + node, + initializerFunction, + factory.createBlock(bodyFunction.part, /*multiLine*/ true), + ); + loop = factory.restoreEnclosingLabel( + clone, + outermostLabeledStatement, + convertedLoopState && resetLabel, + ); } } else { - const clone = convertIterationStatementCore(node, initializerFunction, visitNode(node.statement, visitor, isStatement, factory.liftToBlock)); - loop = factory.restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel); + const clone = convertIterationStatementCore( + node, + initializerFunction, + visitNode(node.statement, visitor, isStatement, factory.liftToBlock), + ); + loop = factory.restoreEnclosingLabel( + clone, + outermostLabeledStatement, + convertedLoopState && resetLabel, + ); } statements.push(loop); return statements; } - function convertIterationStatementCore(node: IterationStatement, initializerFunction: IterationStatementPartFunction | undefined, convertedLoopBody: Statement) { + function convertIterationStatementCore( + node: IterationStatement, + initializerFunction: IterationStatementPartFunction | undefined, + convertedLoopBody: Statement, + ) { switch (node.kind) { case SyntaxKind.ForStatement: return convertForStatement(node as ForStatement, initializerFunction, convertedLoopBody); @@ -2915,14 +3373,27 @@ namespace ts { } } - function convertForStatement(node: ForStatement, initializerFunction: IterationStatementPartFunction | undefined, convertedLoopBody: Statement) { + function convertForStatement( + node: ForStatement, + initializerFunction: IterationStatementPartFunction | undefined, + convertedLoopBody: Statement, + ) { const shouldConvertCondition = node.condition && shouldConvertPartOfIterationStatement(node.condition); - const shouldConvertIncrementor = shouldConvertCondition || node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor); + const shouldConvertIncrementor = shouldConvertCondition + || node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor); return factory.updateForStatement( node, - visitNode(initializerFunction ? initializerFunction.part : node.initializer, visitorWithUnusedExpressionResult, isForInitializer), + visitNode( + initializerFunction ? initializerFunction.part : node.initializer, + visitorWithUnusedExpressionResult, + isForInitializer, + ), visitNode(shouldConvertCondition ? undefined : node.condition, visitor, isExpression), - visitNode(shouldConvertIncrementor ? undefined : node.incrementor, visitorWithUnusedExpressionResult, isExpression), + visitNode( + shouldConvertIncrementor ? undefined : node.incrementor, + visitorWithUnusedExpressionResult, + isExpression, + ), convertedLoopBody, ); } @@ -2980,11 +3451,17 @@ namespace ts { // variables declared in the loop initializer that will be changed inside the loop const loopOutParameters: LoopOutParameter[] = []; if (loopInitializer && (getCombinedNodeFlags(loopInitializer) & NodeFlags.BlockScoped)) { - const hasCapturedBindingsInForHead = shouldConvertInitializerOfForStatement(node) || - shouldConvertConditionOfForStatement(node) || - shouldConvertIncrementorOfForStatement(node); + const hasCapturedBindingsInForHead = shouldConvertInitializerOfForStatement(node) + || shouldConvertConditionOfForStatement(node) + || shouldConvertIncrementorOfForStatement(node); for (const decl of loopInitializer.declarations) { - processLoopVariableDeclaration(node, decl, loopParameters, loopOutParameters, hasCapturedBindingsInForHead); + processLoopVariableDeclaration( + node, + decl, + loopParameters, + loopOutParameters, + hasCapturedBindingsInForHead, + ); } } @@ -3011,7 +3488,11 @@ namespace ts { return currentState; } - function addExtraDeclarationsForConvertedLoop(statements: Statement[], state: ConvertedLoopState, outerState: ConvertedLoopState | undefined) { + function addExtraDeclarationsForConvertedLoop( + statements: Statement[], + state: ConvertedLoopState, + outerState: ConvertedLoopState | undefined, + ) { let extraVariableDeclarations: VariableDeclaration[] | undefined; // propagate state from the inner loop to the outer loop if necessary if (state.argumentsName) { @@ -3086,7 +3567,14 @@ namespace ts { if (!extraVariableDeclarations) { extraVariableDeclarations = []; } - extraVariableDeclarations.push(factory.createVariableDeclaration(state.conditionVariable, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createFalse())); + extraVariableDeclarations.push( + factory.createVariableDeclaration( + state.conditionVariable, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createFalse(), + ), + ); } // create variable statement to hold all introduced variable declarations @@ -3106,7 +3594,12 @@ namespace ts { } function createOutVariable(p: LoopOutParameter) { - return factory.createVariableDeclaration(p.originalName, /*exclamationToken*/ undefined, /*type*/ undefined, p.outParamName); + return factory.createVariableDeclaration( + p.originalName, + /*exclamationToken*/ undefined, + /*type*/ undefined, + p.outParamName, + ); } /** @@ -3115,17 +3608,27 @@ namespace ts { * used to preserve the per-iteration environment semantics of * [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation). */ - function createFunctionForInitializerOfForStatement(node: ForStatementWithConvertibleInitializer, currentState: ConvertedLoopState): IterationStatementPartFunction { + function createFunctionForInitializerOfForStatement( + node: ForStatementWithConvertibleInitializer, + currentState: ConvertedLoopState, + ): IterationStatementPartFunction { const functionName = factory.createUniqueName("_loop_init"); const containsYield = (node.initializer.transformFlags & TransformFlags.ContainsYield) !== 0; let emitFlags = EmitFlags.None; if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis; - if (containsYield && hierarchyFacts & HierarchyFacts.AsyncFunctionBody) emitFlags |= EmitFlags.AsyncFunctionBody; + if (containsYield && hierarchyFacts & HierarchyFacts.AsyncFunctionBody) { + emitFlags |= EmitFlags.AsyncFunctionBody; + } const statements: Statement[] = []; statements.push(factory.createVariableStatement(/*modifiers*/ undefined, node.initializer)); - copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Initializer, CopyDirection.ToOutParameter, statements); + copyOutParameters( + currentState.loopOutParameters, + LoopOutParameterFlags.Initializer, + CopyDirection.ToOutParameter, + statements, + ); // This transforms the following ES2015 syntax: // @@ -3188,7 +3691,11 @@ namespace ts { * preserve the per-iteration environment semantics of * [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation). */ - function createFunctionForBodyOfIterationStatement(node: IterationStatement, currentState: ConvertedLoopState, outerState: ConvertedLoopState | undefined): IterationStatementPartFunction { + function createFunctionForBodyOfIterationStatement( + node: IterationStatement, + currentState: ConvertedLoopState, + outerState: ConvertedLoopState | undefined, + ): IterationStatementPartFunction { const functionName = factory.createUniqueName("_loop"); startLexicalEnvironment(); const statement = visitNode(node.statement, visitor, isStatement, factory.liftToBlock); @@ -3239,19 +3746,26 @@ namespace ts { statements.push(factory.createIfStatement( currentState.conditionVariable, factory.createExpressionStatement(visitNode(node.incrementor, visitor, isExpression)), - factory.createExpressionStatement(factory.createAssignment(currentState.conditionVariable, factory.createTrue())), + factory.createExpressionStatement( + factory.createAssignment(currentState.conditionVariable, factory.createTrue()), + ), )); } else { statements.push(factory.createIfStatement( factory.createLogicalNot(currentState.conditionVariable), - factory.createExpressionStatement(factory.createAssignment(currentState.conditionVariable, factory.createTrue())), + factory.createExpressionStatement( + factory.createAssignment(currentState.conditionVariable, factory.createTrue()), + ), )); } if (shouldConvertConditionOfForStatement(node)) { statements.push(factory.createIfStatement( - factory.createPrefixUnaryExpression(SyntaxKind.ExclamationToken, visitNode(node.condition, visitor, isExpression)), + factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + visitNode(node.condition, visitor, isExpression), + ), visitNode(factory.createBreakStatement(), visitor, isStatement), )); } @@ -3264,7 +3778,12 @@ namespace ts { statements.push(statement); } - copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOutParameter, statements); + copyOutParameters( + currentState.loopOutParameters, + LoopOutParameterFlags.Body, + CopyDirection.ToOutParameter, + statements, + ); insertStatementsAfterStandardPrologue(statements, lexicalEnvironment); const loopBody = factory.createBlock(statements, /*multiLine*/ true); @@ -3274,7 +3793,9 @@ namespace ts { let emitFlags: EmitFlags = EmitFlags.ReuseTempVariableScope; if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis; - if (containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0) emitFlags |= EmitFlags.AsyncFunctionBody; + if (containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0) { + emitFlags |= EmitFlags.AsyncFunctionBody; + } // This transforms the following ES2015 syntax (in addition to other variations): // @@ -3329,7 +3850,12 @@ namespace ts { return factory.createBinaryExpression(target, SyntaxKind.EqualsToken, source); } - function copyOutParameters(outParams: LoopOutParameter[], partFlags: LoopOutParameterFlags, copyDirection: CopyDirection, statements: Statement[]): void { + function copyOutParameters( + outParams: LoopOutParameter[], + partFlags: LoopOutParameterFlags, + copyDirection: CopyDirection, + statements: Statement[], + ): void { for (const outParam of outParams) { if (outParam.flags & partFlags) { statements.push(factory.createExpressionStatement(copyOutParameter(outParam, copyDirection))); @@ -3337,7 +3863,10 @@ namespace ts { } } - function generateCallToConvertedLoopInitializer(initFunctionExpressionName: Identifier, containsYield: boolean): Statement { + function generateCallToConvertedLoopInitializer( + initFunctionExpressionName: Identifier, + containsYield: boolean, + ): Statement { const call = factory.createCallExpression(initFunctionExpressionName, /*typeArguments*/ undefined, []); const callResult = containsYield ? factory.createYieldExpression( @@ -3348,16 +3877,25 @@ namespace ts { return factory.createExpressionStatement(callResult); } - function generateCallToConvertedLoop(loopFunctionExpressionName: Identifier, state: ConvertedLoopState, outerState: ConvertedLoopState | undefined, containsYield: boolean): Statement[] { + function generateCallToConvertedLoop( + loopFunctionExpressionName: Identifier, + state: ConvertedLoopState, + outerState: ConvertedLoopState | undefined, + containsYield: boolean, + ): Statement[] { const statements: Statement[] = []; // loop is considered simple if it does not have any return statements or break\continue that transfer control outside of the loop // simple loops are emitted as just 'loop()'; // NOTE: if loop uses only 'continue' it still will be emitted as simple loop - const isSimpleLoop = !(state.nonLocalJumps! & ~Jump.Continue) && - !state.labeledNonLocalBreaks && - !state.labeledNonLocalContinues; + const isSimpleLoop = !(state.nonLocalJumps! & ~Jump.Continue) + && !state.labeledNonLocalBreaks + && !state.labeledNonLocalContinues; - const call = factory.createCallExpression(loopFunctionExpressionName, /*typeArguments*/ undefined, map(state.loopParameters, p => p.name as Identifier)); + const call = factory.createCallExpression( + loopFunctionExpressionName, + /*typeArguments*/ undefined, + map(state.loopParameters, p => p.name as Identifier), + ); const callResult = containsYield ? factory.createYieldExpression( factory.createToken(SyntaxKind.AsteriskToken), @@ -3366,18 +3904,33 @@ namespace ts { : call; if (isSimpleLoop) { statements.push(factory.createExpressionStatement(callResult)); - copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements); + copyOutParameters( + state.loopOutParameters, + LoopOutParameterFlags.Body, + CopyDirection.ToOriginal, + statements, + ); } else { const loopResultName = factory.createUniqueName("state"); const stateVariable = factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - [factory.createVariableDeclaration(loopResultName, /*exclamationToken*/ undefined, /*type*/ undefined, callResult)], + [factory.createVariableDeclaration( + loopResultName, + /*exclamationToken*/ undefined, + /*type*/ undefined, + callResult, + )], ), ); statements.push(stateVariable); - copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements); + copyOutParameters( + state.loopOutParameters, + LoopOutParameterFlags.Body, + CopyDirection.ToOriginal, + statements, + ); if (state.nonLocalJumps! & Jump.Return) { let returnStatement: ReturnStatement; @@ -3386,7 +3939,9 @@ namespace ts { returnStatement = factory.createReturnStatement(loopResultName); } else { - returnStatement = factory.createReturnStatement(factory.createPropertyAccessExpression(loopResultName, "value")); + returnStatement = factory.createReturnStatement( + factory.createPropertyAccessExpression(loopResultName, "value"), + ); } statements.push( factory.createIfStatement( @@ -3410,8 +3965,20 @@ namespace ts { if (state.labeledNonLocalBreaks || state.labeledNonLocalContinues) { const caseClauses: CaseClause[] = []; - processLabeledJumps(state.labeledNonLocalBreaks!, /*isBreak*/ true, loopResultName, outerState, caseClauses); - processLabeledJumps(state.labeledNonLocalContinues!, /*isBreak*/ false, loopResultName, outerState, caseClauses); + processLabeledJumps( + state.labeledNonLocalBreaks!, + /*isBreak*/ true, + loopResultName, + outerState, + caseClauses, + ); + processLabeledJumps( + state.labeledNonLocalContinues!, + /*isBreak*/ false, + loopResultName, + outerState, + caseClauses, + ); statements.push( factory.createSwitchStatement( loopResultName, @@ -3423,7 +3990,12 @@ namespace ts { return statements; } - function setLabeledJump(state: ConvertedLoopState, isBreak: boolean, labelText: string, labelMarker: string): void { + function setLabeledJump( + state: ConvertedLoopState, + isBreak: boolean, + labelText: string, + labelMarker: string, + ): void { if (isBreak) { if (!state.labeledNonLocalBreaks) { state.labeledNonLocalBreaks = new Map(); @@ -3438,7 +4010,13 @@ namespace ts { } } - function processLabeledJumps(table: ESMap, isBreak: boolean, loopResultName: Identifier, outerLoop: ConvertedLoopState | undefined, caseClauses: CaseClause[]): void { + function processLabeledJumps( + table: ESMap, + isBreak: boolean, + loopResultName: Identifier, + outerLoop: ConvertedLoopState | undefined, + caseClauses: CaseClause[], + ): void { if (!table) { return; } @@ -3449,7 +4027,9 @@ namespace ts { // otherwise propagate pair 'label -> marker' to outer converted loop and emit 'return labelMarker' so outer loop can later decide what to do if (!outerLoop || (outerLoop.labels && outerLoop.labels.get(labelText))) { const label = factory.createIdentifier(labelText); - statements.push(isBreak ? factory.createBreakStatement(label) : factory.createContinueStatement(label)); + statements.push( + isBreak ? factory.createBreakStatement(label) : factory.createContinueStatement(label), + ); } else { setLabeledJump(outerLoop, isBreak, labelText, labelMarker); @@ -3459,17 +4039,31 @@ namespace ts { }); } - function processLoopVariableDeclaration(container: IterationStatement, decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[], hasCapturedBindingsInForHead: boolean) { + function processLoopVariableDeclaration( + container: IterationStatement, + decl: VariableDeclaration | BindingElement, + loopParameters: ParameterDeclaration[], + loopOutParameters: LoopOutParameter[], + hasCapturedBindingsInForHead: boolean, + ) { const name = decl.name; if (isBindingPattern(name)) { for (const element of name.elements) { if (!isOmittedExpression(element)) { - processLoopVariableDeclaration(container, element, loopParameters, loopOutParameters, hasCapturedBindingsInForHead); + processLoopVariableDeclaration( + container, + element, + loopParameters, + loopOutParameters, + hasCapturedBindingsInForHead, + ); } } } else { - loopParameters.push(factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name)); + loopParameters.push( + factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name), + ); const checkFlags = resolver.getNodeCheckFlags(decl); if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter || hasCapturedBindingsInForHead) { const outParamName = factory.createUniqueName("out_" + idText(name)); @@ -3482,8 +4076,8 @@ namespace ts { flags |= LoopOutParameterFlags.Initializer; } if ( - container.condition && resolver.isBindingCapturedByNode(container.condition, decl) || - container.incrementor && resolver.isBindingCapturedByNode(container.incrementor, decl) + container.condition && resolver.isBindingCapturedByNode(container.condition, decl) + || container.incrementor && resolver.isBindingCapturedByNode(container.incrementor, decl) ) { flags |= LoopOutParameterFlags.Body; } @@ -3502,7 +4096,12 @@ namespace ts { * @param numInitialNonComputedProperties The number of initial properties without * computed property names. */ - function addObjectLiteralMembers(expressions: Expression[], node: ObjectLiteralExpression, receiver: Identifier, start: number) { + function addObjectLiteralMembers( + expressions: Expression[], + node: ObjectLiteralExpression, + receiver: Identifier, + start: number, + ) { const properties = node.properties; const numProperties = properties.length; for (let i = start; i < numProperties; i++) { @@ -3512,13 +4111,22 @@ namespace ts { case SyntaxKind.SetAccessor: const accessors = getAllAccessorDeclarations(node.properties, property); if (property === accessors.firstAccessor) { - expressions.push(transformAccessorsToExpression(receiver, accessors, node, !!node.multiLine)); + expressions.push( + transformAccessorsToExpression(receiver, accessors, node, !!node.multiLine), + ); } break; case SyntaxKind.MethodDeclaration: - expressions.push(transformObjectLiteralMethodDeclarationToExpression(property, receiver, node, node.multiLine!)); + expressions.push( + transformObjectLiteralMethodDeclarationToExpression( + property, + receiver, + node, + node.multiLine!, + ), + ); break; case SyntaxKind.PropertyAssignment: @@ -3526,7 +4134,9 @@ namespace ts { break; case SyntaxKind.ShorthandPropertyAssignment: - expressions.push(transformShorthandPropertyAssignmentToExpression(property, receiver, node.multiLine!)); + expressions.push( + transformShorthandPropertyAssignmentToExpression(property, receiver, node.multiLine!), + ); break; default: @@ -3543,7 +4153,11 @@ namespace ts { * @param property The PropertyAssignment node. * @param receiver The receiver for the assignment. */ - function transformPropertyAssignmentToExpression(property: PropertyAssignment, receiver: Expression, startsOnNewLine: boolean) { + function transformPropertyAssignmentToExpression( + property: PropertyAssignment, + receiver: Expression, + startsOnNewLine: boolean, + ) { const expression = factory.createAssignment( createMemberAccessForPropertyName( factory, @@ -3566,7 +4180,11 @@ namespace ts { * @param property The ShorthandPropertyAssignment node. * @param receiver The receiver for the assignment. */ - function transformShorthandPropertyAssignmentToExpression(property: ShorthandPropertyAssignment, receiver: Expression, startsOnNewLine: boolean) { + function transformShorthandPropertyAssignmentToExpression( + property: ShorthandPropertyAssignment, + receiver: Expression, + startsOnNewLine: boolean, + ) { const expression = factory.createAssignment( createMemberAccessForPropertyName( factory, @@ -3589,7 +4207,12 @@ namespace ts { * @param method The MethodDeclaration node. * @param receiver The receiver for the assignment. */ - function transformObjectLiteralMethodDeclarationToExpression(method: MethodDeclaration, receiver: Expression, container: Node, startsOnNewLine: boolean) { + function transformObjectLiteralMethodDeclarationToExpression( + method: MethodDeclaration, + receiver: Expression, + container: Node, + startsOnNewLine: boolean, + ) { const expression = factory.createAssignment( createMemberAccessForPropertyName( factory, @@ -3608,7 +4231,10 @@ namespace ts { function visitCatchClause(node: CatchClause): CatchClause { const ancestorFacts = enterSubtree(HierarchyFacts.BlockScopeExcludes, HierarchyFacts.BlockScopeIncludes); let updated: CatchClause; - Debug.assert(!!node.variableDeclaration, "Catch clause variable should always be present when downleveling ES2015."); + Debug.assert( + !!node.variableDeclaration, + "Catch clause variable should always be present when downleveling ES2015.", + ); if (isBindingPattern(node.variableDeclaration.name)) { const temp = factory.createTempVariable(/*recordTempVariable*/ undefined); const newVariableDeclaration = factory.createVariableDeclaration(temp); @@ -3623,7 +4249,11 @@ namespace ts { const list = factory.createVariableDeclarationList(vars); setTextRange(list, node.variableDeclaration); const destructure = factory.createVariableStatement(/*modifiers*/ undefined, list); - updated = factory.updateCatchClause(node, newVariableDeclaration, addStatementToStartOfBlock(node.block, destructure)); + updated = factory.updateCatchClause( + node, + newVariableDeclaration, + addStatementToStartOfBlock(node.block, destructure), + ); } else { updated = visitEachChild(node, visitor, context); @@ -3649,7 +4279,12 @@ namespace ts { // Methods on classes are handled in visitClassDeclaration/visitClassExpression. // Methods with computed property names are handled in visitObjectLiteralExpression. Debug.assert(!isComputedPropertyName(node.name)); - const functionExpression = transformFunctionLikeToExpression(node, /*location*/ moveRangePos(node, -1), /*name*/ undefined, /*container*/ undefined); + const functionExpression = transformFunctionLikeToExpression( + node, + /*location*/ moveRangePos(node, -1), + /*name*/ undefined, + /*container*/ undefined, + ); setEmitFlags(functionExpression, EmitFlags.NoLeadingComments | getEmitFlags(functionExpression)); return setTextRange( factory.createPropertyAssignment( @@ -3674,7 +4309,14 @@ namespace ts { const parameters = visitParameterList(node.parameters, visitor, context); const body = transformFunctionBody(node); if (node.kind === SyntaxKind.GetAccessor) { - updated = factory.updateGetAccessorDeclaration(node, node.modifiers, node.name, parameters, node.type, body); + updated = factory.updateGetAccessorDeclaration( + node, + node.modifiers, + node.name, + parameters, + node.type, + body, + ); } else { updated = factory.updateSetAccessorDeclaration(node, node.modifiers, node.name, parameters, body); @@ -3721,7 +4363,12 @@ namespace ts { function visitArrayLiteralExpression(node: ArrayLiteralExpression): Expression { if (some(node.elements, isSpreadElement)) { // We are here because we contain a SpreadElementExpression. - return transformAndSpreadElements(node.elements, /*isArgumentList*/ false, !!node.multiLine, /*hasTrailingComma*/ !!node.elements.hasTrailingComma); + return transformAndSpreadElements( + node.elements, + /*isArgumentList*/ false, + !!node.multiLine, + /*hasTrailingComma*/ !!node.elements.hasTrailingComma, + ); } return visitEachChild(node, visitor, context); } @@ -3738,9 +4385,9 @@ namespace ts { const expression = skipOuterExpressions(node.expression); if ( - expression.kind === SyntaxKind.SuperKeyword || - isSuperProperty(expression) || - some(node.arguments, isSpreadElement) + expression.kind === SyntaxKind.SuperKeyword + || isSuperProperty(expression) + || some(node.arguments, isSpreadElement) ) { return visitCallExpressionWithPotentialCapturedThisAssignment(node, /*assignToCapturedThis*/ true); } @@ -3791,7 +4438,8 @@ namespace ts { // The class statements are the statements generated by visiting the first statement with initializer of the // body (1), while all other statements are added to remainingStatements (2) - const isVariableStatementWithInitializer = (stmt: Statement) => isVariableStatement(stmt) && !!first(stmt.declarationList.declarations).initializer; + const isVariableStatementWithInitializer = (stmt: Statement) => + isVariableStatement(stmt) && !!first(stmt.declarationList.declarations).initializer; // visit the class body statements outside of any converted loop body. const savedConvertedLoopState = convertedLoopState; @@ -3824,12 +4472,18 @@ namespace ts { // }()) // let aliasAssignment = tryCast(initializer, isAssignmentExpression); - if (!aliasAssignment && isBinaryExpression(initializer) && initializer.operatorToken.kind === SyntaxKind.CommaToken) { + if ( + !aliasAssignment && isBinaryExpression(initializer) + && initializer.operatorToken.kind === SyntaxKind.CommaToken + ) { aliasAssignment = tryCast(initializer.left, isAssignmentExpression); } // The underlying call (3) is another IIFE that may contain a '_super' argument. - const call = cast(aliasAssignment ? skipOuterExpressions(aliasAssignment.right) : initializer, isCallExpression); + const call = cast( + aliasAssignment ? skipOuterExpressions(aliasAssignment.right) : initializer, + isCallExpression, + ); const func = cast(skipOuterExpressions(call.expression), isFunctionExpression); const funcStatements = func.body.statements; @@ -3921,13 +4575,16 @@ namespace ts { return visitCallExpressionWithPotentialCapturedThisAssignment(node, /*assignToCapturedThis*/ false); } - function visitCallExpressionWithPotentialCapturedThisAssignment(node: CallExpression, assignToCapturedThis: boolean): CallExpression | BinaryExpression { + function visitCallExpressionWithPotentialCapturedThisAssignment( + node: CallExpression, + assignToCapturedThis: boolean, + ): CallExpression | BinaryExpression { // We are here either because SuperKeyword was used somewhere in the expression, or // because we contain a SpreadElementExpression. if ( - node.transformFlags & TransformFlags.ContainsRestOrSpread || - node.expression.kind === SyntaxKind.SuperKeyword || - isSuperProperty(skipOuterExpressions(node.expression)) + node.transformFlags & TransformFlags.ContainsRestOrSpread + || node.expression.kind === SyntaxKind.SuperKeyword + || isSuperProperty(skipOuterExpressions(node.expression)) ) { const { target, thisArg } = factory.createCallBinding(node.expression, hoistVariableDeclaration); if (node.expression.kind === SyntaxKind.SuperKeyword) { @@ -3952,8 +4609,14 @@ namespace ts { resultingCall = factory.createFunctionApplyCall( visitNode(target, callExpressionVisitor, isExpression), - node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : visitNode(thisArg, visitor, isExpression), - transformAndSpreadElements(node.arguments, /*isArgumentList*/ true, /*multiLine*/ false, /*hasTrailingComma*/ false), + node.expression.kind === SyntaxKind.SuperKeyword ? thisArg + : visitNode(thisArg, visitor, isExpression), + transformAndSpreadElements( + node.arguments, + /*isArgumentList*/ true, + /*multiLine*/ false, + /*hasTrailingComma*/ false, + ), ); } else { @@ -3969,7 +4632,8 @@ namespace ts { resultingCall = setTextRange( factory.createFunctionCallCall( visitNode(target, callExpressionVisitor, isExpression), - node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : visitNode(thisArg, visitor, isExpression), + node.expression.kind === SyntaxKind.SuperKeyword ? thisArg + : visitNode(thisArg, visitor, isExpression), visitNodes(node.arguments, visitor, isExpression), ), node, @@ -3982,7 +4646,13 @@ namespace ts { createActualThis(), ); resultingCall = assignToCapturedThis - ? factory.createAssignment(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), initializer) + ? factory.createAssignment( + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + initializer, + ) : initializer; } return setOriginalNode(resultingCall, node); @@ -4005,12 +4675,20 @@ namespace ts { // [output] // new ((_a = C).bind.apply(_a, [void 0].concat(a)))() - const { target, thisArg } = factory.createCallBinding(factory.createPropertyAccessExpression(node.expression, "bind"), hoistVariableDeclaration); + const { target, thisArg } = factory.createCallBinding( + factory.createPropertyAccessExpression(node.expression, "bind"), + hoistVariableDeclaration, + ); return factory.createNewExpression( factory.createFunctionApplyCall( visitNode(target, visitor, isExpression), thisArg, - transformAndSpreadElements(factory.createNodeArray([factory.createVoidZero(), ...node.arguments!]), /*isArgumentList*/ true, /*multiLine*/ false, /*hasTrailingComma*/ false), + transformAndSpreadElements( + factory.createNodeArray([factory.createVoidZero(), ...node.arguments!]), + /*isArgumentList*/ true, + /*multiLine*/ false, + /*hasTrailingComma*/ false, + ), ), /*typeArguments*/ undefined, [], @@ -4028,7 +4706,12 @@ namespace ts { * argument list. * @param multiLine A value indicating whether the result should be emitted on multiple lines. */ - function transformAndSpreadElements(elements: NodeArray, isArgumentList: boolean, multiLine: boolean, hasTrailingComma: boolean): Expression { + function transformAndSpreadElements( + elements: NodeArray, + isArgumentList: boolean, + multiLine: boolean, + hasTrailingComma: boolean, + ): Expression { // When there is no leading SpreadElement: // // [source] @@ -4067,7 +4750,12 @@ namespace ts { // As we visit each element, we return one of two functions to use as the "key": // - `visitSpanOfSpreads` for one or more contiguous `...` spread expressions, i.e. `...a, ...b` in `[1, 2, ...a, ...b]` // - `visitSpanOfNonSpreads` for one or more contiguous non-spread elements, i.e. `1, 2`, in `[1, 2, ...a, ...b]` - spanMap(elements, partitionSpread, (partition, visitPartition, _start, end) => visitPartition(partition, multiLine, hasTrailingComma && end === numElements)), + spanMap( + elements, + partitionSpread, + (partition, visitPartition, _start, end) => + visitPartition(partition, multiLine, hasTrailingComma && end === numElements), + ), ); if (segments.length === 1) { @@ -4087,8 +4775,8 @@ namespace ts { const helpers = emitHelpers(); const startsWithSpread = segments[0].kind !== SpreadSegmentKind.None; - let expression: Expression = startsWithSpread ? factory.createArrayLiteralExpression() : - segments[0].expression; + let expression: Expression = startsWithSpread ? factory.createArrayLiteralExpression() + : segments[0].expression; for (let i = startsWithSpread ? 0 : 1; i < segments.length; i++) { const segment = segments[i]; // If this is for an argument list, it doesn't matter if the array is packed or sparse @@ -4116,10 +4804,14 @@ namespace ts { // We don't need to pack already packed array literals, or existing calls to the `__read` helper. const isCallToReadHelper = isCallToHelper(expression, "___read" as __String); - let kind = isCallToReadHelper || isPackedArrayLiteral(expression) ? SpreadSegmentKind.PackedSpread : SpreadSegmentKind.UnpackedSpread; + let kind = isCallToReadHelper || isPackedArrayLiteral(expression) ? SpreadSegmentKind.PackedSpread + : SpreadSegmentKind.UnpackedSpread; // We don't need the `__read` helper for array literals. Array packing will be performed by `__spreadArray`. - if (compilerOptions.downlevelIteration && kind === SpreadSegmentKind.UnpackedSpread && !isArrayLiteralExpression(expression) && !isCallToReadHelper) { + if ( + compilerOptions.downlevelIteration && kind === SpreadSegmentKind.UnpackedSpread + && !isArrayLiteralExpression(expression) && !isCallToReadHelper + ) { expression = emitHelpers().createReadHelper(expression, /*count*/ undefined); // the `__read` helper returns a packed array, so we don't need to ensure a packed array kind = SpreadSegmentKind.PackedSpread; @@ -4128,7 +4820,11 @@ namespace ts { return createSpreadSegment(kind, expression); } - function visitSpanOfNonSpreads(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): SpreadSegment { + function visitSpanOfNonSpreads( + chunk: Expression[], + multiLine: boolean, + hasTrailingComma: boolean, + ): SpreadSegment { const expression = factory.createArrayLiteralExpression( visitNodes(factory.createNodeArray(chunk, hasTrailingComma), visitor, isExpression), multiLine, @@ -4222,14 +4918,26 @@ namespace ts { function visitSuperKeyword(isExpressionOfCall: boolean): LeftHandSideExpression { return hierarchyFacts & HierarchyFacts.NonStaticClassElement && !isExpressionOfCall - ? factory.createPropertyAccessExpression(factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), "prototype") - : factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + ? factory.createPropertyAccessExpression( + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + "prototype", + ) + : factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); } function visitMetaProperty(node: MetaProperty) { if (node.keywordToken === SyntaxKind.NewKeyword && node.name.escapedText === "target") { hierarchyFacts |= HierarchyFacts.NewTarget; - return factory.createUniqueName("_newTarget", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + return factory.createUniqueName( + "_newTarget", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); } return node; } @@ -4376,7 +5084,10 @@ namespace ts { function isPartOfClassBody(declaration: ClassLikeDeclaration, node: Identifier) { let currentNode: Node | undefined = getParseTreeNode(node); - if (!currentNode || currentNode === declaration || currentNode.end <= declaration.pos || currentNode.pos >= declaration.end) { + if ( + !currentNode || currentNode === declaration || currentNode.end <= declaration.pos + || currentNode.pos >= declaration.end + ) { // if the node has no correlation to a parse tree node, its definitely not // part of the body. // if the node is outside of the document range of the declaration, its @@ -4408,7 +5119,13 @@ namespace ts { enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis && hierarchyFacts & HierarchyFacts.CapturesThis ) { - return setTextRange(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), node); + return setTextRange( + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + node, + ); } return node; } @@ -4419,7 +5136,10 @@ namespace ts { : factory.createPropertyAccessExpression(factory.getInternalName(node), "prototype"); } - function hasSynthesizedDefaultSuperCall(constructor: ConstructorDeclaration | undefined, hasExtendsClause: boolean) { + function hasSynthesizedDefaultSuperCall( + constructor: ConstructorDeclaration | undefined, + hasExtendsClause: boolean, + ) { if (!constructor || !hasExtendsClause) { return false; } diff --git a/src/compiler/transformers/es2016.ts b/src/compiler/transformers/es2016.ts index cb1a797c6364c..67d144deee29c 100644 --- a/src/compiler/transformers/es2016.ts +++ b/src/compiler/transformers/es2016.ts @@ -51,7 +51,10 @@ namespace ts { target = setTextRange( factory.createElementAccessExpression( setTextRange(factory.createAssignment(expressionTemp, left.expression), left.expression), - setTextRange(factory.createAssignment(argumentExpressionTemp, left.argumentExpression), left.argumentExpression), + setTextRange( + factory.createAssignment(argumentExpressionTemp, left.argumentExpression), + left.argumentExpression, + ), ), left, ); diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index ee9732a583afe..c99d05ad616a9 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -1,6 +1,11 @@ /*@internal*/ namespace ts { - type SuperContainer = ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration; + type SuperContainer = + | ClassDeclaration + | MethodDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration + | ConstructorDeclaration; const enum ES2017SubstitutionFlags { /** Enables substitutions for async methods with `super` calls. */ @@ -116,25 +121,43 @@ namespace ts { return visitAwaitExpression(node as AwaitExpression); case SyntaxKind.MethodDeclaration: - return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitMethodDeclaration, node as MethodDeclaration); + return doWithContext( + ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, + visitMethodDeclaration, + node as MethodDeclaration, + ); case SyntaxKind.FunctionDeclaration: - return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitFunctionDeclaration, node as FunctionDeclaration); + return doWithContext( + ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, + visitFunctionDeclaration, + node as FunctionDeclaration, + ); case SyntaxKind.FunctionExpression: - return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitFunctionExpression, node as FunctionExpression); + return doWithContext( + ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, + visitFunctionExpression, + node as FunctionExpression, + ); case SyntaxKind.ArrowFunction: return doWithContext(ContextFlags.NonTopLevel, visitArrowFunction, node as ArrowFunction); case SyntaxKind.PropertyAccessExpression: - if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) { + if ( + capturedSuperProperties && isPropertyAccessExpression(node) + && node.expression.kind === SyntaxKind.SuperKeyword + ) { capturedSuperProperties.add(node.name.escapedText); } return visitEachChild(node, visitor, context); case SyntaxKind.ElementAccessExpression: - if (capturedSuperProperties && (node as ElementAccessExpression).expression.kind === SyntaxKind.SuperKeyword) { + if ( + capturedSuperProperties + && (node as ElementAccessExpression).expression.kind === SyntaxKind.SuperKeyword + ) { hasSuperElementAccess = true; } return visitEachChild(node, visitor, context); @@ -212,7 +235,10 @@ namespace ts { function visitVariableStatementInAsyncBody(node: VariableStatement) { if (isVariableDeclarationListWithCollidingName(node.declarationList)) { - const expression = visitVariableDeclarationListWithCollidingNames(node.declarationList, /*hasReceiver*/ false); + const expression = visitVariableDeclarationListWithCollidingNames( + node.declarationList, + /*hasReceiver*/ false, + ); return expression ? factory.createExpressionStatement(expression) : undefined; } return visitEachChild(node, visitor, context); @@ -370,7 +396,10 @@ namespace ts { ); } - function recordDeclarationName({ name }: ParameterDeclaration | VariableDeclaration | BindingElement, names: Set<__String>) { + function recordDeclarationName( + { name }: ParameterDeclaration | VariableDeclaration | BindingElement, + names: Set<__String>, + ) { if (isIdentifier(name)) { names.add(name.escapedText); } @@ -396,7 +425,11 @@ namespace ts { const variables = getInitializedVariables(node); if (variables.length === 0) { if (hasReceiver) { - return visitNode(factory.converters.convertToAssignmentElementTarget(node.declarations[0].name), visitor, isExpression); + return visitNode( + factory.converters.convertToAssignmentElementTarget(node.declarations[0].name), + visitor, + isExpression, + ); } return undefined; } @@ -446,14 +479,17 @@ namespace ts { return false; } - function transformAsyncFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody; + function transformAsyncFunctionBody( + node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression, + ): FunctionBody; function transformAsyncFunctionBody(node: ArrowFunction): ConciseBody; function transformAsyncFunctionBody(node: FunctionLikeDeclaration): ConciseBody { resumeLexicalEnvironment(); const original = getOriginalNode(node, isFunctionLike); const nodeType = original.type; - const promiseConstructor = languageVersion < ScriptTarget.ES2015 ? getPromiseConstructor(nodeType) : undefined; + const promiseConstructor = languageVersion < ScriptTarget.ES2015 ? getPromiseConstructor(nodeType) + : undefined; const isArrowFunction = node.kind === SyntaxKind.ArrowFunction; const hasLexicalArguments = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.CaptureArguments) !== 0; @@ -479,7 +515,12 @@ namespace ts { let result: ConciseBody; if (!isArrowFunction) { const statements: Statement[] = []; - const statementOffset = factory.copyPrologue((node.body as Block).statements, statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = factory.copyPrologue( + (node.body as Block).statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); statements.push( factory.createReturnStatement( emitHelpers().createAwaiterHelper( @@ -495,12 +536,19 @@ namespace ts { // Minor optimization, emit `_super` helper to capture `super` access in an arrow. // This step isn't needed if we eventually transform this to ES5. - const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuperBinding | NodeCheckFlags.AsyncMethodWithSuper); + const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 + && resolver.getNodeCheckFlags(node) + & (NodeCheckFlags.AsyncMethodWithSuperBinding | NodeCheckFlags.AsyncMethodWithSuper); if (emitSuperHelpers) { enableSubstitutionForAsyncMethodsWithSuper(); if (capturedSuperProperties.size) { - const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties); + const variableStatement = createSuperAccessVariableStatement( + factory, + resolver, + node, + capturedSuperProperties, + ); substitutedSuperAccessors[getNodeId(variableStatement)] = true; insertStatementsAfterStandardPrologue(statements, [variableStatement]); } @@ -532,7 +580,13 @@ namespace ts { const declarations = endLexicalEnvironment(); if (some(declarations)) { const block = factory.converters.convertToFunctionBlock(expression); - result = factory.updateBlock(block, setTextRange(factory.createNodeArray(concatenate(declarations, block.statements)), block.statements)); + result = factory.updateBlock( + block, + setTextRange( + factory.createNodeArray(concatenate(declarations, block.statements)), + block.statements, + ), + ); } else { result = expression; @@ -603,7 +657,8 @@ namespace ts { // If we need to support substitutions for `super` in an async method, // we should track it here. if (enabledSubstitutions & ES2017SubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) { - const superContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding); + const superContainerFlags = resolver.getNodeCheckFlags(node) + & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding); if (superContainerFlags !== enclosingSuperContainerFlags) { const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags; enclosingSuperContainerFlags = superContainerFlags; @@ -654,7 +709,10 @@ namespace ts { if (node.expression.kind === SyntaxKind.SuperKeyword) { return setTextRange( factory.createPropertyAccessExpression( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), node.name, ), node, @@ -700,12 +758,18 @@ namespace ts { || kind === SyntaxKind.SetAccessor; } - function createSuperElementAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression { + function createSuperElementAccessInAsyncMethod( + argumentExpression: Expression, + location: TextRange, + ): LeftHandSideExpression { if (enclosingSuperContainerFlags & NodeCheckFlags.AsyncMethodWithSuperBinding) { return setTextRange( factory.createPropertyAccessExpression( factory.createCallExpression( - factory.createUniqueName("_superIndex", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_superIndex", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*typeArguments*/ undefined, [argumentExpression], ), @@ -717,7 +781,10 @@ namespace ts { else { return setTextRange( factory.createCallExpression( - factory.createUniqueName("_superIndex", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_superIndex", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*typeArguments*/ undefined, [argumentExpression], ), @@ -728,7 +795,12 @@ namespace ts { } /** Creates a variable named `_super` with accessor properties for the given property names. */ - export function createSuperAccessVariableStatement(factory: NodeFactory, resolver: EmitResolver, node: FunctionLikeDeclaration, names: Set<__String>) { + export function createSuperAccessVariableStatement( + factory: NodeFactory, + resolver: EmitResolver, + node: FunctionLikeDeclaration, + names: Set<__String>, + ) { // Create a variable declaration with a getter/setter (if binding) definition for each name: // const _super = Object.create(null, { x: { get: () => super.x, set: (v) => super.x = v }, ... }); const hasBinding = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuperBinding) !== 0; @@ -804,7 +876,10 @@ namespace ts { factory.createVariableDeclarationList( [ factory.createVariableDeclaration( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*exclamationToken*/ undefined, /* type */ undefined, factory.createCallExpression( diff --git a/src/compiler/transformers/es2018.ts b/src/compiler/transformers/es2018.ts index adc82fa08ab3a..e23e7d747cace 100644 --- a/src/compiler/transformers/es2018.ts +++ b/src/compiler/transformers/es2018.ts @@ -135,7 +135,12 @@ namespace ts { return node; } - function doWithHierarchyFacts(cb: (value: T) => U, value: T, excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) { + function doWithHierarchyFacts( + cb: (value: T) => U, + value: T, + excludeFacts: HierarchyFacts, + includeFacts: HierarchyFacts, + ) { if (affectsSubtree(excludeFacts, includeFacts)) { const ancestorFacts = enterSubtree(excludeFacts, includeFacts); const result = cb(value); @@ -256,12 +261,18 @@ namespace ts { case SyntaxKind.TaggedTemplateExpression: return visitTaggedTemplateExpression(node as TaggedTemplateExpression); case SyntaxKind.PropertyAccessExpression: - if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) { + if ( + capturedSuperProperties && isPropertyAccessExpression(node) + && node.expression.kind === SyntaxKind.SuperKeyword + ) { capturedSuperProperties.add(node.name.escapedText); } return visitEachChild(node, visitor, context); case SyntaxKind.ElementAccessExpression: - if (capturedSuperProperties && (node as ElementAccessExpression).expression.kind === SyntaxKind.SuperKeyword) { + if ( + capturedSuperProperties + && (node as ElementAccessExpression).expression.kind === SyntaxKind.SuperKeyword + ) { hasSuperElementAccess = true; } return visitEachChild(node, visitor, context); @@ -282,7 +293,10 @@ namespace ts { if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { return setOriginalNode( setTextRange( - factory.createYieldExpression(/*asteriskToken*/ undefined, emitHelpers().createAwaitHelper(visitNode(node.expression, visitor, isExpression))), + factory.createYieldExpression( + /*asteriskToken*/ undefined, + emitHelpers().createAwaitHelper(visitNode(node.expression, visitor, isExpression)), + ), /*location*/ node, ), node, @@ -360,7 +374,10 @@ namespace ts { if (statement.kind === SyntaxKind.ForOfStatement && (statement as ForOfStatement).awaitModifier) { return visitForOfStatement(statement as ForOfStatement, node); } - return factory.restoreEnclosingLabel(visitNode(statement, visitor, isStatement, factory.liftToBlock), node); + return factory.restoreEnclosingLabel( + visitNode(statement, visitor, isStatement, factory.liftToBlock), + node, + ); } return visitEachChild(node, visitor, context); } @@ -442,26 +459,39 @@ namespace ts { * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the * expression of an `ExpressionStatement`). */ - function visitParenthesizedExpression(node: ParenthesizedExpression, expressionResultIsUnused: boolean): ParenthesizedExpression { - return visitEachChild(node, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, context); + function visitParenthesizedExpression( + node: ParenthesizedExpression, + expressionResultIsUnused: boolean, + ): ParenthesizedExpression { + return visitEachChild( + node, + expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, + context, + ); } function visitSourceFile(node: SourceFile): SourceFile { const ancestorFacts = enterSubtree( HierarchyFacts.SourceFileExcludes, - isEffectiveStrictModeSourceFile(node, compilerOptions) ? - HierarchyFacts.StrictModeSourceFileIncludes : - HierarchyFacts.SourceFileIncludes, + isEffectiveStrictModeSourceFile(node, compilerOptions) + ? HierarchyFacts.StrictModeSourceFileIncludes + : HierarchyFacts.SourceFileIncludes, ); exportedVariableStatement = false; const visited = visitEachChild(node, visitor, context); const statement = concatenate( visited.statements, taggedTemplateStringDeclarations && [ - factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList(taggedTemplateStringDeclarations)), + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList(taggedTemplateStringDeclarations), + ), ], ); - const result = factory.updateSourceFile(visited, setTextRange(factory.createNodeArray(statement), node.statements)); + const result = factory.updateSourceFile( + visited, + setTextRange(factory.createNodeArray(statement), node.statements), + ); exitSubtree(ancestorFacts); return result; } @@ -485,7 +515,9 @@ namespace ts { * expression of an `ExpressionStatement`). */ function visitBinaryExpression(node: BinaryExpression, expressionResultIsUnused: boolean): Expression { - if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { + if ( + isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread + ) { return flattenDestructuringAssignment( node, visitor, @@ -499,7 +531,11 @@ namespace ts { node, visitNode(node.left, visitorWithUnusedExpressionResult, isExpression), node.operatorToken, - visitNode(node.right, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, isExpression), + visitNode( + node.right, + expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, + isExpression, + ), ); } return visitEachChild(node, visitor, context); @@ -516,7 +552,11 @@ namespace ts { let result: Expression[] | undefined; for (let i = 0; i < node.elements.length; i++) { const element = node.elements[i]; - const visited = visitNode(element, i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, isExpression); + const visited = visitNode( + element, + i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, + isExpression, + ); if (result || visited !== element) { result ||= node.elements.slice(0, i); result.push(visited); @@ -528,13 +568,24 @@ namespace ts { function visitCatchClause(node: CatchClause) { if ( - node.variableDeclaration && - isBindingPattern(node.variableDeclaration.name) && - node.variableDeclaration.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread + node.variableDeclaration + && isBindingPattern(node.variableDeclaration.name) + && node.variableDeclaration.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread ) { const name = factory.getGeneratedNameForNode(node.variableDeclaration.name); - const updatedDecl = factory.updateVariableDeclaration(node.variableDeclaration, node.variableDeclaration.name, /*exclamationToken*/ undefined, /*type*/ undefined, name); - const visitedBindings = flattenDestructuringBinding(updatedDecl, visitor, context, FlattenLevel.ObjectRest); + const updatedDecl = factory.updateVariableDeclaration( + node.variableDeclaration, + node.variableDeclaration.name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + name, + ); + const visitedBindings = flattenDestructuringBinding( + updatedDecl, + visitor, + context, + FlattenLevel.ObjectRest, + ); let block = visitNode(node.block, visitor, isBlock); if (some(visitedBindings)) { block = factory.updateBlock(block, [ @@ -544,7 +595,13 @@ namespace ts { } return factory.updateCatchClause( node, - factory.updateVariableDeclaration(node.variableDeclaration, name, /*exclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined), + factory.updateVariableDeclaration( + node.variableDeclaration, + name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined, + ), block, ); } @@ -578,7 +635,10 @@ namespace ts { return visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ false); } - function visitVariableDeclarationWorker(node: VariableDeclaration, exportedVariableStatement: boolean): VisitResult { + function visitVariableDeclarationWorker( + node: VariableDeclaration, + exportedVariableStatement: boolean, + ): VisitResult { // If we are here it is because the name contains a binding pattern with a rest somewhere in it. if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { return flattenDestructuringBinding( @@ -612,14 +672,20 @@ namespace ts { * * @param node A ForOfStatement. */ - function visitForOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined): VisitResult { - const ancestorFacts = enterSubtree(HierarchyFacts.IterationStatementExcludes, HierarchyFacts.IterationStatementIncludes); + function visitForOfStatement( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement | undefined, + ): VisitResult { + const ancestorFacts = enterSubtree( + HierarchyFacts.IterationStatementExcludes, + HierarchyFacts.IterationStatementIncludes, + ); if (node.initializer.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { node = transformForOfStatementWithObjectRest(node); } - const result = node.awaitModifier ? - transformForAwaitOfStatement(node, outermostLabeledStatement, ancestorFacts) : - factory.restoreEnclosingLabel(visitEachChild(node, visitor, context), outermostLabeledStatement); + const result = node.awaitModifier + ? transformForAwaitOfStatement(node, outermostLabeledStatement, ancestorFacts) + : factory.restoreEnclosingLabel(visitEachChild(node, visitor, context), outermostLabeledStatement); exitSubtree(ancestorFacts); return result; } @@ -696,19 +762,32 @@ namespace ts { function createDownlevelAwait(expression: Expression) { return enclosingFunctionFlags & FunctionFlags.Generator - ? factory.createYieldExpression(/*asteriskToken*/ undefined, emitHelpers().createAwaitHelper(expression)) + ? factory.createYieldExpression( + /*asteriskToken*/ undefined, + emitHelpers().createAwaitHelper(expression), + ) : factory.createAwaitExpression(expression); } - function transformForAwaitOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts) { + function transformForAwaitOfStatement( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement | undefined, + ancestorFacts: HierarchyFacts, + ) { const expression = visitNode(node.expression, visitor, isExpression); - const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined); - const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) : factory.createTempVariable(/*recordTempVariable*/ undefined); + const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) + : factory.createTempVariable(/*recordTempVariable*/ undefined); + const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) + : factory.createTempVariable(/*recordTempVariable*/ undefined); const errorRecord = factory.createUniqueName("e"); const catchVariable = factory.getGeneratedNameForNode(errorRecord); const returnMethod = factory.createTempVariable(/*recordTempVariable*/ undefined); const callValues = setTextRange(emitHelpers().createAsyncValuesHelper(expression), node.expression); - const callNext = factory.createCallExpression(factory.createPropertyAccessExpression(iterator, "next"), /*typeArguments*/ undefined, []); + const callNext = factory.createCallExpression( + factory.createPropertyAccessExpression(iterator, "next"), + /*typeArguments*/ undefined, + [], + ); const getDone = factory.createPropertyAccessExpression(result, "done"); const getValue = factory.createPropertyAccessExpression(result, "value"); const callReturn = factory.createFunctionCallCall(returnMethod, iterator, []); @@ -717,9 +796,12 @@ namespace ts { hoistVariableDeclaration(returnMethod); // if we are enclosed in an outer loop ensure we reset 'errorRecord' per each iteration - const initializer = ancestorFacts & HierarchyFacts.IterationContainer ? - factory.inlineExpressions([factory.createAssignment(errorRecord, factory.createVoidZero()), callValues]) : - callValues; + const initializer = ancestorFacts & HierarchyFacts.IterationContainer + ? factory.inlineExpressions([ + factory.createAssignment(errorRecord, factory.createVoidZero()), + callValues, + ]) + : callValues; const forStatement = setEmitFlags( setTextRange( @@ -727,7 +809,15 @@ namespace ts { /*initializer*/ setEmitFlags( setTextRange( factory.createVariableDeclarationList([ - setTextRange(factory.createVariableDeclaration(iterator, /*exclamationToken*/ undefined, /*type*/ undefined, initializer), node.expression), + setTextRange( + factory.createVariableDeclaration( + iterator, + /*exclamationToken*/ undefined, + /*type*/ undefined, + initializer, + ), + node.expression, + ), factory.createVariableDeclaration(result), ]), node.expression, @@ -1005,10 +1095,17 @@ namespace ts { return updated; } - function transformAsyncGeneratorFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody { + function transformAsyncGeneratorFunctionBody( + node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression, + ): FunctionBody { resumeLexicalEnvironment(); const statements: Statement[] = []; - const statementOffset = factory.copyPrologue(node.body!.statements, statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = factory.copyPrologue( + node.body!.statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); appendObjectRestAssignmentsIfNeeded(statements, node); const savedCapturedSuperProperties = capturedSuperProperties; @@ -1036,11 +1133,18 @@ namespace ts { // Minor optimization, emit `_super` helper to capture `super` access in an arrow. // This step isn't needed if we eventually transform this to ES5. - const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuperBinding | NodeCheckFlags.AsyncMethodWithSuper); + const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 + && resolver.getNodeCheckFlags(node) + & (NodeCheckFlags.AsyncMethodWithSuperBinding | NodeCheckFlags.AsyncMethodWithSuper); if (emitSuperHelpers) { enableSubstitutionForAsyncMethodsWithSuper(); - const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties); + const variableStatement = createSuperAccessVariableStatement( + factory, + resolver, + node, + capturedSuperProperties, + ); substitutedSuperAccessors[getNodeId(variableStatement)] = true; insertStatementsAfterStandardPrologue(statements, [variableStatement]); } @@ -1065,7 +1169,14 @@ namespace ts { return block; } - function transformFunctionBody(node: FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | AccessorDeclaration): FunctionBody; + function transformFunctionBody( + node: + | FunctionDeclaration + | FunctionExpression + | ConstructorDeclaration + | MethodDeclaration + | AccessorDeclaration, + ): FunctionBody; function transformFunctionBody(node: ArrowFunction): ConciseBody; function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody { resumeLexicalEnvironment(); @@ -1087,7 +1198,10 @@ namespace ts { return body; } - function appendObjectRestAssignmentsIfNeeded(statements: Statement[] | undefined, node: FunctionLikeDeclaration): Statement[] | undefined { + function appendObjectRestAssignmentsIfNeeded( + statements: Statement[] | undefined, + node: FunctionLikeDeclaration, + ): Statement[] | undefined { let containsPrecedingObjectRestOrSpread = false; for (const parameter of node.parameters) { if (containsPrecedingObjectRestOrSpread) { @@ -1107,7 +1221,10 @@ namespace ts { ); if (some(declarations)) { const declarationList = factory.createVariableDeclarationList(declarations); - const statement = factory.createVariableStatement(/*modifiers*/ undefined, declarationList); + const statement = factory.createVariableStatement( + /*modifiers*/ undefined, + declarationList, + ); setEmitFlags(statement, EmitFlags.CustomPrologue); statements = append(statements, statement); } @@ -1145,13 +1262,21 @@ namespace ts { const block = factory.createBlock([factory.createExpressionStatement(assignment)]); setTextRange(block, parameter); - setEmitFlags(block, EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments); + setEmitFlags( + block, + EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps + | EmitFlags.NoComments, + ); const typeCheck = factory.createTypeCheck(factory.cloneNode(parameter.name), "undefined"); const statement = factory.createIfStatement(typeCheck, block); startOnNewLine(statement); setTextRange(statement, parameter); - setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue | EmitFlags.NoComments); + setEmitFlags( + statement, + EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue + | EmitFlags.NoComments, + ); statements = append(statements, statement); } } @@ -1209,7 +1334,8 @@ namespace ts { // If we need to support substitutions for `super` in an async method, // we should track it here. if (enabledSubstitutions & ESNextSubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) { - const superContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding); + const superContainerFlags = resolver.getNodeCheckFlags(node) + & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding); if (superContainerFlags !== enclosingSuperContainerFlags) { const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags; enclosingSuperContainerFlags = superContainerFlags; @@ -1260,7 +1386,10 @@ namespace ts { if (node.expression.kind === SyntaxKind.SuperKeyword) { return setTextRange( factory.createPropertyAccessExpression( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), node.name, ), node, @@ -1306,7 +1435,10 @@ namespace ts { || kind === SyntaxKind.SetAccessor; } - function createSuperElementAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression { + function createSuperElementAccessInAsyncMethod( + argumentExpression: Expression, + location: TextRange, + ): LeftHandSideExpression { if (enclosingSuperContainerFlags & NodeCheckFlags.AsyncMethodWithSuperBinding) { return setTextRange( factory.createPropertyAccessExpression( diff --git a/src/compiler/transformers/es2020.ts b/src/compiler/transformers/es2020.ts index bd03a4d443d5b..ba99e06168172 100644 --- a/src/compiler/transformers/es2020.ts +++ b/src/compiler/transformers/es2020.ts @@ -57,17 +57,28 @@ namespace ts { return { expression: chain.expression, chain: links }; } - function visitNonOptionalParenthesizedExpression(node: ParenthesizedExpression, captureThisArg: boolean, isDelete: boolean): Expression { + function visitNonOptionalParenthesizedExpression( + node: ParenthesizedExpression, + captureThisArg: boolean, + isDelete: boolean, + ): Expression { const expression = visitNonOptionalExpression(node.expression, captureThisArg, isDelete); if (isSyntheticReference(expression)) { // `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` } // `(a[b])` -> { expression `((_a = a)[b])`, thisArg: `_a` } - return factory.createSyntheticReferenceExpression(factory.updateParenthesizedExpression(node, expression.expression), expression.thisArg); + return factory.createSyntheticReferenceExpression( + factory.updateParenthesizedExpression(node, expression.expression), + expression.thisArg, + ); } return factory.updateParenthesizedExpression(node, expression); } - function visitNonOptionalPropertyOrElementAccessExpression(node: AccessExpression, captureThisArg: boolean, isDelete: boolean): Expression { + function visitNonOptionalPropertyOrElementAccessExpression( + node: AccessExpression, + captureThisArg: boolean, + isDelete: boolean, + ): Expression { if (isOptionalChain(node)) { // If `node` is an optional chain, then it is the outermost chain of an optional expression. return visitOptionalExpression(node, captureThisArg, isDelete); @@ -89,7 +100,11 @@ namespace ts { expression = node.kind === SyntaxKind.PropertyAccessExpression ? factory.updatePropertyAccessExpression(node, expression, visitNode(node.name, visitor, isIdentifier)) - : factory.updateElementAccessExpression(node, expression, visitNode(node.argumentExpression, visitor, isExpression)); + : factory.updateElementAccessExpression( + node, + expression, + visitNode(node.argumentExpression, visitor, isExpression), + ); return thisArg ? factory.createSyntheticReferenceExpression(expression, thisArg) : expression; } @@ -100,10 +115,17 @@ namespace ts { } if (isParenthesizedExpression(node.expression) && isOptionalChain(skipParentheses(node.expression))) { // capture thisArg for calls of parenthesized optional chains like `(foo?.bar)()` - const expression = visitNonOptionalParenthesizedExpression(node.expression, /*captureThisArg*/ true, /*isDelete*/ false); + const expression = visitNonOptionalParenthesizedExpression( + node.expression, + /*captureThisArg*/ true, + /*isDelete*/ false, + ); const args = visitNodes(node.arguments, visitor, isExpression); if (isSyntheticReference(expression)) { - return setTextRange(factory.createFunctionCallCall(expression.expression, expression.thisArg, args), node); + return setTextRange( + factory.createFunctionCallCall(expression.expression, expression.thisArg, args), + node, + ); } return factory.updateCallExpression(node, expression, /*typeArguments*/ undefined, args); } @@ -113,10 +135,18 @@ namespace ts { function visitNonOptionalExpression(node: Expression, captureThisArg: boolean, isDelete: boolean): Expression { switch (node.kind) { case SyntaxKind.ParenthesizedExpression: - return visitNonOptionalParenthesizedExpression(node as ParenthesizedExpression, captureThisArg, isDelete); + return visitNonOptionalParenthesizedExpression( + node as ParenthesizedExpression, + captureThisArg, + isDelete, + ); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: - return visitNonOptionalPropertyOrElementAccessExpression(node as AccessExpression, captureThisArg, isDelete); + return visitNonOptionalPropertyOrElementAccessExpression( + node as AccessExpression, + captureThisArg, + isDelete, + ); case SyntaxKind.CallExpression: return visitNonOptionalCallExpression(node as CallExpression, captureThisArg); default: @@ -126,10 +156,18 @@ namespace ts { function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean, isDelete: boolean): Expression { const { expression, chain } = flattenChain(node); - const left = visitNonOptionalExpression(skipPartiallyEmittedExpressions(expression), isCallChain(chain[0]), /*isDelete*/ false); + const left = visitNonOptionalExpression( + skipPartiallyEmittedExpressions(expression), + isCallChain(chain[0]), + /*isDelete*/ false, + ); let leftThisArg = isSyntheticReference(left) ? left.thisArg : undefined; let capturedLeft = isSyntheticReference(left) ? left.expression : left; - let leftExpression = factory.restoreOuterExpressions(expression, capturedLeft, OuterExpressionKinds.PartiallyEmittedExpressions); + let leftExpression = factory.restoreOuterExpressions( + expression, + capturedLeft, + OuterExpressionKinds.PartiallyEmittedExpressions, + ); if (!isSimpleCopiableExpression(capturedLeft)) { capturedLeft = factory.createTempVariable(hoistVariableDeclaration); leftExpression = factory.createAssignment(capturedLeft, leftExpression); @@ -151,8 +189,14 @@ namespace ts { } } rightExpression = segment.kind === SyntaxKind.PropertyAccessExpression - ? factory.createPropertyAccessExpression(rightExpression, visitNode(segment.name, visitor, isIdentifier)) - : factory.createElementAccessExpression(rightExpression, visitNode(segment.argumentExpression, visitor, isExpression)); + ? factory.createPropertyAccessExpression( + rightExpression, + visitNode(segment.name, visitor, isIdentifier), + ) + : factory.createElementAccessExpression( + rightExpression, + visitNode(segment.argumentExpression, visitor, isExpression), + ); break; case SyntaxKind.CallExpression: if (i === 0 && leftThisArg) { @@ -179,8 +223,20 @@ namespace ts { } const target = isDelete - ? factory.createConditionalExpression(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), /*questionToken*/ undefined, factory.createTrue(), /*colonToken*/ undefined, factory.createDeleteExpression(rightExpression)) - : factory.createConditionalExpression(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), /*questionToken*/ undefined, factory.createVoidZero(), /*colonToken*/ undefined, rightExpression); + ? factory.createConditionalExpression( + createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), + /*questionToken*/ undefined, + factory.createTrue(), + /*colonToken*/ undefined, + factory.createDeleteExpression(rightExpression), + ) + : factory.createConditionalExpression( + createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), + /*questionToken*/ undefined, + factory.createVoidZero(), + /*colonToken*/ undefined, + rightExpression, + ); setTextRange(target, node); return thisArg ? factory.createSyntheticReferenceExpression(target, thisArg) : target; } @@ -189,13 +245,17 @@ namespace ts { return factory.createBinaryExpression( factory.createBinaryExpression( left, - factory.createToken(invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken), + factory.createToken( + invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken, + ), factory.createNull(), ), factory.createToken(invert ? SyntaxKind.BarBarToken : SyntaxKind.AmpersandAmpersandToken), factory.createBinaryExpression( right, - factory.createToken(invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken), + factory.createToken( + invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken, + ), factory.createVoidZero(), ), ); @@ -222,7 +282,10 @@ namespace ts { function visitDeleteExpression(node: DeleteExpression) { return isOptionalChain(skipParentheses(node.expression)) - ? setOriginalNode(visitNonOptionalExpression(node.expression, /*captureThisArg*/ false, /*isDelete*/ true), node) + ? setOriginalNode( + visitNonOptionalExpression(node.expression, /*captureThisArg*/ false, /*isDelete*/ true), + node, + ) : factory.updateDeleteExpression(node, visitNode(node.expression, visitor, isExpression)); } } diff --git a/src/compiler/transformers/es2021.ts b/src/compiler/transformers/es2021.ts index 71bb4c22f55ca..54cad9ec7c533 100644 --- a/src/compiler/transformers/es2021.ts +++ b/src/compiler/transformers/es2021.ts @@ -31,7 +31,9 @@ namespace ts { } } - function transformLogicalAssignment(binaryExpression: AssignmentExpression>): VisitResult { + function transformLogicalAssignment( + binaryExpression: AssignmentExpression>, + ): VisitResult { const operator = binaryExpression.operatorToken; const nonAssignmentOperator = getNonAssignmentOperatorForCompoundAssignment(operator.kind); let left = skipParentheses(visitNode(binaryExpression.left, visitor, isLeftHandSideExpression)); @@ -40,12 +42,13 @@ namespace ts { if (isAccessExpression(left)) { const propertyAccessTargetSimpleCopiable = isSimpleCopiableExpression(left.expression); - const propertyAccessTarget = propertyAccessTargetSimpleCopiable ? left.expression : - factory.createTempVariable(hoistVariableDeclaration); - const propertyAccessTargetAssignment = propertyAccessTargetSimpleCopiable ? left.expression : factory.createAssignment( - propertyAccessTarget, - left.expression, - ); + const propertyAccessTarget = propertyAccessTargetSimpleCopiable ? left.expression + : factory.createTempVariable(hoistVariableDeclaration); + const propertyAccessTargetAssignment = propertyAccessTargetSimpleCopiable ? left.expression + : factory.createAssignment( + propertyAccessTarget, + left.expression, + ); if (isPropertyAccessExpression(left)) { assignmentTarget = factory.createPropertyAccessExpression( @@ -59,8 +62,8 @@ namespace ts { } else { const elementAccessArgumentSimpleCopiable = isSimpleCopiableExpression(left.argumentExpression); - const elementAccessArgument = elementAccessArgumentSimpleCopiable ? left.argumentExpression : - factory.createTempVariable(hoistVariableDeclaration); + const elementAccessArgument = elementAccessArgumentSimpleCopiable ? left.argumentExpression + : factory.createTempVariable(hoistVariableDeclaration); assignmentTarget = factory.createElementAccessExpression( propertyAccessTarget, diff --git a/src/compiler/transformers/es5.ts b/src/compiler/transformers/es5.ts index e82ba20cf5f9f..b2ab08a1f86bd 100644 --- a/src/compiler/transformers/es5.ts +++ b/src/compiler/transformers/es5.ts @@ -10,7 +10,11 @@ namespace ts { const compilerOptions = context.getCompilerOptions(); // enable emit notification only if using --jsx preserve or react-native - let previousOnEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void; + let previousOnEmitNode: ( + hint: EmitHint, + node: Node, + emitCallback: (hint: EmitHint, node: Node) => void, + ) => void; let noSubstitution: boolean[]; if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) { previousOnEmitNode = context.onEmitNode; @@ -112,7 +116,8 @@ namespace ts { * @param name An Identifier */ function trySubstituteReservedName(name: Identifier) { - const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(idText(name)) : undefined); + const token = name.originalKeywordKind + || (nodeIsSynthesized(name) ? stringToToken(idText(name)) : undefined); if (token !== undefined && token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) { return setTextRange(factory.createStringLiteralFromNode(name), name); } diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index ae3d0bf4be1ac..ca7fd1aed1539 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -135,7 +135,10 @@ namespace ts { Endfinally, // Marks the end of a `finally` block } - type OperationArguments = [Label] | [Label, Expression] | [Statement] | [Expression | undefined] | [Expression, Expression]; + type OperationArguments = [Label] | [Label, Expression] | [Statement] | [Expression | undefined] | [ + Expression, + Expression, + ]; // whether a generated code block is opening or closing at the current operation for a FunctionBuilder const enum BlockAction { @@ -384,7 +387,10 @@ namespace ts { if (node.transformFlags & TransformFlags.ContainsYield) { return visitJavaScriptContainingYield(node); } - else if (node.transformFlags & (TransformFlags.ContainsGenerator | TransformFlags.ContainsHoistedDeclarationOrCompletion)) { + else if ( + node.transformFlags + & (TransformFlags.ContainsGenerator | TransformFlags.ContainsHoistedDeclarationOrCompletion) + ) { return visitEachChild(node, visitor, context); } else { @@ -590,7 +596,12 @@ namespace ts { // Build the generator resumeLexicalEnvironment(); - const statementOffset = factory.copyPrologue(body.statements, statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = factory.copyPrologue( + body.statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); transformAndEmitStatements(body.statements, statementOffset); @@ -698,7 +709,13 @@ namespace ts { target = factory.updatePropertyAccessExpression( left as PropertyAccessExpression, - cacheExpression(visitNode((left as PropertyAccessExpression).expression, visitor, isLeftHandSideExpression)), + cacheExpression( + visitNode( + (left as PropertyAccessExpression).expression, + visitor, + isLeftHandSideExpression, + ), + ), (left as PropertyAccessExpression).name, ); break; @@ -715,7 +732,19 @@ namespace ts { // .mark resumeLabel // _a[_b] = %sent%; - target = factory.updateElementAccessExpression(left as ElementAccessExpression, cacheExpression(visitNode((left as ElementAccessExpression).expression, visitor, isLeftHandSideExpression)), cacheExpression(visitNode((left as ElementAccessExpression).argumentExpression, visitor, isExpression))); + target = factory.updateElementAccessExpression( + left as ElementAccessExpression, + cacheExpression( + visitNode( + (left as ElementAccessExpression).expression, + visitor, + isLeftHandSideExpression, + ), + ), + cacheExpression( + visitNode((left as ElementAccessExpression).argumentExpression, visitor, isExpression), + ), + ); break; default: @@ -741,7 +770,12 @@ namespace ts { ); } else { - return factory.updateBinaryExpression(node, target, node.operatorToken, visitNode(right, visitor, isExpression)); + return factory.updateBinaryExpression( + node, + target, + node.operatorToken, + visitNode(right, visitor, isExpression), + ); } } @@ -766,7 +800,12 @@ namespace ts { // .yield resumeLabel // _a + %sent% + c() - return factory.updateBinaryExpression(node, cacheExpression(visitNode(node.left, visitor, isExpression)), node.operatorToken, visitNode(node.right, visitor, isExpression)); + return factory.updateBinaryExpression( + node, + cacheExpression(visitNode(node.left, visitor, isExpression)), + node.operatorToken, + visitNode(node.right, visitor, isExpression), + ); } return visitEachChild(node, visitor, context); @@ -799,7 +838,9 @@ namespace ts { } else { if (containsYield(node) && pendingExpressions.length > 0) { - emitWorker(OpCode.Statement, [factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))]); + emitWorker(OpCode.Statement, [ + factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions)), + ]); pendingExpressions = []; } @@ -822,7 +863,9 @@ namespace ts { } else { if (containsYield(elem) && pendingExpressions.length > 0) { - emitWorker(OpCode.Statement, [factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))]); + emitWorker(OpCode.Statement, [ + factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions)), + ]); pendingExpressions = []; } pendingExpressions.push(visitNode(elem, visitor, isExpression)); @@ -912,11 +955,23 @@ namespace ts { const whenFalseLabel = defineLabel(); const resultLabel = defineLabel(); const resultLocal = declareLocal(); - emitBreakWhenFalse(whenFalseLabel, visitNode(node.condition, visitor, isExpression), /*location*/ node.condition); - emitAssignment(resultLocal, visitNode(node.whenTrue, visitor, isExpression), /*location*/ node.whenTrue); + emitBreakWhenFalse( + whenFalseLabel, + visitNode(node.condition, visitor, isExpression), + /*location*/ node.condition, + ); + emitAssignment( + resultLocal, + visitNode(node.whenTrue, visitor, isExpression), + /*location*/ node.whenTrue, + ); emitBreak(resultLabel); markLabel(whenFalseLabel); - emitAssignment(resultLocal, visitNode(node.whenFalse, visitor, isExpression), /*location*/ node.whenFalse); + emitAssignment( + resultLocal, + visitNode(node.whenFalse, visitor, isExpression), + /*location*/ node.whenFalse, + ); markLabel(resultLabel); return resultLocal; } @@ -971,7 +1026,12 @@ namespace ts { * @param elements The elements to visit. * @param multiLine Whether array literals created should be emitted on multiple lines. */ - function visitElements(elements: NodeArray, leadingElement?: Expression, location?: TextRange, multiLine?: boolean) { + function visitElements( + elements: NodeArray, + leadingElement?: Expression, + location?: TextRange, + multiLine?: boolean, + ) { // [source] // ar = [1, yield, 2]; // @@ -1003,7 +1063,10 @@ namespace ts { return temp ? factory.createArrayConcatCall(temp, [factory.createArrayLiteralExpression(expressions, multiLine)]) : setTextRange( - factory.createArrayLiteralExpression(leadingElement ? [leadingElement, ...expressions] : expressions, multiLine), + factory.createArrayLiteralExpression( + leadingElement ? [leadingElement, ...expressions] : expressions, + multiLine, + ), location, ); @@ -1069,7 +1132,9 @@ namespace ts { const expressions = reduceLeft(properties, reduceProperty, [] as Expression[], numInitialProperties); // TODO(rbuckton): Does this need to be parented? - expressions.push(multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp); + expressions.push( + multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp, + ); return factory.inlineExpressions(expressions); function reduceProperty(expressions: Expression[], property: ObjectLiteralElementLike) { @@ -1107,7 +1172,11 @@ namespace ts { // .mark resumeLabel // a = _a[%sent%] - return factory.updateElementAccessExpression(node, cacheExpression(visitNode(node.expression, visitor, isLeftHandSideExpression)), visitNode(node.argumentExpression, visitor, isExpression)); + return factory.updateElementAccessExpression( + node, + cacheExpression(visitNode(node.expression, visitor, isLeftHandSideExpression)), + visitNode(node.argumentExpression, visitor, isExpression), + ); } return visitEachChild(node, visitor, context); @@ -1125,7 +1194,12 @@ namespace ts { // .yield resumeLabel // .mark resumeLabel // _b.apply(_a, _c.concat([%sent%, 2])); - const { target, thisArg } = factory.createCallBinding(node.expression, hoistVariableDeclaration, languageVersion, /*cacheIdentifiers*/ true); + const { target, thisArg } = factory.createCallBinding( + node.expression, + hoistVariableDeclaration, + languageVersion, + /*cacheIdentifiers*/ true, + ); return setOriginalNode( setTextRange( factory.createFunctionApplyCall( @@ -1155,7 +1229,10 @@ namespace ts { // .mark resumeLabel // new (_b.apply(_a, _c.concat([%sent%, 2]))); - const { target, thisArg } = factory.createCallBinding(factory.createPropertyAccessExpression(node.expression, "bind"), hoistVariableDeclaration); + const { target, thisArg } = factory.createCallBinding( + factory.createPropertyAccessExpression(node.expression, "bind"), + hoistVariableDeclaration, + ); return setOriginalNode( setTextRange( factory.createNewExpression( @@ -1254,7 +1331,9 @@ namespace ts { emitStatement(visitNode(node, visitor, isStatement)); } - function transformAndEmitVariableDeclarationList(node: VariableDeclarationList): VariableDeclarationList | undefined { + function transformAndEmitVariableDeclarationList( + node: VariableDeclarationList, + ): VariableDeclarationList | undefined { for (const variable of node.declarations) { const name = factory.cloneNode(variable.name as Identifier); setCommentRange(name, variable.name); @@ -1314,7 +1393,11 @@ namespace ts { if (containsYield(node.thenStatement) || containsYield(node.elseStatement)) { const endLabel = defineLabel(); const elseLabel = node.elseStatement ? defineLabel() : undefined; - emitBreakWhenFalse(node.elseStatement ? elseLabel! : endLabel, visitNode(node.expression, visitor, isExpression), /*location*/ node.expression); + emitBreakWhenFalse( + node.elseStatement ? elseLabel! : endLabel, + visitNode(node.expression, visitor, isExpression), + /*location*/ node.expression, + ); transformAndEmitEmbeddedStatement(node.thenStatement); if (node.elseStatement) { emitBreak(endLabel); @@ -1567,7 +1650,10 @@ namespace ts { const endLabel = beginLoopBlock(incrementLabel); markLabel(conditionLabel); - emitBreakWhenFalse(endLabel, factory.createLessThan(keysIndex, factory.createPropertyAccessExpression(keysArray, "length"))); + emitBreakWhenFalse( + endLabel, + factory.createLessThan(keysIndex, factory.createPropertyAccessExpression(keysArray, "length")), + ); let variable: Expression; if (isVariableDeclarationList(initializer)) { @@ -1620,7 +1706,12 @@ namespace ts { hoistVariableDeclaration(variable.name as Identifier); } - node = factory.updateForInStatement(node, initializer.declarations[0].name as Identifier, visitNode(node.expression, visitor, isExpression), visitNode(node.statement, visitor, isStatement, factory.liftToBlock)); + node = factory.updateForInStatement( + node, + initializer.declarations[0].name as Identifier, + visitNode(node.expression, visitor, isExpression), + visitNode(node.statement, visitor, isStatement, factory.liftToBlock), + ); } else { node = visitEachChild(node, visitor, context); @@ -1791,7 +1882,9 @@ namespace ts { } if (pendingClauses.length) { - emitStatement(factory.createSwitchStatement(expression, factory.createCaseBlock(pendingClauses))); + emitStatement( + factory.createSwitchStatement(expression, factory.createCaseBlock(pendingClauses)), + ); clausesWritten += pendingClauses.length; pendingClauses = []; } @@ -2152,7 +2245,14 @@ namespace ts { exception.catchVariable = name; exception.catchLabel = catchLabel; - emitAssignment(name, factory.createCallExpression(factory.createPropertyAccessExpression(state, "sent"), /*typeArguments*/ undefined, [])); + emitAssignment( + name, + factory.createCallExpression( + factory.createPropertyAccessExpression(state, "sent"), + /*typeArguments*/ undefined, + [], + ), + ); emitNop(); } @@ -2363,7 +2463,9 @@ namespace ts { if (supportsLabeledBreakOrContinue(block) && block.labelText === labelText) { return block.breakLabel; } - else if (supportsUnlabeledBreak(block) && hasImmediateContainingLabeledBlock(labelText, i - 1)) { + else if ( + supportsUnlabeledBreak(block) && hasImmediateContainingLabeledBlock(labelText, i - 1) + ) { return block.breakLabel; } } @@ -2653,7 +2755,11 @@ namespace ts { /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, - [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, state)], + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + state, + )], /*type*/ undefined, factory.createBlock( buildResult, @@ -2682,7 +2788,10 @@ namespace ts { if (clauses) { const labelExpression = factory.createPropertyAccessExpression(state, "label"); - const switchStatement = factory.createSwitchStatement(labelExpression, factory.createCaseBlock(clauses)); + const switchStatement = factory.createSwitchStatement( + labelExpression, + factory.createCaseBlock(clauses), + ); return [startOnNewLine(switchStatement)]; } @@ -2771,7 +2880,9 @@ namespace ts { // surround the statements in generated `with` blocks to create the same environment. for (let i = withBlockStack.length - 1; i >= 0; i--) { const withBlock = withBlockStack[i]; - statements = [factory.createWithStatement(withBlock.expression, factory.createBlock(statements))]; + statements = [ + factory.createWithStatement(withBlock.expression, factory.createBlock(statements)), + ]; } } @@ -2783,7 +2894,10 @@ namespace ts { statements.unshift( factory.createExpressionStatement( factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(state, "trys"), "push"), + factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression(state, "trys"), + "push", + ), /*typeArguments*/ undefined, [ factory.createArrayLiteralExpression([ @@ -2988,7 +3102,12 @@ namespace ts { * @param operationLocation The source map location for the operation. */ function writeAssign(left: Expression, right: Expression, operationLocation: TextRange | undefined): void { - writeStatement(setTextRange(factory.createExpressionStatement(factory.createAssignment(left, right)), operationLocation)); + writeStatement( + setTextRange( + factory.createExpressionStatement(factory.createAssignment(left, right)), + operationLocation, + ), + ); } /** @@ -3060,7 +3179,11 @@ namespace ts { * @param condition The condition for the Break. * @param operationLocation The source map location for the operation. */ - function writeBreakWhenTrue(label: Label, condition: Expression, operationLocation: TextRange | undefined): void { + function writeBreakWhenTrue( + label: Label, + condition: Expression, + operationLocation: TextRange | undefined, + ): void { writeStatement( setEmitFlags( factory.createIfStatement( @@ -3090,7 +3213,11 @@ namespace ts { * @param condition The condition for the Break. * @param operationLocation The source map location for the operation. */ - function writeBreakWhenFalse(label: Label, condition: Expression, operationLocation: TextRange | undefined): void { + function writeBreakWhenFalse( + label: Label, + condition: Expression, + operationLocation: TextRange | undefined, + ): void { writeStatement( setEmitFlags( factory.createIfStatement( diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index 751e1ed66adec..3de60e3016137 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -21,7 +21,15 @@ namespace ts { if (currentFileState.filenameDeclaration) { return currentFileState.filenameDeclaration.name; } - const declaration = factory.createVariableDeclaration(factory.createUniqueName("_jsxFileName", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), /*exclaimationToken*/ undefined, /*type*/ undefined, factory.createStringLiteral(currentSourceFile.fileName)); + const declaration = factory.createVariableDeclaration( + factory.createUniqueName( + "_jsxFileName", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + /*exclaimationToken*/ undefined, + /*type*/ undefined, + factory.createStringLiteral(currentSourceFile.fileName), + ); currentFileState.filenameDeclaration = declaration as VariableDeclaration & { name: Identifier; }; return currentFileState.filenameDeclaration.name; } @@ -55,8 +63,16 @@ namespace ts { specifierSourceImports = new Map(); currentFileState.utilizedImplicitRuntimeImports.set(importSource, specifierSourceImports); } - const generatedName = factory.createUniqueName(`_${name}`, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel | GeneratedIdentifierFlags.AllowNameSubstitution); - const specifier = factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier(name), generatedName); + const generatedName = factory.createUniqueName( + `_${name}`, + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel + | GeneratedIdentifierFlags.AllowNameSubstitution, + ); + const specifier = factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier(name), + generatedName, + ); generatedName.generatedImportReference = specifier; specifierSourceImports.set(name, specifier); return generatedName; @@ -79,13 +95,32 @@ namespace ts { addEmitHelpers(visited, context.readEmitHelpers()); let statements: readonly Statement[] = visited.statements; if (currentFileState.filenameDeclaration) { - statements = insertStatementAfterCustomPrologue(statements.slice(), factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([currentFileState.filenameDeclaration], NodeFlags.Const))); + statements = insertStatementAfterCustomPrologue( + statements.slice(), + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([currentFileState.filenameDeclaration], NodeFlags.Const), + ), + ); } if (currentFileState.utilizedImplicitRuntimeImports) { - for (const [importSource, importSpecifiersMap] of arrayFrom(currentFileState.utilizedImplicitRuntimeImports.entries())) { + for ( + const [importSource, importSpecifiersMap] of arrayFrom( + currentFileState.utilizedImplicitRuntimeImports.entries(), + ) + ) { if (isExternalModule(node)) { // Add `import` statement - const importStatement = factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*typeOnly*/ false, /*name*/ undefined, factory.createNamedImports(arrayFrom(importSpecifiersMap.values()))), factory.createStringLiteral(importSource), /*assertClause*/ undefined); + const importStatement = factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause( + /*typeOnly*/ false, + /*name*/ undefined, + factory.createNamedImports(arrayFrom(importSpecifiersMap.values())), + ), + factory.createStringLiteral(importSource), + /*assertClause*/ undefined, + ); setParentRecursive(importStatement, /*incremental*/ false); statements = insertStatementAfterCustomPrologue(statements.slice(), importStatement); } @@ -95,10 +130,21 @@ namespace ts { /*modifiers*/ undefined, factory.createVariableDeclarationList([ factory.createVariableDeclaration( - factory.createObjectBindingPattern(map(arrayFrom(importSpecifiersMap.values()), s => factory.createBindingElement(/*dotdotdot*/ undefined, s.propertyName, s.name))), + factory.createObjectBindingPattern( + map(arrayFrom(importSpecifiersMap.values()), s => + factory.createBindingElement( + /*dotdotdot*/ undefined, + s.propertyName, + s.name, + )), + ), /*exclaimationToken*/ undefined, /*type*/ undefined, - factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [factory.createStringLiteral(importSource)]), + factory.createCallExpression( + factory.createIdentifier("require"), + /*typeArguments*/ undefined, + [factory.createStringLiteral(importSource)], + ), ), ], NodeFlags.Const), ); @@ -188,17 +234,20 @@ namespace ts { } function visitJsxElement(node: JsxElement, isChild: boolean) { - const tagTransform = shouldUseCreateElement(node.openingElement) ? visitJsxOpeningLikeElementCreateElement : visitJsxOpeningLikeElementJSX; + const tagTransform = shouldUseCreateElement(node.openingElement) ? visitJsxOpeningLikeElementCreateElement + : visitJsxOpeningLikeElementJSX; return tagTransform(node.openingElement, node.children, isChild, /*location*/ node); } function visitJsxSelfClosingElement(node: JsxSelfClosingElement, isChild: boolean) { - const tagTransform = shouldUseCreateElement(node) ? visitJsxOpeningLikeElementCreateElement : visitJsxOpeningLikeElementJSX; + const tagTransform = shouldUseCreateElement(node) ? visitJsxOpeningLikeElementCreateElement + : visitJsxOpeningLikeElementJSX; return tagTransform(node, /*children*/ undefined, isChild, /*location*/ node); } function visitJsxFragment(node: JsxFragment, isChild: boolean) { - const tagTransform = currentFileState.importSpecifier === undefined ? visitJsxOpeningFragmentCreateElement : visitJsxOpeningFragmentJSX; + const tagTransform = currentFileState.importSpecifier === undefined ? visitJsxOpeningFragmentCreateElement + : visitJsxOpeningFragmentJSX; return tagTransform(node.openingFragment, node.children, isChild, /*location*/ node); } @@ -214,16 +263,27 @@ namespace ts { return result && factory.createPropertyAssignment("children", result); } const result = mapDefined(children, transformJsxChildToExpression); - return length(result) ? factory.createPropertyAssignment("children", factory.createArrayLiteralExpression(result)) : undefined; + return length(result) + ? factory.createPropertyAssignment("children", factory.createArrayLiteralExpression(result)) + : undefined; } - function visitJsxOpeningLikeElementJSX(node: JsxOpeningLikeElement, children: readonly JsxChild[] | undefined, isChild: boolean, location: TextRange) { + function visitJsxOpeningLikeElementJSX( + node: JsxOpeningLikeElement, + children: readonly JsxChild[] | undefined, + isChild: boolean, + location: TextRange, + ) { const tagName = getTagName(node); - const childrenProp = children && children.length ? convertJsxChildrenToChildrenPropAssignment(children) : undefined; - const keyAttr = find(node.attributes.properties, p => !!p.name && isIdentifier(p.name) && p.name.escapedText === "key") as JsxAttribute | undefined; + const childrenProp = children && children.length ? convertJsxChildrenToChildrenPropAssignment(children) + : undefined; + const keyAttr = find( + node.attributes.properties, + p => !!p.name && isIdentifier(p.name) && p.name.escapedText === "key", + ) as JsxAttribute | undefined; const attrs = keyAttr ? filter(node.attributes.properties, p => p !== keyAttr) : node.attributes.properties; - const objectProperties = length(attrs) ? transformJsxAttributesToObjectProps(attrs, childrenProp) : - factory.createObjectLiteralExpression(childrenProp ? [childrenProp] : emptyArray); // When there are no attributes, React wants {} + const objectProperties = length(attrs) ? transformJsxAttributesToObjectProps(attrs, childrenProp) + : factory.createObjectLiteralExpression(childrenProp ? [childrenProp] : emptyArray); // When there are no attributes, React wants {} return visitJsxOpeningLikeElementOrFragmentJSX( tagName, objectProperties, @@ -243,7 +303,8 @@ namespace ts { location: TextRange, ) { const nonWhitespaceChildren = getSemanticJsxChildren(children); - const isStaticChildren = length(nonWhitespaceChildren) > 1 || !!(nonWhitespaceChildren[0] as JsxExpression)?.dotDotDotToken; + const isStaticChildren = length(nonWhitespaceChildren) > 1 + || !!(nonWhitespaceChildren[0] as JsxExpression)?.dotDotDotToken; const args: Expression[] = [tagName, objectProperties]; // function jsx(type, config, maybeKey) {} // "maybeKey" is optional. It is acceptable to use "_jsx" without a third argument @@ -264,7 +325,10 @@ namespace ts { args.push(factory.createObjectLiteralExpression([ factory.createPropertyAssignment("fileName", getCurrentFileNameExpression()), factory.createPropertyAssignment("lineNumber", factory.createNumericLiteral(lineCol.line + 1)), - factory.createPropertyAssignment("columnNumber", factory.createNumericLiteral(lineCol.character + 1)), + factory.createPropertyAssignment( + "columnNumber", + factory.createNumericLiteral(lineCol.character + 1), + ), ])); // __self development flag args.push(factory.createThis()); @@ -283,11 +347,16 @@ namespace ts { return element; } - function visitJsxOpeningLikeElementCreateElement(node: JsxOpeningLikeElement, children: readonly JsxChild[] | undefined, isChild: boolean, location: TextRange) { + function visitJsxOpeningLikeElementCreateElement( + node: JsxOpeningLikeElement, + children: readonly JsxChild[] | undefined, + isChild: boolean, + location: TextRange, + ) { const tagName = getTagName(node); const attrs = node.attributes.properties; - const objectProperties = length(attrs) ? transformJsxAttributesToObjectProps(attrs) : - factory.createNull(); // When there are no attributes, React wants "null" + const objectProperties = length(attrs) ? transformJsxAttributesToObjectProps(attrs) + : factory.createNull(); // When there are no attributes, React wants "null" const callee = currentFileState.importSpecifier === undefined ? createJsxFactoryExpression( @@ -314,7 +383,12 @@ namespace ts { return element; } - function visitJsxOpeningFragmentJSX(_node: JsxOpeningFragment, children: readonly JsxChild[], isChild: boolean, location: TextRange) { + function visitJsxOpeningFragmentJSX( + _node: JsxOpeningFragment, + children: readonly JsxChild[], + isChild: boolean, + location: TextRange, + ) { let childrenProps: Expression | undefined; if (children && children.length) { const result = convertJsxChildrenToChildrenPropObject(children); @@ -332,7 +406,12 @@ namespace ts { ); } - function visitJsxOpeningFragmentCreateElement(node: JsxOpeningFragment, children: readonly JsxChild[], isChild: boolean, location: TextRange) { + function visitJsxOpeningFragmentCreateElement( + node: JsxOpeningFragment, + children: readonly JsxChild[], + isChild: boolean, + location: TextRange, + ) { const element = createExpressionForJsxFragment( factory, context.getEmitResolver().getJsxFactoryEntity(currentSourceFile), @@ -354,28 +433,52 @@ namespace ts { return factory.createSpreadAssignment(visitNode(node.expression, visitor, isExpression)); } - function transformJsxAttributesToObjectProps(attrs: readonly (JsxSpreadAttribute | JsxAttribute)[], children?: PropertyAssignment) { + function transformJsxAttributesToObjectProps( + attrs: readonly (JsxSpreadAttribute | JsxAttribute)[], + children?: PropertyAssignment, + ) { const target = getEmitScriptTarget(compilerOptions); - return target && target >= ScriptTarget.ES2018 ? factory.createObjectLiteralExpression(transformJsxAttributesToProps(attrs, children)) : - transformJsxAttributesToExpression(attrs, children); + return target && target >= ScriptTarget.ES2018 + ? factory.createObjectLiteralExpression(transformJsxAttributesToProps(attrs, children)) + : transformJsxAttributesToExpression(attrs, children); } - function transformJsxAttributesToProps(attrs: readonly (JsxSpreadAttribute | JsxAttribute)[], children?: PropertyAssignment) { - const props = flatten(spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => map(attrs, attr => isSpread ? transformJsxSpreadAttributeToSpreadAssignment(attr as JsxSpreadAttribute) : transformJsxAttributeToObjectLiteralElement(attr as JsxAttribute)))); + function transformJsxAttributesToProps( + attrs: readonly (JsxSpreadAttribute | JsxAttribute)[], + children?: PropertyAssignment, + ) { + const props = flatten( + spanMap( + attrs, + isJsxSpreadAttribute, + (attrs, isSpread) => + map( + attrs, + attr => + isSpread ? transformJsxSpreadAttributeToSpreadAssignment(attr as JsxSpreadAttribute) + : transformJsxAttributeToObjectLiteralElement(attr as JsxAttribute), + ), + ), + ); if (children) { props.push(children); } return props; } - function transformJsxAttributesToExpression(attrs: readonly (JsxSpreadAttribute | JsxAttribute)[], children?: PropertyAssignment) { + function transformJsxAttributesToExpression( + attrs: readonly (JsxSpreadAttribute | JsxAttribute)[], + children?: PropertyAssignment, + ) { // Map spans of JsxAttribute nodes into object literals and spans // of JsxSpreadAttribute nodes into expressions. const expressions = flatten( spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => isSpread ? map(attrs, transformJsxSpreadAttributeToExpression) - : factory.createObjectLiteralExpression(map(attrs, transformJsxAttributeToObjectLiteralElement))), + : factory.createObjectLiteralExpression( + map(attrs, transformJsxAttributeToObjectLiteralElement), + )), ); if (isJsxSpreadAttribute(attrs[0])) { @@ -408,7 +511,8 @@ namespace ts { if (node.kind === SyntaxKind.StringLiteral) { // Always recreate the literal to escape any escape sequences or newlines which may be in the original jsx string and which // Need to be escaped to be handled correctly in a normal string - const singleQuote = node.singleQuote !== undefined ? node.singleQuote : !isStringDoubleQuoted(node, currentSourceFile); + const singleQuote = node.singleQuote !== undefined ? node.singleQuote + : !isStringDoubleQuoted(node, currentSourceFile); const literal = factory.createStringLiteral(tryDecodeEntities(node.text) || node.text, singleQuote); return setTextRange(literal, node); } @@ -466,7 +570,10 @@ namespace ts { // If we've seen any non-whitespace characters on this line, add the 'trim' of the line. // (lastNonWhitespace === -1 is a special flag to detect whether the first line is all whitespace.) if (firstNonWhitespace !== -1 && lastNonWhitespace !== -1) { - acc = addLineOfJsxText(acc, text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1)); + acc = addLineOfJsxText( + acc, + text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1), + ); } // Reset firstNonWhitespace for the next line. @@ -500,19 +607,22 @@ namespace ts { * See https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references */ function decodeEntities(text: string): string { - return text.replace(/&((#((\d+)|x([\da-fA-F]+)))|(\w+));/g, (match, _all, _number, _digits, decimal, hex, word) => { - if (decimal) { - return utf16EncodeAsString(parseInt(decimal, 10)); - } - else if (hex) { - return utf16EncodeAsString(parseInt(hex, 16)); - } - else { - const ch = entities.get(word); - // If this is not a valid entity, then just use `match` (replace it with itself, i.e. don't replace) - return ch ? utf16EncodeAsString(ch) : match; - } - }); + return text.replace( + /&((#((\d+)|x([\da-fA-F]+)))|(\w+));/g, + (match, _all, _number, _digits, decimal, hex, word) => { + if (decimal) { + return utf16EncodeAsString(parseInt(decimal, 10)); + } + else if (hex) { + return utf16EncodeAsString(parseInt(hex, 16)); + } + else { + const ch = entities.get(word); + // If this is not a valid entity, then just use `match` (replace it with itself, i.e. don't replace) + return ch ? utf16EncodeAsString(ch) : match; + } + }, + ); } /** Like `decodeEntities` but returns `undefined` if there were no entities to decode. */ diff --git a/src/compiler/transformers/legacyDecorators.ts b/src/compiler/transformers/legacyDecorators.ts index 9a122d6df7127..a53468088fdc5 100644 --- a/src/compiler/transformers/legacyDecorators.ts +++ b/src/compiler/transformers/legacyDecorators.ts @@ -66,11 +66,13 @@ namespace ts { } function visitClassDeclaration(node: ClassDeclaration): VisitResult { - if (!(classOrConstructorParameterIsDecorated(node) || childIsDecorated(node))) return visitEachChild(node, visitor, context); + if (!(classOrConstructorParameterIsDecorated(node) || childIsDecorated(node))) { + return visitEachChild(node, visitor, context); + } - const statements = hasDecorators(node) ? - transformClassDeclarationWithClassDecorators(node, node.name) : - transformClassDeclarationWithoutClassDecorators(node, node.name); + const statements = hasDecorators(node) + ? transformClassDeclarationWithClassDecorators(node, node.name) + : transformClassDeclarationWithoutClassDecorators(node, node.name); if (statements.length > 1) { // Add a DeclarationMarker as a marker for the end of the declaration @@ -85,7 +87,9 @@ namespace ts { return !!(decorator.transformFlags & TransformFlags.ContainsPrivateIdentifierInExpression); } - function parameterDecoratorsContainPrivateIdentifierInExpression(parameterDecorators: readonly Decorator[] | undefined) { + function parameterDecoratorsContainPrivateIdentifierInExpression( + parameterDecorators: readonly Decorator[] | undefined, + ) { return some(parameterDecorators, decoratorContainsPrivateIdentifierInExpression); } @@ -94,7 +98,9 @@ namespace ts { if (!canHaveDecorators(member)) continue; const allDecorators = getAllDecoratorsOfClassElement(member, node); if (some(allDecorators?.decorators, decoratorContainsPrivateIdentifierInExpression)) return true; - if (some(allDecorators?.parameters, parameterDecoratorsContainPrivateIdentifierInExpression)) return true; + if (some(allDecorators?.parameters, parameterDecoratorsContainPrivateIdentifierInExpression)) { + return true; + } } return false; } @@ -244,9 +250,9 @@ namespace ts { // When we transform to ES5/3 this will be moved inside an IIFE and should reference the name // without any block-scoped variable collision handling - const declName = languageVersion <= ScriptTarget.ES2015 ? - factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) : - factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); + const declName = languageVersion <= ScriptTarget.ES2015 + ? factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) + : factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); // ... = class ${name} ${heritageClauses} { // ${members} @@ -429,8 +435,18 @@ namespace ts { * @param isStatic A value indicating whether to generate statements for static or * instance members. */ - function addClassElementDecorationStatements(statements: Statement[], node: ClassDeclaration, isStatic: boolean) { - addRange(statements, map(generateClassElementDecorationExpressions(node, isStatic), expr => factory.createExpressionStatement(expr))); + function addClassElementDecorationStatements( + statements: Statement[], + node: ClassDeclaration, + isStatic: boolean, + ) { + addRange( + statements, + map( + generateClassElementDecorationExpressions(node, isStatic), + expr => factory.createExpressionStatement(expr), + ), + ); } /** @@ -452,7 +468,10 @@ namespace ts { * @param isStatic A value indicating whether to retrieve static or instance members of * the class. */ - function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): readonly ClassElement[] { + function getDecoratedClassElements( + node: ClassExpression | ClassDeclaration, + isStatic: boolean, + ): readonly ClassElement[] { return filter(node.members, m => isDecoratedClassElement(m, isStatic, node)); } @@ -464,7 +483,10 @@ namespace ts { * @param isStatic A value indicating whether to generate expressions for static or * instance members. */ - function generateClassElementDecorationExpressions(node: ClassExpression | ClassDeclaration, isStatic: boolean) { + function generateClassElementDecorationExpressions( + node: ClassExpression | ClassDeclaration, + isStatic: boolean, + ) { const members = getDecoratedClassElements(node, isStatic); let expressions: Expression[] | undefined; for (const member of members) { @@ -479,7 +501,10 @@ namespace ts { * @param node The class node that contains the member. * @param member The class member. */ - function generateClassElementDecorationExpression(node: ClassExpression | ClassDeclaration, member: ClassElement) { + function generateClassElementDecorationExpression( + node: ClassExpression | ClassDeclaration, + member: ClassElement, + ) { const allDecorators = getAllDecoratorsOfClassElement(member, node); const decoratorExpressions = transformAllDecoratorsOfDeclaration(allDecorators); if (!decoratorExpressions) { @@ -518,7 +543,10 @@ namespace ts { // const prefix = getClassMemberPrefix(node, member); - const memberName = getExpressionForPropertyName(member, /*generateNameForComputedPropertyName*/ !hasSyntacticModifier(member, ModifierFlags.Ambient)); + const memberName = getExpressionForPropertyName( + member, + /*generateNameForComputedPropertyName*/ !hasSyntacticModifier(member, ModifierFlags.Ambient), + ); const descriptor = languageVersion > ScriptTarget.ES3 ? isPropertyDeclaration(member) && !hasAccessorModifier(member) // We emit `void 0` here to indicate to `__decorate` that it can invoke `Object.defineProperty` directly, but that it @@ -569,11 +597,14 @@ namespace ts { // When we transform to ES5/3 this will be moved inside an IIFE and should reference the name // without any block-scoped variable collision handling - const localName = languageVersion <= ScriptTarget.ES2015 ? - factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) : - factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); + const localName = languageVersion <= ScriptTarget.ES2015 + ? factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) + : factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); const decorate = emitHelpers().createDecorateHelper(decoratorExpressions, localName); - const expression = factory.createAssignment(localName, classAlias ? factory.createAssignment(classAlias, decorate) : decorate); + const expression = factory.createAssignment( + localName, + classAlias ? factory.createAssignment(classAlias, decorate) : decorate, + ); setEmitFlags(expression, EmitFlags.NoComments); setSourceMapRange(expression, moveRangePastModifiers(node)); return expression; @@ -618,7 +649,10 @@ namespace ts { * * @param member The member whose name should be converted into an expression. */ - function getExpressionForPropertyName(member: ClassElement | EnumMember, generateNameForComputedPropertyName: boolean): Expression { + function getExpressionForPropertyName( + member: ClassElement | EnumMember, + generateNameForComputedPropertyName: boolean, + ): Expression { const name = member.name!; if (isPrivateIdentifier(name)) { return factory.createIdentifier(""); @@ -655,7 +689,9 @@ namespace ts { function getClassAliasIfNeeded(node: ClassDeclaration) { if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) { enableSubstitutionForClassAliases(); - const classAlias = factory.createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? idText(node.name) : "default"); + const classAlias = factory.createUniqueName( + node.name && !isGeneratedIdentifier(node.name) ? idText(node.name) : "default", + ); classAliases[getOriginalNodeId(node)] = classAlias; hoistVariableDeclaration(classAlias); return classAlias; diff --git a/src/compiler/transformers/module/esnextAnd2015.ts b/src/compiler/transformers/module/esnextAnd2015.ts index 194c838448944..42d94949a39e0 100644 --- a/src/compiler/transformers/module/esnextAnd2015.ts +++ b/src/compiler/transformers/module/esnextAnd2015.ts @@ -34,7 +34,12 @@ namespace ts { if (importRequireStatements) { result = factory.updateSourceFile( result, - setTextRange(factory.createNodeArray(insertStatementsAfterCustomPrologue(result.statements.slice(), importRequireStatements)), result.statements), + setTextRange( + factory.createNodeArray( + insertStatementsAfterCustomPrologue(result.statements.slice(), importRequireStatements), + ), + result.statements, + ), ); } if (!isExternalModule(node) || some(result.statements, isExternalModuleIndicator)) { @@ -42,7 +47,10 @@ namespace ts { } return factory.updateSourceFile( result, - setTextRange(factory.createNodeArray([...result.statements, createEmptyExports(factory)]), result.statements), + setTextRange( + factory.createNodeArray([...result.statements, createEmptyExports(factory)]), + result.statements, + ), ); } @@ -50,7 +58,12 @@ namespace ts { } function updateExternalModule(node: SourceFile) { - const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded(factory, emitHelpers(), node, compilerOptions); + const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded( + factory, + emitHelpers(), + node, + compilerOptions, + ); if (externalHelpersImportDeclaration) { const statements: Statement[] = []; const statementOffset = factory.copyPrologue(node.statements, statements); @@ -73,7 +86,8 @@ namespace ts { // Though an error in es2020 modules, in node-flavor es2020 modules, we can helpfully transform this to a synthetic `require` call // To give easy access to a synchronous `require` in node-flavor esm. We do the transform even in scenarios where we error, but `import.meta.url` // is available, just because the output is reasonable for a node-like runtime. - return getEmitModuleKind(compilerOptions) >= ModuleKind.Node16 ? visitImportEqualsDeclaration(node as ImportEqualsDeclaration) : undefined; + return getEmitModuleKind(compilerOptions) >= ModuleKind.Node16 + ? visitImportEqualsDeclaration(node as ImportEqualsDeclaration) : undefined; case SyntaxKind.ExportAssignment: return visitExportAssignment(node as ExportAssignment); case SyntaxKind.ExportDeclaration: @@ -90,26 +104,43 @@ namespace ts { * @param importNode The declaration to import. */ function createRequireCall(importNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { - const moduleName = getExternalModuleNameLiteral(factory, importNode, Debug.checkDefined(currentSourceFile), host, resolver, compilerOptions); + const moduleName = getExternalModuleNameLiteral( + factory, + importNode, + Debug.checkDefined(currentSourceFile), + host, + resolver, + compilerOptions, + ); const args: Expression[] = []; if (moduleName) { args.push(moduleName); } if (!importRequireStatements) { - const createRequireName = factory.createUniqueName("_createRequire", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + const createRequireName = factory.createUniqueName( + "_createRequire", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); const importStatement = factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause( /*isTypeOnly*/ false, /*name*/ undefined, factory.createNamedImports([ - factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier("createRequire"), createRequireName), + factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier("createRequire"), + createRequireName, + ), ]), ), factory.createStringLiteral("module"), ); - const requireHelperName = factory.createUniqueName("__require", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + const requireHelperName = factory.createUniqueName( + "__require", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); const requireStatement = factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( @@ -118,9 +149,19 @@ namespace ts { requireHelperName, /*exclamationToken*/ undefined, /*type*/ undefined, - factory.createCallExpression(factory.cloneNode(createRequireName), /*typeArguments*/ undefined, [ - factory.createPropertyAccessExpression(factory.createMetaProperty(SyntaxKind.ImportKeyword, factory.createIdentifier("meta")), factory.createIdentifier("url")), - ]), + factory.createCallExpression( + factory.cloneNode(createRequireName), + /*typeArguments*/ undefined, + [ + factory.createPropertyAccessExpression( + factory.createMetaProperty( + SyntaxKind.ImportKeyword, + factory.createIdentifier("meta"), + ), + factory.createIdentifier("url"), + ), + ], + ), ), ], /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None, @@ -140,7 +181,10 @@ namespace ts { * @param node The node to visit. */ function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { - Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); + Debug.assert( + isExternalModuleImportEqualsDeclaration(node), + "import= for internal module references should be handled in an earlier transformer.", + ); let statements: Statement[] | undefined; statements = append( @@ -172,14 +216,23 @@ namespace ts { return singleOrMany(statements); } - function appendExportsOfImportEqualsDeclaration(statements: Statement[] | undefined, node: ImportEqualsDeclaration) { + function appendExportsOfImportEqualsDeclaration( + statements: Statement[] | undefined, + node: ImportEqualsDeclaration, + ) { if (hasSyntacticModifier(node, ModifierFlags.Export)) { statements = append( statements, factory.createExportDeclaration( /*modifiers*/ undefined, node.isTypeOnly, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, idText(node.name))]), + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + idText(node.name), + ), + ]), ), ); } @@ -218,11 +271,14 @@ namespace ts { ); setOriginalNode(importDecl, node.exportClause); - const exportDecl = isExportNamespaceAsDefaultDeclaration(node) ? factory.createExportDefault(synthName) : factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, synthName, oldIdentifier)]), - ); + const exportDecl = isExportNamespaceAsDefaultDeclaration(node) ? factory.createExportDefault(synthName) + : factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([ + factory.createExportSpecifier(/*isTypeOnly*/ false, synthName, oldIdentifier), + ]), + ); setOriginalNode(exportDecl, node); return [importDecl, exportDecl]; @@ -275,7 +331,13 @@ namespace ts { const name = idText(node); let substitution = helperNameSubstitutions!.get(name); if (!substitution) { - helperNameSubstitutions!.set(name, substitution = factory.createUniqueName(name, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)); + helperNameSubstitutions!.set( + name, + substitution = factory.createUniqueName( + name, + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + ); } return substitution; } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 154d23ce1b844..b9aa22375407c 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -59,10 +59,11 @@ namespace ts { */ function transformSourceFile(node: SourceFile) { if ( - node.isDeclarationFile || - !(isEffectiveExternalModule(node, compilerOptions) || - node.transformFlags & TransformFlags.ContainsDynamicImport || - (isJsonSourceFile(node) && hasJsonModuleEmitEnabled(compilerOptions) && outFile(compilerOptions))) + node.isDeclarationFile + || !(isEffectiveExternalModule(node, compilerOptions) + || node.transformFlags & TransformFlags.ContainsDynamicImport + || (isJsonSourceFile(node) && hasJsonModuleEmitEnabled(compilerOptions) + && outFile(compilerOptions))) ) { return node; } @@ -96,8 +97,14 @@ namespace ts { startLexicalEnvironment(); const statements: Statement[] = []; - const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); - const statementOffset = factory.copyPrologue(node.statements, statements, ensureUseStrict && !isJsonSourceFile(node), topLevelVisitor); + const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") + || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); + const statementOffset = factory.copyPrologue( + node.statements, + statements, + ensureUseStrict && !isJsonSourceFile(node), + topLevelVisitor, + ); if (shouldEmitUnderscoreUnderscoreESModule()) { append(statements, createUnderscoreUnderscoreESModule()); @@ -110,7 +117,14 @@ namespace ts { factory.createExpressionStatement( reduceLeft( currentModuleInfo.exportedNames!.slice(i, i + chunkSize), - (prev, nextId) => factory.createAssignment(factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(idText(nextId))), prev), + (prev, nextId) => + factory.createAssignment( + factory.createPropertyAccessExpression( + factory.createIdentifier("exports"), + factory.createIdentifier(idText(nextId)), + ), + prev, + ), factory.createVoidZero() as Expression, ), ), @@ -118,12 +132,18 @@ namespace ts { } } - append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, topLevelVisitor, isStatement)); + append( + statements, + visitNode(currentModuleInfo.externalHelpersImportDeclaration, topLevelVisitor, isStatement), + ); addRange(statements, visitNodes(node.statements, topLevelVisitor, isStatement, statementOffset)); addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false); insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); - const updated = factory.updateSourceFile(node, setTextRange(factory.createNodeArray(statements), node.statements)); + const updated = factory.updateSourceFile( + node, + setTextRange(factory.createNodeArray(statements), node.statements), + ); addEmitHelpers(updated, context.readEmitHelpers()); return updated; } @@ -159,7 +179,10 @@ namespace ts { // // we need to add modules without alias names to the end of the dependencies list - const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ true); + const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies( + node, + /*includeNonAmdDependencies*/ true, + ); // Create an updated SourceFile: // @@ -191,16 +214,25 @@ namespace ts { // Add the module body function argument: // // function (require, exports, module1, module2) ... - jsonSourceFile ? - jsonSourceFile.statements.length ? jsonSourceFile.statements[0].expression : factory.createObjectLiteralExpression() : - factory.createFunctionExpression( + jsonSourceFile + ? jsonSourceFile.statements.length ? jsonSourceFile.statements[0].expression + : factory.createObjectLiteralExpression() + : factory.createFunctionExpression( /*modifiers*/ undefined, /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, [ - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"), - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "require", + ), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "exports", + ), ...importAliasNames, ], /*type*/ undefined, @@ -224,7 +256,10 @@ namespace ts { * @param node The SourceFile node. */ function transformUMDModule(node: SourceFile) { - const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ false); + const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies( + node, + /*includeNonAmdDependencies*/ false, + ); const moduleName = tryGetModuleNameFromFile(factory, node, host, compilerOptions); const umdHeader = factory.createFunctionExpression( /*modifiers*/ undefined, @@ -239,7 +274,13 @@ namespace ts { factory.createIfStatement( factory.createLogicalAnd( factory.createTypeCheck(factory.createIdentifier("module"), "object"), - factory.createTypeCheck(factory.createPropertyAccessExpression(factory.createIdentifier("module"), "exports"), "object"), + factory.createTypeCheck( + factory.createPropertyAccessExpression( + factory.createIdentifier("module"), + "exports", + ), + "object", + ), ), factory.createBlock([ factory.createVariableStatement( @@ -268,7 +309,10 @@ namespace ts { ), factory.createExpressionStatement( factory.createAssignment( - factory.createPropertyAccessExpression(factory.createIdentifier("module"), "exports"), + factory.createPropertyAccessExpression( + factory.createIdentifier("module"), + "exports", + ), factory.createIdentifier("v"), ), ), @@ -279,7 +323,10 @@ namespace ts { factory.createIfStatement( factory.createLogicalAnd( factory.createTypeCheck(factory.createIdentifier("define"), "function"), - factory.createPropertyAccessExpression(factory.createIdentifier("define"), "amd"), + factory.createPropertyAccessExpression( + factory.createIdentifier("define"), + "amd", + ), ), factory.createBlock([ factory.createExpressionStatement( @@ -339,8 +386,16 @@ namespace ts { /*name*/ undefined, /*typeParameters*/ undefined, [ - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"), - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "require", + ), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "exports", + ), ...importAliasNames, ], /*type*/ undefined, @@ -364,7 +419,10 @@ namespace ts { * @param node The source file. * @param includeNonAmdDependencies A value indicating whether to include non-AMD dependencies. */ - function collectAsynchronousDependencies(node: SourceFile, includeNonAmdDependencies: boolean): AsynchronousDependencies { + function collectAsynchronousDependencies( + node: SourceFile, + includeNonAmdDependencies: boolean, + ): AsynchronousDependencies { // names of modules with corresponding parameter in the factory function const aliasedModuleNames: Expression[] = []; @@ -380,7 +438,13 @@ namespace ts { for (const amdDependency of node.amdDependencies) { if (amdDependency.name) { aliasedModuleNames.push(factory.createStringLiteral(amdDependency.path)); - importAliasNames.push(factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, amdDependency.name)); + importAliasNames.push( + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + amdDependency.name, + ), + ); } else { unaliasedModuleNames.push(factory.createStringLiteral(amdDependency.path)); @@ -389,7 +453,14 @@ namespace ts { for (const importNode of currentModuleInfo.externalImports) { // Find the name of the external module - const externalModuleName = getExternalModuleNameLiteral(factory, importNode, currentSourceFile, host, resolver, compilerOptions); + const externalModuleName = getExternalModuleNameLiteral( + factory, + importNode, + currentSourceFile, + host, + resolver, + compilerOptions, + ); // Find the name of the module alias, if there is one const importAliasName = getLocalNameForExternalImport(factory, importNode, currentSourceFile); @@ -402,7 +473,13 @@ namespace ts { // This is so that when printer will not substitute the identifier setEmitFlags(importAliasName, EmitFlags.NoSubstitution); aliasedModuleNames.push(externalModuleName); - importAliasNames.push(factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, importAliasName)); + importAliasNames.push( + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + importAliasName, + ), + ); } else { unaliasedModuleNames.push(externalModuleName); @@ -413,8 +490,13 @@ namespace ts { return { aliasedModuleNames, unaliasedModuleNames, importAliasNames }; } - function getAMDImportExpressionForImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration) { - if (isImportEqualsDeclaration(node) || isExportDeclaration(node) || !getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions)) { + function getAMDImportExpressionForImport( + node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration, + ) { + if ( + isImportEqualsDeclaration(node) || isExportDeclaration(node) + || !getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions) + ) { return undefined; } const name = getLocalNameForExternalImport(factory, node, currentSourceFile)!; // TODO: GH#18217 @@ -434,17 +516,37 @@ namespace ts { startLexicalEnvironment(); const statements: Statement[] = []; - const statementOffset = factory.copyPrologue(node.statements, statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, topLevelVisitor); + const statementOffset = factory.copyPrologue( + node.statements, + statements, + /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, + topLevelVisitor, + ); if (shouldEmitUnderscoreUnderscoreESModule()) { append(statements, createUnderscoreUnderscoreESModule()); } if (length(currentModuleInfo.exportedNames)) { - append(statements, factory.createExpressionStatement(reduceLeft(currentModuleInfo.exportedNames, (prev, nextId) => factory.createAssignment(factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(idText(nextId))), prev), factory.createVoidZero() as Expression))); + append( + statements, + factory.createExpressionStatement( + reduceLeft(currentModuleInfo.exportedNames, (prev, nextId) => + factory.createAssignment( + factory.createPropertyAccessExpression( + factory.createIdentifier("exports"), + factory.createIdentifier(idText(nextId)), + ), + prev, + ), factory.createVoidZero() as Expression), + ), + ); } // Visit each statement of the module body. - append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, topLevelVisitor, isStatement)); + append( + statements, + visitNode(currentModuleInfo.externalHelpersImportDeclaration, topLevelVisitor, isStatement), + ); if (moduleKind === ModuleKind.AMD) { addRange(statements, mapDefined(currentModuleInfo.externalImports, getAMDImportExpressionForImport)); } @@ -548,7 +650,11 @@ namespace ts { function visitorWorker(node: Node, valueIsDiscarded: boolean): VisitResult { // This visitor does not need to descend into the tree if there is no dynamic import, destructuring assignment, or update expression // as export/import statements are only transformed at the top level of a file. - if (!(node.transformFlags & (TransformFlags.ContainsDynamicImport | TransformFlags.ContainsDestructuringAssignment | TransformFlags.ContainsUpdateExpressionForIdentifier))) { + if ( + !(node.transformFlags + & (TransformFlags.ContainsDynamicImport | TransformFlags.ContainsDestructuringAssignment + | TransformFlags.ContainsUpdateExpressionForIdentifier)) + ) { return node; } @@ -573,7 +679,10 @@ namespace ts { break; case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPreOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded); + return visitPreOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + valueIsDiscarded, + ); } return visitEachChild(node, visitor, context); @@ -635,7 +744,14 @@ namespace ts { function visitDestructuringAssignment(node: DestructuringAssignment, valueIsDiscarded: boolean): Expression { if (destructuringNeedsFlattening(node.left)) { - return flattenDestructuringAssignment(node, visitor, context, FlattenLevel.All, !valueIsDiscarded, createAllExportExpressions); + return flattenDestructuringAssignment( + node, + visitor, + context, + FlattenLevel.All, + !valueIsDiscarded, + createAllExportExpressions, + ); } return visitEachChild(node, visitor, context); } @@ -658,14 +774,23 @@ namespace ts { } function visitParenthesizedExpression(node: ParenthesizedExpression, valueIsDiscarded: boolean) { - return factory.updateParenthesizedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); + return factory.updateParenthesizedExpression( + node, + visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression), + ); } function visitPartiallyEmittedExpression(node: PartiallyEmittedExpression, valueIsDiscarded: boolean) { - return factory.updatePartiallyEmittedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); + return factory.updatePartiallyEmittedExpression( + node, + visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression), + ); } - function visitPreOrPostfixUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded: boolean) { + function visitPreOrPostfixUnaryExpression( + node: PrefixUnaryExpression | PostfixUnaryExpression, + valueIsDiscarded: boolean, + ) { // When we see a prefix or postfix increment expression whose operand is an exported // symbol, we should ensure all exports of that symbol are updated with the correct // value. @@ -718,10 +843,19 @@ namespace ts { } function visitImportCallExpression(node: ImportCall): Expression { - const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions); + const externalModuleName = getExternalModuleNameLiteral( + factory, + node, + currentSourceFile, + host, + resolver, + compilerOptions, + ); const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor); // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output. - const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; + const argument = externalModuleName + && (!firstArgument || !isStringLiteral(firstArgument) + || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; const containsLexicalThis = !!(node.transformFlags & TransformFlags.ContainsLexicalThis); switch (compilerOptions.module) { case ModuleKind.AMD: @@ -750,7 +884,9 @@ namespace ts { // }); needUMDDynamicImportHelper = true; if (isSimpleCopiableExpression(arg)) { - const argClone = isGeneratedIdentifier(arg) ? arg : isStringLiteral(arg) ? factory.createStringLiteralFromNode(arg) : setEmitFlags(setTextRange(factory.cloneNode(arg), arg), EmitFlags.NoComments); + const argClone = isGeneratedIdentifier(arg) ? arg + : isStringLiteral(arg) ? factory.createStringLiteralFromNode(arg) + : setEmitFlags(setTextRange(factory.cloneNode(arg), arg), EmitFlags.NoComments); return factory.createConditionalExpression( /*condition*/ factory.createIdentifier("__syncRequire"), /*questionToken*/ undefined, @@ -784,15 +920,27 @@ namespace ts { const resolve = factory.createUniqueName("resolve"); const reject = factory.createUniqueName("reject"); const parameters = [ - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ resolve), - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ reject), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + /*name*/ resolve, + ), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + /*name*/ reject, + ), ]; const body = factory.createBlock([ factory.createExpressionStatement( factory.createCallExpression( factory.createIdentifier("require"), /*typeArguments*/ undefined, - [factory.createArrayLiteralExpression([arg || factory.createOmittedExpression()]), resolve, reject], + [ + factory.createArrayLiteralExpression([arg || factory.createOmittedExpression()]), + resolve, + reject, + ], ), ), ]); @@ -827,21 +975,40 @@ namespace ts { } } - const promise = factory.createNewExpression(factory.createIdentifier("Promise"), /*typeArguments*/ undefined, [func]); + const promise = factory.createNewExpression( + factory.createIdentifier("Promise"), + /*typeArguments*/ undefined, + [func], + ); if (getESModuleInterop(compilerOptions)) { - return factory.createCallExpression(factory.createPropertyAccessExpression(promise, factory.createIdentifier("then")), /*typeArguments*/ undefined, [emitHelpers().createImportStarCallbackHelper()]); + return factory.createCallExpression( + factory.createPropertyAccessExpression(promise, factory.createIdentifier("then")), + /*typeArguments*/ undefined, + [emitHelpers().createImportStarCallbackHelper()], + ); } return promise; } - function createImportCallExpressionCommonJS(arg: Expression | undefined, containsLexicalThis: boolean): Expression { + function createImportCallExpressionCommonJS( + arg: Expression | undefined, + containsLexicalThis: boolean, + ): Expression { // import("./blah") // emit as // Promise.resolve().then(function () { return require(x); }) /*CommonJs Require*/ // We have to wrap require in then callback so that require is done in asynchronously // if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately - const promiseResolveCall = factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"), /*typeArguments*/ undefined, /*argumentsArray*/ []); - let requireCall: Expression = factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, arg ? [arg] : []); + const promiseResolveCall = factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"), + /*typeArguments*/ undefined, + /*argumentsArray*/ [], + ); + let requireCall: Expression = factory.createCallExpression( + factory.createIdentifier("require"), + /*typeArguments*/ undefined, + arg ? [arg] : [], + ); if (getESModuleInterop(compilerOptions)) { requireCall = emitHelpers().createImportStarHelper(requireCall); } @@ -876,7 +1043,11 @@ namespace ts { } } - return factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]); + return factory.createCallExpression( + factory.createPropertyAccessExpression(promiseResolveCall, "then"), + /*typeArguments*/ undefined, + [func], + ); } function getHelperExpressionForExport(node: ExportDeclaration, innerExpr: Expression) { @@ -913,7 +1084,10 @@ namespace ts { if (moduleKind !== ModuleKind.AMD) { if (!node.importClause) { // import "mod"; - return setOriginalNode(setTextRange(factory.createExpressionStatement(createRequireCall(node)), node), node); + return setOriginalNode( + setTextRange(factory.createExpressionStatement(createRequireCall(node)), node), + node, + ); } else { const variables: VariableDeclaration[] = []; @@ -1017,7 +1191,14 @@ namespace ts { * @param importNode The declararation to import. */ function createRequireCall(importNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { - const moduleName = getExternalModuleNameLiteral(factory, importNode, currentSourceFile, host, resolver, compilerOptions); + const moduleName = getExternalModuleNameLiteral( + factory, + importNode, + currentSourceFile, + host, + resolver, + compilerOptions, + ); const args: Expression[] = []; if (moduleName) { args.push(moduleName); @@ -1032,7 +1213,10 @@ namespace ts { * @param node The node to visit. */ function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { - Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); + Debug.assert( + isExternalModuleImportEqualsDeclaration(node), + "import= for internal module references should be handled in an earlier transformer.", + ); let statements: Statement[] | undefined; if (moduleKind !== ModuleKind.AMD) { @@ -1069,7 +1253,8 @@ namespace ts { createRequireCall(node), ), ], - /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None, + /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const + : NodeFlags.None, ), ), node, @@ -1152,7 +1337,14 @@ namespace ts { setOriginalNode( setTextRange( factory.createExpressionStatement( - emitHelpers().createCreateBindingHelper(generatedName, factory.createStringLiteralFromNode(specifier.propertyName || specifier.name), specifier.propertyName ? factory.createStringLiteralFromNode(specifier.name) : undefined), + emitHelpers().createCreateBindingHelper( + generatedName, + factory.createStringLiteralFromNode( + specifier.propertyName || specifier.name, + ), + specifier.propertyName ? factory.createStringLiteralFromNode(specifier.name) + : undefined, + ), ), specifier, ), @@ -1161,18 +1353,24 @@ namespace ts { ); } else { - const exportNeedsImportDefault = !!getESModuleInterop(compilerOptions) && - !(getEmitFlags(node) & EmitFlags.NeverApplyImportHelper) && - idText(specifier.propertyName || specifier.name) === "default"; + const exportNeedsImportDefault = !!getESModuleInterop(compilerOptions) + && !(getEmitFlags(node) & EmitFlags.NeverApplyImportHelper) + && idText(specifier.propertyName || specifier.name) === "default"; const exportedValue = factory.createPropertyAccessExpression( - exportNeedsImportDefault ? emitHelpers().createImportDefaultHelper(generatedName) : generatedName, + exportNeedsImportDefault ? emitHelpers().createImportDefaultHelper(generatedName) + : generatedName, specifier.propertyName || specifier.name, ); statements.push( setOriginalNode( setTextRange( factory.createExpressionStatement( - createExportExpression(factory.getExportName(specifier), exportedValue, /* location */ undefined, /* liveBinding */ true), + createExportExpression( + factory.getExportName(specifier), + exportedValue, + /* location */ undefined, + /* liveBinding */ true, + ), ), specifier, ), @@ -1196,10 +1394,10 @@ namespace ts { factory.cloneNode(node.exportClause.name), getHelperExpressionForExport( node, - moduleKind !== ModuleKind.AMD ? - createRequireCall(node) : - isExportNamespaceAsDefaultDeclaration(node) ? generatedName : - factory.createIdentifier(idText(node.exportClause.name)), + moduleKind !== ModuleKind.AMD + ? createRequireCall(node) + : isExportNamespaceAsDefaultDeclaration(node) ? generatedName + : factory.createIdentifier(idText(node.exportClause.name)), ), ), ), @@ -1216,7 +1414,9 @@ namespace ts { return setOriginalNode( setTextRange( factory.createExpressionStatement( - emitHelpers().createExportStarHelper(moduleKind !== ModuleKind.AMD ? createRequireCall(node) : generatedName), + emitHelpers().createExportStarHelper( + moduleKind !== ModuleKind.AMD ? createRequireCall(node) : generatedName, + ), ), node, ), @@ -1240,10 +1440,22 @@ namespace ts { if (original && hasAssociatedEndOfDeclarationMarker(original)) { // Defer exports until we encounter an EndOfDeclarationMarker node const id = getOriginalNodeId(node); - deferredExports[id] = appendExportStatement(deferredExports[id], factory.createIdentifier("default"), visitNode(node.expression, visitor), /*location*/ node, /*allowComments*/ true); + deferredExports[id] = appendExportStatement( + deferredExports[id], + factory.createIdentifier("default"), + visitNode(node.expression, visitor), + /*location*/ node, + /*allowComments*/ true, + ); } else { - statements = appendExportStatement(statements, factory.createIdentifier("default"), visitNode(node.expression, visitor), /*location*/ node, /*allowComments*/ true); + statements = appendExportStatement( + statements, + factory.createIdentifier("default"), + visitNode(node.expression, visitor), + /*location*/ node, + /*allowComments*/ true, + ); } return singleOrMany(statements); @@ -1357,7 +1569,11 @@ namespace ts { variables = append(variables, variable); } else if (variable.initializer) { - if (!isBindingPattern(variable.name) && (isArrowFunction(variable.initializer) || isFunctionExpression(variable.initializer) || isClassExpression(variable.initializer))) { + if ( + !isBindingPattern(variable.name) + && (isArrowFunction(variable.initializer) || isFunctionExpression(variable.initializer) + || isClassExpression(variable.initializer)) + ) { const expression = factory.createAssignment( setTextRange( factory.createPropertyAccessExpression( @@ -1380,17 +1596,30 @@ namespace ts { removeCommentsOnExpressions = true; } else { - expressions = append(expressions, transformInitializedVariable(variable as InitializedVariableDeclaration)); + expressions = append( + expressions, + transformInitializedVariable(variable as InitializedVariableDeclaration), + ); } } } if (variables) { - statements = append(statements, factory.updateVariableStatement(node, modifiers, factory.updateVariableDeclarationList(node.declarationList, variables))); + statements = append( + statements, + factory.updateVariableStatement( + node, + modifiers, + factory.updateVariableDeclarationList(node.declarationList, variables), + ), + ); } if (expressions) { - const statement = setOriginalNode(setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node), node); + const statement = setOriginalNode( + setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node), + node, + ); if (removeCommentsOnExpressions) { removeAllComments(statement); } @@ -1475,7 +1704,10 @@ namespace ts { // statement. if (hasAssociatedEndOfDeclarationMarker(node) && node.original!.kind === SyntaxKind.VariableStatement) { const id = getOriginalNodeId(node); - deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node.original as VariableStatement); + deferredExports[id] = appendExportsOfVariableStatement( + deferredExports[id], + node.original as VariableStatement, + ); } return node; @@ -1519,7 +1751,10 @@ namespace ts { * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfImportDeclaration(statements: Statement[] | undefined, decl: ImportDeclaration): Statement[] | undefined { + function appendExportsOfImportDeclaration( + statements: Statement[] | undefined, + decl: ImportDeclaration, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } @@ -1561,7 +1796,10 @@ namespace ts { * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfImportEqualsDeclaration(statements: Statement[] | undefined, decl: ImportEqualsDeclaration): Statement[] | undefined { + function appendExportsOfImportEqualsDeclaration( + statements: Statement[] | undefined, + decl: ImportEqualsDeclaration, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } @@ -1578,7 +1816,10 @@ namespace ts { * appended. * @param node The VariableStatement whose exports are to be recorded. */ - function appendExportsOfVariableStatement(statements: Statement[] | undefined, node: VariableStatement): Statement[] | undefined { + function appendExportsOfVariableStatement( + statements: Statement[] | undefined, + node: VariableStatement, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } @@ -1599,7 +1840,10 @@ namespace ts { * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfBindingElement(statements: Statement[] | undefined, decl: VariableDeclaration | BindingElement): Statement[] | undefined { + function appendExportsOfBindingElement( + statements: Statement[] | undefined, + decl: VariableDeclaration | BindingElement, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } @@ -1627,14 +1871,23 @@ namespace ts { * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfHoistedDeclaration(statements: Statement[] | undefined, decl: ClassDeclaration | FunctionDeclaration): Statement[] | undefined { + function appendExportsOfHoistedDeclaration( + statements: Statement[] | undefined, + decl: ClassDeclaration | FunctionDeclaration, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } if (hasSyntacticModifier(decl, ModifierFlags.Export)) { - const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) ? factory.createIdentifier("default") : factory.getDeclarationName(decl); - statements = appendExportStatement(statements, exportName, factory.getLocalName(decl), /*location*/ decl); + const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) + ? factory.createIdentifier("default") : factory.getDeclarationName(decl); + statements = appendExportStatement( + statements, + exportName, + factory.getLocalName(decl), + /*location*/ decl, + ); } if (decl.name) { @@ -1652,12 +1905,23 @@ namespace ts { * appended. * @param decl The declaration to export. */ - function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration, liveBinding?: boolean): Statement[] | undefined { + function appendExportsOfDeclaration( + statements: Statement[] | undefined, + decl: Declaration, + liveBinding?: boolean, + ): Statement[] | undefined { const name = factory.getDeclarationName(decl); const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(idText(name)); if (exportSpecifiers) { for (const exportSpecifier of exportSpecifiers) { - statements = appendExportStatement(statements, exportSpecifier.name, name, /*location*/ exportSpecifier.name, /* allowComments */ undefined, liveBinding); + statements = appendExportStatement( + statements, + exportSpecifier.name, + name, + /*location*/ exportSpecifier.name, + /* allowComments */ undefined, + liveBinding, + ); } } return statements; @@ -1675,8 +1939,18 @@ namespace ts { * @param location The location to use for source maps and comments for the export. * @param allowComments Whether to allow comments on the export. */ - function appendExportStatement(statements: Statement[] | undefined, exportName: Identifier, expression: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean): Statement[] | undefined { - statements = append(statements, createExportStatement(exportName, expression, location, allowComments, liveBinding)); + function appendExportStatement( + statements: Statement[] | undefined, + exportName: Identifier, + expression: Expression, + location?: TextRange, + allowComments?: boolean, + liveBinding?: boolean, + ): Statement[] | undefined { + statements = append( + statements, + createExportStatement(exportName, expression, location, allowComments, liveBinding), + ); return statements; } @@ -1717,8 +1991,19 @@ namespace ts { * @param location The location to use for source maps and comments for the export. * @param allowComments An optional value indicating whether to emit comments for the statement. */ - function createExportStatement(name: Identifier, value: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean) { - const statement = setTextRange(factory.createExpressionStatement(createExportExpression(name, value, /* location */ undefined, liveBinding)), location); + function createExportStatement( + name: Identifier, + value: Expression, + location?: TextRange, + allowComments?: boolean, + liveBinding?: boolean, + ) { + const statement = setTextRange( + factory.createExpressionStatement( + createExportExpression(name, value, /* location */ undefined, liveBinding), + ), + location, + ); startOnNewLine(statement); if (!allowComments) { setEmitFlags(statement, EmitFlags.NoComments); @@ -1734,7 +2019,12 @@ namespace ts { * @param value The exported value. * @param location The location to use for source maps and comments for the export. */ - function createExportExpression(name: Identifier, value: Expression, location?: TextRange, liveBinding?: boolean) { + function createExportExpression( + name: Identifier, + value: Expression, + location?: TextRange, + liveBinding?: boolean, + ) { return setTextRange( liveBinding && languageVersion !== ScriptTarget.ES3 ? factory.createCallExpression( factory.createPropertyAccessExpression( @@ -1857,7 +2147,10 @@ namespace ts { // A shorthand property with an assignment initializer is probably part of a // destructuring assignment if (node.objectAssignmentInitializer) { - const initializer = factory.createAssignment(exportedOrImportedName, node.objectAssignmentInitializer); + const initializer = factory.createAssignment( + exportedOrImportedName, + node.objectAssignmentInitializer, + ); return setTextRange(factory.createPropertyAssignment(name, initializer), node); } return setTextRange(factory.createPropertyAssignment(name, exportedOrImportedName), node); @@ -1927,7 +2220,10 @@ namespace ts { } return node; } - else if (!(isGeneratedIdentifier(node) && !(node.autoGenerateFlags & GeneratedIdentifierFlags.AllowNameSubstitution)) && !isLocalName(node)) { + else if ( + !(isGeneratedIdentifier(node) + && !(node.autoGenerateFlags & GeneratedIdentifierFlags.AllowNameSubstitution)) && !isLocalName(node) + ) { const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node)); if (exportContainer && exportContainer.kind === SyntaxKind.SourceFile) { return setTextRange( @@ -1953,7 +2249,9 @@ namespace ts { const name = importDeclaration.propertyName || importDeclaration.name; return setTextRange( factory.createPropertyAccessExpression( - factory.getGeneratedNameForNode(importDeclaration.parent?.parent?.parent || importDeclaration), + factory.getGeneratedNameForNode( + importDeclaration.parent?.parent?.parent || importDeclaration, + ), factory.cloneNode(name), ), /*location*/ node, diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index ca7ae5f1e24d5..f3283f730698a 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -48,7 +48,11 @@ namespace ts { * @param node The SourceFile node. */ function transformSourceFile(node: SourceFile) { - if (node.isDeclarationFile || !(isEffectiveExternalModule(node, compilerOptions) || node.transformFlags & TransformFlags.ContainsDynamicImport)) { + if ( + node.isDeclarationFile + || !(isEffectiveExternalModule(node, compilerOptions) + || node.transformFlags & TransformFlags.ContainsDynamicImport) + ) { return node; } @@ -87,8 +91,16 @@ namespace ts { /*name*/ undefined, /*typeParameters*/ undefined, [ - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, exportFunction), - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, contextObject), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + exportFunction, + ), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + contextObject, + ), ], /*type*/ undefined, moduleBodyBlock, @@ -98,7 +110,9 @@ namespace ts { // Clear the emit-helpers flag for later passes since we'll have already used it in the module body // So the helper will be emit at the correct position instead of at the top of the source-file const moduleName = tryGetModuleNameFromFile(factory, node, host, compilerOptions); - const dependencies = factory.createArrayLiteralExpression(map(dependencyGroups, dependencyGroup => dependencyGroup.name)); + const dependencies = factory.createArrayLiteralExpression( + map(dependencyGroups, dependencyGroup => dependencyGroup.name), + ); const updated = setEmitFlags( factory.updateSourceFile( node, @@ -106,7 +120,10 @@ namespace ts { factory.createNodeArray([ factory.createExpressionStatement( factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier("System"), "register"), + factory.createPropertyAccessExpression( + factory.createIdentifier("System"), + "register", + ), /*typeArguments*/ undefined, moduleName ? [moduleName, dependencies, moduleBodyFunction] @@ -143,11 +160,20 @@ namespace ts { * * @param externalImports The imports for the file. */ - function collectDependencyGroups(externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]) { + function collectDependencyGroups( + externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[], + ) { const groupIndices = new Map(); const dependencyGroups: DependencyGroup[] = []; for (const externalImport of externalImports) { - const externalModuleName = getExternalModuleNameLiteral(factory, externalImport, currentSourceFile, host, resolver, compilerOptions); + const externalModuleName = getExternalModuleNameLiteral( + factory, + externalImport, + currentSourceFile, + host, + resolver, + compilerOptions, + ); if (externalModuleName) { const text = externalModuleName.text; const groupIndex = groupIndices.get(text); @@ -224,7 +250,8 @@ namespace ts { startLexicalEnvironment(); // Add any prologue directives. - const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); + const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") + || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); const statementOffset = factory.copyPrologue(node.statements, statements, ensureUseStrict, topLevelVisitor); // var __moduleName = context_1 && context_1.id; @@ -264,9 +291,9 @@ namespace ts { insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); const exportStarFunction = addExportStarIfNeeded(statements)!; // TODO: GH#18217 - const modifiers = node.transformFlags & TransformFlags.ContainsAwait ? - factory.createModifiersFromModifierFlags(ModifierFlags.Async) : - undefined; + const modifiers = node.transformFlags & TransformFlags.ContainsAwait + ? factory.createModifiersFromModifierFlags(ModifierFlags.Async) + : undefined; const moduleObject = factory.createObjectLiteralExpression([ factory.createPropertyAssignment("setters", createSettersArray(exportStarFunction, dependencyGroups)), factory.createPropertyAssignment( @@ -445,8 +472,12 @@ namespace ts { const setters: Expression[] = []; for (const group of dependencyGroups) { // derive a unique name for parameter from the first named entry in the group - const localName = forEach(group.externalImports, i => getLocalNameForExternalImport(factory, i, currentSourceFile)); - const parameterName = localName ? factory.getGeneratedNameForNode(localName) : factory.createUniqueName(""); + const localName = forEach( + group.externalImports, + i => getLocalNameForExternalImport(factory, i, currentSourceFile), + ); + const parameterName = localName ? factory.getGeneratedNameForNode(localName) + : factory.createUniqueName(""); const statements: Statement[] = []; for (const entry of group.externalImports) { const importVariableName = getLocalNameForExternalImport(factory, entry, currentSourceFile)!; // TODO: GH#18217 @@ -559,7 +590,11 @@ namespace ts { /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, - [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)], + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + parameterName, + )], /*type*/ undefined, factory.createBlock(statements, /*multiLine*/ true), ), @@ -631,7 +666,10 @@ namespace ts { * @param node The node to visit. */ function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { - Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); + Debug.assert( + isExternalModuleImportEqualsDeclaration(node), + "import= for internal module references should be handled in an earlier transformer.", + ); let statements: Statement[] | undefined; hoistVariableDeclaration(getLocalNameForExternalImport(factory, node, currentSourceFile)!); // TODO: GH#18217 @@ -664,7 +702,12 @@ namespace ts { if (original && hasAssociatedEndOfDeclarationMarker(original)) { // Defer exports until we encounter an EndOfDeclarationMarker node const id = getOriginalNodeId(node); - deferredExports[id] = appendExportStatement(deferredExports[id], factory.createIdentifier("default"), expression, /*allowComments*/ true); + deferredExports[id] = appendExportStatement( + deferredExports[id], + factory.createIdentifier("default"), + expression, + /*allowComments*/ true, + ); } else { return createExportStatement(factory.createIdentifier("default"), expression, /*allowComments*/ true); @@ -771,7 +814,10 @@ namespace ts { const isMarkedDeclaration = hasAssociatedEndOfDeclarationMarker(node); for (const variable of node.declarationList.declarations) { if (variable.initializer) { - expressions = append(expressions, transformInitializedVariable(variable, isExportedDeclaration && !isMarkedDeclaration)); + expressions = append( + expressions, + transformInitializedVariable(variable, isExportedDeclaration && !isMarkedDeclaration), + ); } else { hoistBindingElement(variable); @@ -780,13 +826,20 @@ namespace ts { let statements: Statement[] | undefined; if (expressions) { - statements = append(statements, setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node)); + statements = append( + statements, + setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node), + ); } if (isMarkedDeclaration) { // Defer exports until we encounter an EndOfDeclarationMarker node const id = getOriginalNodeId(node); - deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node, isExportedDeclaration); + deferredExports[id] = appendExportsOfVariableStatement( + deferredExports[id], + node, + isExportedDeclaration, + ); } else { statements = appendExportsOfVariableStatement(statements, node, /*exportSelf*/ false); @@ -832,7 +885,8 @@ namespace ts { * @param isExportedDeclaration A value indicating whether the variable is exported. */ function transformInitializedVariable(node: VariableDeclaration, isExportedDeclaration: boolean): Expression { - const createAssignment = isExportedDeclaration ? createExportedVariableAssignment : createNonExportedVariableAssignment; + const createAssignment = isExportedDeclaration ? createExportedVariableAssignment + : createNonExportedVariableAssignment; return isBindingPattern(node.name) ? flattenDestructuringAssignment( node, @@ -842,7 +896,8 @@ namespace ts { /*needsValue*/ false, createAssignment, ) - : node.initializer ? createAssignment(node.name, visitNode(node.initializer, visitor, isExpression)) : node.name; + : node.initializer ? createAssignment(node.name, visitNode(node.initializer, visitor, isExpression)) + : node.name; } /** @@ -875,10 +930,18 @@ namespace ts { * @param location The source map location for the assignment. * @param isExportedDeclaration A value indicating whether the variable is exported. */ - function createVariableAssignment(name: Identifier, value: Expression, location: TextRange | undefined, isExportedDeclaration: boolean) { + function createVariableAssignment( + name: Identifier, + value: Expression, + location: TextRange | undefined, + isExportedDeclaration: boolean, + ) { hoistVariableDeclaration(factory.cloneNode(name)); return isExportedDeclaration - ? createExportExpression(name, preventSubstitution(setTextRange(factory.createAssignment(name, value), location))) + ? createExportExpression( + name, + preventSubstitution(setTextRange(factory.createAssignment(name, value), location)), + ) : preventSubstitution(setTextRange(factory.createAssignment(name, value), location)); } @@ -899,7 +962,11 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node) && node.original!.kind === SyntaxKind.VariableStatement) { const id = getOriginalNodeId(node); const isExportedDeclaration = hasSyntacticModifier(node.original!, ModifierFlags.Export); - deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node.original as VariableStatement, isExportedDeclaration); + deferredExports[id] = appendExportsOfVariableStatement( + deferredExports[id], + node.original as VariableStatement, + isExportedDeclaration, + ); } return node; @@ -991,7 +1058,10 @@ namespace ts { * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfImportEqualsDeclaration(statements: Statement[] | undefined, decl: ImportEqualsDeclaration): Statement[] | undefined { + function appendExportsOfImportEqualsDeclaration( + statements: Statement[] | undefined, + decl: ImportEqualsDeclaration, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } @@ -1010,7 +1080,11 @@ namespace ts { * @param exportSelf A value indicating whether to also export each VariableDeclaration of * `nodes` declaration list. */ - function appendExportsOfVariableStatement(statements: Statement[] | undefined, node: VariableStatement, exportSelf: boolean): Statement[] | undefined { + function appendExportsOfVariableStatement( + statements: Statement[] | undefined, + node: VariableStatement, + exportSelf: boolean, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } @@ -1034,7 +1108,11 @@ namespace ts { * @param decl The declaration whose exports are to be recorded. * @param exportSelf A value indicating whether to also export the declaration itself. */ - function appendExportsOfBindingElement(statements: Statement[] | undefined, decl: VariableDeclaration | BindingElement, exportSelf: boolean): Statement[] | undefined { + function appendExportsOfBindingElement( + statements: Statement[] | undefined, + decl: VariableDeclaration | BindingElement, + exportSelf: boolean, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } @@ -1068,14 +1146,18 @@ namespace ts { * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfHoistedDeclaration(statements: Statement[] | undefined, decl: ClassDeclaration | FunctionDeclaration): Statement[] | undefined { + function appendExportsOfHoistedDeclaration( + statements: Statement[] | undefined, + decl: ClassDeclaration | FunctionDeclaration, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } let excludeName: string | undefined; if (hasSyntacticModifier(decl, ModifierFlags.Export)) { - const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) ? factory.createStringLiteral("default") : decl.name!; + const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) + ? factory.createStringLiteral("default") : decl.name!; statements = appendExportStatement(statements, exportName, factory.getLocalName(decl)); excludeName = getTextOfIdentifierOrLiteral(exportName); } @@ -1096,7 +1178,11 @@ namespace ts { * @param decl The declaration to export. * @param excludeName An optional name to exclude from exports. */ - function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration, excludeName?: string): Statement[] | undefined { + function appendExportsOfDeclaration( + statements: Statement[] | undefined, + decl: Declaration, + excludeName?: string, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } @@ -1124,7 +1210,12 @@ namespace ts { * @param expression The expression to export. * @param allowComments Whether to allow comments on the export. */ - function appendExportStatement(statements: Statement[] | undefined, exportName: Identifier | StringLiteral, expression: Expression, allowComments?: boolean): Statement[] | undefined { + function appendExportStatement( + statements: Statement[] | undefined, + exportName: Identifier | StringLiteral, + expression: Expression, + allowComments?: boolean, + ): Statement[] | undefined { statements = append(statements, createExportStatement(exportName, expression, allowComments)); return statements; } @@ -1155,7 +1246,10 @@ namespace ts { function createExportExpression(name: Identifier | StringLiteral, value: Expression) { const exportName = isIdentifier(name) ? factory.createStringLiteralFromNode(name) : name; setEmitFlags(value, getEmitFlags(value) | EmitFlags.NoComments); - return setCommentRange(factory.createCallExpression(exportFunction, /*typeArguments*/ undefined, [exportName, value]), value); + return setCommentRange( + factory.createCallExpression(exportFunction, /*typeArguments*/ undefined, [exportName, value]), + value, + ); } // @@ -1313,7 +1407,10 @@ namespace ts { if (shouldHoistForInitializer(node)) { let expressions: Expression[] | undefined; for (const variable of node.declarations) { - expressions = append(expressions, transformInitializedVariable(variable, /*isExportedDeclaration*/ false)); + expressions = append( + expressions, + transformInitializedVariable(variable, /*isExportedDeclaration*/ false), + ); if (!variable.initializer) { hoistBindingElement(variable); } @@ -1484,7 +1581,11 @@ namespace ts { * @param node The node to visit. */ function visitorWorker(node: Node, valueIsDiscarded: boolean): VisitResult { - if (!(node.transformFlags & (TransformFlags.ContainsDestructuringAssignment | TransformFlags.ContainsDynamicImport | TransformFlags.ContainsUpdateExpressionForIdentifier))) { + if ( + !(node.transformFlags + & (TransformFlags.ContainsDestructuringAssignment | TransformFlags.ContainsDynamicImport + | TransformFlags.ContainsUpdateExpressionForIdentifier)) + ) { return node; } switch (node.kind) { @@ -1508,7 +1609,10 @@ namespace ts { break; case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPrefixOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded); + return visitPrefixOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + valueIsDiscarded, + ); } return visitEachChild(node, visitor, context); } @@ -1527,15 +1631,24 @@ namespace ts { } function visitExpressionStatement(node: ExpressionStatement) { - return factory.updateExpressionStatement(node, visitNode(node.expression, discardedValueVisitor, isExpression)); + return factory.updateExpressionStatement( + node, + visitNode(node.expression, discardedValueVisitor, isExpression), + ); } function visitParenthesizedExpression(node: ParenthesizedExpression, valueIsDiscarded: boolean) { - return factory.updateParenthesizedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); + return factory.updateParenthesizedExpression( + node, + visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression), + ); } function visitPartiallyEmittedExpression(node: PartiallyEmittedExpression, valueIsDiscarded: boolean) { - return factory.updatePartiallyEmittedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); + return factory.updatePartiallyEmittedExpression( + node, + visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression), + ); } function visitImportCallExpression(node: ImportCall): Expression { @@ -1549,10 +1662,19 @@ namespace ts { // } // }; // }); - const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions); + const externalModuleName = getExternalModuleNameLiteral( + factory, + node, + currentSourceFile, + host, + resolver, + compilerOptions, + ); const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor); // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output. - const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; + const argument = externalModuleName + && (!firstArgument || !isStringLiteral(firstArgument) + || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; return factory.createCallExpression( factory.createPropertyAccessExpression( contextObject, @@ -1568,7 +1690,10 @@ namespace ts { * * @param node The node to visit. */ - function visitDestructuringAssignment(node: DestructuringAssignment, valueIsDiscarded: boolean): VisitResult { + function visitDestructuringAssignment( + node: DestructuringAssignment, + valueIsDiscarded: boolean, + ): VisitResult { if (hasExportedReferenceInDestructuringTarget(node.left)) { return flattenDestructuringAssignment( node, @@ -1615,7 +1740,10 @@ namespace ts { } } - function visitPrefixOrPostfixUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded: boolean) { + function visitPrefixOrPostfixUnaryExpression( + node: PrefixUnaryExpression | PostfixUnaryExpression, + valueIsDiscarded: boolean, + ) { // When we see a prefix or postfix increment expression whose operand is an exported // symbol, we should ensure all exports of that symbol are updated with the correct // value. @@ -1786,7 +1914,9 @@ namespace ts { factory.createPropertyAssignment( factory.cloneNode(name), factory.createPropertyAccessExpression( - factory.getGeneratedNameForNode(importDeclaration.parent?.parent?.parent || importDeclaration), + factory.getGeneratedNameForNode( + importDeclaration.parent?.parent?.parent || importDeclaration, + ), factory.cloneNode(importDeclaration.propertyName || importDeclaration.name), ), ), @@ -1852,7 +1982,9 @@ namespace ts { else if (isImportSpecifier(importDeclaration)) { return setTextRange( factory.createPropertyAccessExpression( - factory.getGeneratedNameForNode(importDeclaration.parent?.parent?.parent || importDeclaration), + factory.getGeneratedNameForNode( + importDeclaration.parent?.parent?.parent || importDeclaration, + ), factory.cloneNode(importDeclaration.propertyName || importDeclaration.name), ), /*location*/ node, @@ -1924,7 +2056,10 @@ namespace ts { exportedNames = append(exportedNames, factory.getDeclarationName(valueDeclaration)); } - exportedNames = addRange(exportedNames, moduleInfo && moduleInfo.exportedBindings[getOriginalNodeId(valueDeclaration)]); + exportedNames = addRange( + exportedNames, + moduleInfo && moduleInfo.exportedBindings[getOriginalNodeId(valueDeclaration)], + ); } } diff --git a/src/compiler/transformers/taggedTemplate.ts b/src/compiler/transformers/taggedTemplate.ts index 414863bc5c20d..45fcb7ab1ae4e 100644 --- a/src/compiler/transformers/taggedTemplate.ts +++ b/src/compiler/transformers/taggedTemplate.ts @@ -68,7 +68,9 @@ namespace ts { return factory.createCallExpression(tag, /*typeArguments*/ undefined, templateArguments); } - function createTemplateCooked(template: TemplateHead | TemplateMiddle | TemplateTail | NoSubstitutionTemplateLiteral) { + function createTemplateCooked( + template: TemplateHead | TemplateMiddle | TemplateTail | NoSubstitutionTemplateLiteral, + ) { return template.templateFlags ? factory.createVoidZero() : factory.createStringLiteral(template.text); } @@ -83,14 +85,18 @@ namespace ts { // Examples: `\n` is converted to "\\n", a template string with a newline to "\n". let text = node.rawText; if (text === undefined) { - Debug.assertIsDefined(currentSourceFile, "Template literal node is missing 'rawText' and does not have a source file. Possibly bad transform."); + Debug.assertIsDefined( + currentSourceFile, + "Template literal node is missing 'rawText' and does not have a source file. Possibly bad transform.", + ); text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node); // text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"), // thus we need to remove those characters. // First template piece starts with "`", others with "}" // Last template piece ends with "`", others with "${" - const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail; + const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral + || node.kind === SyntaxKind.TemplateTail; text = text.substring(1, text.length - (isLast ? 1 : 2)); } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 4291af39d70c2..d78c5aaf29026 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -172,7 +172,10 @@ namespace ts { // These nodes should always have names unless they are default-exports; // however, class declaration parsing allows for undefined names, so syntactically invalid // programs may also have an undefined name. - Debug.assert(node.kind === SyntaxKind.ClassDeclaration || hasSyntacticModifier(node, ModifierFlags.Default)); + Debug.assert( + node.kind === SyntaxKind.ClassDeclaration + || hasSyntacticModifier(node, ModifierFlags.Default), + ); } break; @@ -220,13 +223,17 @@ namespace ts { case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.ExportAssignment: case SyntaxKind.ExportDeclaration: - return visitElidableStatement(node as ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration); + return visitElidableStatement( + node as ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration, + ); default: return visitorWorker(node); } } - function visitElidableStatement(node: ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration): VisitResult { + function visitElidableStatement( + node: ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration, + ): VisitResult { const parsed = getParseTreeNode(node); if (parsed !== node) { // If the node has been transformed by a `before` transformer, perform no ellision on it @@ -270,16 +277,19 @@ namespace ts { */ function namespaceElementVisitorWorker(node: Node): VisitResult { if ( - node.kind === SyntaxKind.ExportDeclaration || - node.kind === SyntaxKind.ImportDeclaration || - node.kind === SyntaxKind.ImportClause || - (node.kind === SyntaxKind.ImportEqualsDeclaration && - (node as ImportEqualsDeclaration).moduleReference.kind === SyntaxKind.ExternalModuleReference) + node.kind === SyntaxKind.ExportDeclaration + || node.kind === SyntaxKind.ImportDeclaration + || node.kind === SyntaxKind.ImportClause + || (node.kind === SyntaxKind.ImportEqualsDeclaration + && (node as ImportEqualsDeclaration).moduleReference.kind === SyntaxKind.ExternalModuleReference) ) { // do not emit ES6 imports and exports since they are illegal inside a namespace return undefined; } - else if (node.transformFlags & TransformFlags.ContainsTypeScript || hasSyntacticModifier(node, ModifierFlags.Export)) { + else if ( + node.transformFlags & TransformFlags.ContainsTypeScript + || hasSyntacticModifier(node, ModifierFlags.Export) + ) { return visitTypeScript(node); } @@ -498,7 +508,9 @@ namespace ts { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.ClassStaticBlockDeclaration: - return Debug.fail("Class and object literal elements must be visited with their respective visitors"); + return Debug.fail( + "Class and object literal elements must be visited with their respective visitors", + ); case SyntaxKind.FunctionDeclaration: // Typescript function declarations can have modifiers, decorators, and type annotations. @@ -581,9 +593,9 @@ namespace ts { } function visitSourceFile(node: SourceFile) { - const alwaysStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") && - !(isExternalModule(node) && moduleKind >= ModuleKind.ES2015) && - !isJsonSourceFile(node); + const alwaysStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") + && !(isExternalModule(node) && moduleKind >= ModuleKind.ES2015) + && !isJsonSourceFile(node); return factory.updateSourceFile( node, @@ -602,13 +614,18 @@ namespace ts { let facts = ClassFacts.None; if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties; const extendsClauseElement = getEffectiveBaseTypeNode(node); - if (extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword) facts |= ClassFacts.IsDerivedClass; + if ( + extendsClauseElement + && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword + ) facts |= ClassFacts.IsDerivedClass; if (classOrConstructorParameterIsDecorated(node)) facts |= ClassFacts.HasConstructorDecorators; if (childIsDecorated(node)) facts |= ClassFacts.HasMemberDecorators; if (isExportOfNamespace(node)) facts |= ClassFacts.IsExportOfNamespace; else if (isDefaultExternalModuleExport(node)) facts |= ClassFacts.IsDefaultExternalExport; else if (isNamedExternalModuleExport(node)) facts |= ClassFacts.IsNamedExternalExport; - if (languageVersion <= ScriptTarget.ES5 && (facts & ClassFacts.MayNeedImmediatelyInvokedFunctionExpression)) facts |= ClassFacts.UseImmediatelyInvokedFunctionExpression; + if ( + languageVersion <= ScriptTarget.ES5 && (facts & ClassFacts.MayNeedImmediatelyInvokedFunctionExpression) + ) facts |= ClassFacts.UseImmediatelyInvokedFunctionExpression; return facts; } @@ -624,7 +641,10 @@ namespace ts { } function visitClassDeclaration(node: ClassDeclaration): VisitResult { - if (!isClassLikeDeclarationWithTypeScriptSyntax(node) && !(currentNamespace && hasSyntacticModifier(node, ModifierFlags.Export))) { + if ( + !isClassLikeDeclarationWithTypeScriptSyntax(node) + && !(currentNamespace && hasSyntacticModifier(node, ModifierFlags.Export)) + ) { return factory.updateClassDeclaration( node, visitNodes(node.modifiers, modifierVisitor, isModifier), @@ -642,7 +662,8 @@ namespace ts { context.startLexicalEnvironment(); } - const name = node.name || (facts & ClassFacts.NeedsName ? factory.getGeneratedNameForNode(node) : undefined); + const name = node.name + || (facts & ClassFacts.NeedsName ? factory.getGeneratedNameForNode(node) : undefined); const allDecorators = getAllDecoratorsOfClass(node); const decorators = transformAllDecoratorsOfDeclaration(node, node, allDecorators); @@ -686,7 +707,10 @@ namespace ts { // return C; // }(); // - const closingBraceLocation = createTokenRange(skipTrivia(currentSourceFile.text, node.members.end), SyntaxKind.CloseBraceToken); + const closingBraceLocation = createTokenRange( + skipTrivia(currentSourceFile.text, node.members.end), + SyntaxKind.CloseBraceToken, + ); const localName = factory.getInternalName(node); // The following partially-emitted expression exists purely to align our sourcemap @@ -730,12 +754,23 @@ namespace ts { if (facts & ClassFacts.IsExportOfNamespace) { addExportMemberAssignment(statements, node); } - else if (facts & ClassFacts.UseImmediatelyInvokedFunctionExpression || facts & ClassFacts.HasConstructorDecorators) { + else if ( + facts & ClassFacts.UseImmediatelyInvokedFunctionExpression + || facts & ClassFacts.HasConstructorDecorators + ) { if (facts & ClassFacts.IsDefaultExternalExport) { - statements.push(factory.createExportDefault(factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true))); + statements.push( + factory.createExportDefault( + factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true), + ), + ); } else if (facts & ClassFacts.IsNamedExternalExport) { - statements.push(factory.createExternalModuleExport(factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true))); + statements.push( + factory.createExternalModuleExport( + factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true), + ), + ); } } @@ -757,9 +792,9 @@ namespace ts { node.name, /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - isClassLikeDeclarationWithTypeScriptSyntax(node) ? - transformClassMembers(node) : - visitNodes(node.members, getClassElementVisitor(node), isClassElement), + isClassLikeDeclarationWithTypeScriptSyntax(node) + ? transformClassMembers(node) + : visitNodes(node.members, getClassElementVisitor(node), isClassElement), ); } @@ -771,8 +806,8 @@ namespace ts { function transformClassMembers(node: ClassDeclaration | ClassExpression) { const members: ClassElement[] = []; const constructor = getFirstConstructorWithBody(node); - const parametersWithPropertyAssignments = constructor && - filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor)); + const parametersWithPropertyAssignments = constructor + && filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor)); if (parametersWithPropertyAssignments) { for (const parameter of parametersWithPropertyAssignments) { @@ -801,15 +836,22 @@ namespace ts { * @param node The declaration node. * @param allDecorators An object containing all of the decorators for the declaration. */ - function transformAllDecoratorsOfDeclaration(node: Declaration, container: ClassLikeDeclaration, allDecorators: AllDecorators | undefined) { + function transformAllDecoratorsOfDeclaration( + node: Declaration, + container: ClassLikeDeclaration, + allDecorators: AllDecorators | undefined, + ) { if (!allDecorators) { return undefined; } const decorators = visitArray(allDecorators.decorators, visitor, isDecorator); const parameterDecorators = flatMap(allDecorators.parameters, transformDecoratorsOfParameter); - const metadataDecorators = some(decorators) || some(parameterDecorators) ? getTypeMetadata(node, container) : undefined; - const result = factory.createNodeArray(concatenate(concatenate(decorators, parameterDecorators), metadataDecorators)); + const metadataDecorators = some(decorators) || some(parameterDecorators) ? getTypeMetadata(node, container) + : undefined; + const result = factory.createNodeArray( + concatenate(concatenate(decorators, parameterDecorators), metadataDecorators), + ); const pos = firstOrUndefined(allDecorators.decorators)?.pos ?? -1; const end = lastOrUndefined(allDecorators.decorators)?.end ?? -1; setTextRangePosEnd(result, pos, end); @@ -847,24 +889,40 @@ namespace ts { * @param node The declaration node. */ function getTypeMetadata(node: Declaration, container: ClassLikeDeclaration) { - return USE_NEW_TYPE_METADATA_FORMAT ? - getNewTypeMetadata(node, container) : - getOldTypeMetadata(node, container); + return USE_NEW_TYPE_METADATA_FORMAT + ? getNewTypeMetadata(node, container) + : getOldTypeMetadata(node, container); } function getOldTypeMetadata(node: Declaration, container: ClassLikeDeclaration) { if (typeSerializer) { let decorators: Decorator[] | undefined; if (shouldAddTypeMetadata(node)) { - const typeMetadata = emitHelpers().createMetadataHelper("design:type", typeSerializer.serializeTypeOfNode({ currentLexicalScope, currentNameScope: container }, node)); + const typeMetadata = emitHelpers().createMetadataHelper( + "design:type", + typeSerializer.serializeTypeOfNode({ currentLexicalScope, currentNameScope: container }, node), + ); decorators = append(decorators, factory.createDecorator(typeMetadata)); } if (shouldAddParamTypesMetadata(node)) { - const paramTypesMetadata = emitHelpers().createMetadataHelper("design:paramtypes", typeSerializer.serializeParameterTypesOfNode({ currentLexicalScope, currentNameScope: container }, node, container)); + const paramTypesMetadata = emitHelpers().createMetadataHelper( + "design:paramtypes", + typeSerializer.serializeParameterTypesOfNode( + { currentLexicalScope, currentNameScope: container }, + node, + container, + ), + ); decorators = append(decorators, factory.createDecorator(paramTypesMetadata)); } if (shouldAddReturnTypeMetadata(node)) { - const returnTypeMetadata = emitHelpers().createMetadataHelper("design:returntype", typeSerializer.serializeReturnTypeOfNode({ currentLexicalScope, currentNameScope: container }, node)); + const returnTypeMetadata = emitHelpers().createMetadataHelper( + "design:returntype", + typeSerializer.serializeReturnTypeOfNode( + { currentLexicalScope, currentNameScope: container }, + node, + ), + ); decorators = append(decorators, factory.createDecorator(returnTypeMetadata)); } return decorators; @@ -875,19 +933,62 @@ namespace ts { if (typeSerializer) { let properties: ObjectLiteralElementLike[] | undefined; if (shouldAddTypeMetadata(node)) { - const typeProperty = factory.createPropertyAssignment("type", factory.createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, factory.createToken(SyntaxKind.EqualsGreaterThanToken), typeSerializer.serializeTypeOfNode({ currentLexicalScope, currentNameScope: container }, node))); + const typeProperty = factory.createPropertyAssignment( + "type", + factory.createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, + [], + /*type*/ undefined, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + typeSerializer.serializeTypeOfNode( + { currentLexicalScope, currentNameScope: container }, + node, + ), + ), + ); properties = append(properties, typeProperty); } if (shouldAddParamTypesMetadata(node)) { - const paramTypeProperty = factory.createPropertyAssignment("paramTypes", factory.createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, factory.createToken(SyntaxKind.EqualsGreaterThanToken), typeSerializer.serializeParameterTypesOfNode({ currentLexicalScope, currentNameScope: container }, node, container))); + const paramTypeProperty = factory.createPropertyAssignment( + "paramTypes", + factory.createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, + [], + /*type*/ undefined, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + typeSerializer.serializeParameterTypesOfNode( + { currentLexicalScope, currentNameScope: container }, + node, + container, + ), + ), + ); properties = append(properties, paramTypeProperty); } if (shouldAddReturnTypeMetadata(node)) { - const returnTypeProperty = factory.createPropertyAssignment("returnType", factory.createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, factory.createToken(SyntaxKind.EqualsGreaterThanToken), typeSerializer.serializeReturnTypeOfNode({ currentLexicalScope, currentNameScope: container }, node))); + const returnTypeProperty = factory.createPropertyAssignment( + "returnType", + factory.createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, + [], + /*type*/ undefined, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + typeSerializer.serializeReturnTypeOfNode({ + currentLexicalScope, + currentNameScope: container, + }, node), + ), + ); properties = append(properties, returnTypeProperty); } if (properties) { - const typeInfoMetadata = emitHelpers().createMetadataHelper("design:typeinfo", factory.createObjectLiteralExpression(properties, /*multiLine*/ true)); + const typeInfoMetadata = emitHelpers().createMetadataHelper( + "design:typeinfo", + factory.createObjectLiteralExpression(properties, /*multiLine*/ true), + ); return [factory.createDecorator(typeInfoMetadata)]; } } @@ -900,7 +1001,9 @@ namespace ts { * * @param node The node to test. */ - function shouldAddTypeMetadata(node: Declaration): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration { + function shouldAddTypeMetadata( + node: Declaration, + ): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration { const kind = node.kind; return kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.GetAccessor @@ -926,7 +1029,9 @@ namespace ts { * * @param node The node to test. */ - function shouldAddParamTypesMetadata(node: Declaration): node is ClassLikeDeclaration & { _hasConstructorBrand: never; } | MethodDeclaration | AccessorDeclaration { + function shouldAddParamTypesMetadata( + node: Declaration, + ): node is ClassLikeDeclaration & { _hasConstructorBrand: never; } | MethodDeclaration | AccessorDeclaration { switch (node.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: @@ -945,7 +1050,10 @@ namespace ts { * * @param member The member whose name should be converted into an expression. */ - function getExpressionForPropertyName(member: ClassElement | EnumMember, generateNameForComputedPropertyName: boolean): Expression { + function getExpressionForPropertyName( + member: ClassElement | EnumMember, + generateNameForComputedPropertyName: boolean, + ): Expression { const name = member.name!; if (isPrivateIdentifier(name)) { return factory.createIdentifier(""); @@ -976,13 +1084,19 @@ namespace ts { // The names are used more than once when: // - the property is non-static and its initializer is moved to the constructor (when there are parameter property assignments). // - the property has a decorator. - if (isComputedPropertyName(name) && ((!hasStaticModifier(member) && currentClassHasParameterProperties) || hasDecorators(member))) { + if ( + isComputedPropertyName(name) + && ((!hasStaticModifier(member) && currentClassHasParameterProperties) || hasDecorators(member)) + ) { const expression = visitNode(name.expression, visitor, isExpression); const innerExpression = skipPartiallyEmittedExpressions(expression); if (!isSimpleInlineableExpression(innerExpression)) { const generatedName = factory.getGeneratedNameForNode(name); hoistVariableDeclaration(generatedName); - return factory.updateComputedPropertyName(name, factory.createAssignment(generatedName, expression)); + return factory.updateComputedPropertyName( + name, + factory.createAssignment(generatedName, expression), + ); } } return visitNode(name, visitor, isPropertyName); @@ -1027,7 +1141,9 @@ namespace ts { * * @param node The declaration node. */ - function shouldEmitFunctionLikeDeclaration(node: T): node is T & { body: NonNullable; } { + function shouldEmitFunctionLikeDeclaration( + node: T, + ): node is T & { body: NonNullable; } { return !nodeIsMissing(node.body); } @@ -1044,7 +1160,10 @@ namespace ts { if (isAmbient) { return factory.updatePropertyDeclaration( node, - concatenate(decorators, factory.createModifiersFromModifierFlags(ModifierFlags.Ambient)), + concatenate( + decorators, + factory.createModifiersFromModifierFlags(ModifierFlags.Ambient), + ), visitNode(node.name, visitor, isPropertyName), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, @@ -1076,8 +1195,8 @@ namespace ts { } function transformConstructorBody(body: Block, constructor: ConstructorDeclaration) { - const parametersWithPropertyAssignments = constructor && - filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor)); + const parametersWithPropertyAssignments = constructor + && filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor)); if (!some(parametersWithPropertyAssignments)) { return visitFunctionBody(body, visitor, context); } @@ -1086,14 +1205,25 @@ namespace ts { resumeLexicalEnvironment(); - const prologueStatementCount = factory.copyPrologue(body.statements, statements, /*ensureUseStrict*/ false, visitor); + const prologueStatementCount = factory.copyPrologue( + body.statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); const superStatementIndex = findSuperStatementIndex(body.statements, prologueStatementCount); // If there was a super call, visit existing statements up to and including it if (superStatementIndex >= 0) { addRange( statements, - visitNodes(body.statements, visitor, isStatement, prologueStatementCount, superStatementIndex + 1 - prologueStatementCount), + visitNodes( + body.statements, + visitor, + isStatement, + prologueStatementCount, + superStatementIndex + 1 - prologueStatementCount, + ), ); } @@ -1109,7 +1239,10 @@ namespace ts { // this.y = y; // } // - const parameterPropertyAssignments = mapDefined(parametersWithPropertyAssignments, transformParameterWithPropertyAssignment); + const parameterPropertyAssignments = mapDefined( + parametersWithPropertyAssignments, + transformParameterWithPropertyAssignment, + ); // If there is a super() call, the parameter properties go immediately after it if (superStatementIndex >= 0) { @@ -1130,7 +1263,10 @@ namespace ts { // End the lexical environment. statements = factory.mergeLexicalEnvironment(statements, endLexicalEnvironment()); - const block = factory.createBlock(setTextRange(factory.createNodeArray(statements), body.statements), /*multiLine*/ true); + const block = factory.createBlock( + setTextRange(factory.createNodeArray(statements), body.statements), + /*multiLine*/ true, + ); setTextRange(block, /*location*/ body); setOriginalNode(block, body); return block; @@ -1179,7 +1315,10 @@ namespace ts { ); } - function visitMethodDeclaration(node: MethodDeclaration, parent: ClassLikeDeclaration | ObjectLiteralExpression) { + function visitMethodDeclaration( + node: MethodDeclaration, + parent: ClassLikeDeclaration | ObjectLiteralExpression, + ) { if (!(node.transformFlags & TransformFlags.ContainsTypeScript)) { return node; } @@ -1189,7 +1328,8 @@ namespace ts { } const allDecorators = isClassLike(parent) ? getAllDecoratorsOfClassElement(node, parent) : undefined; - const decorators = isClassLike(parent) ? transformAllDecoratorsOfDeclaration(node, parent, allDecorators) : undefined; + const decorators = isClassLike(parent) ? transformAllDecoratorsOfDeclaration(node, parent, allDecorators) + : undefined; return factory.updateMethodDeclaration( node, concatenate(decorators, visitNodes(node.modifiers, modifierVisitor, isModifierLike)), @@ -1213,7 +1353,10 @@ namespace ts { return !(nodeIsMissing(node.body) && hasSyntacticModifier(node, ModifierFlags.Abstract)); } - function visitGetAccessor(node: GetAccessorDeclaration, parent: ClassLikeDeclaration | ObjectLiteralExpression) { + function visitGetAccessor( + node: GetAccessorDeclaration, + parent: ClassLikeDeclaration | ObjectLiteralExpression, + ) { if (!(node.transformFlags & TransformFlags.ContainsTypeScript)) { return node; } @@ -1222,9 +1365,9 @@ namespace ts { return undefined; } - const decorators = isClassLike(parent) ? - transformAllDecoratorsOfDeclaration(node, parent, getAllDecoratorsOfClassElement(node, parent)) : - undefined; + const decorators = isClassLike(parent) + ? transformAllDecoratorsOfDeclaration(node, parent, getAllDecoratorsOfClassElement(node, parent)) + : undefined; return factory.updateGetAccessorDeclaration( node, @@ -1236,7 +1379,10 @@ namespace ts { ); } - function visitSetAccessor(node: SetAccessorDeclaration, parent: ClassLikeDeclaration | ObjectLiteralExpression) { + function visitSetAccessor( + node: SetAccessorDeclaration, + parent: ClassLikeDeclaration | ObjectLiteralExpression, + ) { if (!(node.transformFlags & TransformFlags.ContainsTypeScript)) { return node; } @@ -1245,9 +1391,9 @@ namespace ts { return undefined; } - const decorators = isClassLike(parent) ? - transformAllDecoratorsOfDeclaration(node, parent, getAllDecoratorsOfClassElement(node, parent)) : - undefined; + const decorators = isClassLike(parent) + ? transformAllDecoratorsOfDeclaration(node, parent, getAllDecoratorsOfClassElement(node, parent)) + : undefined; return factory.updateSetAccessorDeclaration( node, @@ -1531,7 +1677,12 @@ namespace ts { // `exportName` is the expression used within this node's container for any exported references. const exportName = hasSyntacticModifier(node, ModifierFlags.Export) - ? factory.getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true) + ? factory.getExternalModuleOrNamespaceExportName( + currentNamespaceContainerName, + node, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ) : factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); // x || (x = {}) @@ -1563,7 +1714,11 @@ namespace ts { /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, - [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)], + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + parameterName, + )], /*type*/ undefined, transformEnumBody(node, containerName), ), @@ -1628,9 +1783,9 @@ namespace ts { ), valueExpression, ); - const outerAssignment = valueExpression.kind === SyntaxKind.StringLiteral ? - innerAssignment : - factory.createAssignment( + const outerAssignment = valueExpression.kind === SyntaxKind.StringLiteral + ? innerAssignment + : factory.createAssignment( factory.createElementAccessExpression( currentNamespaceContainerName, innerAssignment, @@ -1656,7 +1811,8 @@ namespace ts { function transformEnumMemberDeclarationValue(member: EnumMember): Expression { const value = resolver.getConstantValue(member); if (value !== undefined) { - return typeof value === "string" ? factory.createStringLiteral(value) : factory.createNumericLiteral(value); + return typeof value === "string" ? factory.createStringLiteral(value) + : factory.createNumericLiteral(value); } else { enableSubstitutionForNonQualifiedEnumMembers(); @@ -1701,7 +1857,9 @@ namespace ts { * Records that a declaration was emitted in the current scope, if it was the first * declaration for the provided symbol. */ - function recordEmittedDeclarationInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration) { + function recordEmittedDeclarationInScope( + node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration, + ) { if (!currentScopeFirstDeclarationsOfName) { currentScopeFirstDeclarationsOfName = new Map(); } @@ -1724,7 +1882,9 @@ namespace ts { return true; } - function declaredNameInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration): __String { + function declaredNameInScope( + node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration, + ): __String { Debug.assertNode(node.name, isIdentifier); return node.name.escapedText; } @@ -1832,7 +1992,12 @@ namespace ts { // `exportName` is the expression used within this node's container for any exported references. const exportName = hasSyntacticModifier(node, ModifierFlags.Export) - ? factory.getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true) + ? factory.getExternalModuleOrNamespaceExportName( + currentNamespaceContainerName, + node, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ) : factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); // x || (x = {}) @@ -1863,7 +2028,11 @@ namespace ts { /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, - [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)], + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + parameterName, + )], /*type*/ undefined, transformModuleBody(node, containerName), ), @@ -1908,7 +2077,14 @@ namespace ts { let blockLocation: TextRange | undefined; if (node.body) { if (node.body.kind === SyntaxKind.ModuleBlock) { - saveStateAndInvoke(node.body, body => addRange(statements, visitNodes((body as ModuleBlock).statements, namespaceElementVisitor, isStatement))); + saveStateAndInvoke( + node.body, + body => + addRange( + statements, + visitNodes((body as ModuleBlock).statements, namespaceElementVisitor, isStatement), + ), + ); statementsLocation = node.body.statements; blockLocation = node.body; } @@ -1968,9 +2144,13 @@ namespace ts { return block; } - function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration: ModuleDeclaration): ModuleDeclaration | undefined { + function getInnerMostModuleDeclarationFromDottedModule( + moduleDeclaration: ModuleDeclaration, + ): ModuleDeclaration | undefined { if (moduleDeclaration.body!.kind === SyntaxKind.ModuleDeclaration) { - const recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration.body as ModuleDeclaration); + const recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule( + moduleDeclaration.body as ModuleDeclaration, + ); return recursiveInnerModule || moduleDeclaration.body as ModuleDeclaration; } } @@ -1993,9 +2173,9 @@ namespace ts { // Elide the declaration if the import clause was elided. const importClause = visitNode(node.importClause, visitImportClause, isImportClause); - return importClause || - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error + return importClause + || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve + || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error ? factory.updateImportDeclaration( node, /*modifiers*/ undefined, @@ -2016,7 +2196,8 @@ namespace ts { // Elide the import clause if we elide both its name and its named bindings. const name = shouldEmitAliasDeclaration(node) ? node.name : undefined; const namedBindings = visitNode(node.namedBindings, visitNamedImportBindings, isNamedImportBindings); - return (name || namedBindings) ? factory.updateImportClause(node, /*isTypeOnly*/ false, name, namedBindings) : undefined; + return (name || namedBindings) ? factory.updateImportClause(node, /*isTypeOnly*/ false, name, namedBindings) + : undefined; } /** @@ -2032,8 +2213,8 @@ namespace ts { else { // Elide named imports if all of its import specifiers are elided and settings allow. const allowEmpty = compilerOptions.preserveValueImports && ( - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error + compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve + || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error ); const elements = visitNodes(node.elements, visitImportSpecifier, isImportSpecifier); return allowEmpty || some(elements) ? factory.updateNamedImports(node, elements) : undefined; @@ -2081,8 +2262,8 @@ namespace ts { // Elide the export declaration if all of its named exports are elided. const allowEmpty = !!node.moduleSpecifier && ( - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error + compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve + || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error ); const exportClause = visitNode( node.exportClause, @@ -2118,7 +2299,10 @@ namespace ts { return factory.updateNamespaceExport(node, visitNode(node.name, visitor, isIdentifier)); } - function visitNamedExportBindings(node: NamedExportBindings, allowEmpty: boolean): VisitResult { + function visitNamedExportBindings( + node: NamedExportBindings, + allowEmpty: boolean, + ): VisitResult { return isNamespaceExport(node) ? visitNamespaceExports(node) : visitNamedExports(node, allowEmpty); } @@ -2262,7 +2446,12 @@ namespace ts { function addExportMemberAssignment(statements: Statement[], node: ClassDeclaration | FunctionDeclaration) { const expression = factory.createAssignment( - factory.getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true), + factory.getExternalModuleOrNamespaceExportName( + currentNamespaceContainerName, + node, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ), factory.getLocalName(node), ); setSourceMapRange(expression, createRange(node.name ? node.name.pos : node.pos, node.end)); @@ -2276,7 +2465,12 @@ namespace ts { return setTextRange( factory.createExpressionStatement( factory.createAssignment( - factory.getNamespaceMemberName(currentNamespaceContainerName, exportName, /*allowComments*/ false, /*allowSourceMaps*/ true), + factory.getNamespaceMemberName( + currentNamespaceContainerName, + exportName, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ), exportValue, ), ), @@ -2284,12 +2478,27 @@ namespace ts { ); } - function createNamespaceExportExpression(exportName: Identifier, exportValue: Expression, location?: TextRange) { - return setTextRange(factory.createAssignment(getNamespaceMemberNameWithSourceMapsAndWithoutComments(exportName), exportValue), location); + function createNamespaceExportExpression( + exportName: Identifier, + exportValue: Expression, + location?: TextRange, + ) { + return setTextRange( + factory.createAssignment( + getNamespaceMemberNameWithSourceMapsAndWithoutComments(exportName), + exportValue, + ), + location, + ); } function getNamespaceMemberNameWithSourceMapsAndWithoutComments(name: Identifier) { - return factory.getNamespaceMemberName(currentNamespaceContainerName, name, /*allowComments*/ false, /*allowSourceMaps*/ true); + return factory.getNamespaceMemberName( + currentNamespaceContainerName, + name, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ); } /** @@ -2353,11 +2562,17 @@ namespace ts { currentSourceFile = node; } - if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) { + if ( + enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports + && isTransformedModuleDeclaration(node) + ) { applicableSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports; } - if (enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && isTransformedEnumDeclaration(node)) { + if ( + enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers + && isTransformedEnumDeclaration(node) + ) { applicableSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers; } @@ -2427,8 +2642,10 @@ namespace ts { // an identifier that is exported from a merged namespace. const container = resolver.getReferencedExportContainer(node, /*prefixLocals*/ false); if (container && container.kind !== SyntaxKind.SourceFile) { - const substitute = (applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) || - (applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration); + const substitute = (applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports + && container.kind === SyntaxKind.ModuleDeclaration) + || (applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers + && container.kind === SyntaxKind.EnumDeclaration); if (substitute) { return setTextRange( factory.createPropertyAccessExpression(factory.getGeneratedNameForNode(container), node), @@ -2453,17 +2670,24 @@ namespace ts { return value.replace(/\*\//g, "*_/"); } - function substituteConstantValue(node: PropertyAccessExpression | ElementAccessExpression): LeftHandSideExpression { + function substituteConstantValue( + node: PropertyAccessExpression | ElementAccessExpression, + ): LeftHandSideExpression { const constantValue = tryGetConstEnumValue(node); if (constantValue !== undefined) { // track the constant value on the node for the printer in needsDotDotForPropertyAccess setConstantValue(node, constantValue); - const substitute = typeof constantValue === "string" ? factory.createStringLiteral(constantValue) : factory.createNumericLiteral(constantValue); + const substitute = typeof constantValue === "string" ? factory.createStringLiteral(constantValue) + : factory.createNumericLiteral(constantValue); if (!compilerOptions.removeComments) { const originalNode = getOriginalNode(node, isAccessExpression); - addSyntheticTrailingComment(substitute, SyntaxKind.MultiLineCommentTrivia, ` ${safeMultiLineComment(getTextOfNode(originalNode))} `); + addSyntheticTrailingComment( + substitute, + SyntaxKind.MultiLineCommentTrivia, + ` ${safeMultiLineComment(getTextOfNode(originalNode))} `, + ); } return substitute; } @@ -2476,12 +2700,13 @@ namespace ts { return undefined; } - return isPropertyAccessExpression(node) || isElementAccessExpression(node) ? resolver.getConstantValue(node) : undefined; + return isPropertyAccessExpression(node) || isElementAccessExpression(node) ? resolver.getConstantValue(node) + : undefined; } function shouldEmitAliasDeclaration(node: Node): boolean { - return isInJSFile(node) || - (compilerOptions.preserveValueImports + return isInJSFile(node) + || (compilerOptions.preserveValueImports ? resolver.isValueAliasDeclaration(node) : resolver.isReferencedAliasDeclaration(node)); } diff --git a/src/compiler/transformers/typeSerializer.ts b/src/compiler/transformers/typeSerializer.ts index 4380fd84273c4..84ea502d792e7 100644 --- a/src/compiler/transformers/typeSerializer.ts +++ b/src/compiler/transformers/typeSerializer.ts @@ -42,12 +42,24 @@ namespace ts { * Serializes the type of a node for use with decorator type metadata. * @param node The node that should have its type serialized. */ - serializeTypeOfNode(serializerContext: RuntimeTypeSerializerContext, node: PropertyDeclaration | ParameterDeclaration | AccessorDeclaration | ClassLikeDeclaration | MethodDeclaration): Expression; + serializeTypeOfNode( + serializerContext: RuntimeTypeSerializerContext, + node: + | PropertyDeclaration + | ParameterDeclaration + | AccessorDeclaration + | ClassLikeDeclaration + | MethodDeclaration, + ): Expression; /** * Serializes the types of the parameters of a node for use with decorator type metadata. * @param node The node that should have its parameter types serialized. */ - serializeParameterTypesOfNode(serializerContext: RuntimeTypeSerializerContext, node: Node, container: ClassLikeDeclaration): ArrayLiteralExpression; + serializeParameterTypesOfNode( + serializerContext: RuntimeTypeSerializerContext, + node: Node, + container: ClassLikeDeclaration, + ): ArrayLiteralExpression; /** * Serializes the return type of a node for use with decorator type metadata. * @param node The node that should have its return type serialized. @@ -69,15 +81,33 @@ namespace ts { let currentNameScope: ClassLikeDeclaration | undefined; return { - serializeTypeNode: (serializerContext, node) => setSerializerContextAnd(serializerContext, serializeTypeNode, node), - serializeTypeOfNode: (serializerContext, node) => setSerializerContextAnd(serializerContext, serializeTypeOfNode, node), - serializeParameterTypesOfNode: (serializerContext, node, container) => setSerializerContextAnd(serializerContext, serializeParameterTypesOfNode, node, container), - serializeReturnTypeOfNode: (serializerContext, node) => setSerializerContextAnd(serializerContext, serializeReturnTypeOfNode, node), + serializeTypeNode: (serializerContext, node) => + setSerializerContextAnd(serializerContext, serializeTypeNode, node), + serializeTypeOfNode: (serializerContext, node) => + setSerializerContextAnd(serializerContext, serializeTypeOfNode, node), + serializeParameterTypesOfNode: (serializerContext, node, container) => + setSerializerContextAnd(serializerContext, serializeParameterTypesOfNode, node, container), + serializeReturnTypeOfNode: (serializerContext, node) => + setSerializerContextAnd(serializerContext, serializeReturnTypeOfNode, node), }; - function setSerializerContextAnd(serializerContext: RuntimeTypeSerializerContext, cb: (node: TNode) => R, node: TNode): R; - function setSerializerContextAnd(serializerContext: RuntimeTypeSerializerContext, cb: (node: TNode, arg: T) => R, node: TNode, arg: T): R; - function setSerializerContextAnd(serializerContext: RuntimeTypeSerializerContext, cb: (node: TNode, arg?: T) => R, node: TNode, arg?: T) { + function setSerializerContextAnd( + serializerContext: RuntimeTypeSerializerContext, + cb: (node: TNode) => R, + node: TNode, + ): R; + function setSerializerContextAnd( + serializerContext: RuntimeTypeSerializerContext, + cb: (node: TNode, arg: T) => R, + node: TNode, + arg: T, + ): R; + function setSerializerContextAnd( + serializerContext: RuntimeTypeSerializerContext, + cb: (node: TNode, arg?: T) => R, + node: TNode, + arg?: T, + ) { const savedCurrentLexicalScope = currentLexicalScope; const savedCurrentNameScope = currentNameScope; @@ -101,7 +131,14 @@ namespace ts { * Serializes the type of a node for use with decorator type metadata. * @param node The node that should have its type serialized. */ - function serializeTypeOfNode(node: PropertyDeclaration | ParameterDeclaration | AccessorDeclaration | ClassLikeDeclaration | MethodDeclaration): SerializedTypeNode { + function serializeTypeOfNode( + node: + | PropertyDeclaration + | ParameterDeclaration + | AccessorDeclaration + | ClassLikeDeclaration + | MethodDeclaration, + ): SerializedTypeNode { switch (node.kind) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.Parameter: @@ -215,9 +252,9 @@ namespace ts { return factory.createIdentifier("Array"); case SyntaxKind.TypePredicate: - return (node as TypePredicateNode).assertsModifier ? - factory.createVoidZero() : - factory.createIdentifier("Boolean"); + return (node as TypePredicateNode).assertsModifier + ? factory.createVoidZero() + : factory.createIdentifier("Boolean"); case SyntaxKind.BooleanKeyword: return factory.createIdentifier("Boolean"); @@ -245,13 +282,22 @@ namespace ts { return serializeTypeReferenceNode(node as TypeReferenceNode); case SyntaxKind.IntersectionType: - return serializeUnionOrIntersectionConstituents((node as UnionOrIntersectionTypeNode).types, /*isIntersection*/ true); + return serializeUnionOrIntersectionConstituents( + (node as UnionOrIntersectionTypeNode).types, + /*isIntersection*/ true, + ); case SyntaxKind.UnionType: - return serializeUnionOrIntersectionConstituents((node as UnionOrIntersectionTypeNode).types, /*isIntersection*/ false); + return serializeUnionOrIntersectionConstituents( + (node as UnionOrIntersectionTypeNode).types, + /*isIntersection*/ false, + ); case SyntaxKind.ConditionalType: - return serializeUnionOrIntersectionConstituents([(node as ConditionalTypeNode).trueType, (node as ConditionalTypeNode).falseType], /*isIntersection*/ false); + return serializeUnionOrIntersectionConstituents([ + (node as ConditionalTypeNode).trueType, + (node as ConditionalTypeNode).falseType, + ], /*isIntersection*/ false); case SyntaxKind.TypeOperator: if ((node as TypeOperatorNode).operator === SyntaxKind.ReadonlyKeyword) { @@ -280,7 +326,9 @@ namespace ts { case SyntaxKind.JSDocNullableType: case SyntaxKind.JSDocNonNullableType: case SyntaxKind.JSDocOptionalType: - return serializeTypeNode((node as JSDocNullableType | JSDocNonNullableType | JSDocOptionalType).type); + return serializeTypeNode( + (node as JSDocNullableType | JSDocNonNullableType | JSDocOptionalType).type, + ); default: return Debug.failBadSyntaxKind(node); @@ -324,7 +372,10 @@ namespace ts { } } - function serializeUnionOrIntersectionConstituents(types: readonly TypeNode[], isIntersection: boolean): SerializedTypeNode { + function serializeUnionOrIntersectionConstituents( + types: readonly TypeNode[], + isIntersection: boolean, + ): SerializedTypeNode { // Note when updating logic here also update `getEntityNameForDecoratorMetadata` in checker.ts so that aliases can be marked as referenced let serializedType: SerializedTypeNode | undefined; for (let typeNode of types) { @@ -343,7 +394,11 @@ namespace ts { return factory.createIdentifier("Object"); // Reduce to `any` in a union or intersection } - if (!strictNullChecks && ((isLiteralTypeNode(typeNode) && typeNode.literal.kind === SyntaxKind.NullKeyword) || typeNode.kind === SyntaxKind.UndefinedKeyword)) { + if ( + !strictNullChecks + && ((isLiteralTypeNode(typeNode) && typeNode.literal.kind === SyntaxKind.NullKeyword) + || typeNode.kind === SyntaxKind.UndefinedKeyword) + ) { continue; // Elide null and undefined from unions for metadata, just like what we did prior to the implementation of strict null checks } @@ -374,37 +429,37 @@ namespace ts { function equateSerializedTypeNodes(left: Expression, right: Expression): boolean { return ( // temp vars used in fallback - isGeneratedIdentifier(left) ? isGeneratedIdentifier(right) : + isGeneratedIdentifier(left) ? isGeneratedIdentifier(right) // entity names - isIdentifier(left) ? isIdentifier(right) - && left.escapedText === right.escapedText : - isPropertyAccessExpression(left) ? isPropertyAccessExpression(right) + : isIdentifier(left) ? isIdentifier(right) + && left.escapedText === right.escapedText + : isPropertyAccessExpression(left) ? isPropertyAccessExpression(right) && equateSerializedTypeNodes(left.expression, right.expression) - && equateSerializedTypeNodes(left.name, right.name) : + && equateSerializedTypeNodes(left.name, right.name) // `void 0` - isVoidExpression(left) ? isVoidExpression(right) + : isVoidExpression(left) ? isVoidExpression(right) && isNumericLiteral(left.expression) && left.expression.text === "0" - && isNumericLiteral(right.expression) && right.expression.text === "0" : + && isNumericLiteral(right.expression) && right.expression.text === "0" // `"undefined"` or `"function"` in `typeof` checks - isStringLiteral(left) ? isStringLiteral(right) - && left.text === right.text : + : isStringLiteral(left) ? isStringLiteral(right) + && left.text === right.text // used in `typeof` checks for fallback - isTypeOfExpression(left) ? isTypeOfExpression(right) - && equateSerializedTypeNodes(left.expression, right.expression) : + : isTypeOfExpression(left) ? isTypeOfExpression(right) + && equateSerializedTypeNodes(left.expression, right.expression) // parens in `typeof` checks with temps - isParenthesizedExpression(left) ? isParenthesizedExpression(right) - && equateSerializedTypeNodes(left.expression, right.expression) : + : isParenthesizedExpression(left) ? isParenthesizedExpression(right) + && equateSerializedTypeNodes(left.expression, right.expression) // conditionals used in fallback - isConditionalExpression(left) ? isConditionalExpression(right) + : isConditionalExpression(left) ? isConditionalExpression(right) && equateSerializedTypeNodes(left.condition, right.condition) && equateSerializedTypeNodes(left.whenTrue, right.whenTrue) - && equateSerializedTypeNodes(left.whenFalse, right.whenFalse) : + && equateSerializedTypeNodes(left.whenFalse, right.whenFalse) // logical binary and assignments used in fallback - isBinaryExpression(left) ? isBinaryExpression(right) + : isBinaryExpression(left) ? isBinaryExpression(right) && left.operatorToken.kind === right.operatorToken.kind && equateSerializedTypeNodes(left.left, right.left) - && equateSerializedTypeNodes(left.right, right.right) : - false + && equateSerializedTypeNodes(left.right, right.right) + : false ); } @@ -413,11 +468,18 @@ namespace ts { * @param node The type reference node. */ function serializeTypeReferenceNode(node: TypeReferenceNode): SerializedTypeNode { - const kind = resolver.getTypeReferenceSerializationKind(node.typeName, currentNameScope ?? currentLexicalScope); + const kind = resolver.getTypeReferenceSerializationKind( + node.typeName, + currentNameScope ?? currentLexicalScope, + ); switch (kind) { case TypeReferenceSerializationKind.Unknown: // From conditional type type reference that cannot be resolved is Similar to any or unknown - if (findAncestor(node, n => n.parent && isConditionalTypeNode(n.parent) && (n.parent.trueType === n || n.parent.falseType === n))) { + if ( + findAncestor(node, n => + n.parent && isConditionalTypeNode(n.parent) + && (n.parent.trueType === n || n.parent.falseType === n)) + ) { return factory.createIdentifier("Object"); } @@ -482,7 +544,10 @@ namespace ts { */ function createCheckedValue(left: Expression, right: Expression) { return factory.createLogicalAnd( - factory.createStrictInequality(factory.createTypeOfExpression(left), factory.createStringLiteral("undefined")), + factory.createStrictInequality( + factory.createTypeOfExpression(left), + factory.createStringLiteral("undefined"), + ), right, ); } @@ -499,7 +564,10 @@ namespace ts { } if (node.left.kind === SyntaxKind.Identifier) { // A.B -> typeof A !== "undefined" && A.B - return createCheckedValue(serializeEntityNameAsExpression(node.left), serializeEntityNameAsExpression(node)); + return createCheckedValue( + serializeEntityNameAsExpression(node.left), + serializeEntityNameAsExpression(node), + ); } // A.B.C -> typeof A !== "undefined" && (_a = A.B) !== void 0 && _a.C const left = serializeEntityNameAsExpressionFallback(node.left); @@ -507,7 +575,10 @@ namespace ts { return factory.createLogicalAnd( factory.createLogicalAnd( left.left, - factory.createStrictInequality(factory.createAssignment(temp, left.right), factory.createVoidZero()), + factory.createStrictInequality( + factory.createAssignment(temp, left.right), + factory.createVoidZero(), + ), ), factory.createPropertyAccessExpression(temp, node.right), ); @@ -537,7 +608,10 @@ namespace ts { * @param node The qualified name to serialize. */ function serializeQualifiedNameAsExpression(node: QualifiedName): SerializedEntityName { - return factory.createPropertyAccessExpression(serializeEntityNameAsExpression(node.left), node.right) as PropertyAccessEntityNameExpression; + return factory.createPropertyAccessExpression( + serializeEntityNameAsExpression(node.left), + node.right, + ) as PropertyAccessEntityNameExpression; } function getGlobalConstructorWithFallback(name: string) { @@ -551,9 +625,9 @@ namespace ts { } function getGlobalConstructor(name: string, minLanguageVersion: ScriptTarget): SerializedTypeNode { - return languageVersion < minLanguageVersion ? - getGlobalConstructorWithFallback(name) : - factory.createIdentifier(name); + return languageVersion < minLanguageVersion + ? getGlobalConstructorWithFallback(name) + : factory.createIdentifier(name); } } } diff --git a/src/compiler/transformers/utilities.ts b/src/compiler/transformers/utilities.ts index 49e98346b037b..606c1270d40cf 100644 --- a/src/compiler/transformers/utilities.ts +++ b/src/compiler/transformers/utilities.ts @@ -25,7 +25,10 @@ namespace ts { return e.propertyName !== undefined && e.propertyName.escapedText === InternalSymbolName.Default; } - export function chainBundle(context: CoreTransformationContext, transformSourceFile: (x: SourceFile) => SourceFile): (x: SourceFile | Bundle) => SourceFile | Bundle { + export function chainBundle( + context: CoreTransformationContext, + transformSourceFile: (x: SourceFile) => SourceFile, + ): (x: SourceFile | Bundle) => SourceFile | Bundle { return transformSourceFileOrBundle; function transformSourceFileOrBundle(node: SourceFile | Bundle) { @@ -57,15 +60,24 @@ namespace ts { } } // Import star is required if there's default named refs mixed with non-default refs, or if theres non-default refs and it has a default import - return (defaultRefCount > 0 && defaultRefCount !== bindings.elements.length) || (!!(bindings.elements.length - defaultRefCount) && isDefaultImport(node)); + return (defaultRefCount > 0 && defaultRefCount !== bindings.elements.length) + || (!!(bindings.elements.length - defaultRefCount) && isDefaultImport(node)); } export function getImportNeedsImportDefaultHelper(node: ImportDeclaration): boolean { // Import default is needed if there's a default import or a default ref and no other refs (meaning an import star helper wasn't requested) - return !getImportNeedsImportStarHelper(node) && (isDefaultImport(node) || (!!node.importClause && isNamedImports(node.importClause.namedBindings!) && containsDefaultReference(node.importClause.namedBindings))); // TODO: GH#18217 + return !getImportNeedsImportStarHelper(node) + && (isDefaultImport(node) + || (!!node.importClause && isNamedImports(node.importClause.namedBindings!) + && containsDefaultReference(node.importClause.namedBindings))); // TODO: GH#18217 } - export function collectExternalModuleInfo(context: TransformationContext, sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo { + export function collectExternalModuleInfo( + context: TransformationContext, + sourceFile: SourceFile, + resolver: EmitResolver, + compilerOptions: CompilerOptions, + ): ExternalModuleInfo { const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = []; const exportSpecifiers = createMultiMap(); const exportedBindings: Identifier[][] = []; @@ -153,7 +165,11 @@ namespace ts { if (hasSyntacticModifier(node, ModifierFlags.Default)) { // export default function() { } if (!hasExportDefault) { - multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), context.factory.getDeclarationName(node as FunctionDeclaration)); + multiMapSparseArrayAdd( + exportedBindings, + getOriginalNodeId(node), + context.factory.getDeclarationName(node as FunctionDeclaration), + ); hasExportDefault = true; } } @@ -174,7 +190,11 @@ namespace ts { if (hasSyntacticModifier(node, ModifierFlags.Default)) { // export default class { } if (!hasExportDefault) { - multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), context.factory.getDeclarationName(node as ClassDeclaration)); + multiMapSparseArrayAdd( + exportedBindings, + getOriginalNodeId(node), + context.factory.getDeclarationName(node as ClassDeclaration), + ); hasExportDefault = true; } } @@ -192,12 +212,28 @@ namespace ts { } } - const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded(context.factory, context.getEmitHelperFactory(), sourceFile, compilerOptions, hasExportStarsToExportValues, hasImportStar, hasImportDefault); + const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded( + context.factory, + context.getEmitHelperFactory(), + sourceFile, + compilerOptions, + hasExportStarsToExportValues, + hasImportStar, + hasImportDefault, + ); if (externalHelpersImportDeclaration) { externalImports.unshift(externalHelpersImportDeclaration); } - return { externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues, exportedBindings, exportedNames, externalHelpersImportDeclaration }; + return { + externalImports, + exportSpecifiers, + exportEquals, + hasExportStarsToExportValues, + exportedBindings, + exportedNames, + externalHelpersImportDeclaration, + }; function addExportedNamesForExportDeclaration(node: ExportDeclaration) { for (const specifier of cast(node.exportClause, isNamedExports).elements) { @@ -221,7 +257,11 @@ namespace ts { } } - function collectExportedVariableInfo(decl: VariableDeclaration | BindingElement, uniqueExports: ESMap, exportedNames: Identifier[] | undefined) { + function collectExportedVariableInfo( + decl: VariableDeclaration | BindingElement, + uniqueExports: ESMap, + exportedNames: Identifier[] | undefined, + ) { if (isBindingPattern(decl.name)) { for (const element of decl.name.elements) { if (!isOmittedExpression(element)) { @@ -257,10 +297,10 @@ namespace ts { * - this is mostly subjective beyond the requirement that the expression not be sideeffecting */ export function isSimpleCopiableExpression(expression: Expression) { - return isStringLiteralLike(expression) || - expression.kind === SyntaxKind.NumericLiteral || - isKeyword(expression.kind) || - isIdentifier(expression); + return isStringLiteralLike(expression) + || expression.kind === SyntaxKind.NumericLiteral + || isKeyword(expression.kind) + || isIdentifier(expression); } /** @@ -277,7 +317,9 @@ namespace ts { && kind <= SyntaxKind.LastCompoundAssignment; } - export function getNonAssignmentOperatorForCompoundAssignment(kind: CompoundAssignmentOperator): LogicalOperatorOrHigher | SyntaxKind.QuestionQuestionToken { + export function getNonAssignmentOperatorForCompoundAssignment( + kind: CompoundAssignmentOperator, + ): LogicalOperatorOrHigher | SyntaxKind.QuestionQuestionToken { switch (kind) { case SyntaxKind.PlusEqualsToken: return SyntaxKind.PlusToken; @@ -347,19 +389,42 @@ namespace ts { * @param node The class node. * @param isStatic A value indicating whether to get properties from the static or instance side of the class. */ - export function getProperties(node: ClassExpression | ClassDeclaration, requireInitializer: true, isStatic: boolean): readonly InitializedPropertyDeclaration[]; - export function getProperties(node: ClassExpression | ClassDeclaration, requireInitializer: boolean, isStatic: boolean): readonly PropertyDeclaration[]; - export function getProperties(node: ClassExpression | ClassDeclaration, requireInitializer: boolean, isStatic: boolean): readonly PropertyDeclaration[] { - return filter(node.members, m => isInitializedOrStaticProperty(m, requireInitializer, isStatic)) as PropertyDeclaration[]; + export function getProperties( + node: ClassExpression | ClassDeclaration, + requireInitializer: true, + isStatic: boolean, + ): readonly InitializedPropertyDeclaration[]; + export function getProperties( + node: ClassExpression | ClassDeclaration, + requireInitializer: boolean, + isStatic: boolean, + ): readonly PropertyDeclaration[]; + export function getProperties( + node: ClassExpression | ClassDeclaration, + requireInitializer: boolean, + isStatic: boolean, + ): readonly PropertyDeclaration[] { + return filter( + node.members, + m => isInitializedOrStaticProperty(m, requireInitializer, isStatic), + ) as PropertyDeclaration[]; } - function isStaticPropertyDeclarationOrClassStaticBlockDeclaration(element: ClassElement): element is PropertyDeclaration | ClassStaticBlockDeclaration { + function isStaticPropertyDeclarationOrClassStaticBlockDeclaration( + element: ClassElement, + ): element is PropertyDeclaration | ClassStaticBlockDeclaration { return isStaticPropertyDeclaration(element) || isClassStaticBlockDeclaration(element); } - export function getStaticPropertiesAndClassStaticBlock(node: ClassExpression | ClassDeclaration): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[]; - export function getStaticPropertiesAndClassStaticBlock(node: ClassExpression | ClassDeclaration): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[]; - export function getStaticPropertiesAndClassStaticBlock(node: ClassExpression | ClassDeclaration): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[] { + export function getStaticPropertiesAndClassStaticBlock( + node: ClassExpression | ClassDeclaration, + ): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[]; + export function getStaticPropertiesAndClassStaticBlock( + node: ClassExpression | ClassDeclaration, + ): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[]; + export function getStaticPropertiesAndClassStaticBlock( + node: ClassExpression | ClassDeclaration, + ): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[] { return filter(node.members, isStaticPropertyDeclarationOrClassStaticBlockDeclaration); } @@ -385,7 +450,9 @@ namespace ts { * @param member The class element node. * @param isStatic A value indicating whether the member should be a static or instance member. */ - export function isInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { + export function isInitializedProperty( + member: ClassElement, + ): member is PropertyDeclaration & { initializer: Expression; } { return member.kind === SyntaxKind.PropertyDeclaration && (member as PropertyDeclaration).initializer !== undefined; } @@ -395,8 +462,15 @@ namespace ts { * * @param member The class element node. */ - export function isNonStaticMethodOrAccessorWithPrivateName(member: ClassElement): member is PrivateIdentifierMethodDeclaration | PrivateIdentifierAccessorDeclaration | PrivateIdentifierAutoAccessorPropertyDeclaration { - return !isStatic(member) && (isMethodOrAccessor(member) || isAutoAccessorPropertyDeclaration(member)) && isPrivateIdentifier(member.name); + export function isNonStaticMethodOrAccessorWithPrivateName( + member: ClassElement, + ): member is + | PrivateIdentifierMethodDeclaration + | PrivateIdentifierAccessorDeclaration + | PrivateIdentifierAutoAccessorPropertyDeclaration + { + return !isStatic(member) && (isMethodOrAccessor(member) || isAutoAccessorPropertyDeclaration(member)) + && isPrivateIdentifier(member.name); } /** @@ -452,7 +526,10 @@ namespace ts { * @param parent The class node that contains the member. * @param member The class member. */ - export function getAllDecoratorsOfClassElement(member: ClassElement, parent: ClassLikeDeclaration): AllDecorators | undefined { + export function getAllDecoratorsOfClassElement( + member: ClassElement, + parent: ClassLikeDeclaration, + ): AllDecorators | undefined { switch (member.kind) { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -475,15 +552,21 @@ namespace ts { * @param parent The class node that contains the accessor. * @param accessor The class accessor member. */ - function getAllDecoratorsOfAccessors(accessor: AccessorDeclaration, parent: ClassExpression | ClassDeclaration): AllDecorators | undefined { + function getAllDecoratorsOfAccessors( + accessor: AccessorDeclaration, + parent: ClassExpression | ClassDeclaration, + ): AllDecorators | undefined { if (!accessor.body) { return undefined; } - const { firstAccessor, secondAccessor, getAccessor, setAccessor } = getAllAccessorDeclarations(parent.members, accessor); - const firstAccessorWithDecorators = hasDecorators(firstAccessor) ? firstAccessor : - secondAccessor && hasDecorators(secondAccessor) ? secondAccessor : - undefined; + const { firstAccessor, secondAccessor, getAccessor, setAccessor } = getAllAccessorDeclarations( + parent.members, + accessor, + ); + const firstAccessorWithDecorators = hasDecorators(firstAccessor) ? firstAccessor + : secondAccessor && hasDecorators(secondAccessor) ? secondAccessor + : undefined; if (!firstAccessorWithDecorators || accessor !== firstAccessorWithDecorators) { return undefined; diff --git a/src/compiler/tsbuild.ts b/src/compiler/tsbuild.ts index 9fb3a6b8095ef..604a1e0d4f955 100644 --- a/src/compiler/tsbuild.ts +++ b/src/compiler/tsbuild.ts @@ -71,7 +71,10 @@ namespace ts { * We track what the newest input file is. */ export interface UpToDate { - type: UpToDateStatusType.UpToDate | UpToDateStatusType.UpToDateWithUpstreamTypes | UpToDateStatusType.UpToDateWithInputFileText; + type: + | UpToDateStatusType.UpToDate + | UpToDateStatusType.UpToDateWithUpstreamTypes + | UpToDateStatusType.UpToDateWithInputFileText; newestInputFileTime?: Date; newestInputFileName?: string; oldestOutputFileName: string; diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index b5024e0d5b624..f5bd457557f55 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -54,7 +54,11 @@ namespace ts { /*@internal*/ export type ResolvedConfigFilePath = ResolvedConfigFileName & Path; - function getOrCreateValueFromConfigFileMap(configFileMap: ESMap, resolved: ResolvedConfigFilePath, createT: () => T): T { + function getOrCreateValueFromConfigFileMap( + configFileMap: ESMap, + resolved: ResolvedConfigFilePath, + createT: () => T, + ): T { const existingValue = configFileMap.get(resolved); let newValue: T | undefined; if (!existingValue) { @@ -64,7 +68,10 @@ namespace ts { return existingValue || newValue!; } - function getOrCreateValueMapFromConfigFileMap(configFileMap: ESMap>, resolved: ResolvedConfigFilePath): ESMap { + function getOrCreateValueMapFromConfigFileMap( + configFileMap: ESMap>, + resolved: ResolvedConfigFilePath, + ): ESMap { return getOrCreateValueFromConfigFileMap(configFileMap, resolved, () => new Map()); } @@ -111,7 +118,9 @@ namespace ts { reportErrorSummary?: ReportEmitErrorSummary; } - export interface SolutionBuilderWithWatchHost extends SolutionBuilderHostBase, WatchHost { + export interface SolutionBuilderWithWatchHost + extends SolutionBuilderHostBase, WatchHost + { } /*@internal*/ @@ -135,9 +144,19 @@ namespace ts { } export interface SolutionBuilder { - build(project?: string, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, getCustomTransformers?: (project: string) => CustomTransformers): ExitStatus; + build( + project?: string, + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + getCustomTransformers?: (project: string) => CustomTransformers, + ): ExitStatus; clean(project?: string): ExitStatus; - buildReferences(project: string, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, getCustomTransformers?: (project: string) => CustomTransformers): ExitStatus; + buildReferences( + project: string, + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + getCustomTransformers?: (project: string) => CustomTransformers, + ): ExitStatus; cleanReferences(project?: string): ExitStatus; getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject | undefined; @@ -146,7 +165,10 @@ namespace ts { // Testing only /*@internal*/ getUpToDateStatusOfProject(project: string): UpToDateStatus; - /*@internal*/ invalidateProject(configFilePath: ResolvedConfigFilePath, reloadLevel?: ConfigFileProgramReloadLevel): void; + /*@internal*/ invalidateProject( + configFilePath: ResolvedConfigFilePath, + reloadLevel?: ConfigFileProgramReloadLevel, + ): void; /*@internal*/ close(): void; } @@ -155,13 +177,22 @@ namespace ts { */ export function createBuilderStatusReporter(system: System, pretty?: boolean): DiagnosticReporter { return diagnostic => { - let output = pretty ? `[${formatColorAndReset(getLocaleTimeString(system), ForegroundColorEscapeSequences.Grey)}] ` : `${getLocaleTimeString(system)} - `; - output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${system.newLine + system.newLine}`; + let output = pretty + ? `[${formatColorAndReset(getLocaleTimeString(system), ForegroundColorEscapeSequences.Grey)}] ` + : `${getLocaleTimeString(system)} - `; + output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${ + system.newLine + system.newLine + }`; system.write(output); }; } - function createSolutionBuilderHostBase(system: System, createProgram: CreateProgram | undefined, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter) { + function createSolutionBuilderHostBase( + system: System, + createProgram: CreateProgram | undefined, + reportDiagnostic?: DiagnosticReporter, + reportSolutionBuilderStatus?: DiagnosticReporter, + ) { const host = createProgramHost(system, createProgram) as SolutionBuilderHostBase; host.getModifiedTime = system.getModifiedTime ? path => system.getModifiedTime!(path) : returnUndefined; host.setModifiedTime = system.setModifiedTime ? (path, date) => system.setModifiedTime!(path, date) : noop; @@ -172,14 +203,38 @@ namespace ts { return host; } - export function createSolutionBuilderHost(system = sys, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportErrorSummary?: ReportEmitErrorSummary) { - const host = createSolutionBuilderHostBase(system, createProgram, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderHost; + export function createSolutionBuilderHost( + system = sys, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportSolutionBuilderStatus?: DiagnosticReporter, + reportErrorSummary?: ReportEmitErrorSummary, + ) { + const host = createSolutionBuilderHostBase( + system, + createProgram, + reportDiagnostic, + reportSolutionBuilderStatus, + ) as SolutionBuilderHost; host.reportErrorSummary = reportErrorSummary; return host; } - export function createSolutionBuilderWithWatchHost(system = sys, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter) { - const host = createSolutionBuilderHostBase(system, createProgram, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderWithWatchHost; + export function createSolutionBuilderWithWatchHost< + T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram, + >( + system = sys, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportSolutionBuilderStatus?: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, + ) { + const host = createSolutionBuilderHostBase( + system, + createProgram, + reportDiagnostic, + reportSolutionBuilderStatus, + ) as SolutionBuilderWithWatchHost; const watchHost = createWatchHost(system, reportWatchStatus); copyProperties(host, watchHost); return host; @@ -193,11 +248,20 @@ namespace ts { return result; } - export function createSolutionBuilder(host: SolutionBuilderHost, rootNames: readonly string[], defaultOptions: BuildOptions): SolutionBuilder { + export function createSolutionBuilder( + host: SolutionBuilderHost, + rootNames: readonly string[], + defaultOptions: BuildOptions, + ): SolutionBuilder { return createSolutionBuilderWorker(/*watch*/ false, host, rootNames, defaultOptions); } - export function createSolutionBuilderWithWatch(host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder { + export function createSolutionBuilderWithWatch( + host: SolutionBuilderWithWatchHost, + rootNames: readonly string[], + defaultOptions: BuildOptions, + baseWatchOptions?: WatchOptions, + ): SolutionBuilder { return createSolutionBuilderWorker(/*watch*/ true, host, rootNames, defaultOptions, baseWatchOptions); } @@ -227,7 +291,9 @@ namespace ts { latestChangedDtsTime?: Date | false; } - interface SolutionBuilderState extends WatchFactory { + interface SolutionBuilderState + extends WatchFactory + { readonly host: SolutionBuilderHost; readonly hostWithWatch: SolutionBuilderWithWatchHost; readonly currentDirectory: string; @@ -276,14 +342,23 @@ namespace ts { readonly filesWatched: ESMap; readonly outputTimeStamps: ESMap>; - readonly lastCachedPackageJsonLookups: ESMap; + readonly lastCachedPackageJsonLookups: ESMap< + ResolvedConfigFilePath, + readonly (readonly [Path, object | boolean])[] | undefined + >; timerToBuildInvalidatedProject: any; reportFileChangeDetected: boolean; writeLog: (s: string) => void; } - function createSolutionBuilderState(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: readonly string[], options: BuildOptions, baseWatchOptions: WatchOptions | undefined): SolutionBuilderState { + function createSolutionBuilderState( + watch: boolean, + hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, + rootNames: readonly string[], + options: BuildOptions, + baseWatchOptions: WatchOptions | undefined, + ): SolutionBuilderState { const host = hostOrHostWithWatch as SolutionBuilderHost; const hostWithWatch = hostOrHostWithWatch as SolutionBuilderWithWatchHost; const currentDirectory = host.getCurrentDirectory(); @@ -291,26 +366,100 @@ namespace ts { // State of the solution const baseCompilerOptions = getCompilerOptionsOfBuildOptions(options); - const compilerHost = createCompilerHostFromProgramHost(host, () => state.projectCompilerOptions) as CompilerHost & ReadBuildProgramHost; + const compilerHost = createCompilerHostFromProgramHost(host, () => state.projectCompilerOptions) as + & CompilerHost + & ReadBuildProgramHost; setGetSourceFileAsHashVersioned(compilerHost, host); - compilerHost.getParsedCommandLine = fileName => parseConfigFile(state, fileName as ResolvedConfigFileName, toResolvedConfigFilePath(state, fileName as ResolvedConfigFileName)); + compilerHost.getParsedCommandLine = fileName => + parseConfigFile( + state, + fileName as ResolvedConfigFileName, + toResolvedConfigFilePath(state, fileName as ResolvedConfigFileName), + ); compilerHost.resolveModuleNames = maybeBind(host, host.resolveModuleNames); compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives); compilerHost.getModuleResolutionCache = maybeBind(host, host.getModuleResolutionCache); - const moduleResolutionCache = !compilerHost.resolveModuleNames ? createModuleResolutionCache(currentDirectory, getCanonicalFileName) : undefined; - const typeReferenceDirectiveResolutionCache = !compilerHost.resolveTypeReferenceDirectives ? createTypeReferenceDirectiveResolutionCache(currentDirectory, getCanonicalFileName, /*options*/ undefined, moduleResolutionCache?.getPackageJsonInfoCache()) : undefined; + const moduleResolutionCache = !compilerHost.resolveModuleNames + ? createModuleResolutionCache(currentDirectory, getCanonicalFileName) : undefined; + const typeReferenceDirectiveResolutionCache = !compilerHost.resolveTypeReferenceDirectives + ? createTypeReferenceDirectiveResolutionCache( + currentDirectory, + getCanonicalFileName, + /*options*/ undefined, + moduleResolutionCache?.getPackageJsonInfoCache(), + ) : undefined; if (!compilerHost.resolveModuleNames) { - const loader = (moduleName: string, resolverMode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFile, state.projectCompilerOptions, compilerHost, moduleResolutionCache, redirectedReference, resolverMode).resolvedModule!; - compilerHost.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference, _options, containingSourceFile) => loadWithModeAwareCache(Debug.checkEachDefined(moduleNames), Debug.checkDefined(containingSourceFile), containingFile, redirectedReference, loader); + const loader = ( + moduleName: string, + resolverMode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + ) => resolveModuleName( + moduleName, + containingFile, + state.projectCompilerOptions, + compilerHost, + moduleResolutionCache, + redirectedReference, + resolverMode, + ).resolvedModule!; + compilerHost.resolveModuleNames = ( + moduleNames, + containingFile, + _reusedNames, + redirectedReference, + _options, + containingSourceFile, + ) => loadWithModeAwareCache( + Debug.checkEachDefined(moduleNames), + Debug.checkDefined(containingSourceFile), + containingFile, + redirectedReference, + loader, + ); compilerHost.getModuleResolutionCache = () => moduleResolutionCache; } if (!compilerHost.resolveTypeReferenceDirectives) { - const loader = (moduleName: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined, containingFileMode: SourceFile["impliedNodeFormat"] | undefined) => resolveTypeReferenceDirective(moduleName, containingFile, state.projectCompilerOptions, compilerHost, redirectedReference, state.typeReferenceDirectiveResolutionCache, containingFileMode).resolvedTypeReferenceDirective!; - compilerHost.resolveTypeReferenceDirectives = (typeReferenceDirectiveNames, containingFile, redirectedReference, _options, containingFileMode) => loadWithTypeDirectiveCache(Debug.checkEachDefined(typeReferenceDirectiveNames), containingFile, redirectedReference, containingFileMode, loader); + const loader = ( + moduleName: string, + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + containingFileMode: SourceFile["impliedNodeFormat"] | undefined, + ) => resolveTypeReferenceDirective( + moduleName, + containingFile, + state.projectCompilerOptions, + compilerHost, + redirectedReference, + state.typeReferenceDirectiveResolutionCache, + containingFileMode, + ).resolvedTypeReferenceDirective!; + compilerHost.resolveTypeReferenceDirectives = ( + typeReferenceDirectiveNames, + containingFile, + redirectedReference, + _options, + containingFileMode, + ) => loadWithTypeDirectiveCache( + Debug.checkEachDefined(typeReferenceDirectiveNames), + containingFile, + redirectedReference, + containingFileMode, + loader, + ); } - compilerHost.getBuildInfo = (fileName, configFilePath) => getBuildInfo(state, fileName, toResolvedConfigFilePath(state, configFilePath as ResolvedConfigFileName), /*modifiedTime*/ undefined); + compilerHost.getBuildInfo = (fileName, configFilePath) => + getBuildInfo( + state, + fileName, + toResolvedConfigFilePath(state, configFilePath as ResolvedConfigFileName), + /*modifiedTime*/ undefined, + ); - const { watchFile, watchDirectory, writeLog } = createWatchFactory(hostWithWatch, options); + const { watchFile, watchDirectory, writeLog } = createWatchFactory( + hostWithWatch, + options, + ); const state: SolutionBuilderState = { host, @@ -376,7 +525,10 @@ namespace ts { return ts.toPath(fileName, state.currentDirectory, state.getCanonicalFileName); } - function toResolvedConfigFilePath(state: SolutionBuilderState, fileName: ResolvedConfigFileName): ResolvedConfigFilePath { + function toResolvedConfigFilePath( + state: SolutionBuilderState, + fileName: ResolvedConfigFileName, + ): ResolvedConfigFilePath { const { resolvedConfigFilePaths } = state; const path = resolvedConfigFilePaths.get(fileName); if (path !== undefined) return path; @@ -390,12 +542,19 @@ namespace ts { return !!(entry as ParsedCommandLine).options; } - function getCachedParsedConfigFile(state: SolutionBuilderState, configFilePath: ResolvedConfigFilePath): ParsedCommandLine | undefined { + function getCachedParsedConfigFile( + state: SolutionBuilderState, + configFilePath: ResolvedConfigFilePath, + ): ParsedCommandLine | undefined { const value = state.configFileCache.get(configFilePath); return value && isParsedCommandLine(value) ? value : undefined; } - function parseConfigFile(state: SolutionBuilderState, configFileName: ResolvedConfigFileName, configFilePath: ResolvedConfigFilePath): ParsedCommandLine | undefined { + function parseConfigFile( + state: SolutionBuilderState, + configFileName: ResolvedConfigFileName, + configFilePath: ResolvedConfigFilePath, + ): ParsedCommandLine | undefined { const { configFileCache } = state; const value = configFileCache.get(configFilePath); if (value) { @@ -412,12 +571,22 @@ namespace ts { } else { parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = d => diagnostic = d; - parsed = getParsedCommandLineOfConfigFile(configFileName, baseCompilerOptions, parseConfigFileHost, extendedConfigCache, baseWatchOptions); + parsed = getParsedCommandLineOfConfigFile( + configFileName, + baseCompilerOptions, + parseConfigFileHost, + extendedConfigCache, + baseWatchOptions, + ); parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = noop; } configFileCache.set(configFilePath, parsed || diagnostic!); performance.mark("SolutionBuilder::afterConfigFileParsing"); - performance.measure("SolutionBuilder::Config file parsing", "SolutionBuilder::beforeConfigFileParsing", "SolutionBuilder::afterConfigFileParsing"); + performance.measure( + "SolutionBuilder::Config file parsing", + "SolutionBuilder::beforeConfigFileParsing", + "SolutionBuilder::afterConfigFileParsing", + ); return parsed; } @@ -435,9 +604,9 @@ namespace ts { visit(root); } - return circularDiagnostics ? - { buildOrder: buildOrder || emptyArray, circularDiagnostics } : - buildOrder || emptyArray; + return circularDiagnostics + ? { buildOrder: buildOrder || emptyArray, circularDiagnostics } + : buildOrder || emptyArray; function visit(configFileName: ResolvedConfigFileName, inCircularContext?: boolean) { const projPath = toResolvedConfigFilePath(state, configFileName); @@ -538,7 +707,11 @@ namespace ts { return state.buildOrder = buildOrder; } - function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined): AnyBuildOrder | undefined { + function getBuildOrderFor( + state: SolutionBuilderState, + project: string | undefined, + onlyReferences: boolean | undefined, + ): AnyBuildOrder | undefined { const resolvedProject = project && resolveProjectName(state, project); const buildOrderFromState = getBuildOrder(state); if (isCircularBuildOrder(buildOrderFromState)) return buildOrderFromState; @@ -550,7 +723,8 @@ namespace ts { ); if (projectIndex === -1) return undefined; } - const buildOrder = resolvedProject ? createBuildOrder(state, [resolvedProject]) as BuildOrder : buildOrderFromState; + const buildOrder = resolvedProject ? createBuildOrder(state, [resolvedProject]) as BuildOrder + : buildOrderFromState; Debug.assert(!isCircularBuildOrder(buildOrder)); Debug.assert(!onlyReferences || resolvedProject !== undefined); Debug.assert(!onlyReferences || buildOrder[buildOrder.length - 1] === resolvedProject); @@ -597,7 +771,14 @@ namespace ts { function disableCache(state: SolutionBuilderState) { if (!state.cache) return; - const { cache, host, compilerHost, extendedConfigCache, moduleResolutionCache, typeReferenceDirectiveResolutionCache } = state; + const { + cache, + host, + compilerHost, + extendedConfigCache, + moduleResolutionCache, + typeReferenceDirectiveResolutionCache, + } = state; host.readFile = cache.originalReadFile; host.fileExists = cache.originalFileExists; @@ -617,7 +798,11 @@ namespace ts { state.diagnostics.delete(resolved); } - function addProjToQueue({ projectPendingBuild }: SolutionBuilderState, proj: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { + function addProjToQueue( + { projectPendingBuild }: SolutionBuilderState, + proj: ResolvedConfigFilePath, + reloadLevel: ConfigFileProgramReloadLevel, + ) { const value = projectPendingBuild.get(proj); if (value === undefined) { projectPendingBuild.set(proj, reloadLevel); @@ -660,7 +845,11 @@ namespace ts { /** * To dispose this project and ensure that all the necessary actions are taken and state is updated accordingly */ - done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): ExitStatus; + done( + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + customTransformers?: CustomTransformers, + ): ExitStatus; getCompilerOptions(): CompilerOptions; getCurrentDirectory(): string; } @@ -686,7 +875,10 @@ namespace ts { getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; getAllDependencies(sourceFile: SourceFile): readonly string[]; getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; - getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult; + getSemanticDiagnosticsOfNextAffectedFile( + cancellationToken?: CancellationToken, + ignoreSourceFile?: (sourceFile: SourceFile) => boolean, + ): AffectedFileResult; /* * Calling emit directly with targetSourceFile and emitOnlyDtsFiles set to true is not advised since * emit in build system is responsible in updating status of the project @@ -695,26 +887,38 @@ namespace ts { * (if that emit of that source file is required it would be emitted again when making sure invalidated project is completed) * This emit is not considered actual emit (and hence uptodate status is not reflected if */ - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult | undefined; + emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): EmitResult | undefined; // TODO(shkamat):: investigate later if we can emit even when there are declaration diagnostics // emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): AffectedFileResult; } export interface UpdateBundleProject extends InvalidatedProjectBase { readonly kind: InvalidatedProjectKind.UpdateBundle; - emit(writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): EmitResult | BuildInvalidedProject | undefined; + emit( + writeFile?: WriteFileCallback, + customTransformers?: CustomTransformers, + ): EmitResult | BuildInvalidedProject | undefined; } - export type InvalidatedProject = UpdateOutputFileStampsProject | BuildInvalidedProject | UpdateBundleProject; + export type InvalidatedProject = + | UpdateOutputFileStampsProject + | BuildInvalidedProject + | UpdateBundleProject; function doneInvalidatedProject( state: SolutionBuilderState, projectPath: ResolvedConfigFilePath, ) { state.projectPendingBuild.delete(projectPath); - return state.diagnostics.has(projectPath) ? - ExitStatus.DiagnosticsPresent_OutputsSkipped : - ExitStatus.Success; + return state.diagnostics.has(projectPath) + ? ExitStatus.DiagnosticsPresent_OutputsSkipped + : ExitStatus.Success; } function createUpdateOutputFileStampsProject( @@ -772,8 +976,8 @@ namespace ts { let buildResult: BuildResultFlags | undefined; let invalidatedProjectOfBundle: BuildInvalidedProject | undefined; - return kind === InvalidatedProjectKind.Build ? - { + return kind === InvalidatedProjectKind.Build + ? { kind, project, projectPath, @@ -820,13 +1024,22 @@ namespace ts { getSemanticDiagnosticsOfNextAffectedFile: (cancellationToken, ignoreSourceFile) => withProgramOrUndefined( program => - ((program as any as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile) && - (program as any as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile(cancellationToken, ignoreSourceFile), + ((program as any as SemanticDiagnosticsBuilderProgram) + .getSemanticDiagnosticsOfNextAffectedFile) + && (program as any as SemanticDiagnosticsBuilderProgram) + .getSemanticDiagnosticsOfNextAffectedFile(cancellationToken, ignoreSourceFile), ), emit: (targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers) => { if (targetSourceFile || emitOnlyDtsFiles) { return withProgramOrUndefined( - program => program.emit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers || state.host.getCustomTransformers?.(project)), + program => + program.emit( + targetSourceFile, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers || state.host.getCustomTransformers?.(project), + ), ); } executeSteps(BuildStep.SemanticDiagnostics, cancellationToken); @@ -837,22 +1050,29 @@ namespace ts { return emit(writeFile, cancellationToken, customTransformers); }, done, - } : - { + } + : { kind, project, projectPath, buildOrder, getCompilerOptions: () => config.options, getCurrentDirectory: () => state.currentDirectory, - emit: (writeFile: WriteFileCallback | undefined, customTransformers: CustomTransformers | undefined) => { + emit: ( + writeFile: WriteFileCallback | undefined, + customTransformers: CustomTransformers | undefined, + ) => { if (step !== BuildStep.EmitBundle) return invalidatedProjectOfBundle; return emitBundle(writeFile, customTransformers); }, done, }; - function done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) { + function done( + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + customTransformers?: CustomTransformers, + ) { executeSteps(BuildStep.Done, cancellationToken, writeFile, customTransformers); if (kind === InvalidatedProjectKind.Build) performance.mark("SolutionBuilder::Projects built"); else performance.mark("SolutionBuilder::Bundles updated"); @@ -908,7 +1128,12 @@ namespace ts { projectPath, state.moduleResolutionCache && map( state.moduleResolutionCache.getPackageJsonInfoCache().entries(), - ([path, data]) => ([state.host.realpath && data ? toPath(state, state.host.realpath(path)) : path, data] as const), + ( + [path, data], + ) => ([ + state.host.realpath && data ? toPath(state, state.host.realpath(path)) : path, + data, + ] as const), ), ); @@ -917,7 +1142,11 @@ namespace ts { step++; } - function handleDiagnostics(diagnostics: readonly Diagnostic[], errorFlags: BuildResultFlags, errorType: string) { + function handleDiagnostics( + diagnostics: readonly Diagnostic[], + errorFlags: BuildResultFlags, + errorType: string, + ) { if (diagnostics.length) { ({ buildResult, step } = buildErrors( state, @@ -956,7 +1185,11 @@ namespace ts { ); } - function emit(writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): EmitResult { + function emit( + writeFileCallback?: WriteFileCallback, + cancellationToken?: CancellationToken, + customTransformers?: CustomTransformers, + ): EmitResult { Debug.assertIsDefined(program); Debug.assert(step === BuildStep.Emit); // Before emitting lets backup state, so we can revert it back if there are declaration errors to handle emit and declaration errors correctly @@ -969,7 +1202,8 @@ namespace ts { reportDeclarationDiagnostics, /*write*/ undefined, /*reportSummary*/ undefined, - (name, text, writeByteOrderMark, _onError, _sourceFiles, data) => outputFiles.push({ name, text, writeByteOrderMark, buildInfo: data?.buildInfo }), + (name, text, writeByteOrderMark, _onError, _sourceFiles, data) => + outputFiles.push({ name, text, writeByteOrderMark, buildInfo: data?.buildInfo }), cancellationToken, /*emitOnlyDts*/ false, customTransformers || state.host.getCustomTransformers?.(project), @@ -994,7 +1228,8 @@ namespace ts { // Actual Emit const { host, compilerHost } = state; - const resultFlags = program.hasChangedEmitSignature?.() ? BuildResultFlags.None : BuildResultFlags.DeclarationOutputUnchanged; + const resultFlags = program.hasChangedEmitSignature?.() ? BuildResultFlags.None + : BuildResultFlags.DeclarationOutputUnchanged; const emitterDiagnostics = createDiagnosticCollection(); const emittedOutputs = new Map(); const options = program.getCompilerOptions(); @@ -1005,26 +1240,47 @@ namespace ts { const path = toPath(state, name); emittedOutputs.set(toPath(state, name), name); if (buildInfo) setBuildInfo(state, buildInfo, projectPath, options, resultFlags); - writeFile(writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, emitterDiagnostics, name, text, writeByteOrderMark); + writeFile( + writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, + emitterDiagnostics, + name, + text, + writeByteOrderMark, + ); if (!isIncremental && state.watch) { - (outputTimeStampMap ||= getOutputTimeStampMap(state, projectPath)!).set(path, now ||= getCurrentTime(state.host)); + (outputTimeStampMap ||= getOutputTimeStampMap(state, projectPath)!).set( + path, + now ||= getCurrentTime(state.host), + ); } }); finishEmit( emitterDiagnostics, emittedOutputs, - outputFiles.length ? outputFiles[0].name : getFirstProjectOutput(config, !host.useCaseSensitiveFileNames()), + outputFiles.length ? outputFiles[0].name + : getFirstProjectOutput(config, !host.useCaseSensitiveFileNames()), resultFlags, ); return emitResult; } - function emitBuildInfo(writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult { + function emitBuildInfo( + writeFileCallback?: WriteFileCallback, + cancellationToken?: CancellationToken, + ): EmitResult { Debug.assertIsDefined(program); Debug.assert(step === BuildStep.EmitBuildInfo); const emitResult = program.emitBuildInfo((name, text, writeByteOrderMark, onError, sourceFiles, data) => { - if (data?.buildInfo) setBuildInfo(state, data.buildInfo, projectPath, program!.getCompilerOptions(), BuildResultFlags.DeclarationOutputUnchanged); + if (data?.buildInfo) { + setBuildInfo( + state, + data.buildInfo, + projectPath, + program!.getCompilerOptions(), + BuildResultFlags.DeclarationOutputUnchanged, + ); + } if (writeFileCallback) writeFileCallback(name, text, writeByteOrderMark, onError, sourceFiles, data); else state.compilerHost.writeFile(name, text, writeByteOrderMark, onError, sourceFiles, data); }, cancellationToken); @@ -1067,7 +1323,13 @@ namespace ts { } // Update time stamps for rest of the outputs - updateOutputTimestampsWorker(state, config, projectPath, Diagnostics.Updating_unchanged_output_timestamps_of_project_0, emittedOutputs); + updateOutputTimestampsWorker( + state, + config, + projectPath, + Diagnostics.Updating_unchanged_output_timestamps_of_project_0, + emittedOutputs, + ); state.diagnostics.delete(projectPath); state.projectStatus.set(projectPath, { type: UpToDateStatusType.UpToDate, @@ -1079,7 +1341,10 @@ namespace ts { return emitDiagnostics; } - function emitBundle(writeFileCallback?: WriteFileCallback, customTransformers?: CustomTransformers): EmitResult | BuildInvalidedProject | undefined { + function emitBundle( + writeFileCallback?: WriteFileCallback, + customTransformers?: CustomTransformers, + ): EmitResult | BuildInvalidedProject | undefined { Debug.assert(kind === InvalidatedProjectKind.UpdateBundle); if (state.options.dry) { reportStatus(state, Diagnostics.A_non_dry_build_would_update_output_of_project_0, project); @@ -1104,7 +1369,12 @@ namespace ts { ); if (isString(outputFiles)) { - reportStatus(state, Diagnostics.Cannot_update_output_of_project_0_because_there_was_error_reading_file_1, project, relName(state, outputFiles)); + reportStatus( + state, + Diagnostics.Cannot_update_output_of_project_0_because_there_was_error_reading_file_1, + project, + relName(state, outputFiles), + ); step = BuildStep.BuildInvalidatedProjectOfBundle; return invalidatedProjectOfBundle = createBuildOrUpdateInvalidedProject( InvalidatedProjectKind.Build, @@ -1126,12 +1396,21 @@ namespace ts { outputFiles.forEach(({ name, text, writeByteOrderMark, buildInfo }) => { emittedOutputs.set(toPath(state, name), name); if (buildInfo) { - if ((buildInfo.program as ProgramBundleEmitBuildInfo)?.outSignature !== (existingBuildInfo?.program as ProgramBundleEmitBuildInfo)?.outSignature) { + if ( + (buildInfo.program as ProgramBundleEmitBuildInfo)?.outSignature + !== (existingBuildInfo?.program as ProgramBundleEmitBuildInfo)?.outSignature + ) { resultFlags &= ~BuildResultFlags.DeclarationOutputUnchanged; } setBuildInfo(state, buildInfo, projectPath, config.options, resultFlags); } - writeFile(writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, emitterDiagnostics, name, text, writeByteOrderMark); + writeFile( + writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, + emitterDiagnostics, + name, + text, + writeByteOrderMark, + ); }); const emitDiagnostics = finishEmit( @@ -1143,7 +1422,12 @@ namespace ts { return { emitSkipped: false, diagnostics: emitDiagnostics }; } - function executeSteps(till: BuildStep, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) { + function executeSteps( + till: BuildStep, + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + customTransformers?: CustomTransformers, + ) { while (step <= till && step < BuildStep.Done) { const currentStep = step; switch (step) { @@ -1172,12 +1456,24 @@ namespace ts { break; case BuildStep.BuildInvalidatedProjectOfBundle: - Debug.checkDefined(invalidatedProjectOfBundle).done(cancellationToken, writeFile, customTransformers); + Debug.checkDefined(invalidatedProjectOfBundle).done( + cancellationToken, + writeFile, + customTransformers, + ); step = BuildStep.Done; break; case BuildStep.QueueReferencingProjects: - queueReferencingProjects(state, project, projectPath, projectIndex, config, buildOrder, Debug.checkDefined(buildResult)); + queueReferencingProjects( + state, + project, + projectPath, + projectIndex, + config, + buildOrder, + Debug.checkDefined(buildResult), + ); step++; break; @@ -1193,9 +1489,9 @@ namespace ts { function needsBuild({ options }: SolutionBuilderState, status: UpToDateStatus, config: ParsedCommandLine) { if (status.type !== UpToDateStatusType.OutOfDateWithPrepend || options.force) return true; - return config.fileNames.length === 0 || - !!getConfigFileParsingDiagnostics(config).length || - !isIncrementalCompilation(config.options); + return config.fileNames.length === 0 + || !!getConfigFileParsingDiagnostics(config).length + || !isIncrementalCompilation(config.options); } interface InvalidateProjectCreateInfo { @@ -1243,8 +1539,19 @@ namespace ts { } else if (reloadLevel === ConfigFileProgramReloadLevel.Partial) { // Update file names - config.fileNames = getFileNamesFromConfigSpecs(config.options.configFile!.configFileSpecs!, getDirectoryPath(project), config.options, state.parseConfigFileHost); - updateErrorForNoInputFiles(config.fileNames, project, config.options.configFile!.configFileSpecs!, config.errors, canJsonReportNoInputFiles(config.raw)); + config.fileNames = getFileNamesFromConfigSpecs( + config.options.configFile!.configFileSpecs!, + getDirectoryPath(project), + config.options, + state.parseConfigFileHost, + ); + updateErrorForNoInputFiles( + config.fileNames, + project, + config.options.configFile!.configFileSpecs!, + config.errors, + canJsonReportNoInputFiles(config.raw), + ); watchInputFiles(state, project, projectPath, config); watchPackageJsonFiles(state, project, projectPath, config); } @@ -1263,7 +1570,10 @@ namespace ts { continue; } - if (status.type === UpToDateStatusType.UpToDateWithUpstreamTypes || status.type === UpToDateStatusType.UpToDateWithInputFileText) { + if ( + status.type === UpToDateStatusType.UpToDateWithUpstreamTypes + || status.type === UpToDateStatusType.UpToDateWithInputFileText + ) { reportAndStoreErrors(state, projectPath, getConfigFileParsingDiagnostics(config)); return { kind: InvalidatedProjectKind.UpdateOutputFileStamps, @@ -1283,9 +1593,9 @@ namespace ts { if (options.verbose) { reportStatus( state, - status.upstreamProjectBlocked ? - Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_was_not_built : - Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, + status.upstreamProjectBlocked + ? Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_was_not_built + : Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, project, status.upstreamProjectName, ); @@ -1302,9 +1612,9 @@ namespace ts { } return { - kind: needsBuild(state, status, config) ? - InvalidatedProjectKind.Build : - InvalidatedProjectKind.UpdateBundle, + kind: needsBuild(state, status, config) + ? InvalidatedProjectKind.Build + : InvalidatedProjectKind.UpdateBundle, status, project, projectPath, @@ -1322,8 +1632,8 @@ namespace ts { buildOrder: AnyBuildOrder, ) { verboseReportProjectStatus(state, info.project, info.status); - return info.kind !== InvalidatedProjectKind.UpdateOutputFileStamps ? - createBuildOrUpdateInvalidedProject( + return info.kind !== InvalidatedProjectKind.UpdateOutputFileStamps + ? createBuildOrUpdateInvalidedProject( info.kind, state, info.project, @@ -1331,8 +1641,8 @@ namespace ts { info.projectIndex, info.config, buildOrder as BuildOrder, - ) : - createUpdateOutputFileStampsProject( + ) + : createUpdateOutputFileStampsProject( state, info.project, info.projectPath, @@ -1357,7 +1667,11 @@ namespace ts { } } - function getOldProgram({ options, builderPrograms, compilerHost }: SolutionBuilderState, proj: ResolvedConfigFilePath, parsed: ParsedCommandLine) { + function getOldProgram( + { options, builderPrograms, compilerHost }: SolutionBuilderState, + proj: ResolvedConfigFilePath, + parsed: ParsedCommandLine, + ) { if (options.force) return undefined; const value = builderPrograms.get(proj); if (value) return value; @@ -1401,7 +1715,9 @@ namespace ts { return { buildResult, step: BuildStep.QueueReferencingProjects }; } - function isFileWatcherWithModifiedTime(value: FileWatcherWithModifiedTime | Date): value is FileWatcherWithModifiedTime { + function isFileWatcherWithModifiedTime( + value: FileWatcherWithModifiedTime | Date, + ): value is FileWatcherWithModifiedTime { return !!(value as FileWatcherWithModifiedTime).watcher; } @@ -1423,7 +1739,15 @@ namespace ts { return result; } - function watchFile(state: SolutionBuilderState, file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined, watchType: WatchType, project?: ResolvedConfigFileName): FileWatcher { + function watchFile( + state: SolutionBuilderState, + file: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, + watchType: WatchType, + project?: ResolvedConfigFileName, + ): FileWatcher { const path = toPath(state, file); const existing = state.filesWatched.get(path); if (existing && isFileWatcherWithModifiedTime(existing)) { @@ -1482,25 +1806,37 @@ namespace ts { if (existing) { existing.buildInfo = buildInfo; existing.modifiedTime = modifiedTime; - if (!(resultFlags & BuildResultFlags.DeclarationOutputUnchanged)) existing.latestChangedDtsTime = modifiedTime; + if (!(resultFlags & BuildResultFlags.DeclarationOutputUnchanged)) { + existing.latestChangedDtsTime = modifiedTime; + } } else { state.buildInfoCache.set(resolvedConfigPath, { path: toPath(state, buildInfoPath), buildInfo, modifiedTime, - latestChangedDtsTime: resultFlags & BuildResultFlags.DeclarationOutputUnchanged ? undefined : modifiedTime, + latestChangedDtsTime: resultFlags & BuildResultFlags.DeclarationOutputUnchanged ? undefined + : modifiedTime, }); } } - function getBuildInfoCacheEntry(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath) { + function getBuildInfoCacheEntry( + state: SolutionBuilderState, + buildInfoPath: string, + resolvedConfigPath: ResolvedConfigFilePath, + ) { const path = toPath(state, buildInfoPath); const existing = state.buildInfoCache.get(resolvedConfigPath); return existing?.path === path ? existing : undefined; } - function getBuildInfo(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath, modifiedTime: Date | undefined): BuildInfo | undefined { + function getBuildInfo( + state: SolutionBuilderState, + buildInfoPath: string, + resolvedConfigPath: ResolvedConfigFilePath, + modifiedTime: Date | undefined, + ): BuildInfo | undefined { const path = toPath(state, buildInfoPath); const existing = state.buildInfoCache.get(resolvedConfigPath); if (existing !== undefined && existing.path === path) { @@ -1508,11 +1844,20 @@ namespace ts { } const value = state.readFileWithCache(buildInfoPath); const buildInfo = value ? ts.getBuildInfo(buildInfoPath, value) : undefined; - state.buildInfoCache.set(resolvedConfigPath, { path, buildInfo: buildInfo || false, modifiedTime: modifiedTime || missingFileModifiedTime }); + state.buildInfoCache.set(resolvedConfigPath, { + path, + buildInfo: buildInfo || false, + modifiedTime: modifiedTime || missingFileModifiedTime, + }); return buildInfo; } - function checkConfigFileUpToDateStatus(state: SolutionBuilderState, configFile: string, oldestOutputFileTime: Date, oldestOutputFileName: string): Status.OutOfDateWithSelf | undefined { + function checkConfigFileUpToDateStatus( + state: SolutionBuilderState, + configFile: string, + oldestOutputFileTime: Date, + oldestOutputFileName: string, + ): Status.OutOfDateWithSelf | undefined { // Check tsconfig time const tsconfigTime = getModifiedTime(state, configFile); if (oldestOutputFileTime < tsconfigTime) { @@ -1524,7 +1869,11 @@ namespace ts { } } - function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { + function getUpToDateStatusWorker( + state: SolutionBuilderState, + project: ParsedCommandLine, + resolvedPath: ResolvedConfigFilePath, + ): UpToDateStatus { // Container if no files are specified in the project if (!project.fileNames.length && !canJsonReportNoInputFiles(project.raw)) { return { @@ -1545,16 +1894,16 @@ namespace ts { // Its a circular reference ignore the status of this project if ( - refStatus.type === UpToDateStatusType.ComputingUpstream || - refStatus.type === UpToDateStatusType.ContainerOnly + refStatus.type === UpToDateStatusType.ComputingUpstream + || refStatus.type === UpToDateStatusType.ContainerOnly ) { // Container only ignore this project continue; } // An upstream project is blocked if ( - refStatus.type === UpToDateStatusType.Unbuildable || - refStatus.type === UpToDateStatusType.UpstreamBlocked + refStatus.type === UpToDateStatusType.Unbuildable + || refStatus.type === UpToDateStatusType.UpstreamBlocked ) { return { type: UpToDateStatusType.UpstreamBlocked, @@ -1624,10 +1973,13 @@ namespace ts { // But if noEmit is true, affectedFilesPendingEmit will have file list even if there are no semantic errors to preserve list of files to be emitted when running with noEmit false // So with noEmit set to true, check on semantic diagnostics needs to be explicit as oppose to when it is false when only files pending emit is sufficient if ( - (buildInfo.program as ProgramMultiFileEmitBuildInfo).changeFileSet?.length || - (!project.options.noEmit ? - (buildInfo.program as ProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit?.length : - some((buildInfo.program as ProgramMultiFileEmitBuildInfo).semanticDiagnosticsPerFile, isArray)) + (buildInfo.program as ProgramMultiFileEmitBuildInfo).changeFileSet?.length + || (!project.options.noEmit + ? (buildInfo.program as ProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit?.length + : some( + (buildInfo.program as ProgramMultiFileEmitBuildInfo).semanticDiagnosticsPerFile, + isArray, + )) ) { return { type: UpToDateStatusType.OutOfDateBuildInfo, @@ -1662,7 +2014,9 @@ namespace ts { let currentVersion: string | undefined; if (buildInfoProgram) { // Read files and see if they are same, read is anyways cached - if (!buildInfoVersionMap) buildInfoVersionMap = getBuildInfoFileVersionMap(buildInfoProgram, buildInfoPath!, host); + if (!buildInfoVersionMap) { + buildInfoVersionMap = getBuildInfoFileVersionMap(buildInfoProgram, buildInfoPath!, host); + } version = buildInfoVersionMap.get(toPath(state, inputFile)); const text = version ? state.readFileWithCache(inputFile) : undefined; currentVersion = text && (host.createHash || generateDjb2Hash)(text); @@ -1749,8 +2103,15 @@ namespace ts { // If the upstream project has only change .d.ts files, and we've built // *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild - const newestDeclarationFileContentChangedTime = getLatestChangedDtsTime(state, resolvedConfig.options, resolvedRefPath); - if (newestDeclarationFileContentChangedTime && newestDeclarationFileContentChangedTime <= oldestOutputFileTime) { + const newestDeclarationFileContentChangedTime = getLatestChangedDtsTime( + state, + resolvedConfig.options, + resolvedRefPath, + ); + if ( + newestDeclarationFileContentChangedTime + && newestDeclarationFileContentChangedTime <= oldestOutputFileTime + ) { pseudoUpToDate = true; upstreamChangedProject = ref.path; continue; @@ -1767,11 +2128,19 @@ namespace ts { } // Check tsconfig time - const configStatus = checkConfigFileUpToDateStatus(state, project.options.configFilePath!, oldestOutputFileTime, oldestOutputFileName!); + const configStatus = checkConfigFileUpToDateStatus( + state, + project.options.configFilePath!, + oldestOutputFileTime, + oldestOutputFileName!, + ); if (configStatus) return configStatus; // Check extended config time - const extendedConfigStatus = forEach(project.options.configFile!.extendedSourceFiles || emptyArray, configFile => checkConfigFileUpToDateStatus(state, configFile, oldestOutputFileTime, oldestOutputFileName!)); + const extendedConfigStatus = forEach( + project.options.configFile!.extendedSourceFiles || emptyArray, + configFile => checkConfigFileUpToDateStatus(state, configFile, oldestOutputFileTime, oldestOutputFileName!), + ); if (extendedConfigStatus) return extendedConfigStatus; // Check package file time @@ -1791,23 +2160,31 @@ namespace ts { // Up to date return { - type: pseudoUpToDate ? - UpToDateStatusType.UpToDateWithUpstreamTypes : - pseudoInputUpToDate ? - UpToDateStatusType.UpToDateWithInputFileText : - UpToDateStatusType.UpToDate, + type: pseudoUpToDate + ? UpToDateStatusType.UpToDateWithUpstreamTypes + : pseudoInputUpToDate + ? UpToDateStatusType.UpToDateWithInputFileText + : UpToDateStatusType.UpToDate, newestInputFileTime, newestInputFileName, oldestOutputFileName: oldestOutputFileName!, }; } - function hasSameBuildInfo(state: SolutionBuilderState, buildInfoCacheEntry: BuildInfoCacheEntry, resolvedRefPath: ResolvedConfigFilePath) { + function hasSameBuildInfo( + state: SolutionBuilderState, + buildInfoCacheEntry: BuildInfoCacheEntry, + resolvedRefPath: ResolvedConfigFilePath, + ) { const refBuildInfo = state.buildInfoCache.get(resolvedRefPath)!; return refBuildInfo.path === buildInfoCacheEntry.path; } - function getUpToDateStatus(state: SolutionBuilderState, project: ParsedCommandLine | undefined, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { + function getUpToDateStatus( + state: SolutionBuilderState, + project: ParsedCommandLine | undefined, + resolvedPath: ResolvedConfigFilePath, + ): UpToDateStatus { if (project === undefined) { return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" }; } @@ -1820,7 +2197,11 @@ namespace ts { performance.mark("SolutionBuilder::beforeUpToDateCheck"); const actual = getUpToDateStatusWorker(state, project, resolvedPath); performance.mark("SolutionBuilder::afterUpToDateCheck"); - performance.measure("SolutionBuilder::Up-to-date check", "SolutionBuilder::beforeUpToDateCheck", "SolutionBuilder::afterUpToDateCheck"); + performance.measure( + "SolutionBuilder::Up-to-date check", + "SolutionBuilder::beforeUpToDateCheck", + "SolutionBuilder::afterUpToDateCheck", + ); state.projectStatus.set(resolvedPath, actual); return actual; } @@ -1875,20 +2256,38 @@ namespace ts { }); } - function getLatestChangedDtsTime(state: SolutionBuilderState, options: CompilerOptions, resolvedConfigPath: ResolvedConfigFilePath) { + function getLatestChangedDtsTime( + state: SolutionBuilderState, + options: CompilerOptions, + resolvedConfigPath: ResolvedConfigFilePath, + ) { if (!options.composite) return undefined; const entry = Debug.checkDefined(state.buildInfoCache.get(resolvedConfigPath)); if (entry.latestChangedDtsTime !== undefined) return entry.latestChangedDtsTime || undefined; - const latestChangedDtsTime = entry.buildInfo && entry.buildInfo.program && entry.buildInfo.program.latestChangedDtsFile ? - state.host.getModifiedTime(getNormalizedAbsolutePath(entry.buildInfo.program.latestChangedDtsFile, getDirectoryPath(entry.path))) : - undefined; + const latestChangedDtsTime = + entry.buildInfo && entry.buildInfo.program && entry.buildInfo.program.latestChangedDtsFile + ? state.host.getModifiedTime( + getNormalizedAbsolutePath( + entry.buildInfo.program.latestChangedDtsFile, + getDirectoryPath(entry.path), + ), + ) + : undefined; entry.latestChangedDtsTime = latestChangedDtsTime || false; return latestChangedDtsTime; } - function updateOutputTimestamps(state: SolutionBuilderState, proj: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath) { + function updateOutputTimestamps( + state: SolutionBuilderState, + proj: ParsedCommandLine, + resolvedPath: ResolvedConfigFilePath, + ) { if (state.options.dry) { - return reportStatus(state, Diagnostics.A_non_dry_build_would_update_timestamps_for_output_of_project_0, proj.options.configFilePath!); + return reportStatus( + state, + Diagnostics.A_non_dry_build_would_update_timestamps_for_output_of_project_0, + proj.options.configFilePath!, + ); } updateOutputTimestampsWorker(state, proj, resolvedPath, Diagnostics.Updating_output_timestamps_of_project_0); state.projectStatus.set(resolvedPath, { @@ -1949,14 +2348,18 @@ namespace ts { if (!(buildResult & BuildResultFlags.DeclarationOutputUnchanged)) { state.projectStatus.set(nextProjectPath, { type: UpToDateStatusType.OutOfDateWithUpstream, - outOfDateOutputFileName: status.type === UpToDateStatusType.OutOfDateWithPrepend ? status.outOfDateOutputFileName : status.oldestOutputFileName, + outOfDateOutputFileName: status.type === UpToDateStatusType.OutOfDateWithPrepend + ? status.outOfDateOutputFileName : status.oldestOutputFileName, newerProjectName: project, }); } break; case UpToDateStatusType.UpstreamBlocked: - if (toResolvedConfigFilePath(state, resolveProjectName(state, status.upstreamProjectName)) === projectPath) { + if ( + toResolvedConfigFilePath(state, resolveProjectName(state, status.upstreamProjectName)) + === projectPath + ) { clearProjectStatus(state, nextProjectPath); } break; @@ -1968,7 +2371,14 @@ namespace ts { } } - function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, getCustomTransformers?: (project: string) => CustomTransformers, onlyReferences?: boolean): ExitStatus { + function build( + state: SolutionBuilderState, + project?: string, + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + getCustomTransformers?: (project: string) => CustomTransformers, + onlyReferences?: boolean, + ): ExitStatus { performance.mark("SolutionBuilder::beforeBuild"); const result = buildWorker(state, project, cancellationToken, writeFile, getCustomTransformers, onlyReferences); performance.mark("SolutionBuilder::afterBuild"); @@ -1976,7 +2386,14 @@ namespace ts { return result; } - function buildWorker(state: SolutionBuilderState, project: string | undefined, cancellationToken: CancellationToken | undefined, writeFile: WriteFileCallback | undefined, getCustomTransformers: ((project: string) => CustomTransformers) | undefined, onlyReferences: boolean | undefined): ExitStatus { + function buildWorker( + state: SolutionBuilderState, + project: string | undefined, + cancellationToken: CancellationToken | undefined, + writeFile: WriteFileCallback | undefined, + getCustomTransformers: ((project: string) => CustomTransformers) | undefined, + onlyReferences: boolean | undefined, + ): ExitStatus { const buildOrder = getBuildOrderFor(state, project, onlyReferences); if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped; @@ -2013,7 +2430,11 @@ namespace ts { return result; } - function cleanWorker(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined) { + function cleanWorker( + state: SolutionBuilderState, + project: string | undefined, + onlyReferences: boolean | undefined, + ) { const buildOrder = getBuildOrderFor(state, project, onlyReferences); if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped; @@ -2051,13 +2472,21 @@ namespace ts { } if (filesToDelete) { - reportStatus(state, Diagnostics.A_non_dry_build_would_delete_the_following_files_Colon_0, filesToDelete.map(f => `\r\n * ${f}`).join("")); + reportStatus( + state, + Diagnostics.A_non_dry_build_would_delete_the_following_files_Colon_0, + filesToDelete.map(f => `\r\n * ${f}`).join(""), + ); } return ExitStatus.Success; } - function invalidateProject(state: SolutionBuilderState, resolved: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { + function invalidateProject( + state: SolutionBuilderState, + resolved: ResolvedConfigFilePath, + reloadLevel: ConfigFileProgramReloadLevel, + ) { // If host implements getParsedCommandLine, we cant get list of files from parseConfigFileHost if (state.host.getParsedCommandLine && reloadLevel === ConfigFileProgramReloadLevel.Partial) { reloadLevel = ConfigFileProgramReloadLevel.Full; @@ -2072,7 +2501,11 @@ namespace ts { enableCache(state); } - function invalidateProjectAndScheduleBuilds(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { + function invalidateProjectAndScheduleBuilds( + state: SolutionBuilderState, + resolvedPath: ResolvedConfigFilePath, + reloadLevel: ConfigFileProgramReloadLevel, + ) { state.reportFileChangeDetected = true; invalidateProject(state, resolvedPath, reloadLevel); scheduleBuildInvalidatedProject(state, 250, /*changeDetected*/ true); @@ -2086,7 +2519,12 @@ namespace ts { if (state.timerToBuildInvalidatedProject) { hostWithWatch.clearTimeout(state.timerToBuildInvalidatedProject); } - state.timerToBuildInvalidatedProject = hostWithWatch.setTimeout(buildNextInvalidatedProject, time, state, changeDetected); + state.timerToBuildInvalidatedProject = hostWithWatch.setTimeout( + buildNextInvalidatedProject, + time, + state, + changeDetected, + ); } function buildNextInvalidatedProject(state: SolutionBuilderState, changeDetected: boolean) { @@ -2116,7 +2554,10 @@ namespace ts { // Before scheduling check if the next project needs build const info = getNextInvalidatedProjectCreateInfo(state, buildOrder, /*reportQueue*/ false); if (!info) break; // Nothing to build any more - if (info.kind !== InvalidatedProjectKind.UpdateOutputFileStamps && (changeDetected || projectsBuilt === 5)) { + if ( + info.kind !== InvalidatedProjectKind.UpdateOutputFileStamps + && (changeDetected || projectsBuilt === 5) + ) { // Schedule next project for build scheduleBuildInvalidatedProject(state, 100, /*changeDetected*/ false); return; @@ -2130,7 +2571,12 @@ namespace ts { return buildOrder; } - function watchConfigFile(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) { + function watchConfigFile( + state: SolutionBuilderState, + resolved: ResolvedConfigFileName, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine | undefined, + ) { if (!state.watch || state.allWatchedConfigFiles.has(resolvedPath)) return; state.allWatchedConfigFiles.set( resolvedPath, @@ -2146,7 +2592,11 @@ namespace ts { ); } - function watchExtendedConfigFiles(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) { + function watchExtendedConfigFiles( + state: SolutionBuilderState, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine | undefined, + ) { updateSharedExtendedConfigFileWatcher( resolvedPath, parsed?.options, @@ -2155,7 +2605,15 @@ namespace ts { watchFile( state, extendedConfigFileName, - () => state.allWatchedExtendedConfigFiles.get(extendedConfigFilePath)?.projects.forEach(projectConfigFilePath => invalidateProjectAndScheduleBuilds(state, projectConfigFilePath, ConfigFileProgramReloadLevel.Full)), + () => + state.allWatchedExtendedConfigFiles.get(extendedConfigFilePath)?.projects.forEach( + projectConfigFilePath => + invalidateProjectAndScheduleBuilds( + state, + projectConfigFilePath, + ConfigFileProgramReloadLevel.Full, + ), + ), PollingInterval.High, parsed?.watchOptions, WatchType.ExtendedConfigFile, @@ -2164,7 +2622,12 @@ namespace ts { ); } - function watchWildCardDirectories(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { + function watchWildCardDirectories( + state: SolutionBuilderState, + resolved: ResolvedConfigFileName, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine, + ) { if (!state.watch) return; updateWatchingWildcardDirectories( getOrCreateValueMapFromConfigFileMap(state.allWatchedWildcardDirectories, resolvedPath), @@ -2181,7 +2644,8 @@ namespace ts { configFileName: resolved, currentDirectory: state.currentDirectory, options: parsed.options, - program: state.builderPrograms.get(resolvedPath) || getCachedParsedConfigFile(state, resolvedPath)?.fileNames, + program: state.builderPrograms.get(resolvedPath) + || getCachedParsedConfigFile(state, resolvedPath)?.fileNames, useCaseSensitiveFileNames: state.parseConfigFileHost.useCaseSensitiveFileNames, writeLog: s => state.writeLog(s), toPath: fileName => toPath(state, fileName), @@ -2198,7 +2662,12 @@ namespace ts { ); } - function watchInputFiles(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { + function watchInputFiles( + state: SolutionBuilderState, + resolved: ResolvedConfigFileName, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine, + ) { if (!state.watch) return; mutateMap( getOrCreateValueMapFromConfigFileMap(state.allWatchedInputFiles, resolvedPath), @@ -2208,7 +2677,8 @@ namespace ts { watchFile( state, input, - () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), + () => + invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), PollingInterval.Low, parsed?.watchOptions, WatchType.SourceFile, @@ -2219,7 +2689,12 @@ namespace ts { ); } - function watchPackageJsonFiles(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { + function watchPackageJsonFiles( + state: SolutionBuilderState, + resolved: ResolvedConfigFileName, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine, + ) { if (!state.watch || !state.lastCachedPackageJsonLookups) return; mutateMap( getOrCreateValueMapFromConfigFileMap(state.allWatchedPackageJsonFiles, resolvedPath), @@ -2229,7 +2704,8 @@ namespace ts { watchFile( state, path, - () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), + () => + invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), PollingInterval.High, parsed?.watchOptions, WatchType.PackageJson, @@ -2262,29 +2738,61 @@ namespace ts { } } performance.mark("SolutionBuilder::afterWatcherCreation"); - performance.measure("SolutionBuilder::Watcher creation", "SolutionBuilder::beforeWatcherCreation", "SolutionBuilder::afterWatcherCreation"); + performance.measure( + "SolutionBuilder::Watcher creation", + "SolutionBuilder::beforeWatcherCreation", + "SolutionBuilder::afterWatcherCreation", + ); } function stopWatching(state: SolutionBuilderState) { clearMap(state.allWatchedConfigFiles, closeFileWatcher); clearMap(state.allWatchedExtendedConfigFiles, closeFileWatcherOf); - clearMap(state.allWatchedWildcardDirectories, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcherOf)); - clearMap(state.allWatchedInputFiles, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcher)); - clearMap(state.allWatchedPackageJsonFiles, watchedPacageJsonFiles => clearMap(watchedPacageJsonFiles, closeFileWatcher)); + clearMap( + state.allWatchedWildcardDirectories, + watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcherOf), + ); + clearMap( + state.allWatchedInputFiles, + watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcher), + ); + clearMap( + state.allWatchedPackageJsonFiles, + watchedPacageJsonFiles => clearMap(watchedPacageJsonFiles, closeFileWatcher), + ); } /** * A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but * can dynamically add/remove other projects based on changes on the rootNames' references */ - function createSolutionBuilderWorker(watch: false, host: SolutionBuilderHost, rootNames: readonly string[], defaultOptions: BuildOptions): SolutionBuilder; - function createSolutionBuilderWorker(watch: true, host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder; - function createSolutionBuilderWorker(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: readonly string[], options: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder { + function createSolutionBuilderWorker( + watch: false, + host: SolutionBuilderHost, + rootNames: readonly string[], + defaultOptions: BuildOptions, + ): SolutionBuilder; + function createSolutionBuilderWorker( + watch: true, + host: SolutionBuilderWithWatchHost, + rootNames: readonly string[], + defaultOptions: BuildOptions, + baseWatchOptions?: WatchOptions, + ): SolutionBuilder; + function createSolutionBuilderWorker( + watch: boolean, + hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, + rootNames: readonly string[], + options: BuildOptions, + baseWatchOptions?: WatchOptions, + ): SolutionBuilder { const state = createSolutionBuilderState(watch, hostOrHostWithWatch, rootNames, options, baseWatchOptions); return { - build: (project, cancellationToken, writeFile, getCustomTransformers) => build(state, project, cancellationToken, writeFile, getCustomTransformers), + build: (project, cancellationToken, writeFile, getCustomTransformers) => + build(state, project, cancellationToken, writeFile, getCustomTransformers), clean: project => clean(state, project), - buildReferences: (project, cancellationToken, writeFile, getCustomTransformers) => build(state, project, cancellationToken, writeFile, getCustomTransformers, /*onlyReferences*/ true), + buildReferences: (project, cancellationToken, writeFile, getCustomTransformers) => + build(state, project, cancellationToken, writeFile, getCustomTransformers, /*onlyReferences*/ true), cleanReferences: project => clean(state, project, /*onlyReferences*/ true), getNextInvalidatedProject: cancellationToken => { setupInitialBuild(state, cancellationToken); @@ -2296,7 +2804,8 @@ namespace ts { const configFilePath = toResolvedConfigFilePath(state, configFileName); return getUpToDateStatus(state, parseConfigFile(state, configFileName, configFilePath), configFilePath); }, - invalidateProject: (configFilePath, reloadLevel) => invalidateProject(state, configFilePath, reloadLevel || ConfigFileProgramReloadLevel.None), + invalidateProject: (configFilePath, reloadLevel) => + invalidateProject(state, configFilePath, reloadLevel || ConfigFileProgramReloadLevel.None), close: () => stopWatching(state), }; } @@ -2309,15 +2818,27 @@ namespace ts { state.host.reportSolutionBuilderStatus(createCompilerDiagnostic(message, ...args)); } - function reportWatchStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: (string | number | undefined)[]) { - state.hostWithWatch.onWatchStatusChange?.(createCompilerDiagnostic(message, ...args), state.host.getNewLine(), state.baseCompilerOptions); + function reportWatchStatus( + state: SolutionBuilderState, + message: DiagnosticMessage, + ...args: (string | number | undefined)[] + ) { + state.hostWithWatch.onWatchStatusChange?.( + createCompilerDiagnostic(message, ...args), + state.host.getNewLine(), + state.baseCompilerOptions, + ); } function reportErrors({ host }: SolutionBuilderState, errors: readonly Diagnostic[]) { errors.forEach(err => host.reportDiagnostic(err)); } - function reportAndStoreErrors(state: SolutionBuilderState, proj: ResolvedConfigFilePath, errors: readonly Diagnostic[]) { + function reportAndStoreErrors( + state: SolutionBuilderState, + proj: ResolvedConfigFilePath, + errors: readonly Diagnostic[], + ) { reportErrors(state, errors); state.projectErrorsReported.set(proj, true); if (errors.length) { @@ -2340,7 +2861,9 @@ namespace ts { reportBuildQueue(state, buildOrder.buildOrder); reportErrors(state, buildOrder.circularDiagnostics); if (canReportSummary) totalErrors += getErrorCountForSummary(buildOrder.circularDiagnostics); - if (canReportSummary) filesInError = [...filesInError, ...getFilesInErrorForSummary(buildOrder.circularDiagnostics)]; + if (canReportSummary) { + filesInError = [...filesInError, ...getFilesInErrorForSummary(buildOrder.circularDiagnostics)]; + } } else { // Report errors from the other projects @@ -2350,8 +2873,14 @@ namespace ts { reportErrors(state, diagnostics.get(projectPath) || emptyArray); } }); - if (canReportSummary) diagnostics.forEach(singleProjectErrors => totalErrors += getErrorCountForSummary(singleProjectErrors)); - if (canReportSummary) diagnostics.forEach(singleProjectErrors => [...filesInError, ...getFilesInErrorForSummary(singleProjectErrors)]); + if (canReportSummary) { + diagnostics.forEach(singleProjectErrors => totalErrors += getErrorCountForSummary(singleProjectErrors)); + } + if (canReportSummary) { + diagnostics.forEach( + singleProjectErrors => [...filesInError, ...getFilesInErrorForSummary(singleProjectErrors)], + ); + } } if (state.watch) { @@ -2367,7 +2896,11 @@ namespace ts { */ function reportBuildQueue(state: SolutionBuilderState, buildQueue: readonly ResolvedConfigFileName[]) { if (state.options.verbose) { - reportStatus(state, Diagnostics.Projects_in_this_build_Colon_0, buildQueue.map(s => "\r\n * " + relName(state, s)).join("")); + reportStatus( + state, + Diagnostics.Projects_in_this_build_Colon_0, + buildQueue.map(s => "\r\n * " + relName(state, s)).join(""), + ); } } @@ -2406,7 +2939,8 @@ namespace ts { case UpToDateStatusType.OutOfDateBuildInfo: return reportStatus( state, - Diagnostics.Project_0_is_out_of_date_because_buildinfo_file_1_indicates_that_some_of_the_changes_were_not_emitted, + Diagnostics + .Project_0_is_out_of_date_because_buildinfo_file_1_indicates_that_some_of_the_changes_were_not_emitted, relName(state, configFileName), relName(state, status.buildInfoFile), ); @@ -2438,7 +2972,8 @@ namespace ts { case UpToDateStatusType.UpToDateWithInputFileText: return reportStatus( state, - Diagnostics.Project_0_is_up_to_date_but_needs_to_update_timestamps_of_output_files_that_are_older_than_input_files, + Diagnostics + .Project_0_is_up_to_date_but_needs_to_update_timestamps_of_output_files_that_are_older_than_input_files, relName(state, configFileName), ); case UpToDateStatusType.UpstreamOutOfDate: @@ -2451,9 +2986,9 @@ namespace ts { case UpToDateStatusType.UpstreamBlocked: return reportStatus( state, - status.upstreamProjectBlocked ? - Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_was_not_built : - Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, + status.upstreamProjectBlocked + ? Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_was_not_built + : Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, relName(state, configFileName), relName(state, status.upstreamProjectName), ); @@ -2467,7 +3002,8 @@ namespace ts { case UpToDateStatusType.TsVersionOutputOfDate: return reportStatus( state, - Diagnostics.Project_0_is_out_of_date_because_output_for_it_was_generated_with_version_1_that_differs_with_current_version_2, + Diagnostics + .Project_0_is_out_of_date_because_output_for_it_was_generated_with_version_1_that_differs_with_current_version_2, relName(state, configFileName), status.version, version, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8551c8ee319f9..9ad21db389101 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4,7 +4,8 @@ namespace ts { export type Path = string & { __pathBrand: any; }; /* @internal */ - export type MatchingKeys = K extends (TRecord[K] extends TMatch ? K : never) ? K : never; + export type MatchingKeys = K extends + (TRecord[K] extends TMatch ? K : never) ? K : never; export interface TextRange { pos: number; @@ -789,7 +790,8 @@ namespace ts { ReachabilityAndEmitFlags = ReachabilityCheckFlags | HasAsyncFunctions, // Parsing context flags - ContextFlags = DisallowInContext | DisallowConditionalTypesContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement | Ambient, + ContextFlags = DisallowInContext | DisallowConditionalTypesContext | YieldContext | DecoratorContext + | AwaitContext | JavaScriptFile | InWithStatement | Ambient, // Exclude these flags when parsing a Type TypeExcludesFlags = YieldContext | AwaitContext, @@ -830,7 +832,8 @@ namespace ts { TypeScriptModifier = Ambient | Public | Private | Protected | Readonly | Abstract | Const | Override | In | Out, ExportDefault = Export | Default, - All = Export | Ambient | Public | Private | Protected | Static | Readonly | Abstract | Accessor | Async | Default | Const | Deprecated | Override | In | Out | Decorator, + All = Export | Ambient | Public | Private | Protected | Static | Readonly | Abstract | Accessor | Async + | Default | Const | Deprecated | Override | In | Out | Decorator, Modifier = All & ~Decorator, } @@ -1641,7 +1644,9 @@ namespace ts { name: PrivateIdentifier; } /*@internal*/ - export type PrivateIdentifierAccessorDeclaration = PrivateIdentifierGetAccessorDeclaration | PrivateIdentifierSetAccessorDeclaration; + export type PrivateIdentifierAccessorDeclaration = + | PrivateIdentifierGetAccessorDeclaration + | PrivateIdentifierSetAccessorDeclaration; /*@internal*/ export type PrivateClassElementDeclaration = | PrivateIdentifierPropertyDeclaration @@ -1790,7 +1795,9 @@ namespace ts { // Because of this, it may be necessary to determine what sort of MethodDeclaration you have // at later stages of the compiler pipeline. In that case, you can either check the parent kind // of the method, or use helpers like isObjectLiteralMethodDeclaration - export interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer { + export interface MethodDeclaration + extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer + { readonly kind: SyntaxKind.MethodDeclaration; readonly parent: ClassLikeDeclaration | ObjectLiteralExpression; readonly modifiers?: NodeArray | undefined; @@ -1821,7 +1828,9 @@ namespace ts { // See the comment on MethodDeclaration for the intuition behind GetAccessorDeclaration being a // ClassElement and an ObjectLiteralElement. - export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer { + export interface GetAccessorDeclaration + extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer + { readonly kind: SyntaxKind.GetAccessor; readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration; readonly modifiers?: NodeArray; @@ -1834,7 +1843,9 @@ namespace ts { // See the comment on MethodDeclaration for the intuition behind SetAccessorDeclaration being a // ClassElement and an ObjectLiteralElement. - export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer { + export interface SetAccessorDeclaration + extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer + { readonly kind: SyntaxKind.SetAccessor; readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration; readonly modifiers?: NodeArray; @@ -1880,7 +1891,9 @@ namespace ts { readonly kind: TypeNodeSyntaxKind; } - export interface KeywordTypeNode extends KeywordToken, TypeNode { + export interface KeywordTypeNode + extends KeywordToken, TypeNode + { readonly kind: TKind; } @@ -1900,7 +1913,9 @@ namespace ts { } /* @internal */ - export type LiteralImportTypeNode = ImportTypeNode & { readonly argument: LiteralTypeNode & { readonly literal: StringLiteral; }; }; + export type LiteralImportTypeNode = ImportTypeNode & { + readonly argument: LiteralTypeNode & { readonly literal: StringLiteral; }; + }; export interface ThisTypeNode extends TypeNode { readonly kind: SyntaxKind.ThisType; @@ -2590,7 +2605,9 @@ namespace ts { * JSXAttribute or JSXSpreadAttribute. ObjectLiteralExpression, on the other hand, can only have properties of type * ObjectLiteralElement (e.g. PropertyAssignment, ShorthandPropertyAssignment etc.) */ - export interface ObjectLiteralExpressionBase extends PrimaryExpression, Declaration { + export interface ObjectLiteralExpressionBase + extends PrimaryExpression, Declaration + { readonly properties: NodeArray; } @@ -2692,7 +2709,9 @@ namespace ts { /** @internal */ export type BindableObjectDefinePropertyCall = CallExpression & { - readonly arguments: readonly [BindableStaticNameExpression, StringLiteralLike | NumericLiteral, ObjectLiteralExpression] & Readonly; + readonly arguments: + & readonly [BindableStaticNameExpression, StringLiteralLike | NumericLiteral, ObjectLiteralExpression] + & Readonly; }; /** @internal */ @@ -3466,8 +3485,16 @@ namespace ts { | ImportClause & { readonly isTypeOnly: true; readonly name: Identifier; } | ImportEqualsDeclaration & { readonly isTypeOnly: true; } | NamespaceImport & { readonly parent: ImportClause & { readonly isTypeOnly: true; }; } - | ImportSpecifier & ({ readonly isTypeOnly: true; } | { readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true; }; }; }) - | ExportSpecifier & ({ readonly isTypeOnly: true; } | { readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true; }; }; }); + | ImportSpecifier + & ({ readonly isTypeOnly: true; } | { + readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true; }; }; + }) + | ExportSpecifier + & ({ readonly isTypeOnly: true; } | { + readonly parent: NamedExports & { + readonly parent: ExportDeclaration & { readonly isTypeOnly: true; }; + }; + }); /** * This is either an `export =` or an `export default` declaration. @@ -3622,12 +3649,16 @@ namespace ts { */ export interface JSDocAugmentsTag extends JSDocTag { readonly kind: SyntaxKind.JSDocAugmentsTag; - readonly class: ExpressionWithTypeArguments & { readonly expression: Identifier | PropertyAccessEntityNameExpression; }; + readonly class: ExpressionWithTypeArguments & { + readonly expression: Identifier | PropertyAccessEntityNameExpression; + }; } export interface JSDocImplementsTag extends JSDocTag { readonly kind: SyntaxKind.JSDocImplementsTag; - readonly class: ExpressionWithTypeArguments & { readonly expression: Identifier | PropertyAccessEntityNameExpression; }; + readonly class: ExpressionWithTypeArguments & { + readonly expression: Identifier | PropertyAccessEntityNameExpression; + }; } export interface JSDocAuthorTag extends JSDocTag { @@ -4145,7 +4176,13 @@ namespace ts { export interface ParseConfigHost { useCaseSensitiveFileNames: boolean; - readDirectory(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[], depth?: number): readonly string[]; + readDirectory( + rootDir: string, + extensions: readonly string[], + excludes: readonly string[] | undefined, + includes: readonly string[], + depth?: number, + ): readonly string[]; /** * Gets a value indicating whether the specified path exists and is a file. @@ -4276,7 +4313,9 @@ namespace ts { } /*@internal*/ - export type FilePreprocessingDiagnostics = FilePreprocessingReferencedDiagnostic | FilePreprocessingFileExplainingDiagnostic; + export type FilePreprocessingDiagnostics = + | FilePreprocessingReferencedDiagnostic + | FilePreprocessingFileExplainingDiagnostic; export interface Program extends ScriptReferenceHost { getCurrentDirectory(): string; @@ -4311,21 +4350,49 @@ namespace ts { * used for writing the JavaScript and declaration files. Otherwise, the writeFile parameter * will be invoked when writing the JavaScript and declaration files. */ - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult; + emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): EmitResult; /*@internal*/ - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult; // eslint-disable-line @typescript-eslint/unified-signatures + emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + forceDtsEmit?: boolean, + ): EmitResult; // eslint-disable-line @typescript-eslint/unified-signatures getOptionsDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[]; getGlobalDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[]; - getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; + getSyntacticDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; /** The first time this is called, it will return global diagnostics (no location). */ getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; - getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; + getDeclarationDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; getConfigFileParsingDiagnostics(): readonly Diagnostic[]; - /* @internal */ getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; - - /* @internal */ getBindAndCheckDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; - /* @internal */ getProgramDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; + /* @internal */ getSuggestionDiagnostics( + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; + + /* @internal */ getBindAndCheckDiagnostics( + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[]; + /* @internal */ getProgramDiagnostics( + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[]; /** * Gets a type checker that can be used to semantically analyze source files in the program. @@ -4346,7 +4413,9 @@ namespace ts { getRelationCacheSizes(): { assignable: number; identity: number; subtype: number; strictSubtype: number; }; /* @internal */ getFileProcessingDiagnostics(): FilePreprocessingDiagnostics[] | undefined; - /* @internal */ getResolvedTypeReferenceDirectives(): ModeAwareCache; + /* @internal */ getResolvedTypeReferenceDirectives(): ModeAwareCache< + ResolvedTypeReferenceDirective | undefined + >; isSourceFileFromExternalLibrary(file: SourceFile): boolean; isSourceFileDefaultLibrary(file: SourceFile): boolean; @@ -4354,7 +4423,10 @@ namespace ts { // This is set on created program to let us know how the program was created using old program /* @internal */ readonly structureIsReused: StructureIsReused; - /* @internal */ getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined; + /* @internal */ getSourceFileFromReference( + referencingFile: SourceFile | UnparsedSource, + ref: FileReference, + ): SourceFile | undefined; /* @internal */ getLibFileFromReference(ref: FileReference): SourceFile | undefined; /** Given a source file, get the name of the package it was imported from. */ @@ -4368,14 +4440,22 @@ namespace ts { /* @internal */ getFileIncludeReasons(): MultiMap; /* @internal */ useCaseSensitiveFileNames(): boolean; - /* @internal */ getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, mode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined; + /* @internal */ getResolvedModuleWithFailedLookupLocationsFromCache( + moduleName: string, + containingFile: string, + mode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): ResolvedModuleWithFailedLookupLocations | undefined; getProjectReferences(): readonly ProjectReference[] | undefined; getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined; /*@internal*/ getProjectReferenceRedirect(fileName: string): string | undefined; /*@internal*/ getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined; - /*@internal*/ forEachResolvedProjectReference(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined; - /*@internal*/ getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined; + /*@internal*/ forEachResolvedProjectReference( + cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, + ): T | undefined; + /*@internal*/ getResolvedProjectReferenceByPath( + projectReferencePath: Path, + ): ResolvedProjectReference | undefined; /*@internal*/ isSourceOfProjectReferenceRedirect(fileName: string): boolean; /*@internal*/ getProgramBuildInfo?(): ProgramBuildInfo | undefined; /*@internal*/ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult; @@ -4521,7 +4601,10 @@ namespace ts { * Returns `any` if the index is not valid. */ /* @internal */ getParameterType(signature: Signature, parameterIndex: number): Type; - /* @internal */ getParameterIdentifierNameAtPosition(signature: Signature, parameterIndex: number): [parameterName: __String, isRestParameter: boolean] | undefined; + /* @internal */ getParameterIdentifierNameAtPosition( + signature: Signature, + parameterIndex: number, + ): [parameterName: __String, isRestParameter: boolean] | undefined; getNullableType(type: Type, flags: TypeFlags): Type; getNonNullableType(type: Type): Type; /* @internal */ getNonOptionalType(type: Type): Type; @@ -4530,26 +4613,82 @@ namespace ts { // TODO: GH#18217 `xToDeclaration` calls are frequently asserted as defined. /** Note that the resulting nodes cannot be checked. */ - typeToTypeNode(type: Type, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): TypeNode | undefined; - /* @internal */ typeToTypeNode(type: Type, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker?: SymbolTracker): TypeNode | undefined; // eslint-disable-line @typescript-eslint/unified-signatures + typeToTypeNode( + type: Type, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): TypeNode | undefined; + /* @internal */ typeToTypeNode( + type: Type, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + tracker?: SymbolTracker, + ): TypeNode | undefined; // eslint-disable-line @typescript-eslint/unified-signatures /** Note that the resulting nodes cannot be checked. */ - signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): SignatureDeclaration & { typeArguments?: NodeArray; } | undefined; - /* @internal */ signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker?: SymbolTracker): SignatureDeclaration & { typeArguments?: NodeArray; } | undefined; // eslint-disable-line @typescript-eslint/unified-signatures + signatureToSignatureDeclaration( + signature: Signature, + kind: SyntaxKind, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): SignatureDeclaration & { typeArguments?: NodeArray; } | undefined; + /* @internal */ signatureToSignatureDeclaration( + signature: Signature, + kind: SyntaxKind, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + tracker?: SymbolTracker, + ): SignatureDeclaration & { typeArguments?: NodeArray; } | undefined; // eslint-disable-line @typescript-eslint/unified-signatures /** Note that the resulting nodes cannot be checked. */ - indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): IndexSignatureDeclaration | undefined; - /* @internal */ indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker?: SymbolTracker): IndexSignatureDeclaration | undefined; // eslint-disable-line @typescript-eslint/unified-signatures + indexInfoToIndexSignatureDeclaration( + indexInfo: IndexInfo, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): IndexSignatureDeclaration | undefined; + /* @internal */ indexInfoToIndexSignatureDeclaration( + indexInfo: IndexInfo, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + tracker?: SymbolTracker, + ): IndexSignatureDeclaration | undefined; // eslint-disable-line @typescript-eslint/unified-signatures /** Note that the resulting nodes cannot be checked. */ - symbolToEntityName(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): EntityName | undefined; + symbolToEntityName( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): EntityName | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToExpression(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): Expression | undefined; + symbolToExpression( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): Expression | undefined; /** Note that the resulting nodes cannot be checked. */ - /* @internal */ symbolToNode(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): Node | undefined; + /* @internal */ symbolToNode( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): Node | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToTypeParameterDeclarations(symbol: Symbol, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): NodeArray | undefined; + symbolToTypeParameterDeclarations( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): NodeArray | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToParameterDeclaration(symbol: Symbol, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): ParameterDeclaration | undefined; + symbolToParameterDeclaration( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): ParameterDeclaration | undefined; /** Note that the resulting nodes cannot be checked. */ - typeParameterToDeclaration(parameter: TypeParameter, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): TypeParameterDeclaration | undefined; + typeParameterToDeclaration( + parameter: TypeParameter, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): TypeParameterDeclaration | undefined; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolAtLocation(node: Node): Symbol | undefined; @@ -4576,15 +4715,47 @@ namespace ts { getTypeAtLocation(node: Node): Type; getTypeFromTypeNode(node: TypeNode): Type; - signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string; + signatureToString( + signature: Signature, + enclosingDeclaration?: Node, + flags?: TypeFormatFlags, + kind?: SignatureKind, + ): string; typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; - symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): string; + symbolToString( + symbol: Symbol, + enclosingDeclaration?: Node, + meaning?: SymbolFlags, + flags?: SymbolFormatFlags, + ): string; typePredicateToString(predicate: TypePredicate, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; - /* @internal */ writeSignature(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind, writer?: EmitTextWriter): string; - /* @internal */ writeType(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags, writer?: EmitTextWriter): string; - /* @internal */ writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags, writer?: EmitTextWriter): string; - /* @internal */ writeTypePredicate(predicate: TypePredicate, enclosingDeclaration?: Node, flags?: TypeFormatFlags, writer?: EmitTextWriter): string; + /* @internal */ writeSignature( + signature: Signature, + enclosingDeclaration?: Node, + flags?: TypeFormatFlags, + kind?: SignatureKind, + writer?: EmitTextWriter, + ): string; + /* @internal */ writeType( + type: Type, + enclosingDeclaration?: Node, + flags?: TypeFormatFlags, + writer?: EmitTextWriter, + ): string; + /* @internal */ writeSymbol( + symbol: Symbol, + enclosingDeclaration?: Node, + meaning?: SymbolFlags, + flags?: SymbolFormatFlags, + writer?: EmitTextWriter, + ): string; + /* @internal */ writeTypePredicate( + predicate: TypePredicate, + enclosingDeclaration?: Node, + flags?: TypeFormatFlags, + writer?: EmitTextWriter, + ): string; getFullyQualifiedName(symbol: Symbol): string; getAugmentedPropertiesOfType(type: Type): Symbol[]; @@ -4594,9 +4765,16 @@ namespace ts { getContextualType(node: Expression): Type | undefined; /* @internal */ getContextualType(node: Expression, contextFlags?: ContextFlags): Type | undefined; // eslint-disable-line @typescript-eslint/unified-signatures /* @internal */ getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike): Type | undefined; - /* @internal */ getContextualTypeForArgumentAtIndex(call: CallLikeExpression, argIndex: number): Type | undefined; - /* @internal */ getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute): Type | undefined; - /* @internal */ isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike): boolean; + /* @internal */ getContextualTypeForArgumentAtIndex( + call: CallLikeExpression, + argIndex: number, + ): Type | undefined; + /* @internal */ getContextualTypeForJsxAttribute( + attribute: JsxAttribute | JsxSpreadAttribute, + ): Type | undefined; + /* @internal */ isContextSensitive( + node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike, + ): boolean; /* @internal */ getTypeOfPropertyOfContextualType(type: Type, name: __String): Type | undefined; /** @@ -4604,9 +4782,21 @@ namespace ts { * returns undefined if the node is not valid. * @param argumentCount Apparent number of arguments, passed in case of a possibly incomplete call. This should come from an ArgumentListInfo. See `signatureHelp.ts`. */ - getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined; - /* @internal */ getResolvedSignatureForSignatureHelp(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined; - /* @internal */ getResolvedSignatureForStringLiteralCompletions(call: CallLikeExpression, editingArgument: Node, candidatesOutArray: Signature[]): Signature | undefined; + getResolvedSignature( + node: CallLikeExpression, + candidatesOutArray?: Signature[], + argumentCount?: number, + ): Signature | undefined; + /* @internal */ getResolvedSignatureForSignatureHelp( + node: CallLikeExpression, + candidatesOutArray?: Signature[], + argumentCount?: number, + ): Signature | undefined; + /* @internal */ getResolvedSignatureForStringLiteralCompletions( + call: CallLikeExpression, + editingArgument: Node, + candidatesOutArray: Signature[], + ): Signature | undefined; /* @internal */ getExpandedParameters(sig: Signature): readonly (readonly Symbol[])[]; /* @internal */ hasEffectiveRestParameter(sig: Signature): boolean; /* @internal */ containsArgumentsReference(declaration: SignatureDeclaration): boolean; @@ -4618,10 +4808,19 @@ namespace ts { isUnknownSymbol(symbol: Symbol): boolean; /* @internal */ getMergedSymbol(symbol: Symbol): Symbol; - getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; - isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: string): boolean; + getConstantValue( + node: EnumMember | PropertyAccessExpression | ElementAccessExpression, + ): string | number | undefined; + isValidPropertyAccess( + node: PropertyAccessExpression | QualifiedName | ImportTypeNode, + propertyName: string, + ): boolean; /** Exclude accesses to private properties. */ - /* @internal */ isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode | QualifiedName, type: Type, property: Symbol): boolean; + /* @internal */ isValidPropertyAccessForCompletions( + node: PropertyAccessExpression | ImportTypeNode | QualifiedName, + type: Type, + property: Symbol, + ): boolean; /** Follow all aliases to get the original symbol. */ getAliasedSymbol(symbol: Symbol): Symbol; /** Follow a *single* alias to get the immediately aliased symbol. */ @@ -4629,7 +4828,10 @@ namespace ts { getExportsOfModule(moduleSymbol: Symbol): Symbol[]; /** Unlike `getExportsOfModule`, this includes properties of an `export =` value. */ /* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[]; - /* @internal */ forEachExportAndPropertyOfModule(moduleSymbol: Symbol, cb: (symbol: Symbol, key: __String) => void): void; + /* @internal */ forEachExportAndPropertyOfModule( + moduleSymbol: Symbol, + cb: (symbol: Symbol, key: __String) => void, + ): void; getJsxIntrinsicTagNamesAt(location: Node): Symbol[]; isOptionalParameter(node: ParameterDeclaration): boolean; getAmbientModules(): Symbol[]; @@ -4639,13 +4841,33 @@ namespace ts { * Unlike `tryGetMemberInModuleExports`, this includes properties of an `export =` value. * Does *not* return properties of primitive types. */ - /* @internal */ tryGetMemberInModuleExportsAndProperties(memberName: string, moduleSymbol: Symbol): Symbol | undefined; + /* @internal */ tryGetMemberInModuleExportsAndProperties( + memberName: string, + moduleSymbol: Symbol, + ): Symbol | undefined; getApparentType(type: Type): Type; - /* @internal */ getSuggestedSymbolForNonexistentProperty(name: MemberName | string, containingType: Type): Symbol | undefined; - /* @internal */ getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | string, containingType: Type): Symbol | undefined; - /* @internal */ getSuggestionForNonexistentProperty(name: MemberName | string, containingType: Type): string | undefined; - /* @internal */ getSuggestedSymbolForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined; - /* @internal */ getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; + /* @internal */ getSuggestedSymbolForNonexistentProperty( + name: MemberName | string, + containingType: Type, + ): Symbol | undefined; + /* @internal */ getSuggestedSymbolForNonexistentJSXAttribute( + name: Identifier | string, + containingType: Type, + ): Symbol | undefined; + /* @internal */ getSuggestionForNonexistentProperty( + name: MemberName | string, + containingType: Type, + ): string | undefined; + /* @internal */ getSuggestedSymbolForNonexistentSymbol( + location: Node, + name: string, + meaning: SymbolFlags, + ): Symbol | undefined; + /* @internal */ getSuggestionForNonexistentSymbol( + location: Node, + name: string, + meaning: SymbolFlags, + ): string | undefined; /* @internal */ getSuggestedSymbolForNonexistentModule(node: Identifier, target: Symbol): Symbol | undefined; /* @internal */ getSuggestedSymbolForNonexistentClassMember(name: string, baseType: Type): Symbol | undefined; /* @internal */ getSuggestionForNonexistentExport(node: Identifier, target: Symbol): string | undefined; @@ -4673,7 +4895,13 @@ namespace ts { /* @internal */ getAsyncIterableType(): Type | undefined; /* @internal */ isTypeAssignableTo(source: Type, target: Type): boolean; - /* @internal */ createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], indexInfos: IndexInfo[]): Type; + /* @internal */ createAnonymousType( + symbol: Symbol | undefined, + members: SymbolTable, + callSignatures: Signature[], + constructSignatures: Signature[], + indexInfos: IndexInfo[], + ): Type; /* @internal */ createSignature( declaration: SignatureDeclaration | undefined, typeParameters: readonly TypeParameter[] | undefined, @@ -4685,8 +4913,18 @@ namespace ts { flags: SignatureFlags, ): Signature; /* @internal */ createSymbol(flags: SymbolFlags, name: __String): TransientSymbol; - /* @internal */ createIndexInfo(keyType: Type, type: Type, isReadonly: boolean, declaration?: SignatureDeclaration): IndexInfo; - /* @internal */ isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult; + /* @internal */ createIndexInfo( + keyType: Type, + type: Type, + isReadonly: boolean, + declaration?: SignatureDeclaration, + ): IndexInfo; + /* @internal */ isSymbolAccessible( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + shouldComputeAliasToMarkVisible: boolean, + ): SymbolAccessibilityResult; /* @internal */ tryFindAmbientModule(moduleName: string): Symbol | undefined; /* @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol | undefined; @@ -4702,9 +4940,19 @@ namespace ts { /* @internal */ getSymbolCount(): number; /* @internal */ getTypeCount(): number; /* @internal */ getInstantiationCount(): number; - /* @internal */ getRelationCacheSizes(): { assignable: number; identity: number; subtype: number; strictSubtype: number; }; + /* @internal */ getRelationCacheSizes(): { + assignable: number; + identity: number; + subtype: number; + strictSubtype: number; + }; /* @internal */ getRecursionIdentity(type: Type): object | undefined; - /* @internal */ getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator; + /* @internal */ getUnmatchedProperties( + source: Type, + target: Type, + requireOptionalProperties: boolean, + matchDiscriminantProperties: boolean, + ): IterableIterator; /* @internal */ isArrayType(type: Type): boolean; /* @internal */ isTupleType(type: Type): boolean; @@ -4714,7 +4962,10 @@ namespace ts { * True if `contextualType` should not be considered for completions because * e.g. it specifies `kind: "a"` and obj has `kind: "b"`. */ - /* @internal */ isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression | JsxAttributes): boolean; + /* @internal */ isTypeInvalidDueToUnionDiscriminant( + contextualType: Type, + obj: ObjectLiteralExpression | JsxAttributes, + ): boolean; /* @internal */ getExactOptionalProperties(type: Type): Symbol[]; /** * For a union, will include a property if it's defined in *any* of the member types. @@ -4722,7 +4973,12 @@ namespace ts { * Does not include properties of primitive types. */ /* @internal */ getAllPossiblePropertiesOfTypes(type: readonly Type[]): Symbol[]; - /* @internal */ resolveName(name: string, location: Node | undefined, meaning: SymbolFlags, excludeGlobals: boolean): Symbol | undefined; + /* @internal */ resolveName( + name: string, + location: Node | undefined, + meaning: SymbolFlags, + excludeGlobals: boolean, + ): Symbol | undefined; /* @internal */ getJsxNamespace(location?: Node): string; /* @internal */ getJsxFragmentFactory(location: Node): string | undefined; @@ -4735,7 +4991,12 @@ namespace ts { * Where `C` is the symbol we're looking for. * This should be called in a loop climbing parents of the symbol, so we'll get `N`. */ - /* @internal */ getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] | undefined; + /* @internal */ getAccessibleSymbolChain( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + useOnlyExternalAliasing: boolean, + ): Symbol[] | undefined; getTypePredicateOfSignature(signature: Signature): TypePredicate | undefined; /* @internal */ resolveExternalModuleName(moduleSpecifier: Expression): Symbol | undefined; /** @@ -4751,7 +5012,10 @@ namespace ts { * Does *not* get *all* suggestion diagnostics, just the ones that were convenient to report in the checker. * Others are added in computeSuggestionDiagnostics. */ - /* @internal */ getSuggestionDiagnostics(file: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; + /* @internal */ getSuggestionDiagnostics( + file: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; /** * Depending on the operation performed, it may be appropriate to throw away the checker @@ -4760,11 +5024,22 @@ namespace ts { */ runWithCancellationToken(token: CancellationToken, cb: (checker: TypeChecker) => T): T; - /* @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): readonly TypeParameter[] | undefined; + /* @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias( + symbol: Symbol, + ): readonly TypeParameter[] | undefined; /* @internal */ isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean; - /* @internal */ isPropertyAccessible(node: Node, isSuper: boolean, isWrite: boolean, containingType: Type, property: Symbol): boolean; + /* @internal */ isPropertyAccessible( + node: Node, + isSuper: boolean, + isWrite: boolean, + containingType: Type, + property: Symbol, + ): boolean; /* @internal */ getTypeOnlyAliasDeclaration(symbol: Symbol): TypeOnlyAliasDeclaration | undefined; - /* @internal */ getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement): MemberOverrideStatus; + /* @internal */ getMemberOverrideModifierStatus( + node: ClassLikeDeclaration, + member: ClassElement, + ): MemberOverrideStatus; /* @internal */ isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node): boolean; } @@ -4830,7 +5105,8 @@ namespace ts { AllowNodeModulesRelativePaths = 1 << 26, /* @internal */ DoNotIncludeSymbolChain = 1 << 27, // Skip looking up and printing an accessible symbol chain - IgnoreErrors = AllowThisInObjectLiteral | AllowQualifiedNameInPlaceOfIdentifier | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple | AllowEmptyIndexInfoType | AllowNodeModulesRelativePaths, + IgnoreErrors = AllowThisInObjectLiteral | AllowQualifiedNameInPlaceOfIdentifier | AllowAnonymousIdentifier + | AllowEmptyUnionOrIntersection | AllowEmptyTuple | AllowEmptyIndexInfoType | AllowNodeModulesRelativePaths, // State InObjectTypeLiteral = 1 << 22, @@ -4876,10 +5152,13 @@ namespace ts { /** @deprecated */ WriteOwnNameForAnyLike = 0, // Does nothing - NodeBuilderFlagsMask = NoTruncation | WriteArrayAsGenericType | UseStructuralFallback | WriteTypeArgumentsOfSignature | - UseFullyQualifiedType | SuppressAnyReturnType | MultilineObjectLiterals | WriteClassExpressionAsTypeLiteral | - UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias | - UseSingleQuotesForStringLiteralType | NoTypeReduction | OmitThisParameter, + NodeBuilderFlagsMask = NoTruncation | WriteArrayAsGenericType | UseStructuralFallback + | WriteTypeArgumentsOfSignature + | UseFullyQualifiedType | SuppressAnyReturnType | MultilineObjectLiterals + | WriteClassExpressionAsTypeLiteral + | UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType + | InTypeAlias + | UseSingleQuotesForStringLiteralType | NoTypeReduction | OmitThisParameter, } export const enum SymbolFormatFlags { @@ -4987,7 +5266,11 @@ namespace ts { type: Type | undefined; } - export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertsThisTypePredicate | AssertsIdentifierTypePredicate; + export type TypePredicate = + | ThisTypePredicate + | IdentifierTypePredicate + | AssertsThisTypePredicate + | AssertsIdentifierTypePredicate; /* @internal */ export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; @@ -4996,7 +5279,9 @@ namespace ts { export type AnyImportOrRequire = AnyImportSyntax | VariableDeclarationInitializedTo; /* @internal */ - export type AnyImportOrBareOrAccessedRequire = AnyImportSyntax | VariableDeclarationInitializedTo; + export type AnyImportOrBareOrAccessedRequire = + | AnyImportSyntax + | VariableDeclarationInitializedTo; /* @internal */ export type AnyImportOrRequireStatement = AnyImportSyntax | RequireVariableStatement; @@ -5121,7 +5406,10 @@ namespace ts { /* @internal */ export interface EmitResolver { hasGlobalName(name: string): boolean; - getReferencedExportContainer(node: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration | undefined; + getReferencedExportContainer( + node: Identifier, + prefixLocals?: boolean, + ): SourceFile | ModuleDeclaration | EnumDeclaration | undefined; getReferencedImportDeclaration(node: Identifier): Declaration | undefined; getReferencedDeclarationWithCollidingName(node: Identifier): Declaration | undefined; isDeclarationWithCollidingName(node: Declaration): boolean; @@ -5137,29 +5425,78 @@ namespace ts { isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean; isExpandoFunctionDeclaration(node: FunctionDeclaration): boolean; getPropertiesOfContainerFunction(node: Declaration): Symbol[]; - createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined; - createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined; - createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined; - createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker): Expression; - isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags | undefined, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult; - isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult; + createTypeOfDeclaration( + declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + addUndefined?: boolean, + ): TypeNode | undefined; + createReturnTypeOfSignatureDeclaration( + signatureDeclaration: SignatureDeclaration, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + ): TypeNode | undefined; + createTypeOfExpression( + expr: Expression, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + ): TypeNode | undefined; + createLiteralConstValue( + node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, + tracker: SymbolTracker, + ): Expression; + isSymbolAccessible( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags | undefined, + shouldComputeAliasToMarkVisible: boolean, + ): SymbolAccessibilityResult; + isEntityNameVisible( + entityName: EntityNameOrEntityNameExpression, + enclosingDeclaration: Node, + ): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant - getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; + getConstantValue( + node: EnumMember | PropertyAccessExpression | ElementAccessExpression, + ): string | number | undefined; getReferencedValueDeclaration(reference: Identifier): Declaration | undefined; getTypeReferenceSerializationKind(typeName: EntityName, location?: Node): TypeReferenceSerializationKind; isOptionalParameter(node: ParameterDeclaration): boolean; moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean; isArgumentsLocalBinding(node: Identifier): boolean; - getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode | ImportCall): SourceFile | undefined; - getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined; - getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined; - isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean; + getExternalModuleFileFromDeclaration( + declaration: + | ImportEqualsDeclaration + | ImportDeclaration + | ExportDeclaration + | ModuleDeclaration + | ImportTypeNode + | ImportCall, + ): SourceFile | undefined; + getTypeReferenceDirectivesForEntityName( + name: EntityNameOrEntityNameExpression, + ): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined; + getTypeReferenceDirectivesForSymbol( + symbol: Symbol, + meaning?: SymbolFlags, + ): [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined; + isLiteralConstDeclaration( + node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, + ): boolean; getJsxFactoryEntity(location?: Node): EntityName | undefined; getJsxFragmentFactoryEntity(location?: Node): EntityName | undefined; getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations; getSymbolOfExternalModuleSpecifier(node: StringLiteralLike): Symbol | undefined; isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean; - getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, tracker: SymbolTracker, bundled?: boolean): Statement[] | undefined; + getDeclarationStatementsForSourceFile( + node: SourceFile, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + bundled?: boolean, + ): Statement[] | undefined; isImportRequiredByAugmentation(decl: ImportDeclaration): boolean; } @@ -5194,12 +5531,15 @@ namespace ts { Assignment = 1 << 26, // Assignment treated as declaration (eg `this.prop = 1`) ModuleExports = 1 << 27, // Symbol for CommonJS `module` of `module.exports` /* @internal */ - All = FunctionScopedVariable | BlockScopedVariable | Property | EnumMember | Function | Class | Interface | ConstEnum | RegularEnum | ValueModule | NamespaceModule | TypeLiteral - | ObjectLiteral | Method | Constructor | GetAccessor | SetAccessor | Signature | TypeParameter | TypeAlias | ExportValue | Alias | Prototype | ExportStar | Optional | Transient, + All = FunctionScopedVariable | BlockScopedVariable | Property | EnumMember | Function | Class | Interface + | ConstEnum | RegularEnum | ValueModule | NamespaceModule | TypeLiteral + | ObjectLiteral | Method | Constructor | GetAccessor | SetAccessor | Signature | TypeParameter | TypeAlias + | ExportValue | Alias | Prototype | ExportStar | Optional | Transient, Enum = RegularEnum | ConstEnum, Variable = FunctionScopedVariable | BlockScopedVariable, - Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, + Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method + | GetAccessor | SetAccessor, Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias, Namespace = ValueModule | NamespaceModule | Enum, Module = ValueModule | NamespaceModule, @@ -5407,7 +5747,10 @@ namespace ts { * with a normal string (which is good, it cannot be misused on assignment or on usage), * while still being comparable with a normal string via === (also good) and castable from a string. */ - export type __String = (string & { __escapedIdentifier: void; }) | (void & { __escapedIdentifier: void; }) | InternalSymbolName; // eslint-disable-line @typescript-eslint/naming-convention + export type __String = + | (string & { __escapedIdentifier: void; }) + | (void & { __escapedIdentifier: void; }) + | InternalSymbolName; // eslint-disable-line @typescript-eslint/naming-convention /** ReadonlyMap where keys are `__String`s. */ export interface ReadonlyUnderscoreEscapedMap extends ReadonlyESMap<__String, T> { @@ -5530,9 +5873,11 @@ namespace ts { DefinitelyFalsy = StringLiteral | NumberLiteral | BigIntLiteral | BooleanLiteral | Void | Undefined | Null, PossiblyFalsy = DefinitelyFalsy | String | Number | BigInt | Boolean, /* @internal */ - Intrinsic = Any | Unknown | String | Number | BigInt | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive, + Intrinsic = Any | Unknown | String | Number | BigInt | Boolean | BooleanLiteral | ESSymbol | Void | Undefined + | Null | Never | NonPrimitive, /* @internal */ - Primitive = String | Number | BigInt | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal | UniqueESSymbol, + Primitive = String | Number | BigInt | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null + | Literal | UniqueESSymbol, StringLike = String | StringLiteral | TemplateLiteral | StringMapping, NumberLike = Number | NumberLiteral | Enum, BigIntLike = BigInt | BigIntLiteral, @@ -5541,9 +5886,11 @@ namespace ts { ESSymbolLike = ESSymbol | UniqueESSymbol, VoidLike = Void | Undefined, /* @internal */ - DefinitelyNonNullable = StringLike | NumberLike | BigIntLike | BooleanLike | EnumLike | ESSymbolLike | Object | NonPrimitive, + DefinitelyNonNullable = StringLike | NumberLike | BigIntLike | BooleanLike | EnumLike | ESSymbolLike | Object + | NonPrimitive, /* @internal */ - DisjointDomains = NonPrimitive | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbolLike | VoidLike | Null, + DisjointDomains = NonPrimitive | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbolLike | VoidLike + | Null, UnionOrIntersection = Union | Intersection, StructuredType = Object | Union | Intersection, TypeVariable = TypeParameter | IndexedAccess, @@ -5556,13 +5903,16 @@ namespace ts { /* @internal */ Simplifiable = IndexedAccess | Conditional, /* @internal */ - Singleton = Any | Unknown | String | Number | Boolean | BigInt | ESSymbol | Void | Undefined | Null | Never | NonPrimitive, + Singleton = Any | Unknown | String | Number | Boolean | BigInt | ESSymbol | Void | Undefined | Null | Never + | NonPrimitive, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, + Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike + | ESSymbol | UniqueESSymbol | NonPrimitive, // The following flags are aggregated during union and intersection type construction /* @internal */ - IncludesMask = Any | Unknown | Primitive | Never | Object | Union | Intersection | NonPrimitive | TemplateLiteral, + IncludesMask = Any | Unknown | Primitive | Never | Object | Union | Intersection | NonPrimitive + | TemplateLiteral, // The following flags are used for different purposes during union and intersection type construction /* @internal */ IncludesMissingType = TypeParameter, @@ -6449,7 +6799,17 @@ namespace ts { FixedChunkSize, } - export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | ProjectReference[] | null | undefined; + export type CompilerOptionsValue = + | string + | number + | boolean + | (string | number)[] + | string[] + | MapLike + | PluginImport[] + | ProjectReference[] + | null + | undefined; export interface CompilerOptions { /*@internal*/ all?: boolean; @@ -6816,12 +7176,23 @@ namespace ts { /* @internal */ export interface CommandLineOptionOfListType extends CommandLineOptionBase { type: "list"; - element: CommandLineOptionOfCustomType | CommandLineOptionOfStringType | CommandLineOptionOfNumberType | CommandLineOptionOfBooleanType | TsConfigOnlyOption; + element: + | CommandLineOptionOfCustomType + | CommandLineOptionOfStringType + | CommandLineOptionOfNumberType + | CommandLineOptionOfBooleanType + | TsConfigOnlyOption; listPreserveFalsyValues?: boolean; } /* @internal */ - export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfStringType | CommandLineOptionOfNumberType | CommandLineOptionOfBooleanType | TsConfigOnlyOption | CommandLineOptionOfListType; + export type CommandLineOption = + | CommandLineOptionOfCustomType + | CommandLineOptionOfStringType + | CommandLineOptionOfNumberType + | CommandLineOptionOfBooleanType + | TsConfigOnlyOption + | CommandLineOptionOfListType; /* @internal */ export const enum CharacterCodes { @@ -7095,8 +7466,19 @@ namespace ts { export type HasChangedAutomaticTypeDirectiveNames = () => boolean; export interface CompilerHost extends ModuleResolutionHost { - getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; - getSourceFileByPath?(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; + getSourceFile( + fileName: string, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean, + ): SourceFile | undefined; + getSourceFileByPath?( + fileName: string, + path: Path, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean, + ): SourceFile | undefined; getCancellationToken?(): CancellationToken; getDefaultLibFileName(options: CompilerOptions): string; getDefaultLibLocation?(): string; @@ -7105,7 +7487,13 @@ namespace ts { getCanonicalFileName(fileName: string): string; useCaseSensitiveFileNames(): boolean; getNewLine(): string; - readDirectory?(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[], depth?: number): string[]; + readDirectory?( + rootDir: string, + extensions: readonly string[], + excludes: readonly string[] | undefined, + includes: readonly string[], + depth?: number, + ): string[]; /* * CompilerHost must either implement resolveModuleNames (in case if it wants to be completely in charge of @@ -7114,7 +7502,14 @@ namespace ts { * If resolveModuleNames is implemented then implementation for members from ModuleResolutionHost can be just * 'throw new Error("NotImplemented")' */ - resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[]; + resolveModuleNames?( + moduleNames: string[], + containingFile: string, + reusedNames: string[] | undefined, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingSourceFile?: SourceFile, + ): (ResolvedModule | undefined)[]; /** * Returns the module resolution cache used by a provided `resolveModuleNames` implementation so that any non-name module resolution operations (eg, package.json lookup) can reuse it */ @@ -7122,10 +7517,24 @@ namespace ts { /** * This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?( + typeReferenceDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, + ): (ResolvedTypeReferenceDirective | undefined)[]; getEnvironmentVariable?(name: string): string | undefined; - /* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void; - /* @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; + /* @internal */ onReleaseOldSourceFile?( + oldSourceFile: SourceFile, + oldOptions: CompilerOptions, + hasSourceFileByPath: boolean, + ): void; + /* @internal */ onReleaseParsedCommandLine?( + configFileName: string, + oldResolvedRef: ResolvedProjectReference | undefined, + optionOptions: CompilerOptions, + ): void; /** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */ hasInvalidatedResolutions?(filePath: Path): boolean; /* @internal */ hasChangedAutomaticTypeDirectiveNames?: HasChangedAutomaticTypeDirectiveNames; @@ -7149,7 +7558,9 @@ namespace ts { /*@internal*/ export interface ResolvedProjectReferenceCallbacks { getSourceOfProjectReferenceRedirect(fileName: string): SourceOfProjectReferenceRedirect | undefined; - forEachResolvedProjectReference(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined; + forEachResolvedProjectReference( + cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, + ): T | undefined; } /* @internal */ @@ -7216,15 +7627,25 @@ namespace ts { OuterExpressionExcludes = HasComputedFlags, PropertyAccessExcludes = OuterExpressionExcludes, NodeExcludes = PropertyAccessExcludes, - ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, - FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, - ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, - MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, + ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsBlockScopedBinding + | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern + | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, + FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper + | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion + | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, + ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding + | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern + | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, + MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper + | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion + | ContainsBindingPattern | ContainsObjectRestOrSpread, PropertyExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper, ClassExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName, - ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion | ContainsPossibleTopLevelAwait, + ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper + | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion | ContainsPossibleTopLevelAwait, TypeExcludes = ~ContainsTypeScript, - ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName | ContainsObjectRestOrSpread, + ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName + | ContainsObjectRestOrSpread, ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsRestOrSpread, VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern | ContainsObjectRestOrSpread, ParameterExcludes = NodeExcludes, @@ -7351,7 +7772,11 @@ namespace ts { export type EmitHelper = ScopedEmitHelper | UnscopedEmitHelper; /* @internal */ - export type UniqueNameHandler = (baseName: string, checkFn?: (name: string) => boolean, optimistic?: boolean) => string; + export type UniqueNameHandler = ( + baseName: string, + checkFn?: (name: string) => boolean, + optimistic?: boolean, + ) => string; export type EmitHelperUniqueNameCallback = (name: string) => string; @@ -7488,7 +7913,11 @@ namespace ts { getParenthesizeLeftSideOfBinaryForOperator(binaryOperator: SyntaxKind): (leftSide: Expression) => Expression; getParenthesizeRightSideOfBinaryForOperator(binaryOperator: SyntaxKind): (rightSide: Expression) => Expression; parenthesizeLeftSideOfBinary(binaryOperator: SyntaxKind, leftSide: Expression): Expression; - parenthesizeRightSideOfBinary(binaryOperator: SyntaxKind, leftSide: Expression | undefined, rightSide: Expression): Expression; + parenthesizeRightSideOfBinary( + binaryOperator: SyntaxKind, + leftSide: Expression | undefined, + rightSide: Expression, + ): Expression; parenthesizeExpressionOfComputedPropertyName(expression: Expression): Expression; parenthesizeConditionOfConditionalExpression(condition: Expression): Expression; parenthesizeBranchOfConditionalExpression(branch: Expression): Expression; @@ -7553,8 +7982,15 @@ namespace ts { createNumericLiteral(value: string | number, numericLiteralFlags?: TokenFlags): NumericLiteral; createBigIntLiteral(value: string | PseudoBigInt): BigIntLiteral; createStringLiteral(text: string, isSingleQuote?: boolean): StringLiteral; - /* @internal*/ createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean): StringLiteral; // eslint-disable-line @typescript-eslint/unified-signatures - createStringLiteralFromNode(sourceNode: PropertyNameLiteral | PrivateIdentifier, isSingleQuote?: boolean): StringLiteral; + /* @internal*/ createStringLiteral( + text: string, + isSingleQuote?: boolean, + hasExtendedUnicodeEscape?: boolean, + ): StringLiteral; // eslint-disable-line @typescript-eslint/unified-signatures + createStringLiteralFromNode( + sourceNode: PropertyNameLiteral | PrivateIdentifier, + isSingleQuote?: boolean, + ): StringLiteral; createRegularExpressionLiteral(text: string): RegularExpressionLiteral; // @@ -7562,8 +7998,16 @@ namespace ts { // createIdentifier(text: string): Identifier; - /* @internal */ createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures - /* @internal */ updateIdentifier(node: Identifier, typeArguments: NodeArray | undefined): Identifier; + /* @internal */ createIdentifier( + text: string, + typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], + originalKeywordKind?: SyntaxKind, + hasExtendedUnicodeEscape?: boolean, + ): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures + /* @internal */ updateIdentifier( + node: Identifier, + typeArguments: NodeArray | undefined, + ): Identifier; /** * Create a unique temporary variable. @@ -7574,8 +8018,16 @@ namespace ts { * during emit so that the variable can be referenced in a nested function body. This is an alternative to * setting `EmitFlags.ReuseTempVariableScope` on the nested function itself. */ - createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean): Identifier; - /*@internal*/ createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean, prefix?: string | GeneratedNamePart, suffix?: string): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures + createTempVariable( + recordTempVariable: ((node: Identifier) => void) | undefined, + reservedInNestedScopes?: boolean, + ): Identifier; + /*@internal*/ createTempVariable( + recordTempVariable: ((node: Identifier) => void) | undefined, + reservedInNestedScopes?: boolean, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures /** * Create a unique temporary variable for use in a loop. @@ -7587,17 +8039,35 @@ namespace ts { /** Create a unique name based on the supplied text. */ createUniqueName(text: string, flags?: GeneratedIdentifierFlags): Identifier; - /*@internal*/ createUniqueName(text: string, flags?: GeneratedIdentifierFlags, prefix?: string | GeneratedNamePart, suffix?: string): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures + /*@internal*/ createUniqueName( + text: string, + flags?: GeneratedIdentifierFlags, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures /** Create a unique name generated for a node. */ getGeneratedNameForNode(node: Node | undefined, flags?: GeneratedIdentifierFlags): Identifier; - /*@internal*/ getGeneratedNameForNode(node: Node | undefined, flags?: GeneratedIdentifierFlags, prefix?: string | GeneratedNamePart, suffix?: string): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures + /*@internal*/ getGeneratedNameForNode( + node: Node | undefined, + flags?: GeneratedIdentifierFlags, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures createPrivateIdentifier(text: string): PrivateIdentifier; createUniquePrivateName(text?: string): PrivateIdentifier; - /*@internal*/ createUniquePrivateName(text?: string, prefix?: string | GeneratedNamePart, suffix?: string): PrivateIdentifier; // eslint-disable-line @typescript-eslint/unified-signatures + /*@internal*/ createUniquePrivateName( + text?: string, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): PrivateIdentifier; // eslint-disable-line @typescript-eslint/unified-signatures getGeneratedPrivateNameForNode(node: Node): PrivateIdentifier; - /*@internal*/ getGeneratedPrivateNameForNode(node: Node, prefix?: string | GeneratedNamePart, suffix?: string): PrivateIdentifier; // eslint-disable-line @typescript-eslint/unified-signatures + /*@internal*/ getGeneratedPrivateNameForNode( + node: Node, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): PrivateIdentifier; // eslint-disable-line @typescript-eslint/unified-signatures // // Punctuation @@ -7645,10 +8115,36 @@ namespace ts { // Signature elements // - createTypeParameterDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration; - updateTypeParameterDeclaration(node: TypeParameterDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration; - createParameterDeclaration(modifiers: readonly ModifierLike[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration; - updateParameterDeclaration(node: ParameterDeclaration, modifiers: readonly ModifierLike[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration; + createTypeParameterDeclaration( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + constraint?: TypeNode, + defaultType?: TypeNode, + ): TypeParameterDeclaration; + updateTypeParameterDeclaration( + node: TypeParameterDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + constraint: TypeNode | undefined, + defaultType: TypeNode | undefined, + ): TypeParameterDeclaration; + createParameterDeclaration( + modifiers: readonly ModifierLike[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken?: QuestionToken, + type?: TypeNode, + initializer?: Expression, + ): ParameterDeclaration; + updateParameterDeclaration( + node: ParameterDeclaration, + modifiers: readonly ModifierLike[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): ParameterDeclaration; createDecorator(expression: Expression): Decorator; updateDecorator(node: Decorator, expression: Expression): Decorator; @@ -7656,29 +8152,155 @@ namespace ts { // Type Elements // - createPropertySignature(modifiers: readonly Modifier[] | undefined, name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined): PropertySignature; - updatePropertySignature(node: PropertySignature, modifiers: readonly Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined): PropertySignature; - createPropertyDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration; - updatePropertyDeclaration(node: PropertyDeclaration, modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration; - createMethodSignature(modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): MethodSignature; - updateMethodSignature(node: MethodSignature, modifiers: readonly Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined): MethodSignature; - createMethodDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration; - updateMethodDeclaration(node: MethodDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration; - createConstructorDeclaration(modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration; - updateConstructorDeclaration(node: ConstructorDeclaration, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration; - createGetAccessorDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration; - updateGetAccessorDeclaration(node: GetAccessorDeclaration, modifiers: readonly ModifierLike[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration; - createSetAccessorDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration; - updateSetAccessorDeclaration(node: SetAccessorDeclaration, modifiers: readonly ModifierLike[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration; - createCallSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): CallSignatureDeclaration; - updateCallSignature(node: CallSignatureDeclaration, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined): CallSignatureDeclaration; - createConstructSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): ConstructSignatureDeclaration; - updateConstructSignature(node: ConstructSignatureDeclaration, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined): ConstructSignatureDeclaration; - createIndexSignature(modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration; - /* @internal */ createIndexSignature(modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): IndexSignatureDeclaration; // eslint-disable-line @typescript-eslint/unified-signatures - updateIndexSignature(node: IndexSignatureDeclaration, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration; + createPropertySignature( + modifiers: readonly Modifier[] | undefined, + name: PropertyName | string, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + ): PropertySignature; + updatePropertySignature( + node: PropertySignature, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + ): PropertySignature; + createPropertyDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration; + updatePropertyDeclaration( + node: PropertyDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration; + createMethodSignature( + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): MethodSignature; + updateMethodSignature( + node: MethodSignature, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode | undefined, + ): MethodSignature; + createMethodDeclaration( + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration; + updateMethodDeclaration( + node: MethodDeclaration, + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration; + createConstructorDeclaration( + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration; + updateConstructorDeclaration( + node: ConstructorDeclaration, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration; + createGetAccessorDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration; + updateGetAccessorDeclaration( + node: GetAccessorDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration; + createSetAccessorDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration; + updateSetAccessorDeclaration( + node: SetAccessorDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration; + createCallSignature( + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): CallSignatureDeclaration; + updateCallSignature( + node: CallSignatureDeclaration, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode | undefined, + ): CallSignatureDeclaration; + createConstructSignature( + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): ConstructSignatureDeclaration; + updateConstructSignature( + node: ConstructSignatureDeclaration, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode | undefined, + ): ConstructSignatureDeclaration; + createIndexSignature( + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): IndexSignatureDeclaration; + /* @internal */ createIndexSignature( + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): IndexSignatureDeclaration; // eslint-disable-line @typescript-eslint/unified-signatures + updateIndexSignature( + node: IndexSignatureDeclaration, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): IndexSignatureDeclaration; createTemplateLiteralTypeSpan(type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan; - updateTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan; + updateTemplateLiteralTypeSpan( + node: TemplateLiteralTypeSpan, + type: TypeNode, + literal: TemplateMiddle | TemplateTail, + ): TemplateLiteralTypeSpan; createClassStaticBlockDeclaration(body: Block): ClassStaticBlockDeclaration; updateClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, body: Block): ClassStaticBlockDeclaration; @@ -7687,24 +8309,72 @@ namespace ts { // createKeywordTypeNode(kind: TKind): KeywordTypeNode; - createTypePredicateNode(assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; - updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; + createTypePredicateNode( + assertsModifier: AssertsKeyword | undefined, + parameterName: Identifier | ThisTypeNode | string, + type: TypeNode | undefined, + ): TypePredicateNode; + updateTypePredicateNode( + node: TypePredicateNode, + assertsModifier: AssertsKeyword | undefined, + parameterName: Identifier | ThisTypeNode, + type: TypeNode | undefined, + ): TypePredicateNode; createTypeReferenceNode(typeName: string | EntityName, typeArguments?: readonly TypeNode[]): TypeReferenceNode; - updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined): TypeReferenceNode; - createFunctionTypeNode(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): FunctionTypeNode; - updateFunctionTypeNode(node: FunctionTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode): FunctionTypeNode; - createConstructorTypeNode(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): ConstructorTypeNode; - updateConstructorTypeNode(node: ConstructorTypeNode, modifiers: readonly Modifier[] | undefined, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode): ConstructorTypeNode; + updateTypeReferenceNode( + node: TypeReferenceNode, + typeName: EntityName, + typeArguments: NodeArray | undefined, + ): TypeReferenceNode; + createFunctionTypeNode( + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): FunctionTypeNode; + updateFunctionTypeNode( + node: FunctionTypeNode, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode, + ): FunctionTypeNode; + createConstructorTypeNode( + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): ConstructorTypeNode; + updateConstructorTypeNode( + node: ConstructorTypeNode, + modifiers: readonly Modifier[] | undefined, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode, + ): ConstructorTypeNode; createTypeQueryNode(exprName: EntityName, typeArguments?: readonly TypeNode[]): TypeQueryNode; - updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName, typeArguments?: readonly TypeNode[]): TypeQueryNode; + updateTypeQueryNode( + node: TypeQueryNode, + exprName: EntityName, + typeArguments?: readonly TypeNode[], + ): TypeQueryNode; createTypeLiteralNode(members: readonly TypeElement[] | undefined): TypeLiteralNode; updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray): TypeLiteralNode; createArrayTypeNode(elementType: TypeNode): ArrayTypeNode; updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode; createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode; updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode; - createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; - updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; + createNamedTupleMember( + dotDotDotToken: DotDotDotToken | undefined, + name: Identifier, + questionToken: QuestionToken | undefined, + type: TypeNode, + ): NamedTupleMember; + updateNamedTupleMember( + node: NamedTupleMember, + dotDotDotToken: DotDotDotToken | undefined, + name: Identifier, + questionToken: QuestionToken | undefined, + type: TypeNode, + ): NamedTupleMember; createOptionalTypeNode(type: TypeNode): OptionalTypeNode; updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode; createRestTypeNode(type: TypeNode): RestTypeNode; @@ -7713,69 +8383,244 @@ namespace ts { updateUnionTypeNode(node: UnionTypeNode, types: NodeArray): UnionTypeNode; createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode; updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray): IntersectionTypeNode; - createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; - updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; + createConditionalTypeNode( + checkType: TypeNode, + extendsType: TypeNode, + trueType: TypeNode, + falseType: TypeNode, + ): ConditionalTypeNode; + updateConditionalTypeNode( + node: ConditionalTypeNode, + checkType: TypeNode, + extendsType: TypeNode, + trueType: TypeNode, + falseType: TypeNode, + ): ConditionalTypeNode; createInferTypeNode(typeParameter: TypeParameterDeclaration): InferTypeNode; updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration): InferTypeNode; - createImportTypeNode(argument: TypeNode, assertions?: ImportTypeAssertionContainer, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean): ImportTypeNode; - updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, assertions: ImportTypeAssertionContainer | undefined, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf?: boolean): ImportTypeNode; + createImportTypeNode( + argument: TypeNode, + assertions?: ImportTypeAssertionContainer, + qualifier?: EntityName, + typeArguments?: readonly TypeNode[], + isTypeOf?: boolean, + ): ImportTypeNode; + updateImportTypeNode( + node: ImportTypeNode, + argument: TypeNode, + assertions: ImportTypeAssertionContainer | undefined, + qualifier: EntityName | undefined, + typeArguments: readonly TypeNode[] | undefined, + isTypeOf?: boolean, + ): ImportTypeNode; createParenthesizedType(type: TypeNode): ParenthesizedTypeNode; updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode; createThisTypeNode(): ThisTypeNode; - createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode; + createTypeOperatorNode( + operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, + type: TypeNode, + ): TypeOperatorNode; updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; - updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; - createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: NodeArray | undefined): MappedTypeNode; - updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: NodeArray | undefined): MappedTypeNode; + updateIndexedAccessTypeNode( + node: IndexedAccessTypeNode, + objectType: TypeNode, + indexType: TypeNode, + ): IndexedAccessTypeNode; + createMappedTypeNode( + readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, + typeParameter: TypeParameterDeclaration, + nameType: TypeNode | undefined, + questionToken: QuestionToken | PlusToken | MinusToken | undefined, + type: TypeNode | undefined, + members: NodeArray | undefined, + ): MappedTypeNode; + updateMappedTypeNode( + node: MappedTypeNode, + readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, + typeParameter: TypeParameterDeclaration, + nameType: TypeNode | undefined, + questionToken: QuestionToken | PlusToken | MinusToken | undefined, + type: TypeNode | undefined, + members: NodeArray | undefined, + ): MappedTypeNode; createLiteralTypeNode(literal: LiteralTypeNode["literal"]): LiteralTypeNode; updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]): LiteralTypeNode; - createTemplateLiteralType(head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]): TemplateLiteralTypeNode; - updateTemplateLiteralType(node: TemplateLiteralTypeNode, head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]): TemplateLiteralTypeNode; + createTemplateLiteralType( + head: TemplateHead, + templateSpans: readonly TemplateLiteralTypeSpan[], + ): TemplateLiteralTypeNode; + updateTemplateLiteralType( + node: TemplateLiteralTypeNode, + head: TemplateHead, + templateSpans: readonly TemplateLiteralTypeSpan[], + ): TemplateLiteralTypeNode; // // Binding Patterns // createObjectBindingPattern(elements: readonly BindingElement[]): ObjectBindingPattern; - updateObjectBindingPattern(node: ObjectBindingPattern, elements: readonly BindingElement[]): ObjectBindingPattern; + updateObjectBindingPattern( + node: ObjectBindingPattern, + elements: readonly BindingElement[], + ): ObjectBindingPattern; createArrayBindingPattern(elements: readonly ArrayBindingElement[]): ArrayBindingPattern; - updateArrayBindingPattern(node: ArrayBindingPattern, elements: readonly ArrayBindingElement[]): ArrayBindingPattern; - createBindingElement(dotDotDotToken: DotDotDotToken | undefined, propertyName: string | PropertyName | undefined, name: string | BindingName, initializer?: Expression): BindingElement; - updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken | undefined, propertyName: PropertyName | undefined, name: BindingName, initializer: Expression | undefined): BindingElement; + updateArrayBindingPattern( + node: ArrayBindingPattern, + elements: readonly ArrayBindingElement[], + ): ArrayBindingPattern; + createBindingElement( + dotDotDotToken: DotDotDotToken | undefined, + propertyName: string | PropertyName | undefined, + name: string | BindingName, + initializer?: Expression, + ): BindingElement; + updateBindingElement( + node: BindingElement, + dotDotDotToken: DotDotDotToken | undefined, + propertyName: PropertyName | undefined, + name: BindingName, + initializer: Expression | undefined, + ): BindingElement; // // Expression // createArrayLiteralExpression(elements?: readonly Expression[], multiLine?: boolean): ArrayLiteralExpression; - updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]): ArrayLiteralExpression; - createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean): ObjectLiteralExpression; - updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression; + updateArrayLiteralExpression( + node: ArrayLiteralExpression, + elements: readonly Expression[], + ): ArrayLiteralExpression; + createObjectLiteralExpression( + properties?: readonly ObjectLiteralElementLike[], + multiLine?: boolean, + ): ObjectLiteralExpression; + updateObjectLiteralExpression( + node: ObjectLiteralExpression, + properties: readonly ObjectLiteralElementLike[], + ): ObjectLiteralExpression; createPropertyAccessExpression(expression: Expression, name: string | MemberName): PropertyAccessExpression; - updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: MemberName): PropertyAccessExpression; - createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName): PropertyAccessChain; - updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName): PropertyAccessChain; + updatePropertyAccessExpression( + node: PropertyAccessExpression, + expression: Expression, + name: MemberName, + ): PropertyAccessExpression; + createPropertyAccessChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + name: string | MemberName, + ): PropertyAccessChain; + updatePropertyAccessChain( + node: PropertyAccessChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + name: MemberName, + ): PropertyAccessChain; createElementAccessExpression(expression: Expression, index: number | Expression): ElementAccessExpression; - updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression; - createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain; - updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression): ElementAccessChain; - createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallExpression; - updateCallExpression(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallExpression; - createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallChain; - updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallChain; - createNewExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression; - updateNewExpression(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression; - createTaggedTemplateExpression(tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression; - updateTaggedTemplateExpression(node: TaggedTemplateExpression, tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression; + updateElementAccessExpression( + node: ElementAccessExpression, + expression: Expression, + argumentExpression: Expression, + ): ElementAccessExpression; + createElementAccessChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + index: number | Expression, + ): ElementAccessChain; + updateElementAccessChain( + node: ElementAccessChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + argumentExpression: Expression, + ): ElementAccessChain; + createCallExpression( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ): CallExpression; + updateCallExpression( + node: CallExpression, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[], + ): CallExpression; + createCallChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ): CallChain; + updateCallChain( + node: CallChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[], + ): CallChain; + createNewExpression( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ): NewExpression; + updateNewExpression( + node: NewExpression, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ): NewExpression; + createTaggedTemplateExpression( + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ): TaggedTemplateExpression; + updateTaggedTemplateExpression( + node: TaggedTemplateExpression, + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ): TaggedTemplateExpression; createTypeAssertion(type: TypeNode, expression: Expression): TypeAssertion; updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression): TypeAssertion; createParenthesizedExpression(expression: Expression): ParenthesizedExpression; updateParenthesizedExpression(node: ParenthesizedExpression, expression: Expression): ParenthesizedExpression; - createFunctionExpression(modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined, body: Block): FunctionExpression; - updateFunctionExpression(node: FunctionExpression, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block): FunctionExpression; - createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction; - updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction; + createFunctionExpression( + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[] | undefined, + type: TypeNode | undefined, + body: Block, + ): FunctionExpression; + updateFunctionExpression( + node: FunctionExpression, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block, + ): FunctionExpression; + createArrowFunction( + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + equalsGreaterThanToken: EqualsGreaterThanToken | undefined, + body: ConciseBody, + ): ArrowFunction; + updateArrowFunction( + node: ArrowFunction, + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + equalsGreaterThanToken: EqualsGreaterThanToken, + body: ConciseBody, + ): ArrowFunction; createDeleteExpression(expression: Expression): DeleteExpression; updateDeleteExpression(node: DeleteExpression, expression: Expression): DeleteExpression; createTypeOfExpression(expression: Expression): TypeOfExpression; @@ -7788,12 +8633,38 @@ namespace ts { updatePrefixUnaryExpression(node: PrefixUnaryExpression, operand: Expression): PrefixUnaryExpression; createPostfixUnaryExpression(operand: Expression, operator: PostfixUnaryOperator): PostfixUnaryExpression; updatePostfixUnaryExpression(node: PostfixUnaryExpression, operand: Expression): PostfixUnaryExpression; - createBinaryExpression(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression): BinaryExpression; - updateBinaryExpression(node: BinaryExpression, left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression): BinaryExpression; - createConditionalExpression(condition: Expression, questionToken: QuestionToken | undefined, whenTrue: Expression, colonToken: ColonToken | undefined, whenFalse: Expression): ConditionalExpression; - updateConditionalExpression(node: ConditionalExpression, condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; + createBinaryExpression( + left: Expression, + operator: BinaryOperator | BinaryOperatorToken, + right: Expression, + ): BinaryExpression; + updateBinaryExpression( + node: BinaryExpression, + left: Expression, + operator: BinaryOperator | BinaryOperatorToken, + right: Expression, + ): BinaryExpression; + createConditionalExpression( + condition: Expression, + questionToken: QuestionToken | undefined, + whenTrue: Expression, + colonToken: ColonToken | undefined, + whenFalse: Expression, + ): ConditionalExpression; + updateConditionalExpression( + node: ConditionalExpression, + condition: Expression, + questionToken: QuestionToken, + whenTrue: Expression, + colonToken: ColonToken, + whenFalse: Expression, + ): ConditionalExpression; createTemplateExpression(head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression; - updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression; + updateTemplateExpression( + node: TemplateExpression, + head: TemplateHead, + templateSpans: readonly TemplateSpan[], + ): TemplateExpression; createTemplateHead(text: string, rawText?: string, templateFlags?: TokenFlags): TemplateHead; createTemplateHead(text: string | undefined, rawText: string, templateFlags?: TokenFlags): TemplateHead; createTemplateMiddle(text: string, rawText?: string, templateFlags?: TokenFlags): TemplateMiddle; @@ -7802,19 +8673,54 @@ namespace ts { createTemplateTail(text: string | undefined, rawText: string, templateFlags?: TokenFlags): TemplateTail; createNoSubstitutionTemplateLiteral(text: string, rawText?: string): NoSubstitutionTemplateLiteral; createNoSubstitutionTemplateLiteral(text: string | undefined, rawText: string): NoSubstitutionTemplateLiteral; - /* @internal */ createLiteralLikeNode(kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, text: string): LiteralToken; - /* @internal */ createTemplateLiteralLikeNode(kind: TemplateLiteralToken["kind"], text: string, rawText: string, templateFlags: TokenFlags | undefined): TemplateLiteralLikeNode; + /* @internal */ createLiteralLikeNode( + kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, + text: string, + ): LiteralToken; + /* @internal */ createTemplateLiteralLikeNode( + kind: TemplateLiteralToken["kind"], + text: string, + rawText: string, + templateFlags: TokenFlags | undefined, + ): TemplateLiteralLikeNode; createYieldExpression(asteriskToken: AsteriskToken, expression: Expression): YieldExpression; createYieldExpression(asteriskToken: undefined, expression: Expression | undefined): YieldExpression; - /* @internal */ createYieldExpression(asteriskToken: AsteriskToken | undefined, expression: Expression | undefined): YieldExpression; // eslint-disable-line @typescript-eslint/unified-signatures - updateYieldExpression(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression | undefined): YieldExpression; + /* @internal */ createYieldExpression( + asteriskToken: AsteriskToken | undefined, + expression: Expression | undefined, + ): YieldExpression; // eslint-disable-line @typescript-eslint/unified-signatures + updateYieldExpression( + node: YieldExpression, + asteriskToken: AsteriskToken | undefined, + expression: Expression | undefined, + ): YieldExpression; createSpreadElement(expression: Expression): SpreadElement; updateSpreadElement(node: SpreadElement, expression: Expression): SpreadElement; - createClassExpression(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression; - updateClassExpression(node: ClassExpression, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression; + createClassExpression( + modifiers: readonly ModifierLike[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression; + updateClassExpression( + node: ClassExpression, + modifiers: readonly ModifierLike[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression; createOmittedExpression(): OmittedExpression; - createExpressionWithTypeArguments(expression: Expression, typeArguments: readonly TypeNode[] | undefined): ExpressionWithTypeArguments; - updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, expression: Expression, typeArguments: readonly TypeNode[] | undefined): ExpressionWithTypeArguments; + createExpressionWithTypeArguments( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + ): ExpressionWithTypeArguments; + updateExpressionWithTypeArguments( + node: ExpressionWithTypeArguments, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + ): ExpressionWithTypeArguments; createAsExpression(expression: Expression, type: TypeNode): AsExpression; updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode): AsExpression; createNonNullExpression(expression: Expression): NonNullExpression; @@ -7824,14 +8730,22 @@ namespace ts { createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier): MetaProperty; updateMetaProperty(node: MetaProperty, name: Identifier): MetaProperty; createSatisfiesExpression(expression: Expression, type: TypeNode): SatisfiesExpression; - updateSatisfiesExpression(node: SatisfiesExpression, expression: Expression, type: TypeNode): SatisfiesExpression; + updateSatisfiesExpression( + node: SatisfiesExpression, + expression: Expression, + type: TypeNode, + ): SatisfiesExpression; // // Misc // createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan; - updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan; + updateTemplateSpan( + node: TemplateSpan, + expression: Expression, + literal: TemplateMiddle | TemplateTail, + ): TemplateSpan; createSemicolonClassElement(): SemicolonClassElement; // @@ -7840,23 +8754,62 @@ namespace ts { createBlock(statements: readonly Statement[], multiLine?: boolean): Block; updateBlock(node: Block, statements: readonly Statement[]): Block; - createVariableStatement(modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList | readonly VariableDeclaration[]): VariableStatement; - updateVariableStatement(node: VariableStatement, modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList): VariableStatement; + createVariableStatement( + modifiers: readonly Modifier[] | undefined, + declarationList: VariableDeclarationList | readonly VariableDeclaration[], + ): VariableStatement; + updateVariableStatement( + node: VariableStatement, + modifiers: readonly Modifier[] | undefined, + declarationList: VariableDeclarationList, + ): VariableStatement; createEmptyStatement(): EmptyStatement; createExpressionStatement(expression: Expression): ExpressionStatement; updateExpressionStatement(node: ExpressionStatement, expression: Expression): ExpressionStatement; createIfStatement(expression: Expression, thenStatement: Statement, elseStatement?: Statement): IfStatement; - updateIfStatement(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement | undefined): IfStatement; + updateIfStatement( + node: IfStatement, + expression: Expression, + thenStatement: Statement, + elseStatement: Statement | undefined, + ): IfStatement; createDoStatement(statement: Statement, expression: Expression): DoStatement; updateDoStatement(node: DoStatement, statement: Statement, expression: Expression): DoStatement; createWhileStatement(expression: Expression, statement: Statement): WhileStatement; updateWhileStatement(node: WhileStatement, expression: Expression, statement: Statement): WhileStatement; - createForStatement(initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement): ForStatement; - updateForStatement(node: ForStatement, initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement): ForStatement; + createForStatement( + initializer: ForInitializer | undefined, + condition: Expression | undefined, + incrementor: Expression | undefined, + statement: Statement, + ): ForStatement; + updateForStatement( + node: ForStatement, + initializer: ForInitializer | undefined, + condition: Expression | undefined, + incrementor: Expression | undefined, + statement: Statement, + ): ForStatement; createForInStatement(initializer: ForInitializer, expression: Expression, statement: Statement): ForInStatement; - updateForInStatement(node: ForInStatement, initializer: ForInitializer, expression: Expression, statement: Statement): ForInStatement; - createForOfStatement(awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement): ForOfStatement; - updateForOfStatement(node: ForOfStatement, awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement): ForOfStatement; + updateForInStatement( + node: ForInStatement, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ): ForInStatement; + createForOfStatement( + awaitModifier: AwaitKeyword | undefined, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ): ForOfStatement; + updateForOfStatement( + node: ForOfStatement, + awaitModifier: AwaitKeyword | undefined, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ): ForOfStatement; createContinueStatement(label?: string | Identifier): ContinueStatement; updateContinueStatement(node: ContinueStatement, label: Identifier | undefined): ContinueStatement; createBreakStatement(label?: string | Identifier): BreakStatement; @@ -7871,59 +8824,235 @@ namespace ts { updateLabeledStatement(node: LabeledStatement, label: Identifier, statement: Statement): LabeledStatement; createThrowStatement(expression: Expression): ThrowStatement; updateThrowStatement(node: ThrowStatement, expression: Expression): ThrowStatement; - createTryStatement(tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined): TryStatement; - updateTryStatement(node: TryStatement, tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined): TryStatement; + createTryStatement( + tryBlock: Block, + catchClause: CatchClause | undefined, + finallyBlock: Block | undefined, + ): TryStatement; + updateTryStatement( + node: TryStatement, + tryBlock: Block, + catchClause: CatchClause | undefined, + finallyBlock: Block | undefined, + ): TryStatement; createDebuggerStatement(): DebuggerStatement; - createVariableDeclaration(name: string | BindingName, exclamationToken?: ExclamationToken, type?: TypeNode, initializer?: Expression): VariableDeclaration; - updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): VariableDeclaration; - createVariableDeclarationList(declarations: readonly VariableDeclaration[], flags?: NodeFlags): VariableDeclarationList; - updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]): VariableDeclarationList; - createFunctionDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; - updateFunctionDeclaration(node: FunctionDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; - createClassDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; - updateClassDeclaration(node: ClassDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; - createInterfaceDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; - updateInterfaceDeclaration(node: InterfaceDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; - createTypeAliasDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; - updateTypeAliasDeclaration(node: TypeAliasDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; - createEnumDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration; - updateEnumDeclaration(node: EnumDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration; - createModuleDeclaration(modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration; - updateModuleDeclaration(node: ModuleDeclaration, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration; + createVariableDeclaration( + name: string | BindingName, + exclamationToken?: ExclamationToken, + type?: TypeNode, + initializer?: Expression, + ): VariableDeclaration; + updateVariableDeclaration( + node: VariableDeclaration, + name: BindingName, + exclamationToken: ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): VariableDeclaration; + createVariableDeclarationList( + declarations: readonly VariableDeclaration[], + flags?: NodeFlags, + ): VariableDeclarationList; + updateVariableDeclarationList( + node: VariableDeclarationList, + declarations: readonly VariableDeclaration[], + ): VariableDeclarationList; + createFunctionDeclaration( + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration; + updateFunctionDeclaration( + node: FunctionDeclaration, + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration; + createClassDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration; + updateClassDeclaration( + node: ClassDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration; + createInterfaceDeclaration( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration; + updateInterfaceDeclaration( + node: InterfaceDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration; + createTypeAliasDeclaration( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration; + updateTypeAliasDeclaration( + node: TypeAliasDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration; + createEnumDeclaration( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + members: readonly EnumMember[], + ): EnumDeclaration; + updateEnumDeclaration( + node: EnumDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + members: readonly EnumMember[], + ): EnumDeclaration; + createModuleDeclaration( + modifiers: readonly Modifier[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + flags?: NodeFlags, + ): ModuleDeclaration; + updateModuleDeclaration( + node: ModuleDeclaration, + modifiers: readonly Modifier[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + ): ModuleDeclaration; createModuleBlock(statements: readonly Statement[]): ModuleBlock; updateModuleBlock(node: ModuleBlock, statements: readonly Statement[]): ModuleBlock; createCaseBlock(clauses: readonly CaseOrDefaultClause[]): CaseBlock; updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]): CaseBlock; createNamespaceExportDeclaration(name: string | Identifier): NamespaceExportDeclaration; - updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration; - createImportEqualsDeclaration(modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; - updateImportEqualsDeclaration(node: ImportEqualsDeclaration, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; - createImportDeclaration(modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause?: AssertClause): ImportDeclaration; - updateImportDeclaration(node: ImportDeclaration, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause: AssertClause | undefined): ImportDeclaration; - createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause; - updateImportClause(node: ImportClause, isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause; + updateNamespaceExportDeclaration( + node: NamespaceExportDeclaration, + name: Identifier, + ): NamespaceExportDeclaration; + createImportEqualsDeclaration( + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + name: string | Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration; + updateImportEqualsDeclaration( + node: ImportEqualsDeclaration, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + name: Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration; + createImportDeclaration( + modifiers: readonly Modifier[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause?: AssertClause, + ): ImportDeclaration; + updateImportDeclaration( + node: ImportDeclaration, + modifiers: readonly Modifier[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause: AssertClause | undefined, + ): ImportDeclaration; + createImportClause( + isTypeOnly: boolean, + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + ): ImportClause; + updateImportClause( + node: ImportClause, + isTypeOnly: boolean, + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + ): ImportClause; createAssertClause(elements: NodeArray, multiLine?: boolean): AssertClause; updateAssertClause(node: AssertClause, elements: NodeArray, multiLine?: boolean): AssertClause; createAssertEntry(name: AssertionKey, value: Expression): AssertEntry; updateAssertEntry(node: AssertEntry, name: AssertionKey, value: Expression): AssertEntry; createImportTypeAssertionContainer(clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer; - updateImportTypeAssertionContainer(node: ImportTypeAssertionContainer, clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer; + updateImportTypeAssertionContainer( + node: ImportTypeAssertionContainer, + clause: AssertClause, + multiLine?: boolean, + ): ImportTypeAssertionContainer; createNamespaceImport(name: Identifier): NamespaceImport; updateNamespaceImport(node: NamespaceImport, name: Identifier): NamespaceImport; createNamespaceExport(name: Identifier): NamespaceExport; updateNamespaceExport(node: NamespaceExport, name: Identifier): NamespaceExport; createNamedImports(elements: readonly ImportSpecifier[]): NamedImports; updateNamedImports(node: NamedImports, elements: readonly ImportSpecifier[]): NamedImports; - createImportSpecifier(isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier; - updateImportSpecifier(node: ImportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier; - createExportAssignment(modifiers: readonly Modifier[] | undefined, isExportEquals: boolean | undefined, expression: Expression): ExportAssignment; - updateExportAssignment(node: ExportAssignment, modifiers: readonly Modifier[] | undefined, expression: Expression): ExportAssignment; - createExportDeclaration(modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, assertClause?: AssertClause): ExportDeclaration; - updateExportDeclaration(node: ExportDeclaration, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, assertClause: AssertClause | undefined): ExportDeclaration; + createImportSpecifier( + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier, + ): ImportSpecifier; + updateImportSpecifier( + node: ImportSpecifier, + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier, + ): ImportSpecifier; + createExportAssignment( + modifiers: readonly Modifier[] | undefined, + isExportEquals: boolean | undefined, + expression: Expression, + ): ExportAssignment; + updateExportAssignment( + node: ExportAssignment, + modifiers: readonly Modifier[] | undefined, + expression: Expression, + ): ExportAssignment; + createExportDeclaration( + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier?: Expression, + assertClause?: AssertClause, + ): ExportDeclaration; + updateExportDeclaration( + node: ExportDeclaration, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier: Expression | undefined, + assertClause: AssertClause | undefined, + ): ExportDeclaration; createNamedExports(elements: readonly ExportSpecifier[]): NamedExports; updateNamedExports(node: NamedExports, elements: readonly ExportSpecifier[]): NamedExports; - createExportSpecifier(isTypeOnly: boolean, propertyName: string | Identifier | undefined, name: string | Identifier): ExportSpecifier; - updateExportSpecifier(node: ExportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier): ExportSpecifier; + createExportSpecifier( + isTypeOnly: boolean, + propertyName: string | Identifier | undefined, + name: string | Identifier, + ): ExportSpecifier; + updateExportSpecifier( + node: ExportSpecifier, + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier, + ): ExportSpecifier; /* @internal*/ createMissingDeclaration(): MissingDeclaration; // @@ -7945,8 +9074,15 @@ namespace ts { updateJSDocNullableType(node: JSDocNullableType, type: TypeNode): JSDocNullableType; createJSDocOptionalType(type: TypeNode): JSDocOptionalType; updateJSDocOptionalType(node: JSDocOptionalType, type: TypeNode): JSDocOptionalType; - createJSDocFunctionType(parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType; - updateJSDocFunctionType(node: JSDocFunctionType, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType; + createJSDocFunctionType( + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): JSDocFunctionType; + updateJSDocFunctionType( + node: JSDocFunctionType, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): JSDocFunctionType; createJSDocVariadicType(type: TypeNode): JSDocVariadicType; updateJSDocVariadicType(node: JSDocVariadicType, type: TypeNode): JSDocVariadicType; createJSDocNamepathType(type: TypeNode): JSDocNamepathType; @@ -7956,89 +9092,344 @@ namespace ts { createJSDocNameReference(name: EntityName | JSDocMemberName): JSDocNameReference; updateJSDocNameReference(node: JSDocNameReference, name: EntityName | JSDocMemberName): JSDocNameReference; createJSDocMemberName(left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName; - updateJSDocMemberName(node: JSDocMemberName, left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName; + updateJSDocMemberName( + node: JSDocMemberName, + left: EntityName | JSDocMemberName, + right: Identifier, + ): JSDocMemberName; createJSDocLink(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink; updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink; createJSDocLinkCode(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode; - updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode; + updateJSDocLinkCode( + node: JSDocLinkCode, + name: EntityName | JSDocMemberName | undefined, + text: string, + ): JSDocLinkCode; createJSDocLinkPlain(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain; - updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain; - createJSDocTypeLiteral(jsDocPropertyTags?: readonly JSDocPropertyLikeTag[], isArrayType?: boolean): JSDocTypeLiteral; - updateJSDocTypeLiteral(node: JSDocTypeLiteral, jsDocPropertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean | undefined): JSDocTypeLiteral; - createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature; - updateJSDocSignature(node: JSDocSignature, typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type: JSDocReturnTag | undefined): JSDocSignature; - createJSDocTemplateTag(tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment?: string | NodeArray): JSDocTemplateTag; - updateJSDocTemplateTag(node: JSDocTemplateTag, tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment: string | NodeArray | undefined): JSDocTemplateTag; - createJSDocTypedefTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression | JSDocTypeLiteral, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray): JSDocTypedefTag; - updateJSDocTypedefTag(node: JSDocTypedefTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocTypedefTag; - createJSDocParameterTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray): JSDocParameterTag; - updateJSDocParameterTag(node: JSDocParameterTag, tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray | undefined): JSDocParameterTag; - createJSDocPropertyTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray): JSDocPropertyTag; - updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray | undefined): JSDocPropertyTag; - createJSDocTypeTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocTypeTag; - updateJSDocTypeTag(node: JSDocTypeTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocTypeTag; - createJSDocSeeTag(tagName: Identifier | undefined, nameExpression: JSDocNameReference | undefined, comment?: string | NodeArray): JSDocSeeTag; - updateJSDocSeeTag(node: JSDocSeeTag, tagName: Identifier | undefined, nameExpression: JSDocNameReference | undefined, comment?: string | NodeArray): JSDocSeeTag; - createJSDocReturnTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string | NodeArray): JSDocReturnTag; - updateJSDocReturnTag(node: JSDocReturnTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment: string | NodeArray | undefined): JSDocReturnTag; - createJSDocThisTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocThisTag; - updateJSDocThisTag(node: JSDocThisTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment: string | NodeArray | undefined): JSDocThisTag; - createJSDocEnumTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocEnumTag; - updateJSDocEnumTag(node: JSDocEnumTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocEnumTag; - createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray): JSDocCallbackTag; - updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocCallbackTag; - createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray): JSDocAugmentsTag; - updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray | undefined): JSDocAugmentsTag; - createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray): JSDocImplementsTag; - updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | NodeArray | undefined): JSDocImplementsTag; - createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocAuthorTag; - updateJSDocAuthorTag(node: JSDocAuthorTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocAuthorTag; + updateJSDocLinkPlain( + node: JSDocLinkPlain, + name: EntityName | JSDocMemberName | undefined, + text: string, + ): JSDocLinkPlain; + createJSDocTypeLiteral( + jsDocPropertyTags?: readonly JSDocPropertyLikeTag[], + isArrayType?: boolean, + ): JSDocTypeLiteral; + updateJSDocTypeLiteral( + node: JSDocTypeLiteral, + jsDocPropertyTags: readonly JSDocPropertyLikeTag[] | undefined, + isArrayType: boolean | undefined, + ): JSDocTypeLiteral; + createJSDocSignature( + typeParameters: readonly JSDocTemplateTag[] | undefined, + parameters: readonly JSDocParameterTag[], + type?: JSDocReturnTag, + ): JSDocSignature; + updateJSDocSignature( + node: JSDocSignature, + typeParameters: readonly JSDocTemplateTag[] | undefined, + parameters: readonly JSDocParameterTag[], + type: JSDocReturnTag | undefined, + ): JSDocSignature; + createJSDocTemplateTag( + tagName: Identifier | undefined, + constraint: JSDocTypeExpression | undefined, + typeParameters: readonly TypeParameterDeclaration[], + comment?: string | NodeArray, + ): JSDocTemplateTag; + updateJSDocTemplateTag( + node: JSDocTemplateTag, + tagName: Identifier | undefined, + constraint: JSDocTypeExpression | undefined, + typeParameters: readonly TypeParameterDeclaration[], + comment: string | NodeArray | undefined, + ): JSDocTemplateTag; + createJSDocTypedefTag( + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression | JSDocTypeLiteral, + fullName?: Identifier | JSDocNamespaceDeclaration, + comment?: string | NodeArray, + ): JSDocTypedefTag; + updateJSDocTypedefTag( + node: JSDocTypedefTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined, + fullName: Identifier | JSDocNamespaceDeclaration | undefined, + comment: string | NodeArray | undefined, + ): JSDocTypedefTag; + createJSDocParameterTag( + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression?: JSDocTypeExpression, + isNameFirst?: boolean, + comment?: string | NodeArray, + ): JSDocParameterTag; + updateJSDocParameterTag( + node: JSDocParameterTag, + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression: JSDocTypeExpression | undefined, + isNameFirst: boolean, + comment: string | NodeArray | undefined, + ): JSDocParameterTag; + createJSDocPropertyTag( + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression?: JSDocTypeExpression, + isNameFirst?: boolean, + comment?: string | NodeArray, + ): JSDocPropertyTag; + updateJSDocPropertyTag( + node: JSDocPropertyTag, + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression: JSDocTypeExpression | undefined, + isNameFirst: boolean, + comment: string | NodeArray | undefined, + ): JSDocPropertyTag; + createJSDocTypeTag( + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment?: string | NodeArray, + ): JSDocTypeTag; + updateJSDocTypeTag( + node: JSDocTypeTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment: string | NodeArray | undefined, + ): JSDocTypeTag; + createJSDocSeeTag( + tagName: Identifier | undefined, + nameExpression: JSDocNameReference | undefined, + comment?: string | NodeArray, + ): JSDocSeeTag; + updateJSDocSeeTag( + node: JSDocSeeTag, + tagName: Identifier | undefined, + nameExpression: JSDocNameReference | undefined, + comment?: string | NodeArray, + ): JSDocSeeTag; + createJSDocReturnTag( + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression, + comment?: string | NodeArray, + ): JSDocReturnTag; + updateJSDocReturnTag( + node: JSDocReturnTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression | undefined, + comment: string | NodeArray | undefined, + ): JSDocReturnTag; + createJSDocThisTag( + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment?: string | NodeArray, + ): JSDocThisTag; + updateJSDocThisTag( + node: JSDocThisTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression | undefined, + comment: string | NodeArray | undefined, + ): JSDocThisTag; + createJSDocEnumTag( + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment?: string | NodeArray, + ): JSDocEnumTag; + updateJSDocEnumTag( + node: JSDocEnumTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment: string | NodeArray | undefined, + ): JSDocEnumTag; + createJSDocCallbackTag( + tagName: Identifier | undefined, + typeExpression: JSDocSignature, + fullName?: Identifier | JSDocNamespaceDeclaration, + comment?: string | NodeArray, + ): JSDocCallbackTag; + updateJSDocCallbackTag( + node: JSDocCallbackTag, + tagName: Identifier | undefined, + typeExpression: JSDocSignature, + fullName: Identifier | JSDocNamespaceDeclaration | undefined, + comment: string | NodeArray | undefined, + ): JSDocCallbackTag; + createJSDocAugmentsTag( + tagName: Identifier | undefined, + className: JSDocAugmentsTag["class"], + comment?: string | NodeArray, + ): JSDocAugmentsTag; + updateJSDocAugmentsTag( + node: JSDocAugmentsTag, + tagName: Identifier | undefined, + className: JSDocAugmentsTag["class"], + comment: string | NodeArray | undefined, + ): JSDocAugmentsTag; + createJSDocImplementsTag( + tagName: Identifier | undefined, + className: JSDocImplementsTag["class"], + comment?: string | NodeArray, + ): JSDocImplementsTag; + updateJSDocImplementsTag( + node: JSDocImplementsTag, + tagName: Identifier | undefined, + className: JSDocImplementsTag["class"], + comment: string | NodeArray | undefined, + ): JSDocImplementsTag; + createJSDocAuthorTag( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocAuthorTag; + updateJSDocAuthorTag( + node: JSDocAuthorTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocAuthorTag; createJSDocClassTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocClassTag; - updateJSDocClassTag(node: JSDocClassTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocClassTag; - createJSDocPublicTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocPublicTag; - updateJSDocPublicTag(node: JSDocPublicTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocPublicTag; - createJSDocPrivateTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocPrivateTag; - updateJSDocPrivateTag(node: JSDocPrivateTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocPrivateTag; - createJSDocProtectedTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocProtectedTag; - updateJSDocProtectedTag(node: JSDocProtectedTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocProtectedTag; - createJSDocReadonlyTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocReadonlyTag; - updateJSDocReadonlyTag(node: JSDocReadonlyTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocReadonlyTag; + updateJSDocClassTag( + node: JSDocClassTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocClassTag; + createJSDocPublicTag( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocPublicTag; + updateJSDocPublicTag( + node: JSDocPublicTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocPublicTag; + createJSDocPrivateTag( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocPrivateTag; + updateJSDocPrivateTag( + node: JSDocPrivateTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocPrivateTag; + createJSDocProtectedTag( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocProtectedTag; + updateJSDocProtectedTag( + node: JSDocProtectedTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocProtectedTag; + createJSDocReadonlyTag( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocReadonlyTag; + updateJSDocReadonlyTag( + node: JSDocReadonlyTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocReadonlyTag; createJSDocUnknownTag(tagName: Identifier, comment?: string | NodeArray): JSDocUnknownTag; - updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag; + updateJSDocUnknownTag( + node: JSDocUnknownTag, + tagName: Identifier, + comment: string | NodeArray | undefined, + ): JSDocUnknownTag; createJSDocDeprecatedTag(tagName: Identifier, comment?: string | NodeArray): JSDocDeprecatedTag; - updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier, comment?: string | NodeArray): JSDocDeprecatedTag; + updateJSDocDeprecatedTag( + node: JSDocDeprecatedTag, + tagName: Identifier, + comment?: string | NodeArray, + ): JSDocDeprecatedTag; createJSDocOverrideTag(tagName: Identifier, comment?: string | NodeArray): JSDocOverrideTag; - updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier, comment?: string | NodeArray): JSDocOverrideTag; + updateJSDocOverrideTag( + node: JSDocOverrideTag, + tagName: Identifier, + comment?: string | NodeArray, + ): JSDocOverrideTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; - createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; - updateJSDocComment(node: JSDoc, comment: string | NodeArray | undefined, tags: readonly JSDocTag[] | undefined): JSDoc; + createJSDocComment( + comment?: string | NodeArray | undefined, + tags?: readonly JSDocTag[] | undefined, + ): JSDoc; + updateJSDocComment( + node: JSDoc, + comment: string | NodeArray | undefined, + tags: readonly JSDocTag[] | undefined, + ): JSDoc; // // JSX // - createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement): JsxElement; - updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement): JsxElement; - createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxSelfClosingElement; - updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxSelfClosingElement; - createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxOpeningElement; - updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxOpeningElement; + createJsxElement( + openingElement: JsxOpeningElement, + children: readonly JsxChild[], + closingElement: JsxClosingElement, + ): JsxElement; + updateJsxElement( + node: JsxElement, + openingElement: JsxOpeningElement, + children: readonly JsxChild[], + closingElement: JsxClosingElement, + ): JsxElement; + createJsxSelfClosingElement( + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ): JsxSelfClosingElement; + updateJsxSelfClosingElement( + node: JsxSelfClosingElement, + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ): JsxSelfClosingElement; + createJsxOpeningElement( + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ): JsxOpeningElement; + updateJsxOpeningElement( + node: JsxOpeningElement, + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ): JsxOpeningElement; createJsxClosingElement(tagName: JsxTagNameExpression): JsxClosingElement; updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression): JsxClosingElement; - createJsxFragment(openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment): JsxFragment; + createJsxFragment( + openingFragment: JsxOpeningFragment, + children: readonly JsxChild[], + closingFragment: JsxClosingFragment, + ): JsxFragment; createJsxText(text: string, containsOnlyTriviaWhiteSpaces?: boolean): JsxText; updateJsxText(node: JsxText, text: string, containsOnlyTriviaWhiteSpaces?: boolean): JsxText; createJsxOpeningFragment(): JsxOpeningFragment; createJsxJsxClosingFragment(): JsxClosingFragment; - updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment): JsxFragment; + updateJsxFragment( + node: JsxFragment, + openingFragment: JsxOpeningFragment, + children: readonly JsxChild[], + closingFragment: JsxClosingFragment, + ): JsxFragment; createJsxAttribute(name: Identifier, initializer: JsxAttributeValue | undefined): JsxAttribute; - updateJsxAttribute(node: JsxAttribute, name: Identifier, initializer: JsxAttributeValue | undefined): JsxAttribute; + updateJsxAttribute( + node: JsxAttribute, + name: Identifier, + initializer: JsxAttributeValue | undefined, + ): JsxAttribute; createJsxAttributes(properties: readonly JsxAttributeLike[]): JsxAttributes; updateJsxAttributes(node: JsxAttributes, properties: readonly JsxAttributeLike[]): JsxAttributes; createJsxSpreadAttribute(expression: Expression): JsxSpreadAttribute; updateJsxSpreadAttribute(node: JsxSpreadAttribute, expression: Expression): JsxSpreadAttribute; - createJsxExpression(dotDotDotToken: DotDotDotToken | undefined, expression: Expression | undefined): JsxExpression; + createJsxExpression( + dotDotDotToken: DotDotDotToken | undefined, + expression: Expression | undefined, + ): JsxExpression; updateJsxExpression(node: JsxExpression, expression: Expression | undefined): JsxExpression; // @@ -8049,19 +9440,40 @@ namespace ts { updateCaseClause(node: CaseClause, expression: Expression, statements: readonly Statement[]): CaseClause; createDefaultClause(statements: readonly Statement[]): DefaultClause; updateDefaultClause(node: DefaultClause, statements: readonly Statement[]): DefaultClause; - createHeritageClause(token: HeritageClause["token"], types: readonly ExpressionWithTypeArguments[]): HeritageClause; + createHeritageClause( + token: HeritageClause["token"], + types: readonly ExpressionWithTypeArguments[], + ): HeritageClause; updateHeritageClause(node: HeritageClause, types: readonly ExpressionWithTypeArguments[]): HeritageClause; - createCatchClause(variableDeclaration: string | BindingName | VariableDeclaration | undefined, block: Block): CatchClause; - updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block): CatchClause; + createCatchClause( + variableDeclaration: string | BindingName | VariableDeclaration | undefined, + block: Block, + ): CatchClause; + updateCatchClause( + node: CatchClause, + variableDeclaration: VariableDeclaration | undefined, + block: Block, + ): CatchClause; // // Property assignments // createPropertyAssignment(name: string | PropertyName, initializer: Expression): PropertyAssignment; - updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression): PropertyAssignment; - createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression): ShorthandPropertyAssignment; - updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression | undefined): ShorthandPropertyAssignment; + updatePropertyAssignment( + node: PropertyAssignment, + name: PropertyName, + initializer: Expression, + ): PropertyAssignment; + createShorthandPropertyAssignment( + name: string | Identifier, + objectAssignmentInitializer?: Expression, + ): ShorthandPropertyAssignment; + updateShorthandPropertyAssignment( + node: ShorthandPropertyAssignment, + name: Identifier, + objectAssignmentInitializer: Expression | undefined, + ): ShorthandPropertyAssignment; createSpreadAssignment(expression: Expression): SpreadAssignment; updateSpreadAssignment(node: SpreadAssignment, expression: Expression): SpreadAssignment; @@ -8076,20 +9488,45 @@ namespace ts { // Top-level nodes // - createSourceFile(statements: readonly Statement[], endOfFileToken: EndOfFileToken, flags: NodeFlags): SourceFile; - updateSourceFile(node: SourceFile, statements: readonly Statement[], isDeclarationFile?: boolean, referencedFiles?: readonly FileReference[], typeReferences?: readonly FileReference[], hasNoDefaultLib?: boolean, libReferences?: readonly FileReference[]): SourceFile; - - /* @internal */ createUnparsedSource(prologues: readonly UnparsedPrologue[], syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, texts: readonly UnparsedSourceText[]): UnparsedSource; + createSourceFile( + statements: readonly Statement[], + endOfFileToken: EndOfFileToken, + flags: NodeFlags, + ): SourceFile; + updateSourceFile( + node: SourceFile, + statements: readonly Statement[], + isDeclarationFile?: boolean, + referencedFiles?: readonly FileReference[], + typeReferences?: readonly FileReference[], + hasNoDefaultLib?: boolean, + libReferences?: readonly FileReference[], + ): SourceFile; + + /* @internal */ createUnparsedSource( + prologues: readonly UnparsedPrologue[], + syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, + texts: readonly UnparsedSourceText[], + ): UnparsedSource; /* @internal */ createUnparsedPrologue(data?: string): UnparsedPrologue; - /* @internal */ createUnparsedPrepend(data: string | undefined, texts: readonly UnparsedSourceText[]): UnparsedPrepend; + /* @internal */ createUnparsedPrepend( + data: string | undefined, + texts: readonly UnparsedSourceText[], + ): UnparsedPrepend; /* @internal */ createUnparsedTextLike(data: string | undefined, internal: boolean): UnparsedTextLike; - /* @internal */ createUnparsedSyntheticReference(section: BundleFileHasNoDefaultLib | BundleFileReference): UnparsedSyntheticReference; + /* @internal */ createUnparsedSyntheticReference( + section: BundleFileHasNoDefaultLib | BundleFileReference, + ): UnparsedSyntheticReference; /* @internal */ createInputFiles(): InputFiles; // // Synthetic Nodes // - /* @internal */ createSyntheticExpression(type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember): SyntheticExpression; + /* @internal */ createSyntheticExpression( + type: Type, + isSpread?: boolean, + tupleNameSource?: ParameterDeclaration | NamedTupleMember, + ): SyntheticExpression; /* @internal */ createSyntaxList(children: Node[]): SyntaxList; // @@ -8100,20 +9537,37 @@ namespace ts { /* @internal */ createEndOfDeclarationMarker(original: Node): EndOfDeclarationMarker; /* @internal */ createMergeDeclarationMarker(original: Node): MergeDeclarationMarker; createPartiallyEmittedExpression(expression: Expression, original?: Node): PartiallyEmittedExpression; - updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression): PartiallyEmittedExpression; - /* @internal */ createSyntheticReferenceExpression(expression: Expression, thisArg: Expression): SyntheticReferenceExpression; - /* @internal */ updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression): SyntheticReferenceExpression; + updatePartiallyEmittedExpression( + node: PartiallyEmittedExpression, + expression: Expression, + ): PartiallyEmittedExpression; + /* @internal */ createSyntheticReferenceExpression( + expression: Expression, + thisArg: Expression, + ): SyntheticReferenceExpression; + /* @internal */ updateSyntheticReferenceExpression( + node: SyntheticReferenceExpression, + expression: Expression, + thisArg: Expression, + ): SyntheticReferenceExpression; createCommaListExpression(elements: readonly Expression[]): CommaListExpression; updateCommaListExpression(node: CommaListExpression, elements: readonly Expression[]): CommaListExpression; createBundle(sourceFiles: readonly SourceFile[], prepends?: readonly (UnparsedSource | InputFiles)[]): Bundle; - updateBundle(node: Bundle, sourceFiles: readonly SourceFile[], prepends?: readonly (UnparsedSource | InputFiles)[]): Bundle; + updateBundle( + node: Bundle, + sourceFiles: readonly SourceFile[], + prepends?: readonly (UnparsedSource | InputFiles)[], + ): Bundle; // // Common operators // createComma(left: Expression, right: Expression): BinaryExpression; - createAssignment(left: ObjectLiteralExpression | ArrayLiteralExpression, right: Expression): DestructuringAssignment; + createAssignment( + left: ObjectLiteralExpression | ArrayLiteralExpression, + right: Expression, + ): DestructuringAssignment; createAssignment(left: Expression, right: Expression): AssignmentExpression; createLogicalOr(left: Expression, right: Expression): BinaryExpression; createLogicalAnd(left: Expression, right: Expression): BinaryExpression; @@ -8151,27 +9605,76 @@ namespace ts { // createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression; - createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; + createImmediatelyInvokedFunctionExpression( + statements: readonly Statement[], + param: ParameterDeclaration, + paramValue: Expression, + ): CallExpression; createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): CallExpression; - createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; + createImmediatelyInvokedArrowFunction( + statements: readonly Statement[], + param: ParameterDeclaration, + paramValue: Expression, + ): CallExpression; createVoidZero(): VoidExpression; createExportDefault(expression: Expression): ExportAssignment; createExternalModuleExport(exportName: Identifier): ExportDeclaration; /* @internal */ createTypeCheck(value: Expression, tag: TypeOfTag): Expression; - /* @internal */ createMethodCall(object: Expression, methodName: string | Identifier, argumentsList: readonly Expression[]): CallExpression; - /* @internal */ createGlobalMethodCall(globalObjectName: string, globalMethodName: string, argumentsList: readonly Expression[]): CallExpression; - /* @internal */ createFunctionBindCall(target: Expression, thisArg: Expression, argumentsList: readonly Expression[]): CallExpression; - /* @internal */ createFunctionCallCall(target: Expression, thisArg: Expression, argumentsList: readonly Expression[]): CallExpression; - /* @internal */ createFunctionApplyCall(target: Expression, thisArg: Expression, argumentsExpression: Expression): CallExpression; - /* @internal */ createObjectDefinePropertyCall(target: Expression, propertyName: string | Expression, attributes: Expression): CallExpression; - /* @internal */ createReflectGetCall(target: Expression, propertyKey: Expression, receiver?: Expression): CallExpression; - /* @internal */ createReflectSetCall(target: Expression, propertyKey: Expression, value: Expression, receiver?: Expression): CallExpression; - /* @internal */ createPropertyDescriptor(attributes: PropertyDescriptorAttributes, singleLine?: boolean): ObjectLiteralExpression; + /* @internal */ createMethodCall( + object: Expression, + methodName: string | Identifier, + argumentsList: readonly Expression[], + ): CallExpression; + /* @internal */ createGlobalMethodCall( + globalObjectName: string, + globalMethodName: string, + argumentsList: readonly Expression[], + ): CallExpression; + /* @internal */ createFunctionBindCall( + target: Expression, + thisArg: Expression, + argumentsList: readonly Expression[], + ): CallExpression; + /* @internal */ createFunctionCallCall( + target: Expression, + thisArg: Expression, + argumentsList: readonly Expression[], + ): CallExpression; + /* @internal */ createFunctionApplyCall( + target: Expression, + thisArg: Expression, + argumentsExpression: Expression, + ): CallExpression; + /* @internal */ createObjectDefinePropertyCall( + target: Expression, + propertyName: string | Expression, + attributes: Expression, + ): CallExpression; + /* @internal */ createReflectGetCall( + target: Expression, + propertyKey: Expression, + receiver?: Expression, + ): CallExpression; + /* @internal */ createReflectSetCall( + target: Expression, + propertyKey: Expression, + value: Expression, + receiver?: Expression, + ): CallExpression; + /* @internal */ createPropertyDescriptor( + attributes: PropertyDescriptorAttributes, + singleLine?: boolean, + ): ObjectLiteralExpression; /* @internal */ createArraySliceCall(array: Expression, start?: number | Expression): CallExpression; /* @internal */ createArrayConcatCall(array: Expression, values: readonly Expression[]): CallExpression; - /* @internal */ createCallBinding(expression: Expression, recordTempVariable: (temp: Identifier) => void, languageVersion?: ScriptTarget, cacheIdentifiers?: boolean): CallBinding; + /* @internal */ createCallBinding( + expression: Expression, + recordTempVariable: (temp: Identifier) => void, + languageVersion?: ScriptTarget, + cacheIdentifiers?: boolean, + ): CallBinding; /** * Wraps an expression that cannot be an assignment target in an expression that can be. * @@ -8187,7 +9690,10 @@ namespace ts { * @param paramName * @param expression */ - /* @internal */ createAssignmentTargetWrapper(paramName: Identifier, expression: Expression): LeftHandSideExpression; + /* @internal */ createAssignmentTargetWrapper( + paramName: Identifier, + expression: Expression, + ): LeftHandSideExpression; /* @internal */ inlineExpressions(expressions: readonly Expression[]): Expression; /** * Gets the internal name of a declaration. This is primarily used for declarations that can be @@ -8200,7 +9706,11 @@ namespace ts { * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - /* @internal */ getInternalName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier; + /* @internal */ getInternalName( + node: Declaration, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): Identifier; /** * Gets the local name of a declaration. This is primarily used for declarations that can be * referred to by name in the declaration's immediate scope (classes, enums, namespaces). A @@ -8222,7 +9732,11 @@ namespace ts { * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - /* @internal */ getExportName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier; + /* @internal */ getExportName( + node: Declaration, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): Identifier; /** * Gets the name of a declaration for use in declarations. * @@ -8230,7 +9744,11 @@ namespace ts { * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - /* @internal */ getDeclarationName(node: Declaration | undefined, allowComments?: boolean, allowSourceMaps?: boolean): Identifier; + /* @internal */ getDeclarationName( + node: Declaration | undefined, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): Identifier; /** * Gets a namespace-qualified name for use in expressions. * @@ -8239,7 +9757,12 @@ namespace ts { * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - /* @internal */ getNamespaceMemberName(ns: Identifier, name: Identifier, allowComments?: boolean, allowSourceMaps?: boolean): PropertyAccessExpression; + /* @internal */ getNamespaceMemberName( + ns: Identifier, + name: Identifier, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): PropertyAccessExpression; /** * Gets the exported name of a declaration for use in expressions. * @@ -8251,14 +9774,27 @@ namespace ts { * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - /* @internal */ getExternalModuleOrNamespaceExportName(ns: Identifier | undefined, node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier | PropertyAccessExpression; + /* @internal */ getExternalModuleOrNamespaceExportName( + ns: Identifier | undefined, + node: Declaration, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): Identifier | PropertyAccessExpression; // // Utilities // - restoreOuterExpressions(outerExpression: Expression | undefined, innerExpression: Expression, kinds?: OuterExpressionKinds): Expression; - /* @internal */ restoreEnclosingLabel(node: Statement, outermostLabeledStatement: LabeledStatement | undefined, afterRestoreLabelCallback?: (node: LabeledStatement) => void): Statement; + restoreOuterExpressions( + outerExpression: Expression | undefined, + innerExpression: Expression, + kinds?: OuterExpressionKinds, + ): Expression; + /* @internal */ restoreEnclosingLabel( + node: Statement, + outermostLabeledStatement: LabeledStatement | undefined, + afterRestoreLabelCallback?: (node: LabeledStatement) => void, + ): Statement; /* @internal */ createUseStrictPrologue(): PrologueDirective; /** * Copies any necessary standard and custom prologue-directives into target array. @@ -8267,7 +9803,12 @@ namespace ts { * @param ensureUseStrict boolean determining whether the function need to add prologue-directives * @param visitor Optional callback used to visit any custom prologue directives. */ - /* @internal */ copyPrologue(source: readonly Statement[], target: Push, ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number; + /* @internal */ copyPrologue( + source: readonly Statement[], + target: Push, + ensureUseStrict?: boolean, + visitor?: (node: Node) => VisitResult, + ): number; /** * Copies only the standard (string-expression) prologue-directives into the target statement-array. * @param source origin statements array @@ -8275,7 +9816,12 @@ namespace ts { * @param statementOffset The offset at which to begin the copy. * @param ensureUseStrict boolean determining whether the function need to add prologue-directives */ - /* @internal */ copyStandardPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, ensureUseStrict?: boolean): number; + /* @internal */ copyStandardPrologue( + source: readonly Statement[], + target: Push, + statementOffset: number | undefined, + ensureUseStrict?: boolean, + ): number; /** * Copies only the custom prologue-directives into target statement-array. * @param source origin statements array @@ -8283,18 +9829,36 @@ namespace ts { * @param statementOffset The offset at which to begin the copy. * @param visitor Optional callback used to visit any custom prologue directives. */ - /* @internal */ copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number; - /* @internal */ copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number | undefined; + /* @internal */ copyCustomPrologue( + source: readonly Statement[], + target: Push, + statementOffset: number, + visitor?: (node: Node) => VisitResult, + filter?: (node: Node) => boolean, + ): number; + /* @internal */ copyCustomPrologue( + source: readonly Statement[], + target: Push, + statementOffset: number | undefined, + visitor?: (node: Node) => VisitResult, + filter?: (node: Node) => boolean, + ): number | undefined; /* @internal */ ensureUseStrict(statements: NodeArray): NodeArray; /* @internal */ liftToBlock(nodes: readonly Node[]): Statement; /** * Merges generated lexical declarations into a new statement list. */ - /* @internal */ mergeLexicalEnvironment(statements: NodeArray, declarations: readonly Statement[] | undefined): NodeArray; + /* @internal */ mergeLexicalEnvironment( + statements: NodeArray, + declarations: readonly Statement[] | undefined, + ): NodeArray; /** * Appends generated lexical declarations to an array of statements. */ - /* @internal */ mergeLexicalEnvironment(statements: Statement[], declarations: readonly Statement[] | undefined): Statement[]; + /* @internal */ mergeLexicalEnvironment( + statements: Statement[], + declarations: readonly Statement[] | undefined, + ): Statement[]; /** * Creates a shallow, memberwise clone of a node. * - The result will have its `original` pointer set to `node`. @@ -8302,7 +9866,10 @@ namespace ts { * - *DO NOT USE THIS* if a more appropriate function is available. */ /* @internal */ cloneNode(node: T): T; - /* @internal */ updateModifiers(node: T, modifiers: readonly Modifier[] | ModifierFlags | undefined): T; + /* @internal */ updateModifiers( + node: T, + modifiers: readonly Modifier[] | ModifierFlags | undefined, + ): T; } /* @internal */ @@ -8454,13 +10021,35 @@ namespace ts { export type Visitor = (node: Node) => VisitResult; export interface NodeVisitor { - (nodes: T, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T; - (nodes: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined; + ( + nodes: T, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + lift?: (node: readonly Node[]) => T, + ): T; + ( + nodes: T | undefined, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + lift?: (node: readonly Node[]) => T, + ): T | undefined; } export interface NodesVisitor { - (nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; - (nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; + ( + nodes: NodeArray, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray; + ( + nodes: NodeArray | undefined, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray | undefined; } export type VisitResult = T | readonly T[] | undefined; @@ -8492,10 +10081,28 @@ namespace ts { * Prints a bundle of source files as-is, without any emit transformations. */ printBundle(bundle: Bundle): string; - /*@internal*/ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void; - /*@internal*/ writeList(format: ListFormat, list: NodeArray | undefined, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void; - /*@internal*/ writeFile(sourceFile: SourceFile, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; - /*@internal*/ writeBundle(bundle: Bundle, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; + /*@internal*/ writeNode( + hint: EmitHint, + node: Node, + sourceFile: SourceFile | undefined, + writer: EmitTextWriter, + ): void; + /*@internal*/ writeList( + format: ListFormat, + list: NodeArray | undefined, + sourceFile: SourceFile | undefined, + writer: EmitTextWriter, + ): void; + /*@internal*/ writeFile( + sourceFile: SourceFile, + writer: EmitTextWriter, + sourceMapGenerator: SourceMapGenerator | undefined, + ): void; + /*@internal*/ writeBundle( + bundle: Bundle, + writer: EmitTextWriter, + sourceMapGenerator: SourceMapGenerator | undefined, + ): void; /*@internal*/ bundleFileInfo?: BundleFileInfo; } @@ -8540,7 +10147,12 @@ namespace ts { /*@internal*/ export interface BundleFileReference extends BundleFileSectionBase { - kind: BundleFileSectionKind.Reference | BundleFileSectionKind.Type | BundleFileSectionKind.Lib | BundleFileSectionKind.TypeResolutionModeImport | BundleFileSectionKind.TypeResolutionModeRequire; + kind: + | BundleFileSectionKind.Reference + | BundleFileSectionKind.Type + | BundleFileSectionKind.Lib + | BundleFileSectionKind.TypeResolutionModeImport + | BundleFileSectionKind.TypeResolutionModeRequire; data: string; } @@ -8663,8 +10275,18 @@ namespace ts { * ``` */ substituteNode?(hint: EmitHint, node: Node): Node; - /*@internal*/ onEmitSourceMapOfNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void; - /*@internal*/ onEmitSourceMapOfToken?: (node: Node | undefined, token: SyntaxKind, writer: (s: string) => void, pos: number, emitCallback: (token: SyntaxKind, writer: (s: string) => void, pos: number) => number) => number; + /*@internal*/ onEmitSourceMapOfNode?: ( + hint: EmitHint, + node: Node, + emitCallback: (hint: EmitHint, node: Node) => void, + ) => void; + /*@internal*/ onEmitSourceMapOfToken?: ( + node: Node | undefined, + token: SyntaxKind, + writer: (s: string) => void, + pos: number, + emitCallback: (token: SyntaxKind, writer: (s: string) => void, pos: number) => number, + ) => number; /*@internal*/ onEmitSourceMapOfPosition?: (pos: number) => void; /*@internal*/ onSetSourceFile?: (node: SourceFile) => void; /*@internal*/ onBeforeEmitNode?: (node: Node | undefined) => void; @@ -8732,11 +10354,25 @@ namespace ts { /** * Adds a mapping with source information. */ - addMapping(generatedLine: number, generatedCharacter: number, sourceIndex: number, sourceLine: number, sourceCharacter: number, nameIndex?: number): void; + addMapping( + generatedLine: number, + generatedCharacter: number, + sourceIndex: number, + sourceLine: number, + sourceCharacter: number, + nameIndex?: number, + ): void; /** * Appends a source map. */ - appendSourceMap(generatedLine: number, generatedCharacter: number, sourceMap: RawSourceMap, sourceMapPath: string, start?: LineAndCharacter, end?: LineAndCharacter): void; + appendSourceMap( + generatedLine: number, + generatedCharacter: number, + sourceMap: RawSourceMap, + sourceMapPath: string, + start?: LineAndCharacter, + end?: LineAndCharacter, + ): void; /** * Gets the source map as a `RawSourceMap` object. */ @@ -8839,10 +10475,34 @@ namespace ts { /* @internal */ export interface ModuleSpecifierCache { - get(fromFileName: Path, toFileName: Path, preferences: UserPreferences, options: ModuleSpecifierOptions): Readonly | undefined; - set(fromFileName: Path, toFileName: Path, preferences: UserPreferences, options: ModuleSpecifierOptions, modulePaths: readonly ModulePath[], moduleSpecifiers: readonly string[]): void; - setBlockedByPackageJsonDependencies(fromFileName: Path, toFileName: Path, preferences: UserPreferences, options: ModuleSpecifierOptions, isBlockedByPackageJsonDependencies: boolean): void; - setModulePaths(fromFileName: Path, toFileName: Path, preferences: UserPreferences, options: ModuleSpecifierOptions, modulePaths: readonly ModulePath[]): void; + get( + fromFileName: Path, + toFileName: Path, + preferences: UserPreferences, + options: ModuleSpecifierOptions, + ): Readonly | undefined; + set( + fromFileName: Path, + toFileName: Path, + preferences: UserPreferences, + options: ModuleSpecifierOptions, + modulePaths: readonly ModulePath[], + moduleSpecifiers: readonly string[], + ): void; + setBlockedByPackageJsonDependencies( + fromFileName: Path, + toFileName: Path, + preferences: UserPreferences, + options: ModuleSpecifierOptions, + isBlockedByPackageJsonDependencies: boolean, + ): void; + setModulePaths( + fromFileName: Path, + toFileName: Path, + preferences: UserPreferences, + options: ModuleSpecifierOptions, + modulePaths: readonly ModulePath[], + ): void; clear(): void; count(): number; } @@ -8954,11 +10614,16 @@ namespace ts { MultiLineTupleTypeElements = CommaDelimited | Indented | SpaceBetweenSiblings | MultiLine, UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine, IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine, - ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings | NoSpaceIfEmpty, - ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings | NoSpaceIfEmpty, - ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces | NoSpaceIfEmpty, - ImportClauseEntries = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces | NoSpaceIfEmpty, - ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets, + ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited + | SpaceBetweenSiblings | NoSpaceIfEmpty, + ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings + | NoSpaceIfEmpty, + ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces + | Indented | Braces | NoSpaceIfEmpty, + ImportClauseEntries = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented + | Braces | NoSpaceIfEmpty, + ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma + | Indented | SquareBrackets, CommaListElements = CommaDelimited | SpaceBetweenSiblings | SingleLine, CallExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis, NewExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis | OptionalIfUndefined, @@ -8973,7 +10638,8 @@ namespace ts { InterfaceMembers = Indented | MultiLine, EnumMembers = CommaDelimited | Indented | MultiLine, CaseBlockClauses = Indented | MultiLine, - NamedImportsOrExportsElements = CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | SingleLine | SpaceBetweenBraces | NoSpaceIfEmpty, + NamedImportsOrExportsElements = CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | SingleLine + | SpaceBetweenBraces | NoSpaceIfEmpty, JsxElementOrFragmentChildren = SingleLine | NoInterveningComments, JsxElementAttributes = SingleLine | SpaceBetweenSiblings | NoInterveningComments, CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty, @@ -9019,12 +10685,26 @@ namespace ts { } /* @internal */ - export interface PragmaDefinition { + export interface PragmaDefinition< + T1 extends string = string, + T2 extends string = string, + T3 extends string = string, + T4 extends string = string, + > { args?: | readonly [PragmaArgumentSpecification] | readonly [PragmaArgumentSpecification, PragmaArgumentSpecification] - | readonly [PragmaArgumentSpecification, PragmaArgumentSpecification, PragmaArgumentSpecification] - | readonly [PragmaArgumentSpecification, PragmaArgumentSpecification, PragmaArgumentSpecification, PragmaArgumentSpecification]; + | readonly [ + PragmaArgumentSpecification, + PragmaArgumentSpecification, + PragmaArgumentSpecification, + ] + | readonly [ + PragmaArgumentSpecification, + PragmaArgumentSpecification, + PragmaArgumentSpecification, + PragmaArgumentSpecification, + ]; // If not present, defaults to PragmaKindFlags.Default kind?: PragmaKindFlags; } @@ -9076,10 +10756,13 @@ namespace ts { } as const; /* @internal */ - type PragmaArgTypeMaybeCapture = TDesc extends { captureSpan: true; } ? { value: string; pos: number; end: number; } : string; + type PragmaArgTypeMaybeCapture = TDesc extends { captureSpan: true; } + ? { value: string; pos: number; end: number; } + : string; /* @internal */ - type PragmaArgTypeOptional = TDesc extends { optional: true; } ? { [K in TName]?: PragmaArgTypeMaybeCapture; } + type PragmaArgTypeOptional = TDesc extends { optional: true; } + ? { [K in TName]?: PragmaArgTypeMaybeCapture; } : { [K in TName]: PragmaArgTypeMaybeCapture; }; /* @internal */ @@ -9087,29 +10770,45 @@ namespace ts { /* @internal */ type ArgumentDefinitionToFieldUnion[]> = { - [K in keyof T]: PragmaArgTypeOptional; + [K in keyof T]: PragmaArgTypeOptional< + T[K], + T[K] extends { name: infer TName; } ? TName extends string ? TName : never : never + >; }[Extract]; // The mapped type maps over only the tuple members, but this reindex gets _all_ members - by extracting only `number` keys, we get only the tuple members /** * Maps a pragma definition into the desired shape for its arguments object */ /* @internal */ - type PragmaArgumentType = ConcretePragmaSpecs[KPrag] extends { args: readonly PragmaArgumentSpecification[]; } ? UnionToIntersection> + type PragmaArgumentType = ConcretePragmaSpecs[KPrag] extends + { args: readonly PragmaArgumentSpecification[]; } + ? UnionToIntersection> : never; /* @internal */ type ConcretePragmaSpecs = typeof commentPragmas; /* @internal */ - export type PragmaPseudoMap = { [K in keyof ConcretePragmaSpecs]: { arguments: PragmaArgumentType; range: CommentRange; }; }; + export type PragmaPseudoMap = { + [K in keyof ConcretePragmaSpecs]: { arguments: PragmaArgumentType; range: CommentRange; }; + }; /* @internal */ - export type PragmaPseudoMapEntry = { [K in keyof PragmaPseudoMap]: { name: K; args: PragmaPseudoMap[K]; }; }[keyof PragmaPseudoMap]; + export type PragmaPseudoMapEntry = { + [K in keyof PragmaPseudoMap]: { name: K; args: PragmaPseudoMap[K]; }; + }[keyof PragmaPseudoMap]; /* @internal */ - export interface ReadonlyPragmaMap extends ReadonlyESMap { + export interface ReadonlyPragmaMap + extends ReadonlyESMap + { get(key: TKey): PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][]; - forEach(action: (value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], key: TKey) => void): void; + forEach( + action: ( + value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], + key: TKey, + ) => void, + ): void; } /** @@ -9118,10 +10817,22 @@ namespace ts { * in multiple places */ /* @internal */ - export interface PragmaMap extends ESMap, ReadonlyPragmaMap { - set(key: TKey, value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][]): this; + export interface PragmaMap + extends + ESMap, + ReadonlyPragmaMap + { + set( + key: TKey, + value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], + ): this; get(key: TKey): PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][]; - forEach(action: (value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], key: TKey) => void): void; + forEach( + action: ( + value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], + key: TKey, + ) => void, + ): void; } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 253cba77ebdcc..7e42149380a14 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -80,8 +80,8 @@ namespace ts { } export function changesAffectModuleResolution(oldOptions: CompilerOptions, newOptions: CompilerOptions): boolean { - return oldOptions.configFilePath !== newOptions.configFilePath || - optionsHaveModuleResolutionChanges(oldOptions, newOptions); + return oldOptions.configFilePath !== newOptions.configFilePath + || optionsHaveModuleResolutionChanges(oldOptions, newOptions); } export function optionsHaveModuleResolutionChanges(oldOptions: CompilerOptions, newOptions: CompilerOptions) { @@ -92,8 +92,15 @@ namespace ts { return optionsHaveChanges(oldOptions, newOptions, optionsAffectingProgramStructure); } - export function optionsHaveChanges(oldOptions: CompilerOptions, newOptions: CompilerOptions, optionDeclarations: readonly CommandLineOption[]) { - return oldOptions !== newOptions && optionDeclarations.some(o => !isJsonEqual(getCompilerOptionValue(oldOptions, o), getCompilerOptionValue(newOptions, o))); + export function optionsHaveChanges( + oldOptions: CompilerOptions, + newOptions: CompilerOptions, + optionDeclarations: readonly CommandLineOption[], + ) { + return oldOptions !== newOptions + && optionDeclarations.some(o => + !isJsonEqual(getCompilerOptionValue(oldOptions, o), getCompilerOptionValue(newOptions, o)) + ); } export function forEachAncestor(node: Node, callback: (n: Node) => T | undefined | "quit"): T | undefined { @@ -110,7 +117,10 @@ namespace ts { * Calls `callback` for each entry in the map, returning the first truthy result. * Use `map.forEach` instead for normal iteration. */ - export function forEachEntry(map: ReadonlyESMap, callback: (value: V, key: K) => U | undefined): U | undefined { + export function forEachEntry( + map: ReadonlyESMap, + callback: (value: V, key: K) => U | undefined, + ): U | undefined { const iterator = map.entries(); for (let iterResult = iterator.next(); !iterResult.done; iterResult = iterator.next()) { const [key, value] = iterResult.value; @@ -157,11 +167,20 @@ namespace ts { return node.end - node.pos; } - export function getResolvedModule(sourceFile: SourceFile | undefined, moduleNameText: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined): ResolvedModuleFull | undefined { + export function getResolvedModule( + sourceFile: SourceFile | undefined, + moduleNameText: string, + mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, + ): ResolvedModuleFull | undefined { return sourceFile && sourceFile.resolvedModules && sourceFile.resolvedModules.get(moduleNameText, mode); } - export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModuleFull | undefined, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined): void { + export function setResolvedModule( + sourceFile: SourceFile, + moduleNameText: string, + resolvedModule: ResolvedModuleFull | undefined, + mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, + ): void { if (!sourceFile.resolvedModules) { sourceFile.resolvedModules = createModeAwareCache(); } @@ -169,30 +188,42 @@ namespace ts { sourceFile.resolvedModules.set(moduleNameText, mode, resolvedModule); } - export function setResolvedTypeReferenceDirective(sourceFile: SourceFile, typeReferenceDirectiveName: string, resolvedTypeReferenceDirective?: ResolvedTypeReferenceDirective): void { + export function setResolvedTypeReferenceDirective( + sourceFile: SourceFile, + typeReferenceDirectiveName: string, + resolvedTypeReferenceDirective?: ResolvedTypeReferenceDirective, + ): void { if (!sourceFile.resolvedTypeReferenceDirectiveNames) { sourceFile.resolvedTypeReferenceDirectiveNames = createModeAwareCache(); } - sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, /*mode*/ undefined, resolvedTypeReferenceDirective); + sourceFile.resolvedTypeReferenceDirectiveNames.set( + typeReferenceDirectiveName, + /*mode*/ undefined, + resolvedTypeReferenceDirective, + ); } export function projectReferenceIsEqualTo(oldRef: ProjectReference, newRef: ProjectReference) { - return oldRef.path === newRef.path && - !oldRef.prepend === !newRef.prepend && - !oldRef.circular === !newRef.circular; + return oldRef.path === newRef.path + && !oldRef.prepend === !newRef.prepend + && !oldRef.circular === !newRef.circular; } - export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleFull, newResolution: ResolvedModuleFull): boolean { - return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport && - oldResolution.extension === newResolution.extension && - oldResolution.resolvedFileName === newResolution.resolvedFileName && - oldResolution.originalPath === newResolution.originalPath && - packageIdIsEqual(oldResolution.packageId, newResolution.packageId); + export function moduleResolutionIsEqualTo( + oldResolution: ResolvedModuleFull, + newResolution: ResolvedModuleFull, + ): boolean { + return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport + && oldResolution.extension === newResolution.extension + && oldResolution.resolvedFileName === newResolution.resolvedFileName + && oldResolution.originalPath === newResolution.originalPath + && packageIdIsEqual(oldResolution.packageId, newResolution.packageId); } function packageIdIsEqual(a: PackageId | undefined, b: PackageId | undefined): boolean { - return a === b || !!a && !!b && a.name === b.name && a.subModuleName === b.subModuleName && a.version === b.version; + return a === b + || !!a && !!b && a.name === b.name && a.subModuleName === b.subModuleName && a.version === b.version; } export function packageIdToPackageName({ name, subModuleName }: PackageId): string { @@ -203,7 +234,10 @@ namespace ts { return `${packageIdToPackageName(packageId)}@${packageId.version}`; } - export function typeDirectiveIsEqualTo(oldResolution: ResolvedTypeReferenceDirective, newResolution: ResolvedTypeReferenceDirective): boolean { + export function typeDirectiveIsEqualTo( + oldResolution: ResolvedTypeReferenceDirective, + newResolution: ResolvedTypeReferenceDirective, + ): boolean { return oldResolution.resolvedFileName === newResolution.resolvedFileName && oldResolution.primary === newResolution.primary && oldResolution.originalPath === newResolution.originalPath; @@ -223,7 +257,8 @@ namespace ts { const entry = names[i]; // We lower-case all type references because npm automatically lowercases all packages. See GH#9824. const name = !isString(entry) ? entry.fileName.toLowerCase() : entry; - const mode = !isString(entry) ? getModeForFileReference(entry, oldSourceFile?.impliedNodeFormat) : oldSourceFile && getModeForResolutionAtIndex(oldSourceFile, i); + const mode = !isString(entry) ? getModeForFileReference(entry, oldSourceFile?.impliedNodeFormat) + : oldSourceFile && getModeForResolutionAtIndex(oldSourceFile, i); const oldResolution = oldResolutions && oldResolutions.get(name, mode); const changed = oldResolution ? !newResolution || !comparer(oldResolution, newResolution) @@ -246,8 +281,8 @@ namespace ts { // A node is considered to contain a parse error if: // a) the parser explicitly marked that it had an error // b) any of it's children reported that it had an error. - const thisNodeOrAnySubNodesHasError = ((node.flags & NodeFlags.ThisNodeHasError) !== 0) || - forEachChild(node, containsParseError); + const thisNodeOrAnySubNodesHasError = ((node.flags & NodeFlags.ThisNodeHasError) !== 0) + || forEachChild(node, containsParseError); // If so, mark ourselves accordingly. if (thisNodeOrAnySubNodesHasError) { @@ -275,7 +310,8 @@ namespace ts { } export function isPlainJsFile(file: SourceFile | undefined, checkJs: boolean | undefined): boolean { - return !!file && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX) && !file.checkJsDirective && checkJs === undefined; + return !!file && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX) + && !file.checkJsDirective && checkJs === undefined; } export function isStatementWithLocals(node: Node) { @@ -333,7 +369,11 @@ namespace ts { * Returns a value indicating whether a name is unique globally or within the current file. * Note: This does not consider whether a name appears as a free identifier or not, so at the expression `x.y` this includes both `x` and `y`. */ - export function isFileLevelUniqueName(sourceFile: SourceFile, name: string, hasGlobalName?: PrintHandlers["hasGlobalName"]): boolean { + export function isFileLevelUniqueName( + sourceFile: SourceFile, + name: string, + hasGlobalName?: PrintHandlers["hasGlobalName"], + ): boolean { return !(hasGlobalName && hasGlobalName(name)) && !sourceFile.identifiers.has(name); } @@ -361,7 +401,11 @@ namespace ts { return !nodeIsMissing(node); } - function insertStatementsAfterPrologue(to: T[], from: readonly T[] | undefined, isPrologueDirective: (node: Node) => boolean): T[] { + function insertStatementsAfterPrologue( + to: T[], + from: readonly T[] | undefined, + isPrologueDirective: (node: Node) => boolean, + ): T[] { if (from === undefined || from.length === 0) return to; let statementIndex = 0; // skip all prologue directives to insert at the correct position @@ -374,7 +418,11 @@ namespace ts { return to; } - function insertStatementAfterPrologue(to: T[], statement: T | undefined, isPrologueDirective: (node: Node) => boolean): T[] { + function insertStatementAfterPrologue( + to: T[], + statement: T | undefined, + isPrologueDirective: (node: Node) => boolean, + ): T[] { if (statement === undefined) return to; let statementIndex = 0; // skip all prologue directives to insert at the correct position @@ -394,11 +442,17 @@ namespace ts { /** * Prepends statements to an array while taking care of prologue directives. */ - export function insertStatementsAfterStandardPrologue(to: T[], from: readonly T[] | undefined): T[] { + export function insertStatementsAfterStandardPrologue( + to: T[], + from: readonly T[] | undefined, + ): T[] { return insertStatementsAfterPrologue(to, from, isPrologueDirective); } - export function insertStatementsAfterCustomPrologue(to: T[], from: readonly T[] | undefined): T[] { + export function insertStatementsAfterCustomPrologue( + to: T[], + from: readonly T[] | undefined, + ): T[] { return insertStatementsAfterPrologue(to, from, isAnyPrologueDirective); } @@ -422,26 +476,29 @@ namespace ts { // Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text // so that we don't end up computing comment string and doing match for all // comments if ( - text.charCodeAt(commentPos + 1) === CharacterCodes.slash && - commentPos + 2 < commentEnd && - text.charCodeAt(commentPos + 2) === CharacterCodes.slash + text.charCodeAt(commentPos + 1) === CharacterCodes.slash + && commentPos + 2 < commentEnd + && text.charCodeAt(commentPos + 2) === CharacterCodes.slash ) { const textSubStr = text.substring(commentPos, commentEnd); - return fullTripleSlashReferencePathRegEx.test(textSubStr) || - fullTripleSlashAMDReferencePathRegEx.test(textSubStr) || - fullTripleSlashReferenceTypeReferenceDirectiveRegEx.test(textSubStr) || - defaultLibReferenceRegEx.test(textSubStr) ? - true : false; + return fullTripleSlashReferencePathRegEx.test(textSubStr) + || fullTripleSlashAMDReferencePathRegEx.test(textSubStr) + || fullTripleSlashReferenceTypeReferenceDirectiveRegEx.test(textSubStr) + || defaultLibReferenceRegEx.test(textSubStr) + ? true : false; } return false; } export function isPinnedComment(text: string, start: number) { - return text.charCodeAt(start + 1) === CharacterCodes.asterisk && - text.charCodeAt(start + 2) === CharacterCodes.exclamation; + return text.charCodeAt(start + 1) === CharacterCodes.asterisk + && text.charCodeAt(start + 2) === CharacterCodes.exclamation; } - export function createCommentDirectivesMap(sourceFile: SourceFile, commentDirectives: CommentDirective[]): CommentDirectivesMap { + export function createCommentDirectivesMap( + sourceFile: SourceFile, + commentDirectives: CommentDirective[], + ): CommentDirectivesMap { const directivesByLine = new Map( commentDirectives.map(commentDirective => [ `${getLineAndCharacterOfPosition(sourceFile, commentDirective.range.end).line}`, @@ -455,7 +512,9 @@ namespace ts { function getUnusedExpectations() { return arrayFrom(directivesByLine.entries()) - .filter(([line, directive]) => directive.type === CommentDirectiveType.ExpectError && !usedLines.get(line)) + .filter(([line, directive]) => + directive.type === CommentDirectiveType.ExpectError && !usedLines.get(line) + ) .map(([_, directive]) => directive); } @@ -478,7 +537,12 @@ namespace ts { if (isJSDocNode(node) || node.kind === SyntaxKind.JsxText) { // JsxText cannot actually contain comments, even though the scanner will think it sees comments - return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); + return skipTrivia( + (sourceFile || getSourceFileOfNode(node)).text, + node.pos, + /*stopAfterLineBreak*/ false, + /*stopAtComments*/ true, + ); } if (includeJsDoc && hasJSDocNodes(node)) { @@ -503,7 +567,8 @@ namespace ts { } export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFileLike): number { - const lastDecorator = !nodeIsMissing(node) && canHaveModifiers(node) ? findLast(node.modifiers, isDecorator) : undefined; + const lastDecorator = !nodeIsMissing(node) && canHaveModifiers(node) ? findLast(node.modifiers, isDecorator) + : undefined; if (!lastDecorator) { return getTokenPosOfNode(node, sourceFile); } @@ -511,7 +576,11 @@ namespace ts { return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, lastDecorator.end); } - export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node, includeTrivia = false): string { + export function getSourceTextOfNodeFromSourceFile( + sourceFile: SourceFile, + node: Node, + includeTrivia = false, + ): string { return getTextOfNodeFromSourceText(sourceFile.text, node, includeTrivia); } @@ -520,7 +589,8 @@ namespace ts { } export function isExportNamespaceAsDefaultDeclaration(node: Node): boolean { - return !!(isExportDeclaration(node) && node.exportClause && isNamespaceExport(node.exportClause) && node.exportClause.name.escapedText === "default"); + return !!(isExportDeclaration(node) && node.exportClause && isNamespaceExport(node.exportClause) + && node.exportClause.name.escapedText === "default"); } export function getTextOfNodeFromSourceText(sourceText: string, node: Node, includeTrivia = false): string { @@ -571,11 +641,43 @@ namespace ts { es2015: { Array: ["find", "findIndex", "fill", "copyWithin", "entries", "keys", "values"], RegExp: ["flags", "sticky", "unicode"], - Reflect: ["apply", "construct", "defineProperty", "deleteProperty", "get", " getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf"], + Reflect: [ + "apply", + "construct", + "defineProperty", + "deleteProperty", + "get", + " getOwnPropertyDescriptor", + "getPrototypeOf", + "has", + "isExtensible", + "ownKeys", + "preventExtensions", + "set", + "setPrototypeOf", + ], ArrayConstructor: ["from", "of"], ObjectConstructor: ["assign", "getOwnPropertySymbols", "keys", "is", "setPrototypeOf"], NumberConstructor: ["isFinite", "isInteger", "isNaN", "isSafeInteger", "parseFloat", "parseInt"], - Math: ["clz32", "imul", "sign", "log10", "log2", "log1p", "expm1", "cosh", "sinh", "tanh", "acosh", "asinh", "atanh", "hypot", "trunc", "fround", "cbrt"], + Math: [ + "clz32", + "imul", + "sign", + "log10", + "log2", + "log1p", + "expm1", + "cosh", + "sinh", + "tanh", + "acosh", + "asinh", + "atanh", + "hypot", + "trunc", + "fround", + "cbrt", + ], Map: ["entries", "keys", "values"], Set: ["entries", "keys", "values"], Promise: emptyArray, @@ -585,7 +687,27 @@ namespace ts { WeakSet: ["entries", "keys", "values"], Iterator: emptyArray, AsyncIterator: emptyArray, - String: ["codePointAt", "includes", "endsWith", "normalize", "repeat", "startsWith", "anchor", "big", "blink", "bold", "fixed", "fontcolor", "fontsize", "italics", "link", "small", "strike", "sub", "sup"], + String: [ + "codePointAt", + "includes", + "endsWith", + "normalize", + "repeat", + "startsWith", + "anchor", + "big", + "blink", + "bold", + "fixed", + "fontcolor", + "fontsize", + "italics", + "link", + "small", + "strike", + "sub", + "sup", + ], StringConstructor: ["fromCodePoint", "raw"], }, es2016: { @@ -658,7 +780,11 @@ namespace ts { AllowNumericSeparator = 1 << 3, } - export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile | undefined, flags: GetLiteralTextFlags) { + export function getLiteralText( + node: LiteralLikeNode, + sourceFile: SourceFile | undefined, + flags: GetLiteralTextFlags, + ) { // If we don't need to downlevel and we can reach the original source text using // the node's parent reference, then simply get the text as it was originally written. if (sourceFile && canUseOriginalText(node, flags)) { @@ -669,9 +795,10 @@ namespace ts { // or a (possibly escaped) quoted form of the original text if it's string-like. switch (node.kind) { case SyntaxKind.StringLiteral: { - const escapeText = flags & GetLiteralTextFlags.JsxAttributeEscape ? escapeJsxAttributeString : - flags & GetLiteralTextFlags.NeverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : - escapeNonAsciiString; + const escapeText = flags & GetLiteralTextFlags.JsxAttributeEscape ? escapeJsxAttributeString + : flags & GetLiteralTextFlags.NeverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) + ? escapeString + : escapeNonAsciiString; if ((node as StringLiteral).singleQuote) { return "'" + escapeText(node.text, CharacterCodes.singleQuote) + "'"; } @@ -685,10 +812,13 @@ namespace ts { case SyntaxKind.TemplateTail: { // If a NoSubstitutionTemplateLiteral appears to have a substitution in it, the original text // had to include a backslash: `not \${a} substitution`. - const escapeText = flags & GetLiteralTextFlags.NeverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : - escapeNonAsciiString; + const escapeText = + flags & GetLiteralTextFlags.NeverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) + ? escapeString + : escapeNonAsciiString; - const rawText = (node as TemplateLiteralLikeNode).rawText ?? escapeTemplateSubstitution(escapeText(node.text, CharacterCodes.backtick)); + const rawText = (node as TemplateLiteralLikeNode).rawText + ?? escapeTemplateSubstitution(escapeText(node.text, CharacterCodes.backtick)); switch (node.kind) { case SyntaxKind.NoSubstitutionTemplateLiteral: return "`" + rawText + "`"; @@ -706,7 +836,8 @@ namespace ts { return node.text; case SyntaxKind.RegularExpressionLiteral: if (flags & GetLiteralTextFlags.TerminateUnterminatedLiterals && node.isUnterminated) { - return node.text + (node.text.charCodeAt(node.text.length - 1) === CharacterCodes.backslash ? " /" : "/"); + return node.text + + (node.text.charCodeAt(node.text.length - 1) === CharacterCodes.backslash ? " /" : "/"); } return node.text; } @@ -715,7 +846,10 @@ namespace ts { } function canUseOriginalText(node: LiteralLikeNode, flags: GetLiteralTextFlags): boolean { - if (nodeIsSynthesized(node) || !node.parent || (flags & GetLiteralTextFlags.TerminateUnterminatedLiterals && node.isUnterminated)) { + if ( + nodeIsSynthesized(node) || !node.parent + || (flags & GetLiteralTextFlags.TerminateUnterminatedLiterals && node.isUnterminated) + ) { return false; } @@ -737,8 +871,8 @@ namespace ts { } export function isBlockOrCatchScoped(declaration: Declaration) { - return (getCombinedNodeFlags(declaration) & NodeFlags.BlockScoped) !== 0 || - isCatchClauseVariableDeclarationOrBindingElement(declaration); + return (getCombinedNodeFlags(declaration) & NodeFlags.BlockScoped) !== 0 + || isCatchClauseVariableDeclarationOrBindingElement(declaration); } export function isCatchClauseVariableDeclarationOrBindingElement(declaration: Declaration) { @@ -747,7 +881,8 @@ namespace ts { } export function isAmbientModule(node: Node): node is AmbientModuleDeclaration { - return isModuleDeclaration(node) && (node.name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(node)); + return isModuleDeclaration(node) + && (node.name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(node)); } export function isModuleWithStringLiteralName(node: Node): node is ModuleDeclaration { @@ -779,9 +914,9 @@ namespace ts { } export function isBlockScopedContainerTopLevel(node: Node): boolean { - return node.kind === SyntaxKind.SourceFile || - node.kind === SyntaxKind.ModuleDeclaration || - isFunctionLikeOrClassStaticBlockDeclaration(node); + return node.kind === SyntaxKind.SourceFile + || node.kind === SyntaxKind.ModuleDeclaration + || isFunctionLikeOrClassStaticBlockDeclaration(node); } export function isGlobalScopeAugmentation(module: ModuleDeclaration): boolean { @@ -800,13 +935,16 @@ namespace ts { case SyntaxKind.SourceFile: return isExternalModule(node.parent); case SyntaxKind.ModuleBlock: - return isAmbientModule(node.parent.parent) && isSourceFile(node.parent.parent.parent) && !isExternalModule(node.parent.parent.parent); + return isAmbientModule(node.parent.parent) && isSourceFile(node.parent.parent.parent) + && !isExternalModule(node.parent.parent.parent); } return false; } export function getNonAugmentationDeclaration(symbol: Symbol) { - return symbol.declarations?.find(d => !isExternalModuleAugmentation(d) && !(isModuleDeclaration(d) && isGlobalScopeAugmentation(d))); + return symbol.declarations?.find(d => + !isExternalModuleAugmentation(d) && !(isModuleDeclaration(d) && isGlobalScopeAugmentation(d)) + ); } function isCommonJSContainingModuleKind(kind: ModuleKind) { @@ -814,7 +952,8 @@ namespace ts { } export function isEffectiveExternalModule(node: SourceFile, compilerOptions: CompilerOptions) { - return isExternalModule(node) || compilerOptions.isolatedModules || (isCommonJSContainingModuleKind(getEmitModuleKind(compilerOptions)) && !!node.commonJsModuleIndicator); + return isExternalModule(node) || compilerOptions.isolatedModules + || (isCommonJSContainingModuleKind(getEmitModuleKind(compilerOptions)) && !!node.commonJsModuleIndicator); } /** @@ -888,7 +1027,9 @@ namespace ts { } export function isDeclarationWithTypeParameters(node: Node): node is DeclarationWithTypeParameters; - export function isDeclarationWithTypeParameters(node: DeclarationWithTypeParameters): node is DeclarationWithTypeParameters { + export function isDeclarationWithTypeParameters( + node: DeclarationWithTypeParameters, + ): node is DeclarationWithTypeParameters { switch (node.kind) { case SyntaxKind.JSDocCallbackTag: case SyntaxKind.JSDocTypedefTag: @@ -901,7 +1042,9 @@ namespace ts { } export function isDeclarationWithTypeParameterChildren(node: Node): node is DeclarationWithTypeParameterChildren; - export function isDeclarationWithTypeParameterChildren(node: DeclarationWithTypeParameterChildren): node is DeclarationWithTypeParameterChildren { + export function isDeclarationWithTypeParameterChildren( + node: DeclarationWithTypeParameterChildren, + ): node is DeclarationWithTypeParameterChildren { switch (node.kind) { case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: @@ -960,7 +1103,9 @@ namespace ts { } } - export function hasPossibleExternalModuleReference(node: Node): node is AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall { + export function hasPossibleExternalModuleReference( + node: Node, + ): node is AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall { return isAnyImportOrReExport(node) || isModuleDeclaration(node) || isImportTypeNode(node) || isImportCall(node); } @@ -1007,7 +1152,9 @@ namespace ts { case SyntaxKind.NoSubstitutionTemplateLiteral: return escapeLeadingUnderscores(name.text); case SyntaxKind.ComputedPropertyName: - if (isStringOrNumericLiteralLike(name.expression)) return escapeLeadingUnderscores(name.expression.text); + if (isStringOrNumericLiteralLike(name.expression)) { + return escapeLeadingUnderscores(name.expression.text); + } return undefined; default: return Debug.assertNever(name); @@ -1018,7 +1165,9 @@ namespace ts { return Debug.checkDefined(tryGetTextOfPropertyName(name)); } - export function entityNameToString(name: EntityNameOrEntityNameExpression | JSDocMemberName | JsxTagNameExpression | PrivateIdentifier): string { + export function entityNameToString( + name: EntityNameOrEntityNameExpression | JSDocMemberName | JsxTagNameExpression | PrivateIdentifier, + ): string { switch (name.kind) { case SyntaxKind.ThisKeyword: return "this"; @@ -1041,25 +1190,58 @@ namespace ts { } } - export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { + export function createDiagnosticForNode( + node: Node, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): DiagnosticWithLocation { const sourceFile = getSourceFileOfNode(node); return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2, arg3); } - export function createDiagnosticForNodeArray(sourceFile: SourceFile, nodes: NodeArray, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { + export function createDiagnosticForNodeArray( + sourceFile: SourceFile, + nodes: NodeArray, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): DiagnosticWithLocation { const start = skipTrivia(sourceFile.text, nodes.pos); return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2, arg3); } - export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { + export function createDiagnosticForNodeInSourceFile( + sourceFile: SourceFile, + node: Node, + message: DiagnosticMessage, + arg0?: string | number, + arg1?: string | number, + arg2?: string | number, + arg3?: string | number, + ): DiagnosticWithLocation { const span = getErrorSpanForNode(sourceFile, node); return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2, arg3); } - export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation { + export function createDiagnosticForNodeFromMessageChain( + node: Node, + messageChain: DiagnosticMessageChain, + relatedInformation?: DiagnosticRelatedInformation[], + ): DiagnosticWithLocation { const sourceFile = getSourceFileOfNode(node); const span = getErrorSpanForNode(sourceFile, node); - return createFileDiagnosticFromMessageChain(sourceFile, span.start, span.length, messageChain, relatedInformation); + return createFileDiagnosticFromMessageChain( + sourceFile, + span.start, + span.length, + messageChain, + relatedInformation, + ); } function assertDiagnosticLocation(file: SourceFile | undefined, start: number, length: number) { @@ -1072,7 +1254,13 @@ namespace ts { } } - export function createFileDiagnosticFromMessageChain(file: SourceFile, start: number, length: number, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation { + export function createFileDiagnosticFromMessageChain( + file: SourceFile, + start: number, + length: number, + messageChain: DiagnosticMessageChain, + relatedInformation?: DiagnosticRelatedInformation[], + ): DiagnosticWithLocation { assertDiagnosticLocation(file, start, length); return { file, @@ -1085,7 +1273,11 @@ namespace ts { }; } - export function createDiagnosticForFileFromMessageChain(sourceFile: SourceFile, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation { + export function createDiagnosticForFileFromMessageChain( + sourceFile: SourceFile, + messageChain: DiagnosticMessageChain, + relatedInformation?: DiagnosticRelatedInformation[], + ): DiagnosticWithLocation { return { file: sourceFile, start: 0, @@ -1097,7 +1289,9 @@ namespace ts { }; } - export function createDiagnosticMessageChainFromDiagnostic(diagnostic: DiagnosticRelatedInformation): DiagnosticMessageChain { + export function createDiagnosticMessageChainFromDiagnostic( + diagnostic: DiagnosticRelatedInformation, + ): DiagnosticMessageChain { return typeof diagnostic.messageText === "string" ? { code: diagnostic.code, category: diagnostic.category, @@ -1106,7 +1300,11 @@ namespace ts { } : diagnostic.messageText; } - export function createDiagnosticForRange(sourceFile: SourceFile, range: TextRange, message: DiagnosticMessage): DiagnosticWithLocation { + export function createDiagnosticForRange( + sourceFile: SourceFile, + range: TextRange, + message: DiagnosticMessage, + ): DiagnosticWithLocation { return { file: sourceFile, start: range.pos, @@ -1118,7 +1316,14 @@ namespace ts { } export function getSpanOfTokenAtPosition(sourceFile: SourceFile, pos: number): TextSpan { - const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.languageVariant, sourceFile.text, /*onError:*/ undefined, pos); + const scanner = createScanner( + sourceFile.languageVersion, + /*skipTrivia*/ true, + sourceFile.languageVariant, + sourceFile.text, + /*onError:*/ undefined, + pos, + ); scanner.scan(); const start = scanner.getTokenPos(); return createTextSpanFromBounds(start, scanner.getTextPos()); @@ -1174,7 +1379,8 @@ namespace ts { case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: const start = skipTrivia(sourceFile.text, (node as CaseOrDefaultClause).pos); - const end = (node as CaseOrDefaultClause).statements.length > 0 ? (node as CaseOrDefaultClause).statements[0].pos : (node as CaseOrDefaultClause).end; + const end = (node as CaseOrDefaultClause).statements.length > 0 + ? (node as CaseOrDefaultClause).statements[0].pos : (node as CaseOrDefaultClause).end; return createTextSpanFromBounds(start, end); } @@ -1193,12 +1399,24 @@ namespace ts { // These asserts should all be satisfied for a properly constructed `errorNode`. if (isMissing) { - Debug.assert(pos === errorNode.pos, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); - Debug.assert(pos === errorNode.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); + Debug.assert( + pos === errorNode.pos, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809", + ); + Debug.assert( + pos === errorNode.end, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809", + ); } else { - Debug.assert(pos >= errorNode.pos, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); - Debug.assert(pos <= errorNode.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); + Debug.assert( + pos >= errorNode.pos, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809", + ); + Debug.assert( + pos <= errorNode.end, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809", + ); } return createTextSpanFromBounds(pos, errorNode.end); @@ -1217,7 +1435,8 @@ namespace ts { } export function isDeclarationReadonly(declaration: Declaration): boolean { - return !!(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration, declaration.parent)); + return !!(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly + && !isParameterPropertyDeclaration(declaration, declaration.parent)); } export function isVarConst(node: VariableDeclaration | VariableDeclarationList): boolean { @@ -1229,11 +1448,13 @@ namespace ts { } export function isSuperCall(n: Node): n is SuperCall { - return n.kind === SyntaxKind.CallExpression && (n as CallExpression).expression.kind === SyntaxKind.SuperKeyword; + return n.kind === SyntaxKind.CallExpression + && (n as CallExpression).expression.kind === SyntaxKind.SuperKeyword; } export function isImportCall(n: Node): n is ImportCall { - return n.kind === SyntaxKind.CallExpression && (n as CallExpression).expression.kind === SyntaxKind.ImportKeyword; + return n.kind === SyntaxKind.CallExpression + && (n as CallExpression).expression.kind === SyntaxKind.ImportKeyword; } export function isImportMeta(n: Node): n is ImportMetaProperty { @@ -1276,25 +1497,27 @@ namespace ts { } export function getJSDocCommentRanges(node: Node, text: string) { - const commentRanges = (node.kind === SyntaxKind.Parameter || - node.kind === SyntaxKind.TypeParameter || - node.kind === SyntaxKind.FunctionExpression || - node.kind === SyntaxKind.ArrowFunction || - node.kind === SyntaxKind.ParenthesizedExpression || - node.kind === SyntaxKind.VariableDeclaration || - node.kind === SyntaxKind.ExportSpecifier) ? - concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) : - getLeadingCommentRanges(text, node.pos); + const commentRanges = (node.kind === SyntaxKind.Parameter + || node.kind === SyntaxKind.TypeParameter + || node.kind === SyntaxKind.FunctionExpression + || node.kind === SyntaxKind.ArrowFunction + || node.kind === SyntaxKind.ParenthesizedExpression + || node.kind === SyntaxKind.VariableDeclaration + || node.kind === SyntaxKind.ExportSpecifier) + ? concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) + : getLeadingCommentRanges(text, node.pos); // True if the comment starts with '/**' but not if it is '/**/' return filter(commentRanges, comment => - text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk && - text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk && - text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash); + text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk + && text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk + && text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash); } export const fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*/; - const fullTripleSlashReferenceTypeReferenceDirectiveRegEx = /^(\/\/\/\s*/; - export const fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*/; + const fullTripleSlashReferenceTypeReferenceDirectiveRegEx = + /^(\/\/\/\s*/; + export const fullTripleSlashAMDReferencePathRegEx = + /^(\/\/\/\s*/; const defaultLibReferenceRegEx = /^(\/\/\/\s*/; export function isPartOfTypeNode(node: Node): boolean { @@ -1328,11 +1551,18 @@ namespace ts { if (node.parent.kind === SyntaxKind.QualifiedName && (node.parent as QualifiedName).right === node) { node = node.parent; } - else if (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent as PropertyAccessExpression).name === node) { + else if ( + node.parent.kind === SyntaxKind.PropertyAccessExpression + && (node.parent as PropertyAccessExpression).name === node + ) { node = node.parent; } // At this point, node is either a qualified name or an identifier - Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression, "'node' was expected to be a qualified name, identifier or property access in 'isPartOfTypeNode'."); + Debug.assert( + node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName + || node.kind === SyntaxKind.PropertyAccessExpression, + "'node' was expected to be a qualified name, identifier or property access in 'isPartOfTypeNode'.", + ); // falls through case SyntaxKind.QualifiedName: @@ -1356,7 +1586,8 @@ namespace ts { } switch (parent.kind) { case SyntaxKind.ExpressionWithTypeArguments: - return isHeritageClause(parent.parent) && !isExpressionWithTypeArgumentsInClassExtendsClause(parent); + return isHeritageClause(parent.parent) + && !isExpressionWithTypeArgumentsInClassExtendsClause(parent); case SyntaxKind.TypeParameter: return node === (parent as TypeParameterDeclaration).constraint; case SyntaxKind.JSDocTemplateTag: @@ -1406,7 +1637,10 @@ namespace ts { // Warning: This has the same semantics as the forEach family of functions, // in that traversal terminates in the event that 'visitor' supplies a truthy value. - export function forEachReturnStatement(body: Block | Statement, visitor: (stmt: ReturnStatement) => T): T | undefined { + export function forEachReturnStatement( + body: Block | Statement, + visitor: (stmt: ReturnStatement) => T, + ): T | undefined { return traverse(body); function traverse(node: Node): T | undefined { @@ -1488,7 +1722,9 @@ namespace ts { } } - export function getMembersOfDeclaration(node: Declaration): NodeArray | undefined { + export function getMembersOfDeclaration( + node: Declaration, + ): NodeArray | undefined { switch (node.kind) { case SyntaxKind.InterfaceDeclaration: case SyntaxKind.ClassDeclaration: @@ -1528,19 +1764,23 @@ namespace ts { export function isCommonJsExportedExpression(node: Node) { if (!isInJSFile(node)) return false; - return (isObjectLiteralExpression(node.parent) && isBinaryExpression(node.parent.parent) && getAssignmentDeclarationKind(node.parent.parent) === AssignmentDeclarationKind.ModuleExports) || - isCommonJsExportPropertyAssignment(node.parent); + return (isObjectLiteralExpression(node.parent) && isBinaryExpression(node.parent.parent) + && getAssignmentDeclarationKind(node.parent.parent) === AssignmentDeclarationKind.ModuleExports) + || isCommonJsExportPropertyAssignment(node.parent); } export function isCommonJsExportPropertyAssignment(node: Node) { if (!isInJSFile(node)) return false; - return (isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ExportsProperty); + return (isBinaryExpression(node) + && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ExportsProperty); } export function isValidESSymbolDeclaration(node: Node): boolean { - return (isVariableDeclaration(node) ? isVarConst(node) && isIdentifier(node.name) && isVariableDeclarationInVariableStatement(node) : - isPropertyDeclaration(node) ? hasEffectiveReadonlyModifier(node) && hasStaticModifier(node) : - isPropertySignature(node) && hasEffectiveReadonlyModifier(node)) || isCommonJsExportPropertyAssignment(node); + return (isVariableDeclaration(node) + ? isVarConst(node) && isIdentifier(node.name) && isVariableDeclarationInVariableStatement(node) + : isPropertyDeclaration(node) ? hasEffectiveReadonlyModifier(node) && hasStaticModifier(node) + : isPropertySignature(node) && hasEffectiveReadonlyModifier(node)) + || isCommonJsExportPropertyAssignment(node); } export function introducesArgumentsExoticObject(node: Node) { @@ -1557,7 +1797,10 @@ namespace ts { return false; } - export function unwrapInnermostStatementOfLabel(node: LabeledStatement, beforeUnwrapLabelCallback?: (node: LabeledStatement) => void): Statement { + export function unwrapInnermostStatementOfLabel( + node: LabeledStatement, + beforeUnwrapLabelCallback?: (node: LabeledStatement) => void, + ): Statement { while (true) { if (beforeUnwrapLabelCallback) { beforeUnwrapLabelCallback(node); @@ -1574,13 +1817,15 @@ namespace ts { } export function isObjectLiteralMethod(node: Node): node is MethodDeclaration { - return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression; + return node && node.kind === SyntaxKind.MethodDeclaration + && node.parent.kind === SyntaxKind.ObjectLiteralExpression; } export function isObjectLiteralOrClassExpressionMethodOrAccessor(node: Node): node is MethodDeclaration { - return (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor) && - (node.parent.kind === SyntaxKind.ObjectLiteralExpression || - node.parent.kind === SyntaxKind.ClassExpression); + return (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.GetAccessor + || node.kind === SyntaxKind.SetAccessor) + && (node.parent.kind === SyntaxKind.ObjectLiteralExpression + || node.parent.kind === SyntaxKind.ClassExpression); } export function isIdentifierTypePredicate(predicate: TypePredicate): predicate is IdentifierTypePredicate { @@ -1591,7 +1836,11 @@ namespace ts { return predicate && predicate.kind === TypePredicateKind.This; } - export function getPropertyAssignment(objectLiteral: ObjectLiteralExpression, key: string, key2?: string): readonly PropertyAssignment[] { + export function getPropertyAssignment( + objectLiteral: ObjectLiteralExpression, + key: string, + key2?: string, + ): readonly PropertyAssignment[] { return objectLiteral.properties.filter((property): property is PropertyAssignment => { if (property.kind === SyntaxKind.PropertyAssignment) { const propName = tryGetTextOfPropertyName(property.name); @@ -1601,28 +1850,55 @@ namespace ts { }); } - export function getPropertyArrayElementValue(objectLiteral: ObjectLiteralExpression, propKey: string, elementValue: string): StringLiteral | undefined { - return firstDefined(getPropertyAssignment(objectLiteral, propKey), property => - isArrayLiteralExpression(property.initializer) ? - find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) : - undefined); + export function getPropertyArrayElementValue( + objectLiteral: ObjectLiteralExpression, + propKey: string, + elementValue: string, + ): StringLiteral | undefined { + return firstDefined( + getPropertyAssignment(objectLiteral, propKey), + property => + isArrayLiteralExpression(property.initializer) + ? find( + property.initializer.elements, + (element): element is StringLiteral => + isStringLiteral(element) && element.text === elementValue, + ) + : undefined, + ); } - export function getTsConfigObjectLiteralExpression(tsConfigSourceFile: TsConfigSourceFile | undefined): ObjectLiteralExpression | undefined { + export function getTsConfigObjectLiteralExpression( + tsConfigSourceFile: TsConfigSourceFile | undefined, + ): ObjectLiteralExpression | undefined { if (tsConfigSourceFile && tsConfigSourceFile.statements.length) { const expression = tsConfigSourceFile.statements[0].expression; return tryCast(expression, isObjectLiteralExpression); } } - export function getTsConfigPropArrayElementValue(tsConfigSourceFile: TsConfigSourceFile | undefined, propKey: string, elementValue: string): StringLiteral | undefined { - return firstDefined(getTsConfigPropArray(tsConfigSourceFile, propKey), property => - isArrayLiteralExpression(property.initializer) ? - find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) : - undefined); + export function getTsConfigPropArrayElementValue( + tsConfigSourceFile: TsConfigSourceFile | undefined, + propKey: string, + elementValue: string, + ): StringLiteral | undefined { + return firstDefined( + getTsConfigPropArray(tsConfigSourceFile, propKey), + property => + isArrayLiteralExpression(property.initializer) + ? find( + property.initializer.elements, + (element): element is StringLiteral => + isStringLiteral(element) && element.text === elementValue, + ) + : undefined, + ); } - export function getTsConfigPropArray(tsConfigSourceFile: TsConfigSourceFile | undefined, propKey: string): readonly PropertyAssignment[] { + export function getTsConfigPropArray( + tsConfigSourceFile: TsConfigSourceFile | undefined, + propKey: string, + ): readonly PropertyAssignment[] { const jsonObjectLiteral = getTsConfigObjectLiteralExpression(tsConfigSourceFile); return jsonObjectLiteral ? getPropertyAssignment(jsonObjectLiteral, propKey) : emptyArray; } @@ -1648,7 +1924,9 @@ namespace ts { }); } - export function getContainingFunctionOrClassStaticBlock(node: Node): SignatureDeclaration | ClassStaticBlockDeclaration | undefined { + export function getContainingFunctionOrClassStaticBlock( + node: Node, + ): SignatureDeclaration | ClassStaticBlockDeclaration | undefined { return findAncestor(node.parent, isFunctionLikeOrClassStaticBlockDeclaration); } @@ -1745,7 +2023,10 @@ namespace ts { export function isInTopLevelContext(node: Node) { // The name of a class or function declaration is a BindingIdentifier in its surrounding scope. - if (isIdentifier(node) && (isClassDeclaration(node.parent) || isFunctionDeclaration(node.parent)) && node.parent.name === node) { + if ( + isIdentifier(node) && (isClassDeclaration(node.parent) || isFunctionDeclaration(node.parent)) + && node.parent.name === node + ) { node = node.parent; } const container = getThisContainer(node, /*includeArrowFunctions*/ true); @@ -1973,9 +2254,9 @@ namespace ts { export function isJSXTagName(node: Node) { const { parent } = node; if ( - parent.kind === SyntaxKind.JsxOpeningElement || - parent.kind === SyntaxKind.JsxSelfClosingElement || - parent.kind === SyntaxKind.JsxClosingElement + parent.kind === SyntaxKind.JsxOpeningElement + || parent.kind === SyntaxKind.JsxSelfClosingElement + || parent.kind === SyntaxKind.JsxClosingElement ) { return (parent as JsxOpeningLikeElement).tagName === node; } @@ -2027,16 +2308,22 @@ namespace ts { while (node.parent.kind === SyntaxKind.QualifiedName) { node = node.parent; } - return node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node); + return node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) + || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node); case SyntaxKind.JSDocMemberName: while (isJSDocMemberName(node.parent)) { node = node.parent; } - return node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node); + return node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) + || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node); case SyntaxKind.PrivateIdentifier: - return isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.InKeyword; + return isBinaryExpression(node.parent) && node.parent.left === node + && node.parent.operatorToken.kind === SyntaxKind.InKeyword; case SyntaxKind.Identifier: - if (node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node)) { + if ( + node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) + || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node) + ) { return true; } // falls through @@ -2075,14 +2362,16 @@ namespace ts { return (parent as ExpressionStatement).expression === node; case SyntaxKind.ForStatement: const forStatement = parent as ForStatement; - return (forStatement.initializer === node && forStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) || - forStatement.condition === node || - forStatement.incrementor === node; + return (forStatement.initializer === node + && forStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) + || forStatement.condition === node + || forStatement.incrementor === node; case SyntaxKind.ForInStatement: case SyntaxKind.ForOfStatement: const forInStatement = parent as ForInStatement | ForOfStatement; - return (forInStatement.initializer === node && forInStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) || - forInStatement.expression === node; + return (forInStatement.initializer === node + && forInStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) + || forInStatement.expression === node; case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: return node === (parent as AssertionExpression).expression; @@ -2117,8 +2406,11 @@ namespace ts { return isNamespaceExport(node) && !!node.parent.moduleSpecifier; } - export function isExternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference; } { - return node.kind === SyntaxKind.ImportEqualsDeclaration && (node as ImportEqualsDeclaration).moduleReference.kind === SyntaxKind.ExternalModuleReference; + export function isExternalModuleImportEqualsDeclaration( + node: Node, + ): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference; } { + return node.kind === SyntaxKind.ImportEqualsDeclaration + && (node as ImportEqualsDeclaration).moduleReference.kind === SyntaxKind.ExternalModuleReference; } export function getExternalModuleImportEqualsDeclarationExpression(node: Node) { @@ -2127,11 +2419,13 @@ namespace ts { } export function getExternalModuleRequireArgument(node: Node) { - return isVariableDeclarationInitializedToBareOrAccessedRequire(node) && (getLeftmostAccessExpression(node.initializer) as CallExpression).arguments[0] as StringLiteral; + return isVariableDeclarationInitializedToBareOrAccessedRequire(node) + && (getLeftmostAccessExpression(node.initializer) as CallExpression).arguments[0] as StringLiteral; } export function isInternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration { - return node.kind === SyntaxKind.ImportEqualsDeclaration && (node as ImportEqualsDeclaration).moduleReference.kind !== SyntaxKind.ExternalModuleReference; + return node.kind === SyntaxKind.ImportEqualsDeclaration + && (node as ImportEqualsDeclaration).moduleReference.kind !== SyntaxKind.ExternalModuleReference; } export function isSourceFileJS(file: SourceFile): boolean { @@ -2159,11 +2453,12 @@ namespace ts { } export function isJSDocIndexSignature(node: TypeReferenceNode | ExpressionWithTypeArguments) { - return isTypeReferenceNode(node) && - isIdentifier(node.typeName) && - node.typeName.escapedText === "Object" && - node.typeArguments && node.typeArguments.length === 2 && - (node.typeArguments[0].kind === SyntaxKind.StringKeyword || node.typeArguments[0].kind === SyntaxKind.NumberKeyword); + return isTypeReferenceNode(node) + && isIdentifier(node.typeName) + && node.typeName.escapedText === "Object" + && node.typeArguments && node.typeArguments.length === 2 + && (node.typeArguments[0].kind === SyntaxKind.StringKeyword + || node.typeArguments[0].kind === SyntaxKind.NumberKeyword); } /** @@ -2171,9 +2466,18 @@ namespace ts { * exactly one argument (of the form 'require("name")'). * This function does not test if the node is in a JavaScript file or not. */ - export function isRequireCall(callExpression: Node, requireStringLiteralLikeArgument: true): callExpression is RequireOrImportCall & { expression: Identifier; arguments: [StringLiteralLike]; }; - export function isRequireCall(callExpression: Node, requireStringLiteralLikeArgument: boolean): callExpression is CallExpression; - export function isRequireCall(callExpression: Node, requireStringLiteralLikeArgument: boolean): callExpression is CallExpression { + export function isRequireCall( + callExpression: Node, + requireStringLiteralLikeArgument: true, + ): callExpression is RequireOrImportCall & { expression: Identifier; arguments: [StringLiteralLike]; }; + export function isRequireCall( + callExpression: Node, + requireStringLiteralLikeArgument: boolean, + ): callExpression is CallExpression; + export function isRequireCall( + callExpression: Node, + requireStringLiteralLikeArgument: boolean, + ): callExpression is CallExpression { if (callExpression.kind !== SyntaxKind.CallExpression) { return false; } @@ -2194,21 +2498,28 @@ namespace ts { * Returns true if the node is a VariableDeclaration initialized to a require call (see `isRequireCall`). * This function does not test if the node is in a JavaScript file or not. */ - export function isVariableDeclarationInitializedToRequire(node: Node): node is VariableDeclarationInitializedTo { + export function isVariableDeclarationInitializedToRequire( + node: Node, + ): node is VariableDeclarationInitializedTo { return isVariableDeclarationInitializedWithRequireHelper(node, /*allowAccessedRequire*/ false); } /** * Like {@link isVariableDeclarationInitializedToRequire} but allows things like `require("...").foo.bar` or `require("...")["baz"]`. */ - export function isVariableDeclarationInitializedToBareOrAccessedRequire(node: Node): node is VariableDeclarationInitializedTo { + export function isVariableDeclarationInitializedToBareOrAccessedRequire( + node: Node, + ): node is VariableDeclarationInitializedTo { return isVariableDeclarationInitializedWithRequireHelper(node, /*allowAccessedRequire*/ true); } function isVariableDeclarationInitializedWithRequireHelper(node: Node, allowAccessedRequire: boolean) { - return isVariableDeclaration(node) && - !!node.initializer && - isRequireCall(allowAccessedRequire ? getLeftmostAccessExpression(node.initializer) : node.initializer, /*requireStringLiteralLikeArgument*/ true); + return isVariableDeclaration(node) + && !!node.initializer + && isRequireCall( + allowAccessedRequire ? getLeftmostAccessExpression(node.initializer) : node.initializer, + /*requireStringLiteralLikeArgument*/ true, + ); } export function isRequireVariableStatement(node: Node): node is RequireVariableStatement { @@ -2232,10 +2543,11 @@ namespace ts { /** Get the initializer, taking into account defaulted Javascript initializers */ export function getEffectiveInitializer(node: HasExpressionInitializer) { if ( - isInJSFile(node) && node.initializer && - isBinaryExpression(node.initializer) && - (node.initializer.operatorToken.kind === SyntaxKind.BarBarToken || node.initializer.operatorToken.kind === SyntaxKind.QuestionQuestionToken) && - node.name && isEntityNameExpression(node.name) && isSameEntityName(node.name, node.initializer.left) + isInJSFile(node) && node.initializer + && isBinaryExpression(node.initializer) + && (node.initializer.operatorToken.kind === SyntaxKind.BarBarToken + || node.initializer.operatorToken.kind === SyntaxKind.QuestionQuestionToken) + && node.name && isEntityNameExpression(node.name) && isSameEntityName(node.name, node.initializer.left) ) { return node.initializer.right; } @@ -2250,11 +2562,11 @@ namespace ts { function hasExpandoValueProperty(node: ObjectLiteralExpression, isPrototypeAssignment: boolean) { return forEach(node.properties, p => - isPropertyAssignment(p) && - isIdentifier(p.name) && - p.name.escapedText === "value" && - p.initializer && - getExpandoInitializer(p.initializer, isPrototypeAssignment)); + isPropertyAssignment(p) + && isIdentifier(p.name) + && p.name.escapedText === "value" + && p.initializer + && getExpandoInitializer(p.initializer, isPrototypeAssignment)); } /** @@ -2262,10 +2574,13 @@ namespace ts { * We treat the right hand side of assignments with container-like initializers as declarations. */ export function getAssignedExpandoInitializer(node: Node | undefined): Expression | undefined { - if (node && node.parent && isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + node && node.parent && isBinaryExpression(node.parent) + && node.parent.operatorToken.kind === SyntaxKind.EqualsToken + ) { const isPrototypeAssignment = isPrototypeAccess(node.parent.left); - return getExpandoInitializer(node.parent.right, isPrototypeAssignment) || - getDefaultedExpandoInitializer(node.parent.left, node.parent.right, isPrototypeAssignment); + return getExpandoInitializer(node.parent.right, isPrototypeAssignment) + || getDefaultedExpandoInitializer(node.parent.left, node.parent.right, isPrototypeAssignment); } if (node && isCallExpression(node) && isBindableObjectDefinePropertyCall(node)) { const result = hasExpandoValueProperty(node.arguments[2], node.arguments[1].text === "prototype"); @@ -2288,12 +2603,13 @@ namespace ts { export function getExpandoInitializer(initializer: Node, isPrototypeAssignment: boolean): Expression | undefined { if (isCallExpression(initializer)) { const e = skipParentheses(initializer.expression); - return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer : undefined; + return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer + : undefined; } if ( - initializer.kind === SyntaxKind.FunctionExpression || - initializer.kind === SyntaxKind.ClassExpression || - initializer.kind === SyntaxKind.ArrowFunction + initializer.kind === SyntaxKind.FunctionExpression + || initializer.kind === SyntaxKind.ClassExpression + || initializer.kind === SyntaxKind.ArrowFunction ) { return initializer as Expression; } @@ -2312,7 +2628,8 @@ namespace ts { */ function getDefaultedExpandoInitializer(name: Expression, initializer: Expression, isPrototypeAssignment: boolean) { const e = isBinaryExpression(initializer) - && (initializer.operatorToken.kind === SyntaxKind.BarBarToken || initializer.operatorToken.kind === SyntaxKind.QuestionQuestionToken) + && (initializer.operatorToken.kind === SyntaxKind.BarBarToken + || initializer.operatorToken.kind === SyntaxKind.QuestionQuestionToken) && getExpandoInitializer(initializer.right, isPrototypeAssignment); if (e && isSameEntityName(name, initializer.left)) { return e; @@ -2320,16 +2637,20 @@ namespace ts { } export function isDefaultedExpandoInitializer(node: BinaryExpression) { - const name = isVariableDeclaration(node.parent) ? node.parent.name : - isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken ? node.parent.left : - undefined; - return name && getExpandoInitializer(node.right, isPrototypeAccess(name)) && isEntityNameExpression(name) && isSameEntityName(name, node.left); + const name = isVariableDeclaration(node.parent) ? node.parent.name + : isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken + ? node.parent.left + : undefined; + return name && getExpandoInitializer(node.right, isPrototypeAccess(name)) && isEntityNameExpression(name) + && isSameEntityName(name, node.left); } /** Given an expando initializer, return its declaration name, or the left-hand side of the assignment if it's part of an assignment declaration. */ export function getNameOfExpando(node: Declaration): DeclarationName | undefined { if (isBinaryExpression(node.parent)) { - const parent = ((node.parent.operatorToken.kind === SyntaxKind.BarBarToken || node.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken) && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent; + const parent = ((node.parent.operatorToken.kind === SyntaxKind.BarBarToken + || node.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken) + && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent; if (parent.operatorToken.kind === SyntaxKind.EqualsToken && isIdentifier(parent.left)) { return parent.left; } @@ -2353,12 +2674,12 @@ namespace ts { return getTextOfIdentifierOrLiteral(name) === getTextOfIdentifierOrLiteral(initializer); } if ( - isMemberName(name) && isLiteralLikeAccess(initializer) && - (initializer.expression.kind === SyntaxKind.ThisKeyword || - isIdentifier(initializer.expression) && - (initializer.expression.escapedText === "window" || - initializer.expression.escapedText === "self" || - initializer.expression.escapedText === "global")) + isMemberName(name) && isLiteralLikeAccess(initializer) + && (initializer.expression.kind === SyntaxKind.ThisKeyword + || isIdentifier(initializer.expression) + && (initializer.expression.escapedText === "window" + || initializer.expression.escapedText === "self" + || initializer.expression.escapedText === "global")) ) { return isSameEntityName(name, getNameOrArgument(initializer)); } @@ -2384,7 +2705,9 @@ namespace ts { return isIdentifier(node) && node.escapedText === "module"; } - export function isModuleExportsAccessExpression(node: Node): node is LiteralLikeElementAccessExpression & { expression: Identifier; } { + export function isModuleExportsAccessExpression( + node: Node, + ): node is LiteralLikeElementAccessExpression & { expression: Identifier; } { return (isPropertyAccessExpression(node) || isLiteralLikeElementAccess(node)) && isModuleIdentifier(node.expression) && getElementOrPropertyAccessName(node) === "exports"; @@ -2394,21 +2717,24 @@ namespace ts { /// assignments we treat as special in the binder export function getAssignmentDeclarationKind(expr: BinaryExpression | CallExpression): AssignmentDeclarationKind { const special = getAssignmentDeclarationKindWorker(expr); - return special === AssignmentDeclarationKind.Property || isInJSFile(expr) ? special : AssignmentDeclarationKind.None; + return special === AssignmentDeclarationKind.Property || isInJSFile(expr) ? special + : AssignmentDeclarationKind.None; } export function isBindableObjectDefinePropertyCall(expr: CallExpression): expr is BindableObjectDefinePropertyCall { - return length(expr.arguments) === 3 && - isPropertyAccessExpression(expr.expression) && - isIdentifier(expr.expression.expression) && - idText(expr.expression.expression) === "Object" && - idText(expr.expression.name) === "defineProperty" && - isStringOrNumericLiteralLike(expr.arguments[1]) && - isBindableStaticNameExpression(expr.arguments[0], /*excludeThisKeyword*/ true); + return length(expr.arguments) === 3 + && isPropertyAccessExpression(expr.expression) + && isIdentifier(expr.expression.expression) + && idText(expr.expression.expression) === "Object" + && idText(expr.expression.name) === "defineProperty" + && isStringOrNumericLiteralLike(expr.arguments[1]) + && isBindableStaticNameExpression(expr.arguments[0], /*excludeThisKeyword*/ true); } /** x.y OR x[0] */ - export function isLiteralLikeAccess(node: Node): node is LiteralLikeElementAccessExpression | PropertyAccessExpression { + export function isLiteralLikeAccess( + node: Node, + ): node is LiteralLikeElementAccessExpression | PropertyAccessExpression { return isPropertyAccessExpression(node) || isLiteralLikeElementAccess(node); } @@ -2418,20 +2744,32 @@ namespace ts { } /** Any series of property and element accesses. */ - export function isBindableStaticAccessExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticAccessExpression { - return isPropertyAccessExpression(node) && (!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword || isIdentifier(node.name) && isBindableStaticNameExpression(node.expression, /*excludeThisKeyword*/ true)) + export function isBindableStaticAccessExpression( + node: Node, + excludeThisKeyword?: boolean, + ): node is BindableStaticAccessExpression { + return isPropertyAccessExpression(node) + && (!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword + || isIdentifier(node.name) + && isBindableStaticNameExpression(node.expression, /*excludeThisKeyword*/ true)) || isBindableStaticElementAccessExpression(node, excludeThisKeyword); } /** Any series of property and element accesses, ending in a literal element access */ - export function isBindableStaticElementAccessExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticElementAccessExpression { + export function isBindableStaticElementAccessExpression( + node: Node, + excludeThisKeyword?: boolean, + ): node is BindableStaticElementAccessExpression { return isLiteralLikeElementAccess(node) - && ((!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword) || - isEntityNameExpression(node.expression) || - isBindableStaticAccessExpression(node.expression, /*excludeThisKeyword*/ true)); + && ((!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword) + || isEntityNameExpression(node.expression) + || isBindableStaticAccessExpression(node.expression, /*excludeThisKeyword*/ true)); } - export function isBindableStaticNameExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticNameExpression { + export function isBindableStaticNameExpression( + node: Node, + excludeThisKeyword?: boolean, + ): node is BindableStaticNameExpression { return isEntityNameExpression(node) || isBindableStaticAccessExpression(node, excludeThisKeyword); } @@ -2451,15 +2789,25 @@ namespace ts { if (isExportsIdentifier(entityName) || isModuleExportsAccessExpression(entityName)) { return AssignmentDeclarationKind.ObjectDefinePropertyExports; } - if (isBindableStaticAccessExpression(entityName) && getElementOrPropertyAccessName(entityName) === "prototype") { + if ( + isBindableStaticAccessExpression(entityName) + && getElementOrPropertyAccessName(entityName) === "prototype" + ) { return AssignmentDeclarationKind.ObjectDefinePrototypeProperty; } return AssignmentDeclarationKind.ObjectDefinePropertyValue; } - if (expr.operatorToken.kind !== SyntaxKind.EqualsToken || !isAccessExpression(expr.left) || isVoidZero(getRightMostAssignedExpression(expr))) { + if ( + expr.operatorToken.kind !== SyntaxKind.EqualsToken || !isAccessExpression(expr.left) + || isVoidZero(getRightMostAssignedExpression(expr)) + ) { return AssignmentDeclarationKind.None; } - if (isBindableStaticNameExpression(expr.left.expression, /*excludeThisKeyword*/ true) && getElementOrPropertyAccessName(expr.left) === "prototype" && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr))) { + if ( + isBindableStaticNameExpression(expr.left.expression, /*excludeThisKeyword*/ true) + && getElementOrPropertyAccessName(expr.left) === "prototype" + && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr)) + ) { // F.prototype = { ... } return AssignmentDeclarationKind.Prototype; } @@ -2475,7 +2823,9 @@ namespace ts { * throughout late binding handling as well, which is awkward (but ultimately probably doable if there is demand) */ /* @internal */ - export function getElementOrPropertyAccessArgumentExpressionOrName(node: AccessExpression): Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ElementAccessExpression | undefined { + export function getElementOrPropertyAccessArgumentExpressionOrName( + node: AccessExpression, + ): Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ElementAccessExpression | undefined { if (isPropertyAccessExpression(node)) { return node.name; } @@ -2487,7 +2837,9 @@ namespace ts { } /* @internal */ - export function getElementOrPropertyAccessName(node: LiteralLikeElementAccessExpression | PropertyAccessExpression): __String; + export function getElementOrPropertyAccessName( + node: LiteralLikeElementAccessExpression | PropertyAccessExpression, + ): __String; export function getElementOrPropertyAccessName(node: AccessExpression): __String | undefined; export function getElementOrPropertyAccessName(node: AccessExpression): __String | undefined { const name = getElementOrPropertyAccessArgumentExpressionOrName(node); @@ -2522,15 +2874,18 @@ namespace ts { } const id = nextToLast.expression; if ( - (id.escapedText === "exports" || - id.escapedText === "module" && getElementOrPropertyAccessName(nextToLast) === "exports") && + (id.escapedText === "exports" + || id.escapedText === "module" && getElementOrPropertyAccessName(nextToLast) === "exports") // ExportsProperty does not support binding with computed names - isBindableStaticAccessExpression(lhs) + && isBindableStaticAccessExpression(lhs) ) { // exports.name = expr OR module.exports.name = expr OR exports["name"] = expr ... return AssignmentDeclarationKind.ExportsProperty; } - if (isBindableStaticNameExpression(lhs, /*excludeThisKeyword*/ true) || (isElementAccessExpression(lhs) && isDynamicName(lhs))) { + if ( + isBindableStaticNameExpression(lhs, /*excludeThisKeyword*/ true) + || (isElementAccessExpression(lhs) && isDynamicName(lhs)) + ) { // F.G...x = expr return AssignmentDeclarationKind.Property; } @@ -2547,23 +2902,26 @@ namespace ts { } export function isPrototypePropertyAssignment(node: Node): node is BinaryExpression { - return isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.PrototypeProperty; + return isBinaryExpression(node) + && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.PrototypeProperty; } - export function isSpecialPropertyDeclaration(expr: PropertyAccessExpression | ElementAccessExpression): expr is PropertyAccessExpression | LiteralLikeElementAccessExpression { - return isInJSFile(expr) && - expr.parent && expr.parent.kind === SyntaxKind.ExpressionStatement && - (!isElementAccessExpression(expr) || isLiteralLikeElementAccess(expr)) && - !!getJSDocTypeTag(expr.parent); + export function isSpecialPropertyDeclaration( + expr: PropertyAccessExpression | ElementAccessExpression, + ): expr is PropertyAccessExpression | LiteralLikeElementAccessExpression { + return isInJSFile(expr) + && expr.parent && expr.parent.kind === SyntaxKind.ExpressionStatement + && (!isElementAccessExpression(expr) || isLiteralLikeElementAccess(expr)) + && !!getJSDocTypeTag(expr.parent); } export function setValueDeclaration(symbol: Symbol, node: Declaration): void { const { valueDeclaration } = symbol; if ( - !valueDeclaration || - !(node.flags & NodeFlags.Ambient && !(valueDeclaration.flags & NodeFlags.Ambient)) && - (isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) || - (valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration)) + !valueDeclaration + || !(node.flags & NodeFlags.Ambient && !(valueDeclaration.flags & NodeFlags.Ambient)) + && (isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) + || (valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration)) ) { // other kinds of value declarations take precedence over modules and assignment declarations symbol.valueDeclaration = node; @@ -2575,17 +2933,27 @@ namespace ts { return false; } const decl = symbol.valueDeclaration; - return decl.kind === SyntaxKind.FunctionDeclaration || isVariableDeclaration(decl) && decl.initializer && isFunctionLike(decl.initializer); + return decl.kind === SyntaxKind.FunctionDeclaration + || isVariableDeclaration(decl) && decl.initializer && isFunctionLike(decl.initializer); } - export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire): StringLiteralLike | undefined { + export function tryGetModuleSpecifierFromDeclaration( + node: AnyImportOrBareOrAccessedRequire, + ): StringLiteralLike | undefined { switch (node.kind) { case SyntaxKind.VariableDeclaration: - return findAncestor(node.initializer, (node): node is RequireOrImportCall => isRequireCall(node, /*requireStringLiteralLikeArgument*/ true))?.arguments[0]; + return findAncestor( + node.initializer, + (node): node is RequireOrImportCall => + isRequireCall(node, /*requireStringLiteralLikeArgument*/ true), + )?.arguments[0]; case SyntaxKind.ImportDeclaration: return tryCast(node.moduleSpecifier, isStringLiteralLike); case SyntaxKind.ImportEqualsDeclaration: - return tryCast(tryCast(node.moduleReference, isExternalModuleReference)?.expression, isStringLiteralLike); + return tryCast( + tryCast(node.moduleReference, isExternalModuleReference)?.expression, + isStringLiteralLike, + ); default: Debug.assertNever(node); } @@ -2603,7 +2971,8 @@ namespace ts { case SyntaxKind.ExternalModuleReference: return (node.parent as ExternalModuleReference).parent as AnyValidImportOrReExport; case SyntaxKind.CallExpression: - return isImportCall(node.parent) || isRequireCall(node.parent, /*checkArg*/ false) ? node.parent as RequireOrImportCall : undefined; + return isImportCall(node.parent) || isRequireCall(node.parent, /*checkArg*/ false) + ? node.parent as RequireOrImportCall : undefined; case SyntaxKind.LiteralType: Debug.assert(isStringLiteral(node)); return tryCast(node.parent.parent, isImportTypeNode) as ValidImportTypeNode | undefined; @@ -2612,13 +2981,16 @@ namespace ts { } } - export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode | ImportCall | ModuleDeclaration): Expression | undefined { + export function getExternalModuleName( + node: AnyImportOrReExport | ImportTypeNode | ImportCall | ModuleDeclaration, + ): Expression | undefined { switch (node.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: return node.moduleSpecifier; case SyntaxKind.ImportEqualsDeclaration: - return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? node.moduleReference.expression : undefined; + return node.moduleReference.kind === SyntaxKind.ExternalModuleReference + ? node.moduleReference.expression : undefined; case SyntaxKind.ImportType: return isLiteralImportTypeNode(node) ? node.argument.literal : undefined; case SyntaxKind.CallExpression: @@ -2630,7 +3002,9 @@ namespace ts { } } - export function getNamespaceDeclarationNode(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): ImportEqualsDeclaration | NamespaceImport | NamespaceExport | undefined { + export function getNamespaceDeclarationNode( + node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration, + ): ImportEqualsDeclaration | NamespaceImport | NamespaceExport | undefined { switch (node.kind) { case SyntaxKind.ImportDeclaration: return node.importClause && tryCast(node.importClause.namedBindings, isNamespaceImport); @@ -2647,7 +3021,10 @@ namespace ts { return node.kind === SyntaxKind.ImportDeclaration && !!node.importClause && !!node.importClause.name; } - export function forEachImportClauseDeclaration(node: ImportClause, action: (declaration: ImportClause | NamespaceImport | ImportSpecifier) => T | undefined): T | undefined { + export function forEachImportClauseDeclaration( + node: ImportClause, + action: (declaration: ImportClause | NamespaceImport | ImportSpecifier) => T | undefined, + ): T | undefined { if (node.name) { const result = action(node); if (result) return result; @@ -2670,7 +3047,8 @@ namespace ts { case SyntaxKind.PropertyAssignment: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - return (node as ParameterDeclaration | MethodDeclaration | PropertyDeclaration).questionToken !== undefined; + return (node as ParameterDeclaration | MethodDeclaration | PropertyDeclaration).questionToken + !== undefined; } } @@ -2684,27 +3062,31 @@ namespace ts { } export function isJSDocTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag { - return node.kind === SyntaxKind.JSDocTypedefTag || node.kind === SyntaxKind.JSDocCallbackTag || node.kind === SyntaxKind.JSDocEnumTag; + return node.kind === SyntaxKind.JSDocTypedefTag || node.kind === SyntaxKind.JSDocCallbackTag + || node.kind === SyntaxKind.JSDocEnumTag; } - export function isTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | TypeAliasDeclaration { + export function isTypeAlias( + node: Node, + ): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | TypeAliasDeclaration { return isJSDocTypeAlias(node) || isTypeAliasDeclaration(node); } function getSourceOfAssignment(node: Node): Node | undefined { - return isExpressionStatement(node) && - isBinaryExpression(node.expression) && - node.expression.operatorToken.kind === SyntaxKind.EqualsToken + return isExpressionStatement(node) + && isBinaryExpression(node.expression) + && node.expression.operatorToken.kind === SyntaxKind.EqualsToken ? getRightMostAssignedExpression(node.expression) : undefined; } function getSourceOfDefaultedAssignment(node: Node): Node | undefined { - return isExpressionStatement(node) && - isBinaryExpression(node.expression) && - getAssignmentDeclarationKind(node.expression) !== AssignmentDeclarationKind.None && - isBinaryExpression(node.expression.right) && - (node.expression.right.operatorToken.kind === SyntaxKind.BarBarToken || node.expression.right.operatorToken.kind === SyntaxKind.QuestionQuestionToken) + return isExpressionStatement(node) + && isBinaryExpression(node.expression) + && getAssignmentDeclarationKind(node.expression) !== AssignmentDeclarationKind.None + && isBinaryExpression(node.expression.right) + && (node.expression.right.operatorToken.kind === SyntaxKind.BarBarToken + || node.expression.right.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? node.expression.right.right : undefined; } @@ -2726,9 +3108,9 @@ namespace ts { } function getNestedModuleDeclaration(node: Node): Node | undefined { - return isModuleDeclaration(node) && - node.body && - node.body.kind === SyntaxKind.ModuleDeclaration + return isModuleDeclaration(node) + && node.body + && node.body.kind === SyntaxKind.ModuleDeclaration ? node.body : undefined; } @@ -2747,11 +3129,19 @@ namespace ts { } if (node.kind === SyntaxKind.Parameter) { - result = addRange(result, (noCache ? getJSDocParameterTagsNoCache : getJSDocParameterTags)(node as ParameterDeclaration)); + result = addRange( + result, + (noCache ? getJSDocParameterTagsNoCache : getJSDocParameterTags)(node as ParameterDeclaration), + ); break; } if (node.kind === SyntaxKind.TypeParameter) { - result = addRange(result, (noCache ? getJSDocTypeParameterTagsNoCache : getJSDocTypeParameterTags)(node as TypeParameterDeclaration)); + result = addRange( + result, + (noCache ? getJSDocTypeParameterTagsNoCache : getJSDocTypeParameterTags)( + node as TypeParameterDeclaration, + ), + ); break; } node = getNextJSDocCommentLocation(node); @@ -2782,13 +3172,13 @@ namespace ts { export function getNextJSDocCommentLocation(node: Node) { const parent = node.parent; if ( - parent.kind === SyntaxKind.PropertyAssignment || - parent.kind === SyntaxKind.ExportAssignment || - parent.kind === SyntaxKind.PropertyDeclaration || - parent.kind === SyntaxKind.ExpressionStatement && node.kind === SyntaxKind.PropertyAccessExpression || - parent.kind === SyntaxKind.ReturnStatement || - getNestedModuleDeclaration(parent) || - isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.EqualsToken + parent.kind === SyntaxKind.PropertyAssignment + || parent.kind === SyntaxKind.ExportAssignment + || parent.kind === SyntaxKind.PropertyDeclaration + || parent.kind === SyntaxKind.ExpressionStatement && node.kind === SyntaxKind.PropertyAccessExpression + || parent.kind === SyntaxKind.ReturnStatement + || getNestedModuleDeclaration(parent) + || isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.EqualsToken ) { return parent; } @@ -2799,17 +3189,17 @@ namespace ts { // */ // var x = function(name) { return name.length; } else if ( - parent.parent && - (getSingleVariableOfVariableStatement(parent.parent) === node || - isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken) + parent.parent + && (getSingleVariableOfVariableStatement(parent.parent) === node + || isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken) ) { return parent.parent; } else if ( - parent.parent && parent.parent.parent && - (getSingleVariableOfVariableStatement(parent.parent.parent) || - getSingleInitializerOfVariableStatementOrPropertyDeclaration(parent.parent.parent) === node || - getSourceOfDefaultedAssignment(parent.parent.parent)) + parent.parent && parent.parent.parent + && (getSingleVariableOfVariableStatement(parent.parent.parent) + || getSingleInitializerOfVariableStatementOrPropertyDeclaration(parent.parent.parent) === node + || getSourceOfDefaultedAssignment(parent.parent.parent)) ) { return parent.parent.parent; } @@ -2828,7 +3218,10 @@ namespace ts { if (!decl) { return undefined; } - const parameter = find(decl.parameters, p => p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name); + const parameter = find( + decl.parameters, + p => p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name, + ); return parameter && parameter.symbol; } @@ -2847,8 +3240,8 @@ namespace ts { export function getHostSignatureFromJSDoc(node: Node): SignatureDeclaration | undefined { const host = getEffectiveJSDocHost(node); if (host) { - return isPropertySignature(host) && host.type && isFunctionLike(host.type) ? host.type : - isFunctionLike(host) ? host : undefined; + return isPropertySignature(host) && host.type && isFunctionLike(host.type) ? host.type + : isFunctionLike(host) ? host : undefined; } return undefined; } @@ -2882,9 +3275,12 @@ namespace ts { return findAncestor(node.parent, isJSDoc); } - export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { parent: JSDocTemplateTag; }): TypeParameterDeclaration | undefined { + export function getTypeParameterFromJsDoc( + node: TypeParameterDeclaration & { parent: JSDocTemplateTag; }, + ): TypeParameterDeclaration | undefined { const name = node.name.escapedText; - const { typeParameters } = (node.parent.parent.parent as SignatureDeclaration | InterfaceDeclaration | ClassDeclaration); + const { typeParameters } = + (node.parent.parent.parent as SignatureDeclaration | InterfaceDeclaration | ClassDeclaration); return typeParameters && find(typeParameters, p => p.name.escapedText === name); } @@ -2904,16 +3300,20 @@ namespace ts { switch (parent.kind) { case SyntaxKind.BinaryExpression: const binaryOperator = (parent as BinaryExpression).operatorToken.kind; - return isAssignmentOperator(binaryOperator) && (parent as BinaryExpression).left === node ? - binaryOperator === SyntaxKind.EqualsToken || isLogicalOrCoalescingAssignmentOperator(binaryOperator) ? AssignmentKind.Definite : AssignmentKind.Compound : - AssignmentKind.None; + return isAssignmentOperator(binaryOperator) && (parent as BinaryExpression).left === node + ? binaryOperator === SyntaxKind.EqualsToken + || isLogicalOrCoalescingAssignmentOperator(binaryOperator) ? AssignmentKind.Definite + : AssignmentKind.Compound + : AssignmentKind.None; case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: const unaryOperator = (parent as PrefixUnaryExpression | PostfixUnaryExpression).operator; - return unaryOperator === SyntaxKind.PlusPlusToken || unaryOperator === SyntaxKind.MinusMinusToken ? AssignmentKind.Compound : AssignmentKind.None; + return unaryOperator === SyntaxKind.PlusPlusToken || unaryOperator === SyntaxKind.MinusMinusToken + ? AssignmentKind.Compound : AssignmentKind.None; case SyntaxKind.ForInStatement: case SyntaxKind.ForOfStatement: - return (parent as ForInOrOfStatement).initializer === node ? AssignmentKind.Definite : AssignmentKind.None; + return (parent as ForInOrOfStatement).initializer === node ? AssignmentKind.Definite + : AssignmentKind.None; case SyntaxKind.ParenthesizedExpression: case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.SpreadElement: @@ -3004,7 +3404,8 @@ namespace ts { | ArrowFunction; export function isValueSignatureDeclaration(node: Node): node is ValueSignatureDeclaration { - return isFunctionExpression(node) || isArrowFunction(node) || isMethodOrAccessor(node) || isFunctionDeclaration(node) || isConstructorDeclaration(node); + return isFunctionExpression(node) || isArrowFunction(node) || isMethodOrAccessor(node) + || isFunctionDeclaration(node) || isConstructorDeclaration(node); } function walkUp(node: Node, kind: SyntaxKind) { @@ -3027,7 +3428,9 @@ namespace ts { * It returns both the outermost parenthesized type and its parent. * If given node is not a parenthesiezd type, undefined is return as the former. */ - export function walkUpParenthesizedTypesAndGetParentAndChild(node: Node): [ParenthesizedTypeNode | undefined, Node] { + export function walkUpParenthesizedTypesAndGetParentAndChild( + node: Node, + ): [ParenthesizedTypeNode | undefined, Node] { let child: ParenthesizedTypeNode | undefined; while (node && node.kind === SyntaxKind.ParenthesizedType) { child = node as ParenthesizedTypeNode; @@ -3044,9 +3447,9 @@ namespace ts { export function skipParentheses(node: Expression, excludeJSDocTypeAssertions?: boolean): Expression; export function skipParentheses(node: Node, excludeJSDocTypeAssertions?: boolean): Node; export function skipParentheses(node: Node, excludeJSDocTypeAssertions?: boolean): Node { - const flags = excludeJSDocTypeAssertions ? - OuterExpressionKinds.Parentheses | OuterExpressionKinds.ExcludeJSDocTypeAssertion : - OuterExpressionKinds.Parentheses; + const flags = excludeJSDocTypeAssertions + ? OuterExpressionKinds.Parentheses | OuterExpressionKinds.ExcludeJSDocTypeAssertion + : OuterExpressionKinds.Parentheses; return skipOuterExpressions(node, flags); } @@ -3069,7 +3472,8 @@ namespace ts { // True if `name` is the name of a declaration node export function isDeclarationName(name: Node): boolean { - return !isSourceFile(name) && !isBindingPattern(name) && isDeclaration(name.parent) && name.parent.name === name; + return !isSourceFile(name) && !isBindingPattern(name) && isDeclaration(name.parent) + && name.parent.name === name; } // See GH#16030 @@ -3091,10 +3495,10 @@ namespace ts { } else { const binExp = parent.parent; - return isBinaryExpression(binExp) && - getAssignmentDeclarationKind(binExp) !== AssignmentDeclarationKind.None && - (binExp.left.symbol || binExp.symbol) && - getNameOfDeclaration(binExp) === name + return isBinaryExpression(binExp) + && getAssignmentDeclarationKind(binExp) !== AssignmentDeclarationKind.None + && (binExp.left.symbol || binExp.symbol) + && getNameOfDeclaration(binExp) === name ? binExp : undefined; } @@ -3106,9 +3510,9 @@ namespace ts { } export function isLiteralComputedPropertyDeclarationName(node: Node) { - return isStringOrNumericLiteralLike(node) && - node.parent.kind === SyntaxKind.ComputedPropertyName && - isDeclaration(node.parent.parent); + return isStringOrNumericLiteralLike(node) + && node.parent.kind === SyntaxKind.ComputedPropertyName + && isDeclaration(node.parent.parent); } // Return true if the given identifier is classified as an IdentifierName @@ -3161,21 +3565,22 @@ namespace ts { // const { x } = require("...").y export function isAliasSymbolDeclaration(node: Node): boolean { if ( - node.kind === SyntaxKind.ImportEqualsDeclaration || - node.kind === SyntaxKind.NamespaceExportDeclaration || - node.kind === SyntaxKind.ImportClause && !!(node as ImportClause).name || - node.kind === SyntaxKind.NamespaceImport || - node.kind === SyntaxKind.NamespaceExport || - node.kind === SyntaxKind.ImportSpecifier || - node.kind === SyntaxKind.ExportSpecifier || - node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node as ExportAssignment) + node.kind === SyntaxKind.ImportEqualsDeclaration + || node.kind === SyntaxKind.NamespaceExportDeclaration + || node.kind === SyntaxKind.ImportClause && !!(node as ImportClause).name + || node.kind === SyntaxKind.NamespaceImport + || node.kind === SyntaxKind.NamespaceExport + || node.kind === SyntaxKind.ImportSpecifier + || node.kind === SyntaxKind.ExportSpecifier + || node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node as ExportAssignment) ) { return true; } return isInJSFile(node) && ( - isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) || - isPropertyAccessExpression(node) + isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports + && exportAssignmentIsAlias(node) + || isPropertyAccessExpression(node) && isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken @@ -3215,9 +3620,12 @@ namespace ts { return isExportAssignment(node) ? node.expression : node.right; } - export function getPropertyAssignmentAliasLikeExpression(node: PropertyAssignment | ShorthandPropertyAssignment | PropertyAccessExpression): Expression { - return node.kind === SyntaxKind.ShorthandPropertyAssignment ? node.name : node.kind === SyntaxKind.PropertyAssignment ? node.initializer : - (node.parent as BinaryExpression).right; + export function getPropertyAssignmentAliasLikeExpression( + node: PropertyAssignment | ShorthandPropertyAssignment | PropertyAccessExpression, + ): Expression { + return node.kind === SyntaxKind.ShorthandPropertyAssignment ? node.name + : node.kind === SyntaxKind.PropertyAssignment ? node.initializer + : (node.parent as BinaryExpression).right; } export function getEffectiveBaseTypeNode(node: ClassLikeDeclaration | InterfaceDeclaration) { @@ -3237,7 +3645,9 @@ namespace ts { return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined; } - export function getEffectiveImplementsTypeNodes(node: ClassLikeDeclaration): undefined | readonly ExpressionWithTypeArguments[] { + export function getEffectiveImplementsTypeNodes( + node: ClassLikeDeclaration, + ): undefined | readonly ExpressionWithTypeArguments[] { if (isInJSFile(node)) { return getJSDocImplementsTags(node).map(n => n.class); } @@ -3249,9 +3659,11 @@ namespace ts { /** Returns the node in an `extends` or `implements` clause of a class or interface. */ export function getAllSuperTypeNodes(node: Node): readonly TypeNode[] { - return isInterfaceDeclaration(node) ? getInterfaceBaseTypeNodes(node) || emptyArray : - isClassLike(node) ? concatenate(singleElementArray(getEffectiveBaseTypeNode(node)), getEffectiveImplementsTypeNodes(node)) || emptyArray : - emptyArray; + return isInterfaceDeclaration(node) ? getInterfaceBaseTypeNodes(node) || emptyArray + : isClassLike(node) + ? concatenate(singleElementArray(getEffectiveBaseTypeNode(node)), getEffectiveImplementsTypeNodes(node)) + || emptyArray + : emptyArray; } export function getInterfaceBaseTypeNodes(node: InterfaceDeclaration) { @@ -3370,7 +3782,9 @@ namespace ts { } export function isSignedNumericLiteral(node: Node): node is PrefixUnaryExpression & { operand: NumericLiteral; } { - return isPrefixUnaryExpression(node) && (node.operator === SyntaxKind.PlusToken || node.operator === SyntaxKind.MinusToken) && isNumericLiteral(node.operand); + return isPrefixUnaryExpression(node) + && (node.operator === SyntaxKind.PlusToken || node.operator === SyntaxKind.MinusToken) + && isNumericLiteral(node.operand); } /** @@ -3381,7 +3795,9 @@ namespace ts { * 4. The computed name is *not* expressed as a PlusToken or MinusToken * immediately followed by a NumericLiteral. */ - export function hasDynamicName(declaration: Declaration): declaration is DynamicNamedDeclaration | DynamicNamedBinaryExpression { + export function hasDynamicName( + declaration: Declaration, + ): declaration is DynamicNamedDeclaration | DynamicNamedBinaryExpression { const name = getNameOfDeclaration(declaration); return !!name && isDynamicName(name); } @@ -3391,8 +3807,8 @@ namespace ts { return false; } const expr = isElementAccessExpression(name) ? skipParentheses(name.argumentExpression) : name.expression; - return !isStringOrNumericLiteralLike(expr) && - !isSignedNumericLiteral(expr); + return !isStringOrNumericLiteralLike(expr) + && !isSignedNumericLiteral(expr); } export function getPropertyNameForPropertyNameNode(name: PropertyName): __String | undefined { @@ -3507,7 +3923,8 @@ namespace ts { export function getExpressionAssociativity(expression: Expression) { const operator = getOperator(expression); - const hasArguments = expression.kind === SyntaxKind.NewExpression && (expression as NewExpression).arguments !== undefined; + const hasArguments = expression.kind === SyntaxKind.NewExpression + && (expression as NewExpression).arguments !== undefined; return getOperatorAssociativity(expression.kind, operator, hasArguments); } @@ -3552,7 +3969,8 @@ namespace ts { export function getExpressionPrecedence(expression: Expression) { const operator = getOperator(expression); - const hasArguments = expression.kind === SyntaxKind.NewExpression && (expression as NewExpression).arguments !== undefined; + const hasArguments = expression.kind === SyntaxKind.NewExpression + && (expression as NewExpression).arguments !== undefined; return getOperatorPrecedence(expression.kind, operator, hasArguments); } @@ -3560,7 +3978,10 @@ namespace ts { if (expression.kind === SyntaxKind.BinaryExpression) { return (expression as BinaryExpression).operatorToken.kind; } - else if (expression.kind === SyntaxKind.PrefixUnaryExpression || expression.kind === SyntaxKind.PostfixUnaryExpression) { + else if ( + expression.kind === SyntaxKind.PrefixUnaryExpression + || expression.kind === SyntaxKind.PostfixUnaryExpression + ) { return (expression as PrefixUnaryExpression | PostfixUnaryExpression).operator; } else { @@ -4058,21 +4479,27 @@ namespace ts { * but augmented for a few select characters (e.g. lineSeparator, paragraphSeparator, nextLine) * Note that this doesn't actually wrap the input in double quotes. */ - export function escapeString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick): string { - const escapedCharsRegExp = quoteChar === CharacterCodes.backtick ? backtickQuoteEscapedCharsRegExp : - quoteChar === CharacterCodes.singleQuote ? singleQuoteEscapedCharsRegExp : - doubleQuoteEscapedCharsRegExp; + export function escapeString( + s: string, + quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick, + ): string { + const escapedCharsRegExp = quoteChar === CharacterCodes.backtick ? backtickQuoteEscapedCharsRegExp + : quoteChar === CharacterCodes.singleQuote ? singleQuoteEscapedCharsRegExp + : doubleQuoteEscapedCharsRegExp; return s.replace(escapedCharsRegExp, getReplacement); } const nonAsciiCharacters = /[^\u0000-\u007F]/g; - export function escapeNonAsciiString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick): string { + export function escapeNonAsciiString( + s: string, + quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick, + ): string { s = escapeString(s, quoteChar); // Replace non-ASCII characters with '\uNNNN' escapes if any exist. // Otherwise just return the original string. - return nonAsciiCharacters.test(s) ? - s.replace(nonAsciiCharacters, c => encodeUtf16EscapeSequence(c.charCodeAt(0))) : - s; + return nonAsciiCharacters.test(s) + ? s.replace(nonAsciiCharacters, c => encodeUtf16EscapeSequence(c.charCodeAt(0))) + : s; } // This consists of the first 19 unprintable ASCII characters, JSX canonical escapes, lineSeparator, @@ -4098,9 +4525,12 @@ namespace ts { return jsxEscapedCharsMap.get(c) || encodeJsxCharacterEntity(c.charCodeAt(0)); } - export function escapeJsxAttributeString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote) { - const escapedCharsRegExp = quoteChar === CharacterCodes.singleQuote ? jsxSingleQuoteEscapedCharsRegExp : - jsxDoubleQuoteEscapedCharsRegExp; + export function escapeJsxAttributeString( + s: string, + quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote, + ) { + const escapedCharsRegExp = quoteChar === CharacterCodes.singleQuote ? jsxSingleQuoteEscapedCharsRegExp + : jsxDoubleQuoteEscapedCharsRegExp; return s.replace(escapedCharsRegExp, getJsxAttributeStringReplacement); } @@ -4111,21 +4541,24 @@ namespace ts { */ export function stripQuotes(name: string) { const length = name.length; - if (length >= 2 && name.charCodeAt(0) === name.charCodeAt(length - 1) && isQuoteOrBacktick(name.charCodeAt(0))) { + if ( + length >= 2 && name.charCodeAt(0) === name.charCodeAt(length - 1) && isQuoteOrBacktick(name.charCodeAt(0)) + ) { return name.substring(1, length - 1); } return name; } function isQuoteOrBacktick(charCode: number) { - return charCode === CharacterCodes.singleQuote || - charCode === CharacterCodes.doubleQuote || - charCode === CharacterCodes.backtick; + return charCode === CharacterCodes.singleQuote + || charCode === CharacterCodes.doubleQuote + || charCode === CharacterCodes.backtick; } export function isIntrinsicJsxName(name: __String | string) { const ch = (name as string).charCodeAt(0); - return (ch >= CharacterCodes.a && ch <= CharacterCodes.z) || stringContains(name as string, "-") || stringContains(name as string, ":"); + return (ch >= CharacterCodes.a && ch <= CharacterCodes.z) || stringContains(name as string, "-") + || stringContains(name as string, ":"); } const indentStrings: string[] = ["", " "]; @@ -4348,15 +4781,29 @@ namespace ts { getCurrentDirectory(): string; } - export function getResolvedExternalModuleName(host: ResolveModuleNameResolutionHost, file: SourceFile, referenceFile?: SourceFile): string { - return file.moduleName || getExternalModuleNameFromPath(host, file.fileName, referenceFile && referenceFile.fileName); + export function getResolvedExternalModuleName( + host: ResolveModuleNameResolutionHost, + file: SourceFile, + referenceFile?: SourceFile, + ): string { + return file.moduleName + || getExternalModuleNameFromPath(host, file.fileName, referenceFile && referenceFile.fileName); } function getCanonicalAbsolutePath(host: ResolveModuleNameResolutionHost, path: string) { return host.getCanonicalFileName(getNormalizedAbsolutePath(path, host.getCurrentDirectory())); } - export function getExternalModuleNameFromDeclaration(host: ResolveModuleNameResolutionHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): string | undefined { + export function getExternalModuleNameFromDeclaration( + host: ResolveModuleNameResolutionHost, + resolver: EmitResolver, + declaration: + | ImportEqualsDeclaration + | ImportDeclaration + | ExportDeclaration + | ModuleDeclaration + | ImportTypeNode, + ): string | undefined { const file = resolver.getExternalModuleFileFromDeclaration(declaration); if (!file || file.isDeclarationFile) { return undefined; @@ -4364,8 +4811,10 @@ namespace ts { // If the declaration already uses a non-relative name, and is outside the common source directory, continue to use it const specifier = getExternalModuleName(declaration); if ( - specifier && isStringLiteralLike(specifier) && !pathIsRelative(specifier.text) && - getCanonicalAbsolutePath(host, file.path).indexOf(getCanonicalAbsolutePath(host, ensureTrailingDirectorySeparator(host.getCommonSourceDirectory()))) === -1 + specifier && isStringLiteralLike(specifier) && !pathIsRelative(specifier.text) + && getCanonicalAbsolutePath(host, file.path).indexOf( + getCanonicalAbsolutePath(host, ensureTrailingDirectorySeparator(host.getCommonSourceDirectory())), + ) === -1 ) { return undefined; } @@ -4375,11 +4824,25 @@ namespace ts { /** * Resolves a local path to a path which is absolute to the base of the emit */ - export function getExternalModuleNameFromPath(host: ResolveModuleNameResolutionHost, fileName: string, referencePath?: string): string { + export function getExternalModuleNameFromPath( + host: ResolveModuleNameResolutionHost, + fileName: string, + referencePath?: string, + ): string { const getCanonicalFileName = (f: string) => host.getCanonicalFileName(f); - const dir = toPath(referencePath ? getDirectoryPath(referencePath) : host.getCommonSourceDirectory(), host.getCurrentDirectory(), getCanonicalFileName); + const dir = toPath( + referencePath ? getDirectoryPath(referencePath) : host.getCommonSourceDirectory(), + host.getCurrentDirectory(), + getCanonicalFileName, + ); const filePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory()); - const relativePath = getRelativePathToDirectoryOrUrl(dir, filePath, dir, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); + const relativePath = getRelativePathToDirectoryOrUrl( + dir, + filePath, + dir, + getCanonicalFileName, + /*isAbsolutePathAnUrl*/ false, + ); const extensionless = removeFileExtension(relativePath); return referencePath ? ensurePathIsNonModuleName(extensionless) : extensionless; } @@ -4388,7 +4851,9 @@ namespace ts { const compilerOptions = host.getCompilerOptions(); let emitOutputFilePathWithoutExtension: string; if (compilerOptions.outDir) { - emitOutputFilePathWithoutExtension = removeFileExtension(getSourceFilePathInNewDir(fileName, host, compilerOptions.outDir)); + emitOutputFilePathWithoutExtension = removeFileExtension( + getSourceFilePathInNewDir(fileName, host, compilerOptions.outDir), + ); } else { emitOutputFilePathWithoutExtension = removeFileExtension(fileName); @@ -4398,34 +4863,54 @@ namespace ts { } export function getDeclarationEmitOutputFilePath(fileName: string, host: EmitHost) { - return getDeclarationEmitOutputFilePathWorker(fileName, host.getCompilerOptions(), host.getCurrentDirectory(), host.getCommonSourceDirectory(), f => host.getCanonicalFileName(f)); + return getDeclarationEmitOutputFilePathWorker( + fileName, + host.getCompilerOptions(), + host.getCurrentDirectory(), + host.getCommonSourceDirectory(), + f => host.getCanonicalFileName(f), + ); } - export function getDeclarationEmitOutputFilePathWorker(fileName: string, options: CompilerOptions, currentDirectory: string, commonSourceDirectory: string, getCanonicalFileName: GetCanonicalFileName): string { + export function getDeclarationEmitOutputFilePathWorker( + fileName: string, + options: CompilerOptions, + currentDirectory: string, + commonSourceDirectory: string, + getCanonicalFileName: GetCanonicalFileName, + ): string { const outputDir = options.declarationDir || options.outDir; // Prefer declaration folder if specified const path = outputDir - ? getSourceFilePathInNewDirWorker(fileName, outputDir, currentDirectory, commonSourceDirectory, getCanonicalFileName) + ? getSourceFilePathInNewDirWorker( + fileName, + outputDir, + currentDirectory, + commonSourceDirectory, + getCanonicalFileName, + ) : fileName; const declarationExtension = getDeclarationEmitExtensionForPath(path); return removeFileExtension(path) + declarationExtension; } export function getDeclarationEmitExtensionForPath(path: string) { - return fileExtensionIsOneOf(path, [Extension.Mjs, Extension.Mts]) ? Extension.Dmts : - fileExtensionIsOneOf(path, [Extension.Cjs, Extension.Cts]) ? Extension.Dcts : - fileExtensionIsOneOf(path, [Extension.Json]) ? `.json.d.ts` : // Drive-by redefinition of json declaration file output name so if it's ever enabled, it behaves well - Extension.Dts; + return fileExtensionIsOneOf(path, [Extension.Mjs, Extension.Mts]) ? Extension.Dmts + : fileExtensionIsOneOf(path, [Extension.Cjs, Extension.Cts]) ? Extension.Dcts + : fileExtensionIsOneOf(path, [Extension.Json]) ? `.json.d.ts` // Drive-by redefinition of json declaration file output name so if it's ever enabled, it behaves well + : Extension.Dts; } /** * This function is an inverse of `getDeclarationEmitExtensionForPath`. */ export function getPossibleOriginalInputExtensionForExtension(path: string) { - return fileExtensionIsOneOf(path, [Extension.Dmts, Extension.Mjs, Extension.Mts]) ? [Extension.Mts, Extension.Mjs] : - fileExtensionIsOneOf(path, [Extension.Dcts, Extension.Cjs, Extension.Cts]) ? [Extension.Cts, Extension.Cjs] : - fileExtensionIsOneOf(path, [`.json.d.ts`]) ? [Extension.Json] : - [Extension.Tsx, Extension.Ts, Extension.Jsx, Extension.Js]; + return fileExtensionIsOneOf(path, [Extension.Dmts, Extension.Mjs, Extension.Mts]) + ? [Extension.Mts, Extension.Mjs] + : fileExtensionIsOneOf(path, [Extension.Dcts, Extension.Cjs, Extension.Cts]) + ? [Extension.Cts, Extension.Cjs] + : fileExtensionIsOneOf(path, [`.json.d.ts`]) ? [Extension.Json] + : [Extension.Tsx, Extension.Ts, Extension.Jsx, Extension.Js]; } export function outFile(options: CompilerOptions) { @@ -4435,7 +4920,11 @@ namespace ts { /** Returns 'undefined' if and only if 'options.paths' is undefined. */ export function getPathsBasePath(options: CompilerOptions, host: { getCurrentDirectory?(): string; }) { if (!options.paths) return undefined; - return options.baseUrl ?? Debug.checkDefined(options.pathsBasePath || host.getCurrentDirectory?.(), "Encountered 'paths' without a 'baseUrl', config file, or host 'getCurrentDirectory'."); + return options.baseUrl + ?? Debug.checkDefined( + options.pathsBasePath || host.getCurrentDirectory?.(), + "Encountered 'paths' without a 'baseUrl', config file, or host 'getCurrentDirectory'.", + ); } export interface EmitFileNames { @@ -4455,17 +4944,22 @@ namespace ts { * @param host An EmitHost. * @param targetSourceFile An optional target source file to emit. */ - export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFile, forceDtsEmit?: boolean): readonly SourceFile[] { + export function getSourceFilesToEmit( + host: EmitHost, + targetSourceFile?: SourceFile, + forceDtsEmit?: boolean, + ): readonly SourceFile[] { const options = host.getCompilerOptions(); if (outFile(options)) { const moduleKind = getEmitModuleKind(options); - const moduleEmitEnabled = options.emitDeclarationOnly || moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System; + const moduleEmitEnabled = options.emitDeclarationOnly || moduleKind === ModuleKind.AMD + || moduleKind === ModuleKind.System; // Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified return filter( host.getSourceFiles(), sourceFile => - (moduleEmitEnabled || !isExternalModule(sourceFile)) && - sourceFileMayBeEmitted(sourceFile, host, forceDtsEmit), + (moduleEmitEnabled || !isExternalModule(sourceFile)) + && sourceFileMayBeEmitted(sourceFile, host, forceDtsEmit), ); } else { @@ -4478,35 +4972,63 @@ namespace ts { } /** Don't call this for `--outFile`, just for `--outDir` or plain emit. `--outFile` needs additional checks. */ - export function sourceFileMayBeEmitted(sourceFile: SourceFile, host: SourceFileMayBeEmittedHost, forceDtsEmit?: boolean) { + export function sourceFileMayBeEmitted( + sourceFile: SourceFile, + host: SourceFileMayBeEmittedHost, + forceDtsEmit?: boolean, + ) { const options = host.getCompilerOptions(); - return !(options.noEmitForJsFiles && isSourceFileJS(sourceFile)) && - !sourceFile.isDeclarationFile && - !host.isSourceFileFromExternalLibrary(sourceFile) && - (forceDtsEmit || ( - !(isJsonSourceFile(sourceFile) && host.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) && - !host.isSourceOfProjectReferenceRedirect(sourceFile.fileName) + return !(options.noEmitForJsFiles && isSourceFileJS(sourceFile)) + && !sourceFile.isDeclarationFile + && !host.isSourceFileFromExternalLibrary(sourceFile) + && (forceDtsEmit || ( + !(isJsonSourceFile(sourceFile) && host.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) + && !host.isSourceOfProjectReferenceRedirect(sourceFile.fileName) )); } export function getSourceFilePathInNewDir(fileName: string, host: EmitHost, newDirPath: string): string { - return getSourceFilePathInNewDirWorker(fileName, newDirPath, host.getCurrentDirectory(), host.getCommonSourceDirectory(), f => host.getCanonicalFileName(f)); + return getSourceFilePathInNewDirWorker( + fileName, + newDirPath, + host.getCurrentDirectory(), + host.getCommonSourceDirectory(), + f => host.getCanonicalFileName(f), + ); } - export function getSourceFilePathInNewDirWorker(fileName: string, newDirPath: string, currentDirectory: string, commonSourceDirectory: string, getCanonicalFileName: GetCanonicalFileName): string { + export function getSourceFilePathInNewDirWorker( + fileName: string, + newDirPath: string, + currentDirectory: string, + commonSourceDirectory: string, + getCanonicalFileName: GetCanonicalFileName, + ): string { let sourceFilePath = getNormalizedAbsolutePath(fileName, currentDirectory); - const isSourceFileInCommonSourceDirectory = getCanonicalFileName(sourceFilePath).indexOf(getCanonicalFileName(commonSourceDirectory)) === 0; - sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath; + const isSourceFileInCommonSourceDirectory = + getCanonicalFileName(sourceFilePath).indexOf(getCanonicalFileName(commonSourceDirectory)) === 0; + sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) + : sourceFilePath; return combinePaths(newDirPath, sourceFilePath); } - export function writeFile(host: { writeFile: WriteFileCallback; }, diagnostics: DiagnosticCollection, fileName: string, text: string, writeByteOrderMark: boolean, sourceFiles?: readonly SourceFile[], data?: WriteFileCallbackData) { + export function writeFile( + host: { writeFile: WriteFileCallback; }, + diagnostics: DiagnosticCollection, + fileName: string, + text: string, + writeByteOrderMark: boolean, + sourceFiles?: readonly SourceFile[], + data?: WriteFileCallbackData, + ) { host.writeFile( fileName, text, writeByteOrderMark, hostErrorMessage => { - diagnostics.add(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage)); + diagnostics.add( + createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage), + ); }, sourceFiles, data, @@ -4553,8 +5075,14 @@ namespace ts { return computeLineOfPosition(lineMap, pos); } - export function getFirstConstructorWithBody(node: ClassLikeDeclaration): ConstructorDeclaration & { body: FunctionBody; } | undefined { - return find(node.members, (member): member is ConstructorDeclaration & { body: FunctionBody; } => isConstructorDeclaration(member) && nodeIsPresent(member.body)); + export function getFirstConstructorWithBody( + node: ClassLikeDeclaration, + ): ConstructorDeclaration & { body: FunctionBody; } | undefined { + return find( + node.members, + (member): member is ConstructorDeclaration & { body: FunctionBody; } => + isConstructorDeclaration(member) && nodeIsPresent(member.body), + ); } export function getSetAccessorValueParameter(accessor: SetAccessorDeclaration): ParameterDeclaration | undefined { @@ -4570,7 +5098,9 @@ namespace ts { return parameter && parameter.type; } - export function getThisParameter(signature: SignatureDeclaration | JSDocSignature): ParameterDeclaration | undefined { + export function getThisParameter( + signature: SignatureDeclaration | JSDocSignature, + ): ParameterDeclaration | undefined { // callback tags do not currently support this parameters if (signature.parameters.length && !isJSDocSignature(signature)) { const thisParameter = signature.parameters[0]; @@ -4604,7 +5134,10 @@ namespace ts { return id.originalKeywordKind === SyntaxKind.ThisKeyword; } - export function getAllAccessorDeclarations(declarations: readonly Declaration[], accessor: AccessorDeclaration): AllAccessorDeclarations { + export function getAllAccessorDeclarations( + declarations: readonly Declaration[], + accessor: AccessorDeclaration, + ): AllAccessorDeclarations { // TODO: GH#18217 let firstAccessor!: AccessorDeclaration; let secondAccessor!: AccessorDeclaration; @@ -4678,18 +5211,21 @@ namespace ts { * JavaScript file, gets the return type annotation from JSDoc. */ export function getEffectiveReturnTypeNode(node: SignatureDeclaration | JSDocSignature): TypeNode | undefined { - return isJSDocSignature(node) ? - node.type && node.type.typeExpression && node.type.typeExpression.type : - node.type || (isInJSFile(node) ? getJSDocReturnType(node) : undefined); + return isJSDocSignature(node) + ? node.type && node.type.typeExpression && node.type.typeExpression.type + : node.type || (isInJSFile(node) ? getJSDocReturnType(node) : undefined); } - export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[] { + export function getJSDocTypeParameterDeclarations( + node: DeclarationWithTypeParameters, + ): readonly TypeParameterDeclaration[] { return flatMap(getJSDocTags(node), tag => isNonTypeAliasTemplate(tag) ? tag.typeParameters : undefined); } /** template tags are only available when a typedef isn't already using them */ function isNonTypeAliasTemplate(tag: JSDocTag): tag is JSDocTemplateTag { - return isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDoc && tag.parent.tags!.some(isJSDocTypeAlias)); + return isJSDocTemplateTag(tag) + && !(tag.parent.kind === SyntaxKind.JSDoc && tag.parent.tags!.some(isJSDocTypeAlias)); } /** @@ -4701,25 +5237,42 @@ namespace ts { return parameter && getEffectiveTypeAnnotationNode(parameter); } - export function emitNewLineBeforeLeadingComments(lineMap: readonly number[], writer: EmitTextWriter, node: TextRange, leadingComments: readonly CommentRange[] | undefined) { + export function emitNewLineBeforeLeadingComments( + lineMap: readonly number[], + writer: EmitTextWriter, + node: TextRange, + leadingComments: readonly CommentRange[] | undefined, + ) { emitNewLineBeforeLeadingCommentsOfPosition(lineMap, writer, node.pos, leadingComments); } - export function emitNewLineBeforeLeadingCommentsOfPosition(lineMap: readonly number[], writer: EmitTextWriter, pos: number, leadingComments: readonly CommentRange[] | undefined) { + export function emitNewLineBeforeLeadingCommentsOfPosition( + lineMap: readonly number[], + writer: EmitTextWriter, + pos: number, + leadingComments: readonly CommentRange[] | undefined, + ) { // If the leading comments start on different line than the start of node, write new line if ( - leadingComments && leadingComments.length && pos !== leadingComments[0].pos && - getLineOfLocalPositionFromLineMap(lineMap, pos) !== getLineOfLocalPositionFromLineMap(lineMap, leadingComments[0].pos) + leadingComments && leadingComments.length && pos !== leadingComments[0].pos + && getLineOfLocalPositionFromLineMap(lineMap, pos) + !== getLineOfLocalPositionFromLineMap(lineMap, leadingComments[0].pos) ) { writer.writeLine(); } } - export function emitNewLineBeforeLeadingCommentOfPosition(lineMap: readonly number[], writer: EmitTextWriter, pos: number, commentPos: number) { + export function emitNewLineBeforeLeadingCommentOfPosition( + lineMap: readonly number[], + writer: EmitTextWriter, + pos: number, + commentPos: number, + ) { // If the leading comments start on different line than the start of node, write new line if ( - pos !== commentPos && - getLineOfLocalPositionFromLineMap(lineMap, pos) !== getLineOfLocalPositionFromLineMap(lineMap, commentPos) + pos !== commentPos + && getLineOfLocalPositionFromLineMap(lineMap, pos) + !== getLineOfLocalPositionFromLineMap(lineMap, commentPos) ) { writer.writeLine(); } @@ -4733,7 +5286,14 @@ namespace ts { leadingSeparator: boolean, trailingSeparator: boolean, newLine: string, - writeComment: (text: string, lineMap: readonly number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void, + writeComment: ( + text: string, + lineMap: readonly number[], + writer: EmitTextWriter, + commentPos: number, + commentEnd: number, + newLine: string, + ) => void, ) { if (comments && comments.length > 0) { if (leadingSeparator) { @@ -4766,7 +5326,22 @@ namespace ts { * Detached comment is a comment at the top of file or function body that is separated from * the next statement by space. */ - export function emitDetachedComments(text: string, lineMap: readonly number[], writer: EmitTextWriter, writeComment: (text: string, lineMap: readonly number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void, node: TextRange, newLine: string, removeComments: boolean) { + export function emitDetachedComments( + text: string, + lineMap: readonly number[], + writer: EmitTextWriter, + writeComment: ( + text: string, + lineMap: readonly number[], + writer: EmitTextWriter, + commentPos: number, + commentEnd: number, + newLine: string, + ) => void, + node: TextRange, + newLine: string, + removeComments: boolean, + ) { let leadingComments: CommentRange[] | undefined; let currentDetachedCommentInfo: { nodePos: number; detachedCommentEndPos: number; } | undefined; if (removeComments) { @@ -4814,8 +5389,20 @@ namespace ts { if (nodeLine >= lastCommentLine + 2) { // Valid detachedComments emitNewLineBeforeLeadingComments(lineMap, writer, node, leadingComments); - emitComments(text, lineMap, writer, detachedComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); - currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: last(detachedComments).end }; + emitComments( + text, + lineMap, + writer, + detachedComments, + /*leadingSeparator*/ false, + /*trailingSeparator*/ true, + newLine, + writeComment, + ); + currentDetachedCommentInfo = { + nodePos: node.pos, + detachedCommentEndPos: last(detachedComments).end, + }; } } } @@ -4827,12 +5414,23 @@ namespace ts { } } - export function writeCommentRange(text: string, lineMap: readonly number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) { + export function writeCommentRange( + text: string, + lineMap: readonly number[], + writer: EmitTextWriter, + commentPos: number, + commentEnd: number, + newLine: string, + ) { if (text.charCodeAt(commentPos + 1) === CharacterCodes.asterisk) { const firstCommentLineAndCharacter = computeLineAndCharacterOfPosition(lineMap, commentPos); const lineCount = lineMap.length; let firstCommentLineIndent: number | undefined; - for (let pos = commentPos, currentLine = firstCommentLineAndCharacter.line; pos < commentEnd; currentLine++) { + for ( + let pos = commentPos, currentLine = firstCommentLineAndCharacter.line; + pos < commentEnd; + currentLine++ + ) { const nextLineStart = (currentLine + 1) === lineCount ? text.length + 1 : lineMap[currentLine + 1]; @@ -4840,7 +5438,11 @@ namespace ts { if (pos !== commentPos) { // If we are not emitting first line, we need to write the spaces to adjust the alignment if (firstCommentLineIndent === undefined) { - firstCommentLineIndent = calculateIndent(text, lineMap[firstCommentLineAndCharacter.line], commentPos); + firstCommentLineIndent = calculateIndent( + text, + lineMap[firstCommentLineAndCharacter.line], + commentPos, + ); } // These are number of spaces writer is going to write at current indent @@ -4860,10 +5462,13 @@ namespace ts { // More right indented comment */ --4 = 8 - 4 + 11 // class c { } // } - const spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + calculateIndent(text, pos, nextLineStart); + const spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + + calculateIndent(text, pos, nextLineStart); if (spacesToEmit > 0) { let numberOfSingleSpacesToEmit = spacesToEmit % getIndentSize(); - const indentSizeSpaceString = getIndentString((spacesToEmit - numberOfSingleSpacesToEmit) / getIndentSize()); + const indentSizeSpaceString = getIndentString( + (spacesToEmit - numberOfSingleSpacesToEmit) / getIndentSize(), + ); // Write indent size string ( in eg 1: = "", 2: "" , 3: string with 8 spaces 4: string with 12 spaces writer.rawWrite(indentSizeSpaceString); @@ -4892,7 +5497,14 @@ namespace ts { } } - function writeTrimmedCurrentLine(text: string, commentEnd: number, writer: EmitTextWriter, newLine: string, pos: number, nextLineStart: number) { + function writeTrimmedCurrentLine( + text: string, + commentEnd: number, + writer: EmitTextWriter, + newLine: string, + pos: number, + nextLineStart: number, + ) { const end = Math.min(commentEnd, nextLineStart - 1); const currentLineText = trimString(text.substring(pos, end)); if (currentLineText) { @@ -4990,7 +5602,10 @@ namespace ts { node.modifierFlagsCache = getSyntacticModifierFlagsNoCache(node) | ModifierFlags.HasComputedFlags; } - if (includeJSDoc && !(node.modifierFlagsCache & ModifierFlags.HasComputedJSDocModifiers) && (alwaysIncludeJSDoc || isInJSFile(node)) && node.parent) { + if ( + includeJSDoc && !(node.modifierFlagsCache & ModifierFlags.HasComputedJSDocModifiers) + && (alwaysIncludeJSDoc || isInJSFile(node)) && node.parent + ) { node.modifierFlagsCache |= getJSDocModifierFlagsNoCache(node) | ModifierFlags.HasComputedJSDocModifiers; } @@ -5051,7 +5666,10 @@ namespace ts { */ export function getSyntacticModifierFlagsNoCache(node: Node): ModifierFlags { let flags = canHaveModifiers(node) ? modifiersToFlags(node.modifiers) : ModifierFlags.None; - if (node.flags & NodeFlags.NestedNamespace || (node.kind === SyntaxKind.Identifier && (node as Identifier).isInJSDocNamespace)) { + if ( + node.flags & NodeFlags.NestedNamespace + || (node.kind === SyntaxKind.Identifier && (node as Identifier).isInJSDocNamespace) + ) { flags |= ModifierFlags.Export; } return flags; @@ -5111,13 +5729,17 @@ namespace ts { || token === SyntaxKind.ExclamationToken; } - export function isLogicalOrCoalescingAssignmentOperator(token: SyntaxKind): token is LogicalOrCoalescingAssignmentOperator { + export function isLogicalOrCoalescingAssignmentOperator( + token: SyntaxKind, + ): token is LogicalOrCoalescingAssignmentOperator { return token === SyntaxKind.BarBarEqualsToken || token === SyntaxKind.AmpersandAmpersandEqualsToken || token === SyntaxKind.QuestionQuestionEqualsToken; } - export function isLogicalOrCoalescingAssignmentExpression(expr: BinaryExpression): expr is AssignmentExpression> { + export function isLogicalOrCoalescingAssignmentExpression( + expr: BinaryExpression, + ): expr is AssignmentExpression> { return isLogicalOrCoalescingAssignmentOperator(expr.operatorToken.kind); } @@ -5135,7 +5757,9 @@ namespace ts { readonly class: ClassLikeDeclaration; readonly isImplements: boolean; } - export function tryGetClassImplementingOrExtendingExpressionWithTypeArguments(node: Node): ClassImplementingOrExtendingExpressionWithTypeArguments | undefined { + export function tryGetClassImplementingOrExtendingExpressionWithTypeArguments( + node: Node, + ): ClassImplementingOrExtendingExpressionWithTypeArguments | undefined { return isExpressionWithTypeArguments(node) && isHeritageClause(node.parent) && isClassLike(node.parent.parent) @@ -5143,9 +5767,18 @@ namespace ts { : undefined; } - export function isAssignmentExpression(node: Node, excludeCompoundAssignment: true): node is AssignmentExpression; - export function isAssignmentExpression(node: Node, excludeCompoundAssignment?: false): node is AssignmentExpression; - export function isAssignmentExpression(node: Node, excludeCompoundAssignment?: boolean): node is AssignmentExpression { + export function isAssignmentExpression( + node: Node, + excludeCompoundAssignment: true, + ): node is AssignmentExpression; + export function isAssignmentExpression( + node: Node, + excludeCompoundAssignment?: false, + ): node is AssignmentExpression; + export function isAssignmentExpression( + node: Node, + excludeCompoundAssignment?: boolean, + ): node is AssignmentExpression { return isBinaryExpression(node) && (excludeCompoundAssignment ? node.operatorToken.kind === SyntaxKind.EqualsToken @@ -5198,8 +5831,10 @@ namespace ts { || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword || node.kind === SyntaxKind.MetaProperty - || node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((node as PropertyAccessExpression).expression) - || node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((node as ParenthesizedExpression).expression); + || node.kind === SyntaxKind.PropertyAccessExpression + && isDottedName((node as PropertyAccessExpression).expression) + || node.kind === SyntaxKind.ParenthesizedExpression + && isDottedName((node as ParenthesizedExpression).expression); } export function isPropertyAccessEntityNameExpression(node: Node): node is PropertyAccessEntityNameExpression { @@ -5230,8 +5865,9 @@ namespace ts { } export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) { - return (node.parent.kind === SyntaxKind.QualifiedName && (node.parent as QualifiedName).right === node) || - (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent as PropertyAccessExpression).name === node); + return (node.parent.kind === SyntaxKind.QualifiedName && (node.parent as QualifiedName).right === node) + || (node.parent.kind === SyntaxKind.PropertyAccessExpression + && (node.parent as PropertyAccessExpression).name === node); } export function isRightSideOfAccessExpression(node: Node) { @@ -5246,13 +5882,13 @@ namespace ts { } export function isEmptyObjectLiteral(expression: Node): boolean { - return expression.kind === SyntaxKind.ObjectLiteralExpression && - (expression as ObjectLiteralExpression).properties.length === 0; + return expression.kind === SyntaxKind.ObjectLiteralExpression + && (expression as ObjectLiteralExpression).properties.length === 0; } export function isEmptyArrayLiteral(expression: Node): boolean { - return expression.kind === SyntaxKind.ArrayLiteralExpression && - (expression as ArrayLiteralExpression).elements.length === 0; + return expression.kind === SyntaxKind.ArrayLiteralExpression + && (expression as ArrayLiteralExpression).elements.length === 0; } export function getLocalSymbolForExportDefault(symbol: Symbol) { @@ -5264,7 +5900,8 @@ namespace ts { } function isExportDefaultSymbol(symbol: Symbol): boolean { - return symbol && length(symbol.declarations) > 0 && hasSyntacticModifier(symbol.declarations![0], ModifierFlags.Default); + return symbol && length(symbol.declarations) > 0 + && hasSyntacticModifier(symbol.declarations![0], ModifierFlags.Default); } /** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */ @@ -5339,7 +5976,8 @@ namespace ts { } // Write to the output - result += base64Digits.charAt(byte1) + base64Digits.charAt(byte2) + base64Digits.charAt(byte3) + base64Digits.charAt(byte4); + result += base64Digits.charAt(byte1) + base64Digits.charAt(byte2) + base64Digits.charAt(byte3) + + base64Digits.charAt(byte4); i += 3; } @@ -5423,7 +6061,10 @@ namespace ts { return getStringFromExpandedCharCodes(expandedCharCodes); } - export function readJsonOrUndefined(path: string, hostOrText: { readFile(fileName: string): string | undefined; } | string): object | undefined { + export function readJsonOrUndefined( + path: string, + hostOrText: { readFile(fileName: string): string | undefined; } | string, + ): object | undefined { const jsonText = isString(hostOrText) ? hostOrText : hostOrText.readFile(path); if (!jsonText) return undefined; // gracefully handle if readFile fails or returns not JSON @@ -5435,7 +6076,10 @@ namespace ts { return readJsonOrUndefined(path, host) || {}; } - export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean; }): boolean { + export function directoryProbablyExists( + directoryName: string, + host: { directoryExists?: (directoryName: string) => boolean; }, + ): boolean { // if host does not support 'directoryExists' assume that directory will exist return !host.directoryExists || host.directoryExists(directoryName); } @@ -5539,14 +6183,27 @@ namespace ts { } export function rangeStartIsOnSameLineAsRangeEnd(range1: TextRange, range2: TextRange, sourceFile: SourceFile) { - return positionsAreOnSameLine(getStartPositionOfRange(range1, sourceFile, /*includeComments*/ false), range2.end, sourceFile); + return positionsAreOnSameLine( + getStartPositionOfRange(range1, sourceFile, /*includeComments*/ false), + range2.end, + sourceFile, + ); } export function rangeEndIsOnSameLineAsRangeStart(range1: TextRange, range2: TextRange, sourceFile: SourceFile) { - return positionsAreOnSameLine(range1.end, getStartPositionOfRange(range2, sourceFile, /*includeComments*/ false), sourceFile); + return positionsAreOnSameLine( + range1.end, + getStartPositionOfRange(range2, sourceFile, /*includeComments*/ false), + sourceFile, + ); } - export function getLinesBetweenRangeEndAndRangeStart(range1: TextRange, range2: TextRange, sourceFile: SourceFile, includeSecondRangeComments: boolean) { + export function getLinesBetweenRangeEndAndRangeStart( + range1: TextRange, + range2: TextRange, + sourceFile: SourceFile, + includeSecondRangeComments: boolean, + ) { const range2Start = getStartPositionOfRange(range2, sourceFile, includeSecondRangeComments); return getLinesBetweenPositions(sourceFile, range1.end, range2Start); } @@ -5564,16 +6221,27 @@ namespace ts { } export function getStartPositionOfRange(range: TextRange, sourceFile: SourceFile, includeComments: boolean) { - return positionIsSynthesized(range.pos) ? -1 : skipTrivia(sourceFile.text, range.pos, /*stopAfterLineBreak*/ false, includeComments); + return positionIsSynthesized(range.pos) ? -1 + : skipTrivia(sourceFile.text, range.pos, /*stopAfterLineBreak*/ false, includeComments); } - export function getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(pos: number, stopPos: number, sourceFile: SourceFile, includeComments?: boolean) { + export function getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter( + pos: number, + stopPos: number, + sourceFile: SourceFile, + includeComments?: boolean, + ) { const startPos = skipTrivia(sourceFile.text, pos, /*stopAfterLineBreak*/ false, includeComments); const prevPos = getPreviousNonWhitespacePosition(startPos, stopPos, sourceFile); return getLinesBetweenPositions(sourceFile, prevPos ?? stopPos, startPos); } - export function getLinesBetweenPositionAndNextNonWhitespaceCharacter(pos: number, stopPos: number, sourceFile: SourceFile, includeComments?: boolean) { + export function getLinesBetweenPositionAndNextNonWhitespaceCharacter( + pos: number, + stopPos: number, + sourceFile: SourceFile, + includeComments?: boolean, + ) { const nextPos = skipTrivia(sourceFile.text, pos, /*stopAfterLineBreak*/ false, includeComments); return getLinesBetweenPositions(sourceFile, pos, Math.min(stopPos, nextPos)); } @@ -5626,15 +6294,17 @@ namespace ts { export function getDeclarationModifierFlagsFromSymbol(s: Symbol, isWrite = false): ModifierFlags { if (s.valueDeclaration) { const declaration = (isWrite && s.declarations && find(s.declarations, isSetAccessorDeclaration)) - || (s.flags & SymbolFlags.GetAccessor && find(s.declarations, isGetAccessorDeclaration)) || s.valueDeclaration; + || (s.flags & SymbolFlags.GetAccessor && find(s.declarations, isGetAccessorDeclaration)) + || s.valueDeclaration; const flags = getCombinedModifierFlags(declaration); - return s.parent && s.parent.flags & SymbolFlags.Class ? flags : flags & ~ModifierFlags.AccessibilityModifier; + return s.parent && s.parent.flags & SymbolFlags.Class ? flags + : flags & ~ModifierFlags.AccessibilityModifier; } if (getCheckFlags(s) & CheckFlags.Synthetic) { const checkFlags = (s as TransientSymbol).checkFlags; - const accessModifier = checkFlags & CheckFlags.ContainsPrivate ? ModifierFlags.Private : - checkFlags & CheckFlags.ContainsPublic ? ModifierFlags.Public : - ModifierFlags.Protected; + const accessModifier = checkFlags & CheckFlags.ContainsPrivate ? ModifierFlags.Private + : checkFlags & CheckFlags.ContainsPublic ? ModifierFlags.Public + : ModifierFlags.Protected; const staticModifier = checkFlags & CheckFlags.ContainsStatic ? ModifierFlags.Static : 0; return accessModifier | staticModifier; } @@ -5679,11 +6349,12 @@ namespace ts { case SyntaxKind.PostfixUnaryExpression: case SyntaxKind.PrefixUnaryExpression: const { operator } = parent as PrefixUnaryExpression | PostfixUnaryExpression; - return operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken ? writeOrReadWrite() : AccessKind.Read; + return operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken + ? writeOrReadWrite() : AccessKind.Read; case SyntaxKind.BinaryExpression: const { left, operatorToken } = parent as BinaryExpression; - return left === node && isAssignmentOperator(operatorToken.kind) ? - operatorToken.kind === SyntaxKind.EqualsToken ? AccessKind.Write : writeOrReadWrite() + return left === node && isAssignmentOperator(operatorToken.kind) + ? operatorToken.kind === SyntaxKind.EqualsToken ? AccessKind.Write : writeOrReadWrite() : AccessKind.Read; case SyntaxKind.PropertyAccessExpression: return (parent as PropertyAccessExpression).name !== node ? AccessKind.Read : accessKind(parent); @@ -5694,7 +6365,8 @@ namespace ts { } case SyntaxKind.ShorthandPropertyAssignment: // Assume it's the local variable being accessed, since we don't check public properties for --noUnusedLocals. - return node === (parent as ShorthandPropertyAssignment).objectAssignmentInitializer ? AccessKind.Read : accessKind(parent.parent); + return node === (parent as ShorthandPropertyAssignment).objectAssignmentInitializer ? AccessKind.Read + : accessKind(parent.parent); case SyntaxKind.ArrayLiteralExpression: return accessKind(parent); default: @@ -5703,7 +6375,9 @@ namespace ts { function writeOrReadWrite(): AccessKind { // If grandparent is not an ExpressionStatement, this is used as an expression in addition to having a side effect. - return parent.parent && walkUpParenthesizedExpressions(parent.parent).kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite; + return parent.parent + && walkUpParenthesizedExpressions(parent.parent).kind === SyntaxKind.ExpressionStatement + ? AccessKind.Write : AccessKind.ReadWrite; } } function reverseAccessKind(a: AccessKind): AccessKind { @@ -5742,7 +6416,10 @@ namespace ts { /** * clears already present map by calling onDeleteExistingValue callback before deleting that key/value */ - export function clearMap(map: { forEach: ESMap["forEach"]; clear: ESMap["clear"]; }, onDeleteValue: (valueInMap: T, key: K) => void) { + export function clearMap( + map: { forEach: ESMap["forEach"]; clear: ESMap["clear"]; }, + onDeleteValue: (valueInMap: T, key: K) => void, + ) { // Remove all map.forEach(onDeleteValue); map.clear(); @@ -5791,7 +6468,11 @@ namespace ts { /** * Mutates the map with newMap such that keys in map will be same as newMap. */ - export function mutateMap(map: ESMap, newMap: ReadonlyESMap, options: MutateMapOptions) { + export function mutateMap( + map: ESMap, + newMap: ReadonlyESMap, + options: MutateMapOptions, + ) { // Needs update mutateMapSkippingNewValues(map, newMap, options); @@ -5822,7 +6503,8 @@ namespace ts { } export function typeHasCallOrConstructSignatures(type: Type, checker: TypeChecker) { - return checker.getSignaturesOfType(type, SignatureKind.Call).length !== 0 || checker.getSignaturesOfType(type, SignatureKind.Construct).length !== 0; + return checker.getSignaturesOfType(type, SignatureKind.Call).length !== 0 + || checker.getSignaturesOfType(type, SignatureKind.Construct).length !== 0; } export function forSomeAncestorDirectory(directory: string, callback: (directory: string) => boolean): boolean { @@ -5830,7 +6512,8 @@ namespace ts { } export function isUMDExportSymbol(symbol: Symbol | undefined): boolean { - return !!symbol && !!symbol.declarations && !!symbol.declarations[0] && isNamespaceExportDeclaration(symbol.declarations[0]); + return !!symbol && !!symbol.declarations && !!symbol.declarations[0] + && isNamespaceExportDeclaration(symbol.declarations[0]); } export function showModuleSpecifier({ moduleSpecifier }: ImportDeclaration): string { @@ -5924,7 +6607,10 @@ namespace ts { return expr; } - export function forEachNameInAccessChainWalkingLeft(name: MemberName | StringLiteralLike, action: (name: MemberName | StringLiteralLike) => T | undefined): T | undefined { + export function forEachNameInAccessChainWalkingLeft( + name: MemberName | StringLiteralLike, + action: (name: MemberName | StringLiteralLike) => T | undefined, + ): T | undefined { if (isAccessExpression(name.parent) && isRightSideOfAccessExpression(name)) { return walkAccessExpression(name.parent); } @@ -5991,7 +6677,14 @@ namespace ts { case SyntaxKind.NonNullExpression: case SyntaxKind.PartiallyEmittedExpression: case SyntaxKind.SatisfiesExpression: - node = (node as CallExpression | PropertyAccessExpression | ElementAccessExpression | AsExpression | NonNullExpression | PartiallyEmittedExpression | SatisfiesExpression).expression; + node = (node as + | CallExpression + | PropertyAccessExpression + | ElementAccessExpression + | AsExpression + | NonNullExpression + | PartiallyEmittedExpression + | SatisfiesExpression).expression; continue; } @@ -6003,12 +6696,20 @@ namespace ts { getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node; getTokenConstructor(): new (kind: TKind, pos?: number, end?: number) => Token; getIdentifierConstructor(): new (kind: SyntaxKind.Identifier, pos?: number, end?: number) => Identifier; - getPrivateIdentifierConstructor(): new (kind: SyntaxKind.PrivateIdentifier, pos?: number, end?: number) => PrivateIdentifier; + getPrivateIdentifierConstructor(): new ( + kind: SyntaxKind.PrivateIdentifier, + pos?: number, + end?: number, + ) => PrivateIdentifier; getSourceFileConstructor(): new (kind: SyntaxKind.SourceFile, pos?: number, end?: number) => SourceFile; getSymbolConstructor(): new (flags: SymbolFlags, name: __String) => Symbol; getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type; getSignatureConstructor(): new (checker: TypeChecker, flags: SignatureFlags) => Signature; - getSourceMapSourceConstructor(): new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource; + getSourceMapSourceConstructor(): new ( + fileName: string, + text: string, + skipTrivia?: (pos: number) => number, + ) => SourceMapSource; } function Symbol(this: Symbol, flags: SymbolFlags, name: __String) { @@ -6069,7 +6770,12 @@ namespace ts { this.flowNode = undefined; } - function SourceMapSource(this: SourceMapSource, fileName: string, text: string, skipTrivia?: (pos: number) => number) { + function SourceMapSource( + this: SourceMapSource, + fileName: string, + text: string, + skipTrivia?: (pos: number) => number, + ) { this.fileName = fileName; this.text = text; this.skipTrivia = skipTrivia || (pos => pos); @@ -6106,7 +6812,9 @@ namespace ts { /* @internal */ // If the localized messages json is unset, and if given function use it to set the json - export function maybeSetLocalizedDiagnosticMessages(getMessages: undefined | (() => typeof localizedDiagnosticMessages)) { + export function maybeSetLocalizedDiagnosticMessages( + getMessages: undefined | (() => typeof localizedDiagnosticMessages), + ) { if (!localizedDiagnosticMessages && getMessages) { localizedDiagnosticMessages = getMessages(); } @@ -6116,8 +6824,19 @@ namespace ts { return localizedDiagnosticMessages && localizedDiagnosticMessages[message.key] || message.message; } - export function createDetachedDiagnostic(fileName: string, start: number, length: number, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticWithDetachedLocation; - export function createDetachedDiagnostic(fileName: string, start: number, length: number, message: DiagnosticMessage): DiagnosticWithDetachedLocation { + export function createDetachedDiagnostic( + fileName: string, + start: number, + length: number, + message: DiagnosticMessage, + ...args: (string | number | undefined)[] + ): DiagnosticWithDetachedLocation; + export function createDetachedDiagnostic( + fileName: string, + start: number, + length: number, + message: DiagnosticMessage, + ): DiagnosticWithDetachedLocation { assertDiagnosticLocation(/*file*/ undefined, start, length); let text = getLocaleSpecificMessage(message); @@ -6138,14 +6857,19 @@ namespace ts { }; } - function isDiagnosticWithDetachedLocation(diagnostic: DiagnosticRelatedInformation | DiagnosticWithDetachedLocation): diagnostic is DiagnosticWithDetachedLocation { + function isDiagnosticWithDetachedLocation( + diagnostic: DiagnosticRelatedInformation | DiagnosticWithDetachedLocation, + ): diagnostic is DiagnosticWithDetachedLocation { return diagnostic.file === undefined && diagnostic.start !== undefined && diagnostic.length !== undefined && typeof (diagnostic as DiagnosticWithDetachedLocation).fileName === "string"; } - function attachFileToDiagnostic(diagnostic: DiagnosticWithDetachedLocation, file: SourceFile): DiagnosticWithLocation { + function attachFileToDiagnostic( + diagnostic: DiagnosticWithDetachedLocation, + file: SourceFile, + ): DiagnosticWithLocation { const fileName = file.fileName || ""; const length = file.text.length; Debug.assertEqual(diagnostic.fileName, fileName); @@ -6176,7 +6900,10 @@ namespace ts { return diagnosticWithLocation; } - export function attachFileToDiagnostics(diagnostics: DiagnosticWithDetachedLocation[], file: SourceFile): DiagnosticWithLocation[] { + export function attachFileToDiagnostics( + diagnostics: DiagnosticWithDetachedLocation[], + file: SourceFile, + ): DiagnosticWithLocation[] { const diagnosticsWithLocation: DiagnosticWithLocation[] = []; for (const diagnostic of diagnostics) { diagnosticsWithLocation.push(attachFileToDiagnostic(diagnostic, file)); @@ -6184,8 +6911,19 @@ namespace ts { return diagnosticsWithLocation; } - export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticWithLocation; - export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): DiagnosticWithLocation { + export function createFileDiagnostic( + file: SourceFile, + start: number, + length: number, + message: DiagnosticMessage, + ...args: (string | number | undefined)[] + ): DiagnosticWithLocation; + export function createFileDiagnostic( + file: SourceFile, + start: number, + length: number, + message: DiagnosticMessage, + ): DiagnosticWithLocation { assertDiagnosticLocation(file, start, length); let text = getLocaleSpecificMessage(message); @@ -6207,7 +6945,11 @@ namespace ts { }; } - export function formatMessage(_dummy: any, message: DiagnosticMessage, ...args: (string | number | undefined)[]): string; + export function formatMessage( + _dummy: any, + message: DiagnosticMessage, + ...args: (string | number | undefined)[] + ): string; export function formatMessage(_dummy: any, message: DiagnosticMessage): string { let text = getLocaleSpecificMessage(message); @@ -6218,7 +6960,10 @@ namespace ts { return text; } - export function createCompilerDiagnostic(message: DiagnosticMessage, ...args: (string | number | undefined)[]): Diagnostic; + export function createCompilerDiagnostic( + message: DiagnosticMessage, + ...args: (string | number | undefined)[] + ): Diagnostic; export function createCompilerDiagnostic(message: DiagnosticMessage): Diagnostic { let text = getLocaleSpecificMessage(message); @@ -6239,7 +6984,10 @@ namespace ts { }; } - export function createCompilerDiagnosticFromMessageChain(chain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): Diagnostic { + export function createCompilerDiagnosticFromMessageChain( + chain: DiagnosticMessageChain, + relatedInformation?: DiagnosticRelatedInformation[], + ): Diagnostic { return { file: undefined, start: undefined, @@ -6252,8 +7000,15 @@ namespace ts { }; } - export function chainDiagnosticMessages(details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticMessageChain; - export function chainDiagnosticMessages(details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, message: DiagnosticMessage): DiagnosticMessageChain { + export function chainDiagnosticMessages( + details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, + message: DiagnosticMessage, + ...args: (string | number | undefined)[] + ): DiagnosticMessageChain; + export function chainDiagnosticMessages( + details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, + message: DiagnosticMessage, + ): DiagnosticMessageChain { let text = getLocaleSpecificMessage(message); if (arguments.length > 2) { @@ -6268,7 +7023,10 @@ namespace ts { }; } - export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): void { + export function concatenateDiagnosticMessageChains( + headChain: DiagnosticMessageChain, + tailChain: DiagnosticMessageChain, + ): void { let lastChain = headChain; while (lastChain.next) { lastChain = lastChain.next[0]; @@ -6282,18 +7040,18 @@ namespace ts { } export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): Comparison { - return compareDiagnosticsSkipRelatedInformation(d1, d2) || - compareRelatedInformation(d1, d2) || - Comparison.EqualTo; + return compareDiagnosticsSkipRelatedInformation(d1, d2) + || compareRelatedInformation(d1, d2) + || Comparison.EqualTo; } export function compareDiagnosticsSkipRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison { - return compareStringsCaseSensitive(getDiagnosticFilePath(d1), getDiagnosticFilePath(d2)) || - compareValues(d1.start, d2.start) || - compareValues(d1.length, d2.length) || - compareValues(d1.code, d2.code) || - compareMessageText(d1.messageText, d2.messageText) || - Comparison.EqualTo; + return compareStringsCaseSensitive(getDiagnosticFilePath(d1), getDiagnosticFilePath(d2)) + || compareValues(d1.start, d2.start) + || compareValues(d1.length, d2.length) + || compareValues(d1.code, d2.code) + || compareMessageText(d1.messageText, d2.messageText) + || Comparison.EqualTo; } function compareRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison { @@ -6301,10 +7059,11 @@ namespace ts { return Comparison.EqualTo; } if (d1.relatedInformation && d2.relatedInformation) { - return compareValues(d1.relatedInformation.length, d2.relatedInformation.length) || forEach(d1.relatedInformation, (d1i, index) => { - const d2i = d2.relatedInformation![index]; - return compareDiagnostics(d1i, d2i); // EqualTo is 0, so falsy, and will cause the next item to be compared - }) || Comparison.EqualTo; + return compareValues(d1.relatedInformation.length, d2.relatedInformation.length) + || forEach(d1.relatedInformation, (d1i, index) => { + const d2i = d2.relatedInformation![index]; + return compareDiagnostics(d1i, d2i); // EqualTo is 0, so falsy, and will cause the next item to be compared + }) || Comparison.EqualTo; } return d1.relatedInformation ? Comparison.LessThan : Comparison.GreaterThan; } @@ -6350,7 +7109,8 @@ namespace ts { export function getLanguageVariant(scriptKind: ScriptKind) { // .tsx and .jsx files are treated as jsx language variant. - return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSON ? LanguageVariant.JSX : LanguageVariant.Standard; + return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS + || scriptKind === ScriptKind.JSON ? LanguageVariant.JSX : LanguageVariant.Standard; } /** @@ -6377,7 +7137,9 @@ namespace ts { // Excludes declaration files - they still require an explicit `export {}` or the like // for back compat purposes. The only non-declaration files _not_ forced to be a module are `.js` files // that aren't esm-mode (meaning not in a `type: module` scope). - return (file.impliedNodeFormat === ModuleKind.ESNext || (fileExtensionIsOneOf(file.fileName, [Extension.Cjs, Extension.Cts, Extension.Mjs, Extension.Mts]))) && !file.isDeclarationFile ? true : undefined; + return (file.impliedNodeFormat === ModuleKind.ESNext + || (fileExtensionIsOneOf(file.fileName, [Extension.Cjs, Extension.Cts, Extension.Mjs, Extension.Mts]))) + && !file.isDeclarationFile ? true : undefined; } export function getSetExternalModuleIndicator(options: CompilerOptions): (file: SourceFile) => void { @@ -6386,7 +7148,8 @@ namespace ts { case ModuleDetectionKind.Force: // All non-declaration files are modules, declaration files still do the usual isFileProbablyExternalModule return (file: SourceFile) => { - file.externalModuleIndicator = isFileProbablyExternalModule(file) || !file.isDeclarationFile || undefined; + file.externalModuleIndicator = isFileProbablyExternalModule(file) || !file.isDeclarationFile + || undefined; }; case ModuleDetectionKind.Legacy: // Files are modules if they have imports, exports, or import.meta @@ -6408,17 +7171,21 @@ namespace ts { } } - export function getEmitScriptTarget(compilerOptions: { module?: CompilerOptions["module"]; target?: CompilerOptions["target"]; }) { - return compilerOptions.target || - (compilerOptions.module === ModuleKind.Node16 && ScriptTarget.ES2022) || - (compilerOptions.module === ModuleKind.NodeNext && ScriptTarget.ESNext) || - ScriptTarget.ES3; + export function getEmitScriptTarget( + compilerOptions: { module?: CompilerOptions["module"]; target?: CompilerOptions["target"]; }, + ) { + return compilerOptions.target + || (compilerOptions.module === ModuleKind.Node16 && ScriptTarget.ES2022) + || (compilerOptions.module === ModuleKind.NodeNext && ScriptTarget.ESNext) + || ScriptTarget.ES3; } - export function getEmitModuleKind(compilerOptions: { module?: CompilerOptions["module"]; target?: CompilerOptions["target"]; }) { - return typeof compilerOptions.module === "number" ? - compilerOptions.module : - getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 ? ModuleKind.ES2015 : ModuleKind.CommonJS; + export function getEmitModuleKind( + compilerOptions: { module?: CompilerOptions["module"]; target?: CompilerOptions["target"]; }, + ) { + return typeof compilerOptions.module === "number" + ? compilerOptions.module + : getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 ? ModuleKind.ES2015 : ModuleKind.CommonJS; } export function getEmitModuleResolutionKind(compilerOptions: CompilerOptions) { @@ -6443,8 +7210,9 @@ namespace ts { } export function getEmitModuleDetectionKind(options: CompilerOptions) { - return options.moduleDetection || - (getEmitModuleKind(options) === ModuleKind.Node16 || getEmitModuleKind(options) === ModuleKind.NodeNext ? ModuleDetectionKind.Force : ModuleDetectionKind.Auto); + return options.moduleDetection + || (getEmitModuleKind(options) === ModuleKind.Node16 || getEmitModuleKind(options) === ModuleKind.NodeNext + ? ModuleDetectionKind.Force : ModuleDetectionKind.Auto); } export function hasJsonModuleEmitEnabled(options: CompilerOptions) { @@ -6491,8 +7259,8 @@ namespace ts { const moduleKind = getEmitModuleKind(compilerOptions); return compilerOptions.allowSyntheticDefaultImports !== undefined ? compilerOptions.allowSyntheticDefaultImports - : getESModuleInterop(compilerOptions) || - moduleKind === ModuleKind.System; + : getESModuleInterop(compilerOptions) + || moduleKind === ModuleKind.System; } export function getEmitDeclarations(compilerOptions: CompilerOptions): boolean { @@ -6526,10 +7294,14 @@ namespace ts { } export function getUseDefineForClassFields(compilerOptions: CompilerOptions): boolean { - return compilerOptions.useDefineForClassFields === undefined ? getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022 : compilerOptions.useDefineForClassFields; + return compilerOptions.useDefineForClassFields === undefined + ? getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022 : compilerOptions.useDefineForClassFields; } - export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions): boolean { + export function compilerOptionsAffectSemanticDiagnostics( + newOptions: CompilerOptions, + oldOptions: CompilerOptions, + ): boolean { return optionsHaveChanges(oldOptions, newOptions, semanticDiagnosticsOptionDeclarations); } @@ -6537,12 +7309,16 @@ namespace ts { return optionsHaveChanges(oldOptions, newOptions, affectsEmitOptionDeclarations); } - export function compilerOptionsAffectDeclarationPath(newOptions: CompilerOptions, oldOptions: CompilerOptions): boolean { + export function compilerOptionsAffectDeclarationPath( + newOptions: CompilerOptions, + oldOptions: CompilerOptions, + ): boolean { return optionsHaveChanges(oldOptions, newOptions, affectsDeclarationPathOptionDeclarations); } export function getCompilerOptionValue(options: CompilerOptions, option: CommandLineOption): unknown { - return option.strictFlag ? getStrictOptionValue(options, option.name as StrictOptionName) : options[option.name]; + return option.strictFlag ? getStrictOptionValue(options, option.name as StrictOptionName) + : options[option.name]; } export function getJSXTransformEnabled(options: CompilerOptions): boolean { @@ -6552,13 +7328,14 @@ namespace ts { export function getJSXImplicitImportBase(compilerOptions: CompilerOptions, file?: SourceFile): string | undefined { const jsxImportSourcePragmas = file?.pragmas.get("jsximportsource"); - const jsxImportSourcePragma = isArray(jsxImportSourcePragmas) ? jsxImportSourcePragmas[jsxImportSourcePragmas.length - 1] : jsxImportSourcePragmas; - return compilerOptions.jsx === JsxEmit.ReactJSX || - compilerOptions.jsx === JsxEmit.ReactJSXDev || - compilerOptions.jsxImportSource || - jsxImportSourcePragma ? - jsxImportSourcePragma?.arguments.factory || compilerOptions.jsxImportSource || "react" : - undefined; + const jsxImportSourcePragma = isArray(jsxImportSourcePragmas) + ? jsxImportSourcePragmas[jsxImportSourcePragmas.length - 1] : jsxImportSourcePragmas; + return compilerOptions.jsx === JsxEmit.ReactJSX + || compilerOptions.jsx === JsxEmit.ReactJSXDev + || compilerOptions.jsxImportSource + || jsxImportSourcePragma + ? jsxImportSourcePragma?.arguments.factory || compilerOptions.jsxImportSource || "react" + : undefined; } export function getJSXRuntimeImport(base: string | undefined, options: CompilerOptions) { @@ -6603,7 +7380,10 @@ namespace ts { * don't include automatic type reference directives. Must be called only when * `hasProcessedResolutions` returns false (once per cache instance). */ - setSymlinksFromResolutions(files: readonly SourceFile[], typeReferenceDirectives: ModeAwareCache | undefined): void; + setSymlinksFromResolutions( + files: readonly SourceFile[], + typeReferenceDirectives: ModeAwareCache | undefined, + ): void; /** * @internal * Whether `setSymlinksFromResolutions` has already been called. @@ -6629,7 +7409,10 @@ namespace ts { if (!containsIgnoredPath(symlinkPath)) { symlinkPath = ensureTrailingDirectorySeparator(symlinkPath); if (real !== false && !symlinkedDirectories?.has(symlinkPath)) { - (symlinkedDirectoriesByRealpath ||= createMultiMap()).add(ensureTrailingDirectorySeparator(real.realPath), symlink); + (symlinkedDirectoriesByRealpath ||= createMultiMap()).add( + ensureTrailingDirectorySeparator(real.realPath), + symlink, + ); } (symlinkedDirectories || (symlinkedDirectories = new Map())).set(symlinkPath, real); } @@ -6645,11 +7428,15 @@ namespace ts { hasProcessedResolutions: () => hasProcessedResolutions, }; - function processResolution(cache: SymlinkCache, resolution: ResolvedModuleFull | ResolvedTypeReferenceDirective | undefined) { + function processResolution( + cache: SymlinkCache, + resolution: ResolvedModuleFull | ResolvedTypeReferenceDirective | undefined, + ) { if (!resolution || !resolution.originalPath || !resolution.resolvedFileName) return; const { resolvedFileName, originalPath } = resolution; cache.setSymlinkedFile(toPath(originalPath, cwd, getCanonicalFileName), resolvedFileName); - const [commonResolved, commonOriginal] = guessDirectorySymlink(resolvedFileName, originalPath, cwd, getCanonicalFileName) || emptyArray; + const [commonResolved, commonOriginal] = + guessDirectorySymlink(resolvedFileName, originalPath, cwd, getCanonicalFileName) || emptyArray; if (commonResolved && commonOriginal) { cache.setSymlinkedDirectory( commonOriginal, @@ -6659,15 +7446,20 @@ namespace ts { } } - function guessDirectorySymlink(a: string, b: string, cwd: string, getCanonicalFileName: GetCanonicalFileName): [string, string] | undefined { + function guessDirectorySymlink( + a: string, + b: string, + cwd: string, + getCanonicalFileName: GetCanonicalFileName, + ): [string, string] | undefined { const aParts = getPathComponents(getNormalizedAbsolutePath(a, cwd)); const bParts = getPathComponents(getNormalizedAbsolutePath(b, cwd)); let isDirectory = false; while ( - aParts.length >= 2 && bParts.length >= 2 && - !isNodeModulesOrScopedPackageDirectory(aParts[aParts.length - 2], getCanonicalFileName) && - !isNodeModulesOrScopedPackageDirectory(bParts[bParts.length - 2], getCanonicalFileName) && - getCanonicalFileName(aParts[aParts.length - 1]) === getCanonicalFileName(bParts[bParts.length - 1]) + aParts.length >= 2 && bParts.length >= 2 + && !isNodeModulesOrScopedPackageDirectory(aParts[aParts.length - 2], getCanonicalFileName) + && !isNodeModulesOrScopedPackageDirectory(bParts[bParts.length - 2], getCanonicalFileName) + && getCanonicalFileName(aParts[aParts.length - 1]) === getCanonicalFileName(bParts[bParts.length - 1]) ) { aParts.pop(); bParts.pop(); @@ -6678,7 +7470,10 @@ namespace ts { // KLUDGE: Don't assume one 'node_modules' links to another. More likely a single directory inside the node_modules is the symlink. // ALso, don't assume that an `@foo` directory is linked. More likely the contents of that are linked. - function isNodeModulesOrScopedPackageDirectory(s: string | undefined, getCanonicalFileName: GetCanonicalFileName): boolean { + function isNodeModulesOrScopedPackageDirectory( + s: string | undefined, + getCanonicalFileName: GetCanonicalFileName, + ): boolean { return s !== undefined && (getCanonicalFileName(s) === "node_modules" || startsWith(s, "@")); } @@ -6686,7 +7481,11 @@ namespace ts { return isAnyDirectorySeparator(s.charCodeAt(0)) ? s.slice(1) : undefined; } - export function tryRemoveDirectoryPrefix(path: string, dirPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined { + export function tryRemoveDirectoryPrefix( + path: string, + dirPath: string, + getCanonicalFileName: GetCanonicalFileName, + ): string | undefined { const withoutPrefix = tryRemovePrefix(path, dirPath, getCanonicalFileName); return withoutPrefix === undefined ? undefined : stripLeadingDirectorySeparator(withoutPrefix); } @@ -6739,7 +7538,8 @@ namespace ts { * files or directories, does not match subdirectories that start with a . character */ doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`, - replaceWildcardCharacter: match => replaceWildcardCharacter(match, directoriesMatcher.singleAsteriskRegexFragment), + replaceWildcardCharacter: match => + replaceWildcardCharacter(match, directoriesMatcher.singleAsteriskRegexFragment), }; const excludeMatcher: WildcardMatcher = { @@ -6754,7 +7554,11 @@ namespace ts { exclude: excludeMatcher, }; - export function getRegularExpressionForWildcard(specs: readonly string[] | undefined, basePath: string, usage: "files" | "directories" | "exclude"): string | undefined { + export function getRegularExpressionForWildcard( + specs: readonly string[] | undefined, + basePath: string, + usage: "files" | "directories" | "exclude", + ): string | undefined { const patterns = getRegularExpressionsForWildcards(specs, basePath, usage); if (!patterns || !patterns.length) { return undefined; @@ -6766,7 +7570,11 @@ namespace ts { return `^(${pattern})${terminator}`; } - export function getRegularExpressionsForWildcards(specs: readonly string[] | undefined, basePath: string, usage: "files" | "directories" | "exclude"): readonly string[] | undefined { + export function getRegularExpressionsForWildcards( + specs: readonly string[] | undefined, + basePath: string, + usage: "files" | "directories" | "exclude", + ): readonly string[] | undefined { if (specs === undefined || specs.length === 0) { return undefined; } @@ -6787,7 +7595,12 @@ namespace ts { return pattern && `^(${pattern})${usage === "exclude" ? "($|/)" : "$"}`; } - function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }: WildcardMatcher): string | undefined { + function getSubPatternFromSpec( + spec: string, + basePath: string, + usage: "files" | "directories" | "exclude", + { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }: WildcardMatcher, + ): string | undefined { let subpattern = ""; let hasWrittenComponent = false; const components = getNormalizedPathComponents(spec, basePath); @@ -6883,13 +7696,22 @@ namespace ts { } /** @param path directory of the tsconfig.json */ - export function getFileMatcherPatterns(path: string, excludes: readonly string[] | undefined, includes: readonly string[] | undefined, useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns { + export function getFileMatcherPatterns( + path: string, + excludes: readonly string[] | undefined, + includes: readonly string[] | undefined, + useCaseSensitiveFileNames: boolean, + currentDirectory: string, + ): FileMatcherPatterns { path = normalizePath(path); currentDirectory = normalizePath(currentDirectory); const absolutePath = combinePaths(currentDirectory, path); return { - includeFilePatterns: map(getRegularExpressionsForWildcards(includes, absolutePath, "files"), pattern => `^${pattern}$`), + includeFilePatterns: map( + getRegularExpressionsForWildcards(includes, absolutePath, "files"), + pattern => `^${pattern}$`, + ), includeFilePattern: getRegularExpressionForWildcard(includes, absolutePath, "files"), includeDirectoryPattern: getRegularExpressionForWildcard(includes, absolutePath, "directories"), excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, "exclude"), @@ -6902,15 +7724,28 @@ namespace ts { } /** @param path directory of the tsconfig.json */ - export function matchFiles(path: string, extensions: readonly string[] | undefined, excludes: readonly string[] | undefined, includes: readonly string[] | undefined, useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries, realpath: (path: string) => string): string[] { + export function matchFiles( + path: string, + extensions: readonly string[] | undefined, + excludes: readonly string[] | undefined, + includes: readonly string[] | undefined, + useCaseSensitiveFileNames: boolean, + currentDirectory: string, + depth: number | undefined, + getFileSystemEntries: (path: string) => FileSystemEntries, + realpath: (path: string) => string, + ): string[] { path = normalizePath(path); currentDirectory = normalizePath(currentDirectory); const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory); - const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames)); - const includeDirectoryRegex = patterns.includeDirectoryPattern && getRegexFromPattern(patterns.includeDirectoryPattern, useCaseSensitiveFileNames); - const excludeRegex = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, useCaseSensitiveFileNames); + const includeFileRegexes = patterns.includeFilePatterns + && patterns.includeFilePatterns.map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames)); + const includeDirectoryRegex = patterns.includeDirectoryPattern + && getRegexFromPattern(patterns.includeDirectoryPattern, useCaseSensitiveFileNames); + const excludeRegex = patterns.excludePattern + && getRegexFromPattern(patterns.excludePattern, useCaseSensitiveFileNames); // Associate an array of results with each include regex. This keeps results in order of the "include" order. // If there are no "includes", then just put everything in results[0]. @@ -6956,8 +7791,8 @@ namespace ts { const name = combinePaths(path, current); const absoluteName = combinePaths(absolutePath, current); if ( - (!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) && - (!excludeRegex || !excludeRegex.test(absoluteName)) + (!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) + && (!excludeRegex || !excludeRegex.test(absoluteName)) ) { visitDirectory(name, absoluteName, depth); } @@ -6968,7 +7803,11 @@ namespace ts { /** * Computes the unique non-wildcard base paths amongst the provided include patterns. */ - function getBasePaths(path: string, includes: readonly string[] | undefined, useCaseSensitiveFileNames: boolean): string[] { + function getBasePaths( + path: string, + includes: readonly string[] | undefined, + useCaseSensitiveFileNames: boolean, + ): string[] { // Storage for our results in the form of literal paths (e.g. the paths as written by the user). const basePaths: string[] = [path]; @@ -6978,7 +7817,8 @@ namespace ts { for (const include of includes) { // We also need to check the relative paths by converting them to absolute and normalizing // in case they escape the base path (e.g "..\somedirectory") - const absolute: string = isRootedDiskPath(include) ? include : normalizePath(combinePaths(path, include)); + const absolute: string = isRootedDiskPath(include) ? include + : normalizePath(combinePaths(path, include)); // Append the literal and canonical candidate base paths. includeBasePaths.push(getIncludeBasePath(absolute)); } @@ -6989,7 +7829,12 @@ namespace ts { // Iterate over each include base path and include unique base paths that are not a // subpath of an existing base path for (const includeBasePath of includeBasePaths) { - if (every(basePaths, basePath => !containsPath(basePath, includeBasePath, path, !useCaseSensitiveFileNames))) { + if ( + every( + basePaths, + basePath => !containsPath(basePath, includeBasePath, path, !useCaseSensitiveFileNames), + ) + ) { basePaths.push(includeBasePath); } } @@ -7044,20 +7889,45 @@ namespace ts { /** * Groups of supported extensions in order of file resolution precedence. (eg, TS > TSX > DTS and seperately, CTS > DCTS) */ - export const supportedTSExtensions: readonly Extension[][] = [[Extension.Ts, Extension.Tsx, Extension.Dts], [Extension.Cts, Extension.Dcts], [Extension.Mts, Extension.Dmts]]; + export const supportedTSExtensions: readonly Extension[][] = [[Extension.Ts, Extension.Tsx, Extension.Dts], [ + Extension.Cts, + Extension.Dcts, + ], [Extension.Mts, Extension.Dmts]]; export const supportedTSExtensionsFlat: readonly Extension[] = flatten(supportedTSExtensions); const supportedTSExtensionsWithJson: readonly Extension[][] = [...supportedTSExtensions, [Extension.Json]]; /** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */ - const supportedTSExtensionsForExtractExtension: readonly Extension[] = [Extension.Dts, Extension.Dcts, Extension.Dmts, Extension.Cts, Extension.Mts, Extension.Ts, Extension.Tsx, Extension.Cts, Extension.Mts]; - export const supportedJSExtensions: readonly Extension[][] = [[Extension.Js, Extension.Jsx], [Extension.Mjs], [Extension.Cjs]]; + const supportedTSExtensionsForExtractExtension: readonly Extension[] = [ + Extension.Dts, + Extension.Dcts, + Extension.Dmts, + Extension.Cts, + Extension.Mts, + Extension.Ts, + Extension.Tsx, + Extension.Cts, + Extension.Mts, + ]; + export const supportedJSExtensions: readonly Extension[][] = [[Extension.Js, Extension.Jsx], [Extension.Mjs], [ + Extension.Cjs, + ]]; export const supportedJSExtensionsFlat: readonly Extension[] = flatten(supportedJSExtensions); - const allSupportedExtensions: readonly Extension[][] = [[Extension.Ts, Extension.Tsx, Extension.Dts, Extension.Js, Extension.Jsx], [Extension.Cts, Extension.Dcts, Extension.Cjs], [Extension.Mts, Extension.Dmts, Extension.Mjs]]; + const allSupportedExtensions: readonly Extension[][] = [ + [Extension.Ts, Extension.Tsx, Extension.Dts, Extension.Js, Extension.Jsx], + [Extension.Cts, Extension.Dcts, Extension.Cjs], + [Extension.Mts, Extension.Dmts, Extension.Mjs], + ]; const allSupportedExtensionsWithJson: readonly Extension[][] = [...allSupportedExtensions, [Extension.Json]]; export const supportedDeclarationExtensions: readonly Extension[] = [Extension.Dts, Extension.Dcts, Extension.Dmts]; export function getSupportedExtensions(options?: CompilerOptions): readonly Extension[][]; - export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: readonly FileExtensionInfo[]): readonly string[][]; - export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: readonly FileExtensionInfo[]): readonly string[][] { + export function getSupportedExtensions( + options?: CompilerOptions, + extraFileExtensions?: readonly FileExtensionInfo[], + ): readonly string[][]; + export function getSupportedExtensions( + options?: CompilerOptions, + extraFileExtensions?: readonly FileExtensionInfo[], + ): readonly string[][] { const needJsExtensions = options && getAllowJSCompilerOption(options); if (!extraFileExtensions || extraFileExtensions.length === 0) { @@ -7068,15 +7938,29 @@ namespace ts { const flatBuiltins = flatten(builtins); const extensions = [ ...builtins, - ...mapDefined(extraFileExtensions, x => x.scriptKind === ScriptKind.Deferred || needJsExtensions && isJSLike(x.scriptKind) && flatBuiltins.indexOf(x.extension as Extension) === -1 ? [x.extension] : undefined), + ...mapDefined( + extraFileExtensions, + x => x.scriptKind === ScriptKind.Deferred + || needJsExtensions && isJSLike(x.scriptKind) + && flatBuiltins.indexOf(x.extension as Extension) === -1 ? [x.extension] : undefined, + ), ]; return extensions; } - export function getSupportedExtensionsWithJsonIfResolveJsonModule(options: CompilerOptions | undefined, supportedExtensions: readonly Extension[][]): readonly Extension[][]; - export function getSupportedExtensionsWithJsonIfResolveJsonModule(options: CompilerOptions | undefined, supportedExtensions: readonly string[][]): readonly string[][]; - export function getSupportedExtensionsWithJsonIfResolveJsonModule(options: CompilerOptions | undefined, supportedExtensions: readonly string[][]): readonly string[][] { + export function getSupportedExtensionsWithJsonIfResolveJsonModule( + options: CompilerOptions | undefined, + supportedExtensions: readonly Extension[][], + ): readonly Extension[][]; + export function getSupportedExtensionsWithJsonIfResolveJsonModule( + options: CompilerOptions | undefined, + supportedExtensions: readonly string[][], + ): readonly string[][]; + export function getSupportedExtensionsWithJsonIfResolveJsonModule( + options: CompilerOptions | undefined, + supportedExtensions: readonly string[][], + ): readonly string[][] { if (!options || !options.resolveJsonModule) return supportedExtensions; if (supportedExtensions === allSupportedExtensions) return allSupportedExtensionsWithJson; if (supportedExtensions === supportedTSExtensions) return supportedTSExtensionsWithJson; @@ -7095,11 +7979,19 @@ namespace ts { return some(supportedTSExtensionsFlat, extension => fileExtensionIs(fileName, extension)); } - export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: readonly FileExtensionInfo[]) { + export function isSupportedSourceFileName( + fileName: string, + compilerOptions?: CompilerOptions, + extraFileExtensions?: readonly FileExtensionInfo[], + ) { if (!fileName) return false; const supportedExtensions = getSupportedExtensions(compilerOptions, extraFileExtensions); - for (const extension of flatten(getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, supportedExtensions))) { + for ( + const extension of flatten( + getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, supportedExtensions), + ) + ) { if (fileExtensionIs(fileName, extension)) { return true; } @@ -7119,7 +8011,20 @@ namespace ts { ); } - const extensionsToRemove = [Extension.Dts, Extension.Dmts, Extension.Dcts, Extension.Mjs, Extension.Mts, Extension.Cjs, Extension.Cts, Extension.Ts, Extension.Js, Extension.Tsx, Extension.Jsx, Extension.Json]; + const extensionsToRemove = [ + Extension.Dts, + Extension.Dmts, + Extension.Dcts, + Extension.Mjs, + Extension.Mts, + Extension.Cjs, + Extension.Cts, + Extension.Ts, + Extension.Js, + Extension.Tsx, + Extension.Jsx, + Extension.Json, + ]; export function removeFileExtension(path: string): string { for (const ext of extensionsToRemove) { const extensionless = tryRemoveExtension(path, ext); @@ -7171,7 +8076,8 @@ namespace ts { /** True if an extension is one of the supported TypeScript extensions. */ export function extensionIsTS(ext: Extension): boolean { - return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts || ext === Extension.Cts || ext === Extension.Mts || ext === Extension.Dmts || ext === Extension.Dcts; + return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts || ext === Extension.Cts + || ext === Extension.Mts || ext === Extension.Dmts || ext === Extension.Dcts; } export function resolutionExtensionIsTSOrJson(ext: Extension) { @@ -7209,7 +8115,10 @@ namespace ts { * Return an exact match if possible, or a pattern match, or undefined. * (These are verified by verifyCompilerOptions to have 0 or 1 "*" characters.) */ - export function matchPatternOrExact(patternOrStrings: readonly (string | Pattern)[], candidate: string): string | Pattern | undefined { + export function matchPatternOrExact( + patternOrStrings: readonly (string | Pattern)[], + candidate: string, + ): string | Pattern | undefined { const patterns: Pattern[] = []; for (const patternOrString of patternOrStrings) { if (patternOrString === candidate) { @@ -7232,19 +8141,28 @@ namespace ts { return arr.slice(index); } - export function addRelatedInfo(diagnostic: T, ...relatedInformation: DiagnosticRelatedInformation[]): T { + export function addRelatedInfo( + diagnostic: T, + ...relatedInformation: DiagnosticRelatedInformation[] + ): T { if (!relatedInformation.length) { return diagnostic; } if (!diagnostic.relatedInformation) { diagnostic.relatedInformation = []; } - Debug.assert(diagnostic.relatedInformation !== emptyArray, "Diagnostic had empty array singleton for related info, but is still being constructed!"); + Debug.assert( + diagnostic.relatedInformation !== emptyArray, + "Diagnostic had empty array singleton for related info, but is still being constructed!", + ); diagnostic.relatedInformation.push(...relatedInformation); return diagnostic; } - export function minAndMax(arr: readonly T[], getValue: (value: T) => number): { readonly min: number; readonly max: number; } { + export function minAndMax( + arr: readonly T[], + getValue: (value: T) => number, + ): { readonly min: number; readonly max: number; } { Debug.assert(arr.length !== 0); let min = getValue(arr[0]); let max = min; @@ -7264,7 +8182,10 @@ namespace ts { return { pos: getTokenPosOfNode(node), end: node.end }; } - export function rangeOfTypeParameters(sourceFile: SourceFile, typeParameters: NodeArray): TextRange { + export function rangeOfTypeParameters( + sourceFile: SourceFile, + typeParameters: NodeArray, + ): TextRange { // Include the `<>` const pos = typeParameters.pos - 1; const end = skipTrivia(sourceFile.text, typeParameters.end) + 1; @@ -7274,18 +8195,24 @@ namespace ts { export interface HostWithIsSourceOfProjectReferenceRedirect { isSourceOfProjectReferenceRedirect(fileName: string): boolean; } - export function skipTypeChecking(sourceFile: SourceFile, options: CompilerOptions, host: HostWithIsSourceOfProjectReferenceRedirect) { + export function skipTypeChecking( + sourceFile: SourceFile, + options: CompilerOptions, + host: HostWithIsSourceOfProjectReferenceRedirect, + ) { // If skipLibCheck is enabled, skip reporting errors if file is a declaration file. // If skipDefaultLibCheck is enabled, skip reporting errors if file contains a // '/// ' directive. - return (options.skipLibCheck && sourceFile.isDeclarationFile || - options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib) || - host.isSourceOfProjectReferenceRedirect(sourceFile.fileName); + return (options.skipLibCheck && sourceFile.isDeclarationFile + || options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib) + || host.isSourceOfProjectReferenceRedirect(sourceFile.fileName); } export function isJsonEqual(a: unknown, b: unknown): boolean { // eslint-disable-next-line no-null/no-null - return a === b || typeof a === "object" && a !== null && typeof b === "object" && b !== null && equalOwnProperties(a as MapLike, b as MapLike, isJsonEqual); + return a === b + || typeof a === "object" && a !== null && typeof b === "object" && b !== null + && equalOwnProperties(a as MapLike, b as MapLike, isJsonEqual); } /** @@ -7330,8 +8257,8 @@ namespace ts { // Find character range: 0-9 < A-F < a-f const digit = digitChar <= CharacterCodes._9 ? digitChar - CharacterCodes._0 - : 10 + digitChar - - (digitChar <= CharacterCodes.F ? CharacterCodes.A : CharacterCodes.a); + : 10 + digitChar + - (digitChar <= CharacterCodes.F ? CharacterCodes.A : CharacterCodes.a); const shiftedDigit = digit << (bitOffset & 15); segments[segment] |= shiftedDigit; const residual = shiftedDigit >>> 16; @@ -7372,7 +8299,8 @@ namespace ts { } function isShorthandPropertyNameUseSite(useSite: Node) { - return isIdentifier(useSite) && isShorthandPropertyAssignment(useSite.parent) && useSite.parent.name === useSite; + return isIdentifier(useSite) && isShorthandPropertyAssignment(useSite.parent) + && useSite.parent.name === useSite; } function isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(node: Node) { @@ -7403,7 +8331,8 @@ namespace ts { return "quit"; } }) as HeritageClause | undefined; - return heritageClause?.token === SyntaxKind.ImplementsKeyword || heritageClause?.parent.kind === SyntaxKind.InterfaceDeclaration; + return heritageClause?.token === SyntaxKind.ImplementsKeyword + || heritageClause?.parent.kind === SyntaxKind.InterfaceDeclaration; } export function isIdentifierTypeReference(node: Node): node is TypeReferenceNode & { typeName: Identifier; } { @@ -7489,8 +8418,14 @@ namespace ts { /* @internal */ export function setEachParent(children: T, parent: T[number]["parent"]): T; /* @internal */ - export function setEachParent(children: T | undefined, parent: T[number]["parent"]): T | undefined; - export function setEachParent(children: T | undefined, parent: T[number]["parent"]): T | undefined { + export function setEachParent( + children: T | undefined, + parent: T[number]["parent"], + ): T | undefined; + export function setEachParent( + children: T | undefined, + parent: T[number]["parent"], + ): T | undefined { if (children) { for (const child of children) { setParent(child, parent); @@ -7562,9 +8497,9 @@ namespace ts { } // result is unused in an expression statement, `void` expression, or the initializer or incrementer of a `for` loop if ( - isExpressionStatement(parent) || - isVoidExpression(parent) || - isForStatement(parent) && (parent.initializer === node || parent.incrementor === node) + isExpressionStatement(parent) + || isVoidExpression(parent) + || isForStatement(parent) && (parent.initializer === node || parent.incrementor === node) ) { return true; } @@ -7604,9 +8539,9 @@ namespace ts { return (node as TemplateSpan).parent.templateSpans; case SyntaxKind.Decorator: { const { parent } = node as Decorator; - return canHaveDecorators(parent) ? parent.modifiers : - canHaveIllegalDecorators(parent) ? parent.illegalDecorators : - undefined; + return canHaveDecorators(parent) ? parent.modifiers + : canHaveIllegalDecorators(parent) ? parent.illegalDecorators + : undefined; } case SyntaxKind.HeritageClause: return (node as HeritageClause).parent.heritageClauses; @@ -7629,21 +8564,27 @@ namespace ts { case SyntaxKind.CommaListExpression: case SyntaxKind.NamedImports: case SyntaxKind.NamedExports: - return (parent as TupleTypeNode | ArrayLiteralExpression | CommaListExpression | NamedImports | NamedExports).elements; + return (parent as + | TupleTypeNode + | ArrayLiteralExpression + | CommaListExpression + | NamedImports + | NamedExports).elements; case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.JsxAttributes: return (parent as ObjectLiteralExpressionBase).properties; case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: - return isTypeNode(node) ? (parent as CallExpression | NewExpression).typeArguments : - (parent as CallExpression | NewExpression).expression === node ? undefined : - (parent as CallExpression | NewExpression).arguments; + return isTypeNode(node) ? (parent as CallExpression | NewExpression).typeArguments + : (parent as CallExpression | NewExpression).expression === node ? undefined + : (parent as CallExpression | NewExpression).arguments; case SyntaxKind.JsxElement: case SyntaxKind.JsxFragment: return isJsxChild(node) ? (parent as JsxElement | JsxFragment).children : undefined; case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxSelfClosingElement: - return isTypeNode(node) ? (parent as JsxOpeningElement | JsxSelfClosingElement).typeArguments : undefined; + return isTypeNode(node) ? (parent as JsxOpeningElement | JsxSelfClosingElement).typeArguments + : undefined; case SyntaxKind.Block: case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: @@ -7727,10 +8668,15 @@ namespace ts { return (+name).toString() === name; } - export function createPropertyNameNodeForIdentifierOrLiteral(name: string, target: ScriptTarget, singleQuote?: boolean, stringNamed?: boolean) { - return isIdentifierText(name, target) ? factory.createIdentifier(name) : - !stringNamed && isNumericLiteralName(name) && +name >= 0 ? factory.createNumericLiteral(+name) : - factory.createStringLiteral(name, !!singleQuote); + export function createPropertyNameNodeForIdentifierOrLiteral( + name: string, + target: ScriptTarget, + singleQuote?: boolean, + stringNamed?: boolean, + ) { + return isIdentifierText(name, target) ? factory.createIdentifier(name) + : !stringNamed && isNumericLiteralName(name) && +name >= 0 ? factory.createNumericLiteral(+name) + : factory.createStringLiteral(name, !!singleQuote); } export function isThisTypeParameter(type: Type): boolean { @@ -7798,14 +8744,29 @@ namespace ts { fileNameIndex = partStart; - return state > States.NodeModules ? { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex, fileNameIndex } : undefined; + return state > States.NodeModules + ? { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex, fileNameIndex } : undefined; } export function getParameterTypeNode(parameter: ParameterDeclaration | JSDocParameterTag) { return parameter.kind === SyntaxKind.JSDocParameterTag ? parameter.typeExpression?.type : parameter.type; } - export function isTypeDeclaration(node: Node): node is TypeParameterDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | EnumDeclaration | ImportClause | ImportSpecifier | ExportSpecifier { + export function isTypeDeclaration( + node: Node, + ): node is + | TypeParameterDeclaration + | ClassDeclaration + | InterfaceDeclaration + | TypeAliasDeclaration + | JSDocTypedefTag + | JSDocCallbackTag + | JSDocEnumTag + | EnumDeclaration + | ImportClause + | ImportSpecifier + | ExportSpecifier + { switch (node.kind) { case SyntaxKind.TypeParameter: case SyntaxKind.ClassDeclaration: @@ -7827,7 +8788,9 @@ namespace ts { } export function canHaveExportModifier(node: Node): node is Extract { - return isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) || isClassDeclaration(node) - || isInterfaceDeclaration(node) || isTypeDeclaration(node) || (isModuleDeclaration(node) && !isExternalModuleAugmentation(node) && !isGlobalScopeAugmentation(node)); + return isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) + || isClassDeclaration(node) + || isInterfaceDeclaration(node) || isTypeDeclaration(node) + || (isModuleDeclaration(node) && !isExternalModuleAugmentation(node) && !isGlobalScopeAugmentation(node)); } } diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index fe9dd099cd6d6..f8de0a3a789dd 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -6,7 +6,9 @@ namespace ts { return pathIsRelative(moduleName) || isRootedDiskPath(moduleName); } - export function sortAndDeduplicateDiagnostics(diagnostics: readonly T[]): SortedReadonlyArray { + export function sortAndDeduplicateDiagnostics( + diagnostics: readonly T[], + ): SortedReadonlyArray { return sortAndDeduplicate(diagnostics, compareDiagnostics); } @@ -131,7 +133,9 @@ namespace ts { * This function will then merge those changes into a single change range valid between V1 and * Vn. */ - export function collapseTextChangeRangesAcrossMultipleVersions(changes: readonly TextChangeRange[]): TextChangeRange { + export function collapseTextChangeRangesAcrossMultipleVersions( + changes: readonly TextChangeRange[], + ): TextChangeRange { if (changes.length === 0) { return unchangedTextChangeRange; } @@ -250,16 +254,22 @@ namespace ts { export function getTypeParameterOwner(d: Declaration): Declaration | undefined { if (d && d.kind === SyntaxKind.TypeParameter) { for (let current: Node = d; current; current = current.parent) { - if (isFunctionLike(current) || isClassLike(current) || current.kind === SyntaxKind.InterfaceDeclaration) { + if ( + isFunctionLike(current) || isClassLike(current) || current.kind === SyntaxKind.InterfaceDeclaration + ) { return current as Declaration; } } } } - export type ParameterPropertyDeclaration = ParameterDeclaration & { parent: ConstructorDeclaration; name: Identifier; }; + export type ParameterPropertyDeclaration = ParameterDeclaration & { + parent: ConstructorDeclaration; + name: Identifier; + }; export function isParameterPropertyDeclaration(node: Node, parent: Node): node is ParameterPropertyDeclaration { - return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) && parent.kind === SyntaxKind.Constructor; + return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) + && parent.kind === SyntaxKind.Constructor; } export function isEmptyBindingPattern(node: BindingName): node is BindingPattern { @@ -276,7 +286,9 @@ namespace ts { return isEmptyBindingPattern(node.name); } - export function walkUpBindingElementsAndPatterns(binding: BindingElement): VariableDeclaration | ParameterDeclaration { + export function walkUpBindingElementsAndPatterns( + binding: BindingElement, + ): VariableDeclaration | ParameterDeclaration { let node = binding.parent; while (isBindingElement(node.parent)) { node = node.parent.parent; @@ -323,7 +335,21 @@ namespace ts { } /* @internal */ - export const supportedLocaleDirectories = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"]; + export const supportedLocaleDirectories = [ + "cs", + "de", + "es", + "fr", + "it", + "ja", + "ko", + "pl", + "pt-br", + "ru", + "tr", + "zh-cn", + "zh-tw", + ]; /** * Checks to see if the locale is in the appropriate format, @@ -331,7 +357,12 @@ namespace ts { */ export function validateLocaleAndSetLanguage( locale: string, - sys: { getExecutingFilePath(): string; resolvePath(path: string): string; fileExists(fileName: string): boolean; readFile(fileName: string): string | undefined; }, + sys: { + getExecutingFilePath(): string; + resolvePath(path: string): string; + fileExists(fileName: string): boolean; + readFile(fileName: string): string | undefined; + }, errors?: Push, ) { const lowerCaseLocale = locale.toLowerCase(); @@ -339,7 +370,13 @@ namespace ts { if (!matchResult) { if (errors) { - errors.push(createCompilerDiagnostic(Diagnostics.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, "en", "ja-jp")); + errors.push( + createCompilerDiagnostic( + Diagnostics.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, + "en", + "ja-jp", + ), + ); } return; } @@ -349,14 +386,21 @@ namespace ts { // First try the entire locale, then fall back to just language if that's all we have. // Either ways do not fail, and fallback to the English diagnostic strings. - if (contains(supportedLocaleDirectories, lowerCaseLocale) && !trySetLanguageAndTerritory(language, territory, errors)) { + if ( + contains(supportedLocaleDirectories, lowerCaseLocale) + && !trySetLanguageAndTerritory(language, territory, errors) + ) { trySetLanguageAndTerritory(language, /*territory*/ undefined, errors); } // Set the UI locale for string collation setUILocale(locale); - function trySetLanguageAndTerritory(language: string, territory: string | undefined, errors?: Push): boolean { + function trySetLanguageAndTerritory( + language: string, + territory: string | undefined, + errors?: Push, + ): boolean { const compilerFilePath = normalizePath(sys.getExecutingFilePath()); const containingDirectoryPath = getDirectoryPath(compilerFilePath); @@ -401,8 +445,14 @@ namespace ts { export function getOriginalNode(node: Node): Node; export function getOriginalNode(node: Node, nodeTest: (node: Node) => node is T): T; export function getOriginalNode(node: Node | undefined): Node | undefined; - export function getOriginalNode(node: Node | undefined, nodeTest: (node: Node | undefined) => node is T): T | undefined; - export function getOriginalNode(node: Node | undefined, nodeTest?: (node: Node | undefined) => boolean): Node | undefined { + export function getOriginalNode( + node: Node | undefined, + nodeTest: (node: Node | undefined) => node is T, + ): T | undefined; + export function getOriginalNode( + node: Node | undefined, + nodeTest?: (node: Node | undefined) => boolean, + ): Node | undefined { if (node) { while (node.original !== undefined) { node = node.original; @@ -418,8 +468,14 @@ namespace ts { * If no such value is found, it applies the callback until the parent pointer is undefined or the callback returns "quit" * At that point findAncestor returns undefined. */ - export function findAncestor(node: Node | undefined, callback: (element: Node) => element is T): T | undefined; - export function findAncestor(node: Node | undefined, callback: (element: Node) => boolean | "quit"): Node | undefined; + export function findAncestor( + node: Node | undefined, + callback: (element: Node) => element is T, + ): T | undefined; + export function findAncestor( + node: Node | undefined, + callback: (element: Node) => boolean | "quit", + ): Node | undefined; export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node | undefined { while (node) { const result = callback(node); @@ -458,7 +514,10 @@ namespace ts { * @param nodeTest A callback used to ensure the correct type of parse tree node is returned. * @returns The original parse tree node if found; otherwise, undefined. */ - export function getParseTreeNode(node: T | undefined, nodeTest?: (node: Node) => node is T): T | undefined; + export function getParseTreeNode( + node: T | undefined, + nodeTest?: (node: Node) => node is T, + ): T | undefined; export function getParseTreeNode(node: Node | undefined, nodeTest?: (node: Node) => boolean): Node | undefined { if (node === undefined || isParseTreeNode(node)) { return node; @@ -475,7 +534,8 @@ namespace ts { /** Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' */ export function escapeLeadingUnderscores(identifier: string): __String { - return (identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier) as __String; + return (identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ + && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier) as __String; } /** @@ -486,7 +546,8 @@ namespace ts { */ export function unescapeLeadingUnderscores(identifier: __String): string { const id = identifier as string; - return id.length >= 3 && id.charCodeAt(0) === CharacterCodes._ && id.charCodeAt(1) === CharacterCodes._ && id.charCodeAt(2) === CharacterCodes._ ? id.substr(1) : id; + return id.length >= 3 && id.charCodeAt(0) === CharacterCodes._ && id.charCodeAt(1) === CharacterCodes._ + && id.charCodeAt(2) === CharacterCodes._ ? id.substr(1) : id; } export function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string { @@ -504,7 +565,9 @@ namespace ts { * attempt to draw the name from the node the declaration is on (as that declaration is what its' symbol * will be merged with) */ - function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag | JSDocEnumTag): Identifier | PrivateIdentifier | undefined { + function nameForNamelessJSDocTypedef( + declaration: JSDocTypedefTag | JSDocEnumTag, + ): Identifier | PrivateIdentifier | undefined { const hostNode = declaration.parent.parent; if (!hostNode) { return undefined; @@ -522,7 +585,10 @@ namespace ts { break; case SyntaxKind.ExpressionStatement: let expr = hostNode.expression; - if (expr.kind === SyntaxKind.BinaryExpression && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + expr.kind === SyntaxKind.BinaryExpression + && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { expr = (expr as BinaryExpression).left; } switch (expr.kind) { @@ -554,7 +620,10 @@ namespace ts { /** @internal */ export function nodeHasName(statement: Node, name: Identifier) { - if (isNamedDeclaration(statement) && isIdentifier(statement.name) && idText(statement.name as Identifier) === idText(name)) { + if ( + isNamedDeclaration(statement) && isIdentifier(statement.name) + && idText(statement.name as Identifier) === idText(name) + ) { return true; } if (isVariableStatement(statement) && some(statement.declarationList.declarations, d => nodeHasName(d, name))) { @@ -573,7 +642,9 @@ namespace ts { } /** @internal */ - export function getNonAssignedNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined { + export function getNonAssignedNameOfDeclaration( + declaration: Declaration | Expression, + ): DeclarationName | undefined { switch (declaration.kind) { case SyntaxKind.Identifier: return declaration as Identifier; @@ -593,7 +664,9 @@ namespace ts { case AssignmentDeclarationKind.ThisProperty: case AssignmentDeclarationKind.Property: case AssignmentDeclarationKind.PrototypeProperty: - return getElementOrPropertyAccessArgumentExpressionOrName((expr as BinaryExpression).left as AccessExpression); + return getElementOrPropertyAccessArgumentExpressionOrName( + (expr as BinaryExpression).left as AccessExpression, + ); case AssignmentDeclarationKind.ObjectDefinePropertyValue: case AssignmentDeclarationKind.ObjectDefinePropertyExports: case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: @@ -619,10 +692,13 @@ namespace ts { return (declaration as NamedDeclaration).name; } - export function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined { + export function getNameOfDeclaration( + declaration: Declaration | Expression | undefined, + ): DeclarationName | undefined { if (declaration === undefined) return undefined; - return getNonAssignedNameOfDeclaration(declaration) || - (isFunctionExpression(declaration) || isArrowFunction(declaration) || isClassExpression(declaration) ? getAssignedName(declaration) : undefined); + return getNonAssignedNameOfDeclaration(declaration) + || (isFunctionExpression(declaration) || isArrowFunction(declaration) || isClassExpression(declaration) + ? getAssignedName(declaration) : undefined); } /*@internal*/ @@ -662,7 +738,9 @@ namespace ts { if (param.name) { if (isIdentifier(param.name)) { const name = param.name.escapedText; - return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name); + return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocParameterTag => + isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name + ); } else { const i = param.parent.parameters.indexOf(param); @@ -698,9 +776,14 @@ namespace ts { return getJSDocParameterTagsWorker(param, /*noCache*/ true); } - function getJSDocTypeParameterTagsWorker(param: TypeParameterDeclaration, noCache?: boolean): readonly JSDocTemplateTag[] { + function getJSDocTypeParameterTagsWorker( + param: TypeParameterDeclaration, + noCache?: boolean, + ): readonly JSDocTemplateTag[] { const name = param.name.escapedText; - return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocTemplateTag => isJSDocTemplateTag(tag) && tag.typeParameters.some(tp => tp.name.escapedText === name)); + return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocTemplateTag => + isJSDocTemplateTag(tag) && tag.typeParameters.some(tp => tp.name.escapedText === name) + ); } /** @@ -900,12 +983,19 @@ namespace ts { } /** Get the first JSDoc tag of a specified kind, or undefined if not present. */ - function getFirstJSDocTag(node: Node, predicate: (tag: JSDocTag) => tag is T, noCache?: boolean): T | undefined { + function getFirstJSDocTag( + node: Node, + predicate: (tag: JSDocTag) => tag is T, + noCache?: boolean, + ): T | undefined { return find(getJSDocTagsWorker(node, noCache), predicate); } /** Gets all JSDoc tags that match a specified predicate */ - export function getAllJSDocTags(node: Node, predicate: (tag: JSDocTag) => tag is T): readonly T[] { + export function getAllJSDocTags( + node: Node, + predicate: (tag: JSDocTag) => tag is T, + ): readonly T[] { return getJSDocTags(node).filter(predicate); } @@ -939,7 +1029,9 @@ namespace ts { * /** @type {Id} / * function id(x) { return x } */ - export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[] { + export function getEffectiveTypeParameterDeclarations( + node: DeclarationWithTypeParameters, + ): readonly TypeParameterDeclaration[] { if (isJSDocSignature(node)) { return emptyArray; } @@ -967,9 +1059,9 @@ namespace ts { } export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined { - return node.constraint ? node.constraint : - isJSDocTemplateTag(node.parent) && node === node.parent.typeParameters[0] ? node.parent.constraint : - undefined; + return node.constraint ? node.constraint + : isJSDocTemplateTag(node.parent) && node === node.parent.typeParameters[0] ? node.parent.constraint + : undefined; } // #region @@ -995,10 +1087,12 @@ namespace ts { return isCallExpression(node) && !!(node.flags & NodeFlags.OptionalChain); } - export function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain { + export function isOptionalChain( + node: Node, + ): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain { const kind = node.kind; - return !!(node.flags & NodeFlags.OptionalChain) && - (kind === SyntaxKind.PropertyAccessExpression + return !!(node.flags & NodeFlags.OptionalChain) + && (kind === SyntaxKind.PropertyAccessExpression || kind === SyntaxKind.ElementAccessExpression || kind === SyntaxKind.CallExpression || kind === SyntaxKind.NonNullExpression); @@ -1036,12 +1130,13 @@ namespace ts { } export function isNullishCoalesce(node: Node) { - return node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken; + return node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken; } export function isConstTypeReference(node: Node) { - return isTypeReferenceNode(node) && isIdentifier(node.typeName) && - node.typeName.escapedText === "const" && !node.typeArguments; + return isTypeReferenceNode(node) && isIdentifier(node.typeName) + && node.typeName.escapedText === "const" && !node.typeArguments; } export function skipPartiallyEmittedExpressions(node: Expression): Expression; @@ -1073,9 +1168,9 @@ namespace ts { } export function isUnparsedNode(node: Node): node is UnparsedNode { - return isUnparsedTextLike(node) || - node.kind === SyntaxKind.UnparsedPrologue || - node.kind === SyntaxKind.UnparsedSyntheticReference; + return isUnparsedTextLike(node) + || node.kind === SyntaxKind.UnparsedPrologue + || node.kind === SyntaxKind.UnparsedSyntheticReference; } export function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag { @@ -1173,7 +1268,8 @@ namespace ts { switch (node.kind) { case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: - return (node as ImportOrExportSpecifier).isTypeOnly || (node as ImportOrExportSpecifier).parent.parent.isTypeOnly; + return (node as ImportOrExportSpecifier).isTypeOnly + || (node as ImportOrExportSpecifier).parent.parent.isTypeOnly; case SyntaxKind.NamespaceImport: return (node as NamespaceImport).parent.isTypeOnly; case SyntaxKind.ImportClause: @@ -1196,12 +1292,14 @@ namespace ts { /* @internal */ export function isGeneratedIdentifier(node: Node): node is GeneratedIdentifier { - return isIdentifier(node) && (node.autoGenerateFlags! & GeneratedIdentifierFlags.KindMask) > GeneratedIdentifierFlags.None; + return isIdentifier(node) + && (node.autoGenerateFlags! & GeneratedIdentifierFlags.KindMask) > GeneratedIdentifierFlags.None; } /* @internal */ export function isGeneratedPrivateIdentifier(node: Node): node is GeneratedPrivateIdentifier { - return isPrivateIdentifier(node) && (node.autoGenerateFlags! & GeneratedIdentifierFlags.KindMask) > GeneratedIdentifierFlags.None; + return isPrivateIdentifier(node) + && (node.autoGenerateFlags! & GeneratedIdentifierFlags.KindMask) > GeneratedIdentifierFlags.None; } // Private Identifiers @@ -1211,7 +1309,9 @@ namespace ts { } /*@internal*/ - export function isPrivateIdentifierPropertyAccessExpression(node: Node): node is PrivateIdentifierPropertyAccessExpression { + export function isPrivateIdentifierPropertyAccessExpression( + node: Node, + ): node is PrivateIdentifierPropertyAccessExpression { return isPropertyAccessExpression(node) && isPrivateIdentifier(node.name); } @@ -1247,10 +1347,10 @@ namespace ts { /* @internal */ export function isClassMemberModifier(idToken: SyntaxKind): boolean { - return isParameterPropertyModifier(idToken) || - idToken === SyntaxKind.StaticKeyword || - idToken === SyntaxKind.OverrideKeyword || - idToken === SyntaxKind.AccessorKeyword; + return isParameterPropertyModifier(idToken) + || idToken === SyntaxKind.StaticKeyword + || idToken === SyntaxKind.OverrideKeyword + || idToken === SyntaxKind.AccessorKeyword; } export function isModifier(node: Node): node is Modifier { @@ -1286,7 +1386,9 @@ namespace ts { } /* @internal */ - export function isFunctionLikeOrClassStaticBlockDeclaration(node: Node | undefined): node is SignatureDeclaration | ClassStaticBlockDeclaration { + export function isFunctionLikeOrClassStaticBlockDeclaration( + node: Node | undefined, + ): node is SignatureDeclaration | ClassStaticBlockDeclaration { return !!node && (isFunctionLikeKind(node.kind) || isClassStaticBlockDeclaration(node)); } @@ -1375,7 +1477,9 @@ namespace ts { } /* @internal */ - export function isNamedClassElement(node: Node): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration { + export function isNamedClassElement( + node: Node, + ): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration { switch (node.kind) { case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: @@ -1470,7 +1574,9 @@ namespace ts { * Determines whether the BindingOrAssignmentElement is a BindingElement-like declaration */ /* @internal */ - export function isDeclarationBindingElement(bindingElement: BindingOrAssignmentElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { + export function isDeclarationBindingElement( + bindingElement: BindingOrAssignmentElement, + ): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { switch (bindingElement.kind) { case SyntaxKind.VariableDeclaration: case SyntaxKind.Parameter: @@ -1485,7 +1591,9 @@ namespace ts { * Determines whether a node is a BindingOrAssignmentPattern */ /* @internal */ - export function isBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is BindingOrAssignmentPattern { + export function isBindingOrAssignmentPattern( + node: BindingOrAssignmentElementTarget, + ): node is BindingOrAssignmentPattern { return isObjectBindingOrAssignmentPattern(node) || isArrayBindingOrAssignmentPattern(node); } @@ -1494,7 +1602,9 @@ namespace ts { * Determines whether a node is an ObjectBindingOrAssignmentPattern */ /* @internal */ - export function isObjectBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ObjectBindingOrAssignmentPattern { + export function isObjectBindingOrAssignmentPattern( + node: BindingOrAssignmentElementTarget, + ): node is ObjectBindingOrAssignmentPattern { switch (node.kind) { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ObjectLiteralExpression: @@ -1520,7 +1630,9 @@ namespace ts { * Determines whether a node is an ArrayBindingOrAssignmentPattern */ /* @internal */ - export function isArrayBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ArrayBindingOrAssignmentPattern { + export function isArrayBindingOrAssignmentPattern( + node: BindingOrAssignmentElementTarget, + ): node is ArrayBindingOrAssignmentPattern { switch (node.kind) { case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ArrayLiteralExpression: @@ -1531,7 +1643,9 @@ namespace ts { } /* @internal */ - export function isPropertyAccessOrQualifiedNameOrImportTypeNode(node: Node): node is PropertyAccessExpression | QualifiedName | ImportTypeNode { + export function isPropertyAccessOrQualifiedNameOrImportTypeNode( + node: Node, + ): node is PropertyAccessExpression | QualifiedName | ImportTypeNode { const kind = node.kind; return kind === SyntaxKind.PropertyAccessExpression || kind === SyntaxKind.QualifiedName @@ -1639,8 +1753,8 @@ namespace ts { case SyntaxKind.PostfixUnaryExpression: return true; case SyntaxKind.PrefixUnaryExpression: - return (expr as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken || - (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken; + return (expr as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken + || (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken; default: return false; } @@ -1680,7 +1794,9 @@ namespace ts { } /* @internal */ - export function isNotEmittedOrPartiallyEmittedNode(node: Node): node is NotEmittedStatement | PartiallyEmittedExpression { + export function isNotEmittedOrPartiallyEmittedNode( + node: Node, + ): node is NotEmittedStatement | PartiallyEmittedExpression { return isNotEmittedStatement(node) || isPartiallyEmittedExpression(node); } @@ -1688,7 +1804,10 @@ namespace ts { // Statement export function isIterationStatement(node: Node, lookInLabeledStatements: false): node is IterationStatement; - export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement | LabeledStatement; + export function isIterationStatement( + node: Node, + lookInLabeledStatements: boolean, + ): node is IterationStatement | LabeledStatement; export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement { switch (node.kind) { case SyntaxKind.ForStatement: @@ -1698,7 +1817,8 @@ namespace ts { case SyntaxKind.WhileStatement: return true; case SyntaxKind.LabeledStatement: - return lookInLabeledStatements && isIterationStatement((node as LabeledStatement).statement, lookInLabeledStatements); + return lookInLabeledStatements + && isIterationStatement((node as LabeledStatement).statement, lookInLabeledStatements); } return false; @@ -1716,13 +1836,15 @@ namespace ts { /* @internal */ export function needsScopeMarker(result: Statement) { - return !isAnyImportOrReExport(result) && !isExportAssignment(result) && !hasSyntacticModifier(result, ModifierFlags.Export) && !isAmbientModule(result); + return !isAnyImportOrReExport(result) && !isExportAssignment(result) + && !hasSyntacticModifier(result, ModifierFlags.Export) && !isAmbientModule(result); } /* @internal */ export function isExternalModuleIndicator(result: Statement) { // Exported top-level member indicates moduleness - return isAnyImportOrReExport(result) || isExportAssignment(result) || hasSyntacticModifier(result, ModifierFlags.Export); + return isAnyImportOrReExport(result) || isExportAssignment(result) + || hasSyntacticModifier(result, ModifierFlags.Export); } /* @internal */ @@ -2038,7 +2160,8 @@ namespace ts { } export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement { - return node.kind === SyntaxKind.JsxAttribute || node.kind === SyntaxKind.JsxSpreadAttribute || isObjectLiteralElementLike(node); + return node.kind === SyntaxKind.JsxAttribute || node.kind === SyntaxKind.JsxSpreadAttribute + || isObjectLiteralElementLike(node); } /* @internal */ @@ -2075,7 +2198,8 @@ namespace ts { } export function isJSDocLinkLike(node: Node): node is JSDocLink | JSDocLinkCode | JSDocLinkPlain { - return node.kind === SyntaxKind.JSDocLink || node.kind === SyntaxKind.JSDocLinkCode || node.kind === SyntaxKind.JSDocLinkPlain; + return node.kind === SyntaxKind.JSDocLink || node.kind === SyntaxKind.JSDocLinkCode + || node.kind === SyntaxKind.JSDocLinkPlain; } export function hasRestParameter(s: SignatureDeclaration | JSDocSignature): boolean { @@ -2085,7 +2209,8 @@ namespace ts { export function isRestParameter(node: ParameterDeclaration | JSDocParameterTag): boolean { const type = isJSDocParameterTag(node) ? (node.typeExpression && node.typeExpression.type) : node.type; - return (node as ParameterDeclaration).dotDotDotToken !== undefined || !!type && type.kind === SyntaxKind.JSDocVariadicType; + return (node as ParameterDeclaration).dotDotDotToken !== undefined + || !!type && type.kind === SyntaxKind.JSDocVariadicType; } // #endregion diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index f58e430480f47..14064bbe43b71 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -7,7 +7,12 @@ namespace ts { * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ - export function visitNode(node: T, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T; + export function visitNode( + node: T, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + lift?: (node: readonly Node[]) => T, + ): T; /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. @@ -17,9 +22,19 @@ namespace ts { * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ - export function visitNode(node: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined; - - export function visitNode(node: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined { + export function visitNode( + node: T | undefined, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + lift?: (node: readonly Node[]) => T, + ): T | undefined; + + export function visitNode( + node: T | undefined, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + lift?: (node: readonly Node[]) => T, + ): T | undefined { if (node === undefined || visitor === undefined) { return node; } @@ -45,7 +60,13 @@ namespace ts { } /* @internal */ - export function visitNodes(nodes: NodeArray, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number): NodeArray; + export function visitNodes( + nodes: NodeArray, + visitor: Visitor, + test: (node: Node) => node is U, + start?: number, + count?: number, + ): NodeArray; /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. @@ -56,10 +77,22 @@ namespace ts { * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - export function visitNodes(nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; + export function visitNodes( + nodes: NodeArray, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray; /* @internal */ - export function visitNodes(nodes: NodeArray | undefined, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number): NodeArray | undefined; + export function visitNodes( + nodes: NodeArray | undefined, + visitor: Visitor, + test: (node: Node) => node is U, + start?: number, + count?: number, + ): NodeArray | undefined; /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. @@ -70,7 +103,13 @@ namespace ts { * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - export function visitNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; + export function visitNodes( + nodes: NodeArray | undefined, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray | undefined; /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. @@ -81,7 +120,13 @@ namespace ts { * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - export function visitNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined { + export function visitNodes( + nodes: NodeArray | undefined, + visitor: Visitor | undefined, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray | undefined { if (nodes === undefined || visitor === undefined) { return nodes; } @@ -122,14 +167,44 @@ namespace ts { } /* @internal */ - export function visitArray(nodes: T[] | undefined, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number): U[] | undefined; + export function visitArray( + nodes: T[] | undefined, + visitor: Visitor, + test: (node: Node) => node is U, + start?: number, + count?: number, + ): U[] | undefined; /* @internal */ - export function visitArray(nodes: readonly T[] | undefined, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number): readonly U[] | undefined; + export function visitArray( + nodes: readonly T[] | undefined, + visitor: Visitor, + test: (node: Node) => node is U, + start?: number, + count?: number, + ): readonly U[] | undefined; /* @internal */ - export function visitArray(nodes: T[] | undefined, visitor: Visitor, test: (node: Node) => node is T, start?: number, count?: number): T[] | undefined; + export function visitArray( + nodes: T[] | undefined, + visitor: Visitor, + test: (node: Node) => node is T, + start?: number, + count?: number, + ): T[] | undefined; /* @internal */ - export function visitArray(nodes: readonly T[] | undefined, visitor: Visitor, test: (node: Node) => node is T, start?: number, count?: number): readonly T[] | undefined; - export function visitArray(nodes: readonly T[] | undefined, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number) { + export function visitArray( + nodes: readonly T[] | undefined, + visitor: Visitor, + test: (node: Node) => node is T, + start?: number, + count?: number, + ): readonly T[] | undefined; + export function visitArray( + nodes: readonly T[] | undefined, + visitor: Visitor, + test: (node: Node) => node is U, + start?: number, + count?: number, + ) { if (nodes === undefined) { return nodes; } @@ -148,7 +223,13 @@ namespace ts { } /* @internal */ - function visitArrayWorker(nodes: readonly T[], visitor: Visitor, test: ((node: Node) => boolean) | undefined, start: number, count: number): readonly T[] | undefined { + function visitArrayWorker( + nodes: readonly T[], + visitor: Visitor, + test: ((node: Node) => boolean) | undefined, + start: number, + count: number, + ): readonly T[] | undefined { let updated: T[] | undefined; const length = nodes.length; @@ -188,7 +269,14 @@ namespace ts { * Starts a new lexical environment and visits a statement list, ending the lexical environment * and merging hoisted declarations upon completion. */ - export function visitLexicalEnvironment(statements: NodeArray, visitor: Visitor, context: TransformationContext, start?: number, ensureUseStrict?: boolean, nodesVisitor: NodesVisitor = visitNodes) { + export function visitLexicalEnvironment( + statements: NodeArray, + visitor: Visitor, + context: TransformationContext, + start?: number, + ensureUseStrict?: boolean, + nodesVisitor: NodesVisitor = visitNodes, + ) { context.startLexicalEnvironment(); statements = nodesVisitor(statements, visitor, isStatement, start); if (ensureUseStrict) statements = context.factory.ensureUseStrict(statements); @@ -199,9 +287,24 @@ namespace ts { * Starts a new lexical environment and visits a parameter list, suspending the lexical * environment upon completion. */ - export function visitParameterList(nodes: NodeArray, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor): NodeArray; - export function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor): NodeArray | undefined; - export function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes) { + export function visitParameterList( + nodes: NodeArray, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: NodesVisitor, + ): NodeArray; + export function visitParameterList( + nodes: NodeArray | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: NodesVisitor, + ): NodeArray | undefined; + export function visitParameterList( + nodes: NodeArray | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor = visitNodes, + ) { let updated: NodeArray | undefined; context.startLexicalEnvironment(); if (nodes) { @@ -215,8 +318,8 @@ namespace ts { // in a parameter list to the body if we detect a variable being hoisted while visiting a parameter list // when the emit target is greater than ES2015. if ( - context.getLexicalEnvironmentFlags() & LexicalEnvironmentFlags.VariablesHoistedInParameters && - getEmitScriptTarget(context.getCompilerOptions()) >= ScriptTarget.ES2015 + context.getLexicalEnvironmentFlags() & LexicalEnvironmentFlags.VariablesHoistedInParameters + && getEmitScriptTarget(context.getCompilerOptions()) >= ScriptTarget.ES2015 ) { updated = addDefaultValueAssignmentsIfNeeded(updated, context); } @@ -226,7 +329,10 @@ namespace ts { return updated; } - function addDefaultValueAssignmentsIfNeeded(parameters: NodeArray, context: TransformationContext) { + function addDefaultValueAssignmentsIfNeeded( + parameters: NodeArray, + context: TransformationContext, + ) { let result: ParameterDeclaration[] | undefined; for (let i = 0; i < parameters.length; i++) { const parameter = parameters[i]; @@ -245,13 +351,17 @@ namespace ts { function addDefaultValueAssignmentIfNeeded(parameter: ParameterDeclaration, context: TransformationContext) { // A rest parameter cannot have a binding pattern or an initializer, // so let's just ignore it. - return parameter.dotDotDotToken ? parameter : - isBindingPattern(parameter.name) ? addDefaultValueAssignmentForBindingPattern(parameter, context) : - parameter.initializer ? addDefaultValueAssignmentForInitializer(parameter, parameter.name, parameter.initializer, context) : - parameter; + return parameter.dotDotDotToken ? parameter + : isBindingPattern(parameter.name) ? addDefaultValueAssignmentForBindingPattern(parameter, context) + : parameter.initializer + ? addDefaultValueAssignmentForInitializer(parameter, parameter.name, parameter.initializer, context) + : parameter; } - function addDefaultValueAssignmentForBindingPattern(parameter: ParameterDeclaration, context: TransformationContext) { + function addDefaultValueAssignmentForBindingPattern( + parameter: ParameterDeclaration, + context: TransformationContext, + ) { const { factory } = context; context.addInitializationStatement( factory.createVariableStatement( @@ -261,8 +371,8 @@ namespace ts { parameter.name, /*exclamationToken*/ undefined, parameter.type, - parameter.initializer ? - factory.createConditionalExpression( + parameter.initializer + ? factory.createConditionalExpression( factory.createStrictEquality( factory.getGeneratedNameForNode(parameter), factory.createVoidZero(), @@ -271,16 +381,29 @@ namespace ts { parameter.initializer, /*colonToken*/ undefined, factory.getGeneratedNameForNode(parameter), - ) : - factory.getGeneratedNameForNode(parameter), + ) + : factory.getGeneratedNameForNode(parameter), ), ]), ), ); - return factory.updateParameterDeclaration(parameter, parameter.modifiers, parameter.dotDotDotToken, factory.getGeneratedNameForNode(parameter), parameter.questionToken, parameter.type, /*initializer*/ undefined); + return factory.updateParameterDeclaration( + parameter, + parameter.modifiers, + parameter.dotDotDotToken, + factory.getGeneratedNameForNode(parameter), + parameter.questionToken, + parameter.type, + /*initializer*/ undefined, + ); } - function addDefaultValueAssignmentForInitializer(parameter: ParameterDeclaration, name: Identifier, initializer: Expression, context: TransformationContext) { + function addDefaultValueAssignmentForInitializer( + parameter: ParameterDeclaration, + name: Identifier, + initializer: Expression, + context: TransformationContext, + ) { const factory = context.factory; context.addInitializationStatement( factory.createIfStatement( @@ -293,7 +416,11 @@ namespace ts { setTextRange( factory.createAssignment( setEmitFlags(factory.cloneNode(name), EmitFlags.NoSourceMap), - setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer) | EmitFlags.NoComments), + setEmitFlags( + initializer, + EmitFlags.NoSourceMap | getEmitFlags(initializer) + | EmitFlags.NoComments, + ), ), parameter, ), @@ -303,32 +430,69 @@ namespace ts { ]), parameter, ), - EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments, + EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps + | EmitFlags.NoComments, ), ), ); - return factory.updateParameterDeclaration(parameter, parameter.modifiers, parameter.dotDotDotToken, parameter.name, parameter.questionToken, parameter.type, /*initializer*/ undefined); + return factory.updateParameterDeclaration( + parameter, + parameter.modifiers, + parameter.dotDotDotToken, + parameter.name, + parameter.questionToken, + parameter.type, + /*initializer*/ undefined, + ); } /** * Resumes a suspended lexical environment and visits a function body, ending the lexical * environment and merging hoisted declarations upon completion. */ - export function visitFunctionBody(node: FunctionBody, visitor: Visitor, context: TransformationContext): FunctionBody; + export function visitFunctionBody( + node: FunctionBody, + visitor: Visitor, + context: TransformationContext, + ): FunctionBody; /** * Resumes a suspended lexical environment and visits a function body, ending the lexical * environment and merging hoisted declarations upon completion. */ - export function visitFunctionBody(node: FunctionBody | undefined, visitor: Visitor, context: TransformationContext): FunctionBody | undefined; + export function visitFunctionBody( + node: FunctionBody | undefined, + visitor: Visitor, + context: TransformationContext, + ): FunctionBody | undefined; /** * Resumes a suspended lexical environment and visits a concise body, ending the lexical * environment and merging hoisted declarations upon completion. */ export function visitFunctionBody(node: ConciseBody, visitor: Visitor, context: TransformationContext): ConciseBody; - /* @internal*/ export function visitFunctionBody(node: FunctionBody, visitor: Visitor, context: TransformationContext, nodeVisitor?: NodeVisitor): FunctionBody; // eslint-disable-line @typescript-eslint/unified-signatures - /* @internal*/ export function visitFunctionBody(node: FunctionBody | undefined, visitor: Visitor, context: TransformationContext, nodeVisitor?: NodeVisitor): FunctionBody | undefined; // eslint-disable-line @typescript-eslint/unified-signatures - /* @internal*/ export function visitFunctionBody(node: ConciseBody, visitor: Visitor, context: TransformationContext, nodeVisitor?: NodeVisitor): ConciseBody; // eslint-disable-line @typescript-eslint/unified-signatures - export function visitFunctionBody(node: ConciseBody | undefined, visitor: Visitor, context: TransformationContext, nodeVisitor: NodeVisitor = visitNode): ConciseBody | undefined { + /* @internal*/ export function visitFunctionBody( + node: FunctionBody, + visitor: Visitor, + context: TransformationContext, + nodeVisitor?: NodeVisitor, + ): FunctionBody; // eslint-disable-line @typescript-eslint/unified-signatures + /* @internal*/ export function visitFunctionBody( + node: FunctionBody | undefined, + visitor: Visitor, + context: TransformationContext, + nodeVisitor?: NodeVisitor, + ): FunctionBody | undefined; // eslint-disable-line @typescript-eslint/unified-signatures + /* @internal*/ export function visitFunctionBody( + node: ConciseBody, + visitor: Visitor, + context: TransformationContext, + nodeVisitor?: NodeVisitor, + ): ConciseBody; // eslint-disable-line @typescript-eslint/unified-signatures + export function visitFunctionBody( + node: ConciseBody | undefined, + visitor: Visitor, + context: TransformationContext, + nodeVisitor: NodeVisitor = visitNode, + ): ConciseBody | undefined { context.resumeLexicalEnvironment(); const updated = nodeVisitor(node, visitor, isConciseBody); const declarations = context.endLexicalEnvironment(); @@ -348,8 +512,18 @@ namespace ts { */ export function visitIterationBody(body: Statement, visitor: Visitor, context: TransformationContext): Statement; /* @internal */ - export function visitIterationBody(body: Statement, visitor: Visitor, context: TransformationContext, nodeVisitor?: NodeVisitor): Statement; // eslint-disable-line @typescript-eslint/unified-signatures - export function visitIterationBody(body: Statement, visitor: Visitor, context: TransformationContext, nodeVisitor: NodeVisitor = visitNode): Statement { + export function visitIterationBody( + body: Statement, + visitor: Visitor, + context: TransformationContext, + nodeVisitor?: NodeVisitor, + ): Statement; // eslint-disable-line @typescript-eslint/unified-signatures + export function visitIterationBody( + body: Statement, + visitor: Visitor, + context: TransformationContext, + nodeVisitor: NodeVisitor = visitNode, + ): Statement { context.startBlockScope(); const updated = nodeVisitor(body, visitor, isStatement, context.factory.liftToBlock); const declarations = context.endBlockScope(); @@ -373,7 +547,14 @@ namespace ts { */ export function visitEachChild(node: T, visitor: Visitor, context: TransformationContext): T; /* @internal */ - export function visitEachChild(node: T, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor, tokenVisitor?: Visitor, nodeVisitor?: NodeVisitor): T; // eslint-disable-line @typescript-eslint/unified-signatures + export function visitEachChild( + node: T, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: NodesVisitor, + tokenVisitor?: Visitor, + nodeVisitor?: NodeVisitor, + ): T; // eslint-disable-line @typescript-eslint/unified-signatures /** * Visits each child of a Node using the supplied visitor, possibly returning a new Node of the same kind in its place. * @@ -381,10 +562,30 @@ namespace ts { * @param visitor The callback used to visit each child. * @param context A lexical environment context for the visitor. */ - export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes, tokenVisitor?: Visitor): T | undefined; + export function visitEachChild( + node: T | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: typeof visitNodes, + tokenVisitor?: Visitor, + ): T | undefined; /* @internal */ - export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor, tokenVisitor?: Visitor, nodeVisitor?: NodeVisitor): T | undefined; // eslint-disable-line @typescript-eslint/unified-signatures - export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes, tokenVisitor?: Visitor, nodeVisitor: NodeVisitor = visitNode): T | undefined { + export function visitEachChild( + node: T | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: NodesVisitor, + tokenVisitor?: Visitor, + nodeVisitor?: NodeVisitor, + ): T | undefined; // eslint-disable-line @typescript-eslint/unified-signatures + export function visitEachChild( + node: T | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor = visitNodes, + tokenVisitor?: Visitor, + nodeVisitor: NodeVisitor = visitNode, + ): T | undefined { if (node === undefined) { return undefined; } @@ -393,7 +594,14 @@ namespace ts { return fn === undefined ? node : fn(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor); } - type VisitEachChildFunction = (node: T, visitor: Visitor, context: TransformationContext, nodesVisitor: NodesVisitor, nodeVisitor: NodeVisitor, tokenVisitor: Visitor | undefined) => T; + type VisitEachChildFunction = ( + node: T, + visitor: Visitor, + context: TransformationContext, + nodesVisitor: NodesVisitor, + nodeVisitor: NodeVisitor, + tokenVisitor: Visitor | undefined, + ) => T; // A type that correlates a `SyntaxKind` to a `VisitEachChildFunction`, for nodes in the `HasChildren` union. // This looks something like: @@ -411,37 +619,123 @@ namespace ts { // NOTE: Before you can add a new method to `visitEachChildTable`, you must first ensure the `Node` subtype you // wish to add is defined in the `HasChildren` union in types.ts. const visitEachChildTable: VisitEachChildTable = { - [SyntaxKind.Identifier]: function visitEachChildOfIdentifier(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateIdentifier(node, nodesVisitor(node.typeArguments, visitor, isTypeNodeOrTypeParameterDeclaration)); + [SyntaxKind.Identifier]: function visitEachChildOfIdentifier( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateIdentifier( + node, + nodesVisitor(node.typeArguments, visitor, isTypeNodeOrTypeParameterDeclaration), + ); }, - [SyntaxKind.QualifiedName]: function visitEachChildOfQualifiedName(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateQualifiedName(node, nodeVisitor(node.left, visitor, isEntityName), nodeVisitor(node.right, visitor, isIdentifier)); + [SyntaxKind.QualifiedName]: function visitEachChildOfQualifiedName( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateQualifiedName( + node, + nodeVisitor(node.left, visitor, isEntityName), + nodeVisitor(node.right, visitor, isIdentifier), + ); }, - [SyntaxKind.ComputedPropertyName]: function visitEachChildOfComputedPropertyName(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateComputedPropertyName(node, nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.ComputedPropertyName]: function visitEachChildOfComputedPropertyName( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateComputedPropertyName( + node, + nodeVisitor(node.expression, visitor, isExpression), + ); }, // Signature elements - [SyntaxKind.TypeParameter]: function visitEachChildOfTypeParameterDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeParameterDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.name, visitor, isIdentifier), nodeVisitor(node.constraint, visitor, isTypeNode), nodeVisitor(node.default, visitor, isTypeNode)); + [SyntaxKind.TypeParameter]: function visitEachChildOfTypeParameterDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeParameterDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.constraint, visitor, isTypeNode), + nodeVisitor(node.default, visitor, isTypeNode), + ); }, - [SyntaxKind.Parameter]: function visitEachChildOfParameterDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateParameterDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), nodeVisitor(node.name, visitor, isBindingName), nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), nodeVisitor(node.type, visitor, isTypeNode), nodeVisitor(node.initializer, visitor, isExpression)); + [SyntaxKind.Parameter]: function visitEachChildOfParameterDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateParameterDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifierLike), + nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), + nodeVisitor(node.name, visitor, isBindingName), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.initializer, visitor, isExpression), + ); }, - [SyntaxKind.Decorator]: function visitEachChildOfDecorator(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.Decorator]: function visitEachChildOfDecorator( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateDecorator(node, nodeVisitor(node.expression, visitor, isExpression)); }, // Type elements - [SyntaxKind.PropertySignature]: function visitEachChildOfPropertySignature(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updatePropertySignature(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.name, visitor, isPropertyName), nodeVisitor(node.questionToken, tokenVisitor, isToken), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.PropertySignature]: function visitEachChildOfPropertySignature( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updatePropertySignature( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.questionToken, tokenVisitor, isToken), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.PropertyDeclaration]: function visitEachChildOfPropertyDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { + [SyntaxKind.PropertyDeclaration]: function visitEachChildOfPropertyDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { return context.factory.updatePropertyDeclaration( node, nodesVisitor(node.modifiers, visitor, isModifierLike), @@ -453,533 +747,1887 @@ namespace ts { ); }, - [SyntaxKind.MethodSignature]: function visitEachChildOfMethodSignature(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateMethodSignature(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.name, visitor, isPropertyName), nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameterDeclaration), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.MethodSignature]: function visitEachChildOfMethodSignature( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateMethodSignature( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.MethodDeclaration]: function visitEachChildOfMethodDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateMethodDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), nodeVisitor(node.name, visitor, isPropertyName), nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), visitFunctionBody(node.body!, visitor, context, nodeVisitor)); + [SyntaxKind.MethodDeclaration]: function visitEachChildOfMethodDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateMethodDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifierLike), + nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + visitFunctionBody(node.body!, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.Constructor]: function visitEachChildOfConstructorDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateConstructorDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), visitParameterList(node.parameters, visitor, context, nodesVisitor), visitFunctionBody(node.body!, visitor, context, nodeVisitor)); + [SyntaxKind.Constructor]: function visitEachChildOfConstructorDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateConstructorDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + visitFunctionBody(node.body!, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.GetAccessor]: function visitEachChildOfGetAccessorDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateGetAccessorDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodeVisitor(node.name, visitor, isPropertyName), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), visitFunctionBody(node.body!, visitor, context, nodeVisitor)); + [SyntaxKind.GetAccessor]: function visitEachChildOfGetAccessorDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateGetAccessorDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifierLike), + nodeVisitor(node.name, visitor, isPropertyName), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + visitFunctionBody(node.body!, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.SetAccessor]: function visitEachChildOfSetAccessorDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateSetAccessorDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodeVisitor(node.name, visitor, isPropertyName), visitParameterList(node.parameters, visitor, context, nodesVisitor), visitFunctionBody(node.body!, visitor, context, nodeVisitor)); + [SyntaxKind.SetAccessor]: function visitEachChildOfSetAccessorDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSetAccessorDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifierLike), + nodeVisitor(node.name, visitor, isPropertyName), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + visitFunctionBody(node.body!, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ClassStaticBlockDeclaration]: function visitEachChildOfClassStaticBlockDeclaration(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.ClassStaticBlockDeclaration]: function visitEachChildOfClassStaticBlockDeclaration( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { context.startLexicalEnvironment(); context.suspendLexicalEnvironment(); - return context.factory.updateClassStaticBlockDeclaration(node, visitFunctionBody(node.body, visitor, context, nodeVisitor)); + return context.factory.updateClassStaticBlockDeclaration( + node, + visitFunctionBody(node.body, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.CallSignature]: function visitEachChildOfCallSignatureDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateCallSignature(node, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameterDeclaration), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.CallSignature]: function visitEachChildOfCallSignatureDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateCallSignature( + node, + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.ConstructSignature]: function visitEachChildOfConstructSignatureDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateConstructSignature(node, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameterDeclaration), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.ConstructSignature]: function visitEachChildOfConstructSignatureDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateConstructSignature( + node, + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.IndexSignature]: function visitEachChildOfIndexSignatureDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateIndexSignature(node, nodesVisitor(node.modifiers, visitor, isModifier), nodesVisitor(node.parameters, visitor, isParameterDeclaration), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.IndexSignature]: function visitEachChildOfIndexSignatureDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateIndexSignature( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, // Types - [SyntaxKind.TypePredicate]: function visitEachChildOfTypePredicateNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypePredicateNode(node, nodeVisitor(node.assertsModifier, visitor, isAssertsKeyword), nodeVisitor(node.parameterName, visitor, isIdentifierOrThisTypeNode), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.TypePredicate]: function visitEachChildOfTypePredicateNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypePredicateNode( + node, + nodeVisitor(node.assertsModifier, visitor, isAssertsKeyword), + nodeVisitor(node.parameterName, visitor, isIdentifierOrThisTypeNode), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.TypeReference]: function visitEachChildOfTypeReferenceNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeReferenceNode(node, nodeVisitor(node.typeName, visitor, isEntityName), nodesVisitor(node.typeArguments, visitor, isTypeNode)); + [SyntaxKind.TypeReference]: function visitEachChildOfTypeReferenceNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeReferenceNode( + node, + nodeVisitor(node.typeName, visitor, isEntityName), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + ); }, - [SyntaxKind.FunctionType]: function visitEachChildOfFunctionTypeNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateFunctionTypeNode(node, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameterDeclaration), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.FunctionType]: function visitEachChildOfFunctionTypeNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateFunctionTypeNode( + node, + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.ConstructorType]: function visitEachChildOfConstructorTypeNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateConstructorTypeNode(node, nodesVisitor(node.modifiers, visitor, isModifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameterDeclaration), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.ConstructorType]: function visitEachChildOfConstructorTypeNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateConstructorTypeNode( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.TypeQuery]: function visitEachChildOfTypeQueryNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeQueryNode(node, nodeVisitor(node.exprName, visitor, isEntityName), nodesVisitor(node.typeArguments, visitor, isTypeNode)); + [SyntaxKind.TypeQuery]: function visitEachChildOfTypeQueryNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeQueryNode( + node, + nodeVisitor(node.exprName, visitor, isEntityName), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + ); }, - [SyntaxKind.TypeLiteral]: function visitEachChildOfTypeLiteralNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.TypeLiteral]: function visitEachChildOfTypeLiteralNode( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateTypeLiteralNode(node, nodesVisitor(node.members, visitor, isTypeElement)); }, - [SyntaxKind.ArrayType]: function visitEachChildOfArrayTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.ArrayType]: function visitEachChildOfArrayTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateArrayTypeNode(node, nodeVisitor(node.elementType, visitor, isTypeNode)); }, - [SyntaxKind.TupleType]: function visitEachChildOfTupleTypeNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.TupleType]: function visitEachChildOfTupleTypeNode( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateTupleTypeNode(node, nodesVisitor(node.elements, visitor, isTypeNode)); }, - [SyntaxKind.OptionalType]: function visitEachChildOfOptionalTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.OptionalType]: function visitEachChildOfOptionalTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateOptionalTypeNode(node, nodeVisitor(node.type, visitor, isTypeNode)); }, - [SyntaxKind.RestType]: function visitEachChildOfRestTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.RestType]: function visitEachChildOfRestTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateRestTypeNode(node, nodeVisitor(node.type, visitor, isTypeNode)); }, - [SyntaxKind.UnionType]: function visitEachChildOfUnionTypeNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.UnionType]: function visitEachChildOfUnionTypeNode( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateUnionTypeNode(node, nodesVisitor(node.types, visitor, isTypeNode)); }, - [SyntaxKind.IntersectionType]: function visitEachChildOfIntersectionTypeNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.IntersectionType]: function visitEachChildOfIntersectionTypeNode( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateIntersectionTypeNode(node, nodesVisitor(node.types, visitor, isTypeNode)); }, - [SyntaxKind.ConditionalType]: function visitEachChildOfConditionalTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateConditionalTypeNode(node, nodeVisitor(node.checkType, visitor, isTypeNode), nodeVisitor(node.extendsType, visitor, isTypeNode), nodeVisitor(node.trueType, visitor, isTypeNode), nodeVisitor(node.falseType, visitor, isTypeNode)); + [SyntaxKind.ConditionalType]: function visitEachChildOfConditionalTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateConditionalTypeNode( + node, + nodeVisitor(node.checkType, visitor, isTypeNode), + nodeVisitor(node.extendsType, visitor, isTypeNode), + nodeVisitor(node.trueType, visitor, isTypeNode), + nodeVisitor(node.falseType, visitor, isTypeNode), + ); }, - [SyntaxKind.InferType]: function visitEachChildOfInferTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateInferTypeNode(node, nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration)); + [SyntaxKind.InferType]: function visitEachChildOfInferTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateInferTypeNode( + node, + nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration), + ); }, - [SyntaxKind.ImportType]: function visitEachChildOfImportTypeNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportTypeNode(node, nodeVisitor(node.argument, visitor, isTypeNode), nodeVisitor(node.assertions, visitor, isImportTypeAssertionContainer), nodeVisitor(node.qualifier, visitor, isEntityName), nodesVisitor(node.typeArguments, visitor, isTypeNode), node.isTypeOf); + [SyntaxKind.ImportType]: function visitEachChildOfImportTypeNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportTypeNode( + node, + nodeVisitor(node.argument, visitor, isTypeNode), + nodeVisitor(node.assertions, visitor, isImportTypeAssertionContainer), + nodeVisitor(node.qualifier, visitor, isEntityName), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + node.isTypeOf, + ); }, - [SyntaxKind.ImportTypeAssertionContainer]: function visitEachChildOfImportTypeAssertionContainer(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportTypeAssertionContainer(node, nodeVisitor(node.assertClause, visitor, isAssertClause), node.multiLine); + [SyntaxKind.ImportTypeAssertionContainer]: function visitEachChildOfImportTypeAssertionContainer( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportTypeAssertionContainer( + node, + nodeVisitor(node.assertClause, visitor, isAssertClause), + node.multiLine, + ); }, - [SyntaxKind.NamedTupleMember]: function visitEachChildOfNamedTupleMember(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateNamedTupleMember(node, nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), nodeVisitor(node.name, visitor, isIdentifier), nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.NamedTupleMember]: function visitEachChildOfNamedTupleMember( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateNamedTupleMember( + node, + nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.ParenthesizedType]: function visitEachChildOfParenthesizedType(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.ParenthesizedType]: function visitEachChildOfParenthesizedType( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateParenthesizedType(node, nodeVisitor(node.type, visitor, isTypeNode)); }, - [SyntaxKind.TypeOperator]: function visitEachChildOfTypeOperatorNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.TypeOperator]: function visitEachChildOfTypeOperatorNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateTypeOperatorNode(node, nodeVisitor(node.type, visitor, isTypeNode)); }, - [SyntaxKind.IndexedAccessType]: function visitEachChildOfIndexedAccessType(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateIndexedAccessTypeNode(node, nodeVisitor(node.objectType, visitor, isTypeNode), nodeVisitor(node.indexType, visitor, isTypeNode)); + [SyntaxKind.IndexedAccessType]: function visitEachChildOfIndexedAccessType( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateIndexedAccessTypeNode( + node, + nodeVisitor(node.objectType, visitor, isTypeNode), + nodeVisitor(node.indexType, visitor, isTypeNode), + ); }, - [SyntaxKind.MappedType]: function visitEachChildOfMappedType(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateMappedTypeNode(node, nodeVisitor(node.readonlyToken, tokenVisitor, isReadonlyKeywordOrPlusOrMinusToken), nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration), nodeVisitor(node.nameType, visitor, isTypeNode), nodeVisitor(node.questionToken, tokenVisitor, isQuestionOrPlusOrMinusToken), nodeVisitor(node.type, visitor, isTypeNode), nodesVisitor(node.members, visitor, isTypeElement)); + [SyntaxKind.MappedType]: function visitEachChildOfMappedType( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateMappedTypeNode( + node, + nodeVisitor(node.readonlyToken, tokenVisitor, isReadonlyKeywordOrPlusOrMinusToken), + nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration), + nodeVisitor(node.nameType, visitor, isTypeNode), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionOrPlusOrMinusToken), + nodeVisitor(node.type, visitor, isTypeNode), + nodesVisitor(node.members, visitor, isTypeElement), + ); }, - [SyntaxKind.LiteralType]: function visitEachChildOfLiteralTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.LiteralType]: function visitEachChildOfLiteralTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateLiteralTypeNode(node, nodeVisitor(node.literal, visitor, isExpression)); }, - [SyntaxKind.TemplateLiteralType]: function visitEachChildOfTemplateLiteralType(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTemplateLiteralType(node, nodeVisitor(node.head, visitor, isTemplateHead), nodesVisitor(node.templateSpans, visitor, isTemplateLiteralTypeSpan)); + [SyntaxKind.TemplateLiteralType]: function visitEachChildOfTemplateLiteralType( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTemplateLiteralType( + node, + nodeVisitor(node.head, visitor, isTemplateHead), + nodesVisitor(node.templateSpans, visitor, isTemplateLiteralTypeSpan), + ); }, - [SyntaxKind.TemplateLiteralTypeSpan]: function visitEachChildOfTemplateLiteralTypeSpan(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTemplateLiteralTypeSpan(node, nodeVisitor(node.type, visitor, isTypeNode), nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail)); + [SyntaxKind.TemplateLiteralTypeSpan]: function visitEachChildOfTemplateLiteralTypeSpan( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTemplateLiteralTypeSpan( + node, + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail), + ); }, // Binding patterns - [SyntaxKind.ObjectBindingPattern]: function visitEachChildOfObjectBindingPattern(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateObjectBindingPattern(node, nodesVisitor(node.elements, visitor, isBindingElement)); + [SyntaxKind.ObjectBindingPattern]: function visitEachChildOfObjectBindingPattern( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateObjectBindingPattern( + node, + nodesVisitor(node.elements, visitor, isBindingElement), + ); }, - [SyntaxKind.ArrayBindingPattern]: function visitEachChildOfArrayBindingPattern(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateArrayBindingPattern(node, nodesVisitor(node.elements, visitor, isArrayBindingElement)); + [SyntaxKind.ArrayBindingPattern]: function visitEachChildOfArrayBindingPattern( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateArrayBindingPattern( + node, + nodesVisitor(node.elements, visitor, isArrayBindingElement), + ); }, - [SyntaxKind.BindingElement]: function visitEachChildOfBindingElement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateBindingElement(node, nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), nodeVisitor(node.propertyName, visitor, isPropertyName), nodeVisitor(node.name, visitor, isBindingName), nodeVisitor(node.initializer, visitor, isExpression)); + [SyntaxKind.BindingElement]: function visitEachChildOfBindingElement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateBindingElement( + node, + nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), + nodeVisitor(node.propertyName, visitor, isPropertyName), + nodeVisitor(node.name, visitor, isBindingName), + nodeVisitor(node.initializer, visitor, isExpression), + ); }, // Expression - [SyntaxKind.ArrayLiteralExpression]: function visitEachChildOfArrayLiteralExpression(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateArrayLiteralExpression(node, nodesVisitor(node.elements, visitor, isExpression)); - }, - - [SyntaxKind.ObjectLiteralExpression]: function visitEachChildOfObjectLiteralExpression(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateObjectLiteralExpression(node, nodesVisitor(node.properties, visitor, isObjectLiteralElementLike)); - }, - - [SyntaxKind.PropertyAccessExpression]: function visitEachChildOfPropertyAccessExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return isPropertyAccessChain(node) ? - context.factory.updatePropertyAccessChain(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), nodeVisitor(node.name, visitor, isMemberName)) : - context.factory.updatePropertyAccessExpression(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.name, visitor, isMemberName)); - }, - - [SyntaxKind.ElementAccessExpression]: function visitEachChildOfElementAccessExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return isElementAccessChain(node) ? - context.factory.updateElementAccessChain(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), nodeVisitor(node.argumentExpression, visitor, isExpression)) : - context.factory.updateElementAccessExpression(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.argumentExpression, visitor, isExpression)); + [SyntaxKind.ArrayLiteralExpression]: function visitEachChildOfArrayLiteralExpression( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateArrayLiteralExpression( + node, + nodesVisitor(node.elements, visitor, isExpression), + ); }, - [SyntaxKind.CallExpression]: function visitEachChildOfCallExpression(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return isCallChain(node) ? - context.factory.updateCallChain(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), nodesVisitor(node.typeArguments, visitor, isTypeNode), nodesVisitor(node.arguments, visitor, isExpression)) : - context.factory.updateCallExpression(node, nodeVisitor(node.expression, visitor, isExpression), nodesVisitor(node.typeArguments, visitor, isTypeNode), nodesVisitor(node.arguments, visitor, isExpression)); + [SyntaxKind.ObjectLiteralExpression]: function visitEachChildOfObjectLiteralExpression( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateObjectLiteralExpression( + node, + nodesVisitor(node.properties, visitor, isObjectLiteralElementLike), + ); }, - [SyntaxKind.NewExpression]: function visitEachChildOfNewExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateNewExpression(node, nodeVisitor(node.expression, visitor, isExpression), nodesVisitor(node.typeArguments, visitor, isTypeNode), nodesVisitor(node.arguments, visitor, isExpression)); + [SyntaxKind.PropertyAccessExpression]: function visitEachChildOfPropertyAccessExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return isPropertyAccessChain(node) + ? context.factory.updatePropertyAccessChain( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), + nodeVisitor(node.name, visitor, isMemberName), + ) + : context.factory.updatePropertyAccessExpression( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.name, visitor, isMemberName), + ); + }, + + [SyntaxKind.ElementAccessExpression]: function visitEachChildOfElementAccessExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return isElementAccessChain(node) + ? context.factory.updateElementAccessChain( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), + nodeVisitor(node.argumentExpression, visitor, isExpression), + ) + : context.factory.updateElementAccessExpression( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.argumentExpression, visitor, isExpression), + ); + }, + + [SyntaxKind.CallExpression]: function visitEachChildOfCallExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return isCallChain(node) + ? context.factory.updateCallChain( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodesVisitor(node.arguments, visitor, isExpression), + ) + : context.factory.updateCallExpression( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodesVisitor(node.arguments, visitor, isExpression), + ); + }, + + [SyntaxKind.NewExpression]: function visitEachChildOfNewExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateNewExpression( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodesVisitor(node.arguments, visitor, isExpression), + ); }, - [SyntaxKind.TaggedTemplateExpression]: function visitEachChildOfTaggedTemplateExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTaggedTemplateExpression(node, nodeVisitor(node.tag, visitor, isExpression), nodesVisitor(node.typeArguments, visitor, isTypeNode), nodeVisitor(node.template, visitor, isTemplateLiteral)); + [SyntaxKind.TaggedTemplateExpression]: function visitEachChildOfTaggedTemplateExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTaggedTemplateExpression( + node, + nodeVisitor(node.tag, visitor, isExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodeVisitor(node.template, visitor, isTemplateLiteral), + ); }, - [SyntaxKind.TypeAssertionExpression]: function visitEachChildOfTypeAssertionExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeAssertion(node, nodeVisitor(node.type, visitor, isTypeNode), nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.TypeAssertionExpression]: function visitEachChildOfTypeAssertionExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeAssertion( + node, + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.expression, visitor, isExpression), + ); }, - [SyntaxKind.ParenthesizedExpression]: function visitEachChildOfParenthesizedExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateParenthesizedExpression(node, nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.ParenthesizedExpression]: function visitEachChildOfParenthesizedExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateParenthesizedExpression( + node, + nodeVisitor(node.expression, visitor, isExpression), + ); }, - [SyntaxKind.FunctionExpression]: function visitEachChildOfFunctionExpression(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateFunctionExpression(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), visitFunctionBody(node.body, visitor, context, nodeVisitor)); + [SyntaxKind.FunctionExpression]: function visitEachChildOfFunctionExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateFunctionExpression( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + visitFunctionBody(node.body, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ArrowFunction]: function visitEachChildOfArrowFunction(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateArrowFunction(node, nodesVisitor(node.modifiers, visitor, isModifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), nodeVisitor(node.equalsGreaterThanToken, tokenVisitor, isEqualsGreaterThanToken), visitFunctionBody(node.body, visitor, context, nodeVisitor)); + [SyntaxKind.ArrowFunction]: function visitEachChildOfArrowFunction( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateArrowFunction( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.equalsGreaterThanToken, tokenVisitor, isEqualsGreaterThanToken), + visitFunctionBody(node.body, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.DeleteExpression]: function visitEachChildOfDeleteExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.DeleteExpression]: function visitEachChildOfDeleteExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateDeleteExpression(node, nodeVisitor(node.expression, visitor, isExpression)); }, - [SyntaxKind.TypeOfExpression]: function visitEachChildOfTypeOfExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.TypeOfExpression]: function visitEachChildOfTypeOfExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateTypeOfExpression(node, nodeVisitor(node.expression, visitor, isExpression)); }, - [SyntaxKind.VoidExpression]: function visitEachChildOfVoidExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.VoidExpression]: function visitEachChildOfVoidExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateVoidExpression(node, nodeVisitor(node.expression, visitor, isExpression)); }, - [SyntaxKind.AwaitExpression]: function visitEachChildOfAwaitExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.AwaitExpression]: function visitEachChildOfAwaitExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateAwaitExpression(node, nodeVisitor(node.expression, visitor, isExpression)); }, - [SyntaxKind.PrefixUnaryExpression]: function visitEachChildOfPrefixUnaryExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.PrefixUnaryExpression]: function visitEachChildOfPrefixUnaryExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updatePrefixUnaryExpression(node, nodeVisitor(node.operand, visitor, isExpression)); }, - [SyntaxKind.PostfixUnaryExpression]: function visitEachChildOfPostfixUnaryExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.PostfixUnaryExpression]: function visitEachChildOfPostfixUnaryExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updatePostfixUnaryExpression(node, nodeVisitor(node.operand, visitor, isExpression)); }, - [SyntaxKind.BinaryExpression]: function visitEachChildOfBinaryExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateBinaryExpression(node, nodeVisitor(node.left, visitor, isExpression), nodeVisitor(node.operatorToken, tokenVisitor, isBinaryOperatorToken), nodeVisitor(node.right, visitor, isExpression)); + [SyntaxKind.BinaryExpression]: function visitEachChildOfBinaryExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateBinaryExpression( + node, + nodeVisitor(node.left, visitor, isExpression), + nodeVisitor(node.operatorToken, tokenVisitor, isBinaryOperatorToken), + nodeVisitor(node.right, visitor, isExpression), + ); }, - [SyntaxKind.ConditionalExpression]: function visitEachChildOfConditionalExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateConditionalExpression(node, nodeVisitor(node.condition, visitor, isExpression), nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), nodeVisitor(node.whenTrue, visitor, isExpression), nodeVisitor(node.colonToken, tokenVisitor, isColonToken), nodeVisitor(node.whenFalse, visitor, isExpression)); + [SyntaxKind.ConditionalExpression]: function visitEachChildOfConditionalExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateConditionalExpression( + node, + nodeVisitor(node.condition, visitor, isExpression), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + nodeVisitor(node.whenTrue, visitor, isExpression), + nodeVisitor(node.colonToken, tokenVisitor, isColonToken), + nodeVisitor(node.whenFalse, visitor, isExpression), + ); }, - [SyntaxKind.TemplateExpression]: function visitEachChildOfTemplateExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTemplateExpression(node, nodeVisitor(node.head, visitor, isTemplateHead), nodesVisitor(node.templateSpans, visitor, isTemplateSpan)); + [SyntaxKind.TemplateExpression]: function visitEachChildOfTemplateExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTemplateExpression( + node, + nodeVisitor(node.head, visitor, isTemplateHead), + nodesVisitor(node.templateSpans, visitor, isTemplateSpan), + ); }, - [SyntaxKind.YieldExpression]: function visitEachChildOfYieldExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateYieldExpression(node, nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.YieldExpression]: function visitEachChildOfYieldExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateYieldExpression( + node, + nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + nodeVisitor(node.expression, visitor, isExpression), + ); }, - [SyntaxKind.SpreadElement]: function visitEachChildOfSpreadElement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.SpreadElement]: function visitEachChildOfSpreadElement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateSpreadElement(node, nodeVisitor(node.expression, visitor, isExpression)); }, - [SyntaxKind.ClassExpression]: function visitEachChildOfClassExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateClassExpression(node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.heritageClauses, visitor, isHeritageClause), nodesVisitor(node.members, visitor, isClassElement)); - }, - - [SyntaxKind.ExpressionWithTypeArguments]: function visitEachChildOfExpressionWithTypeArguments(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExpressionWithTypeArguments(node, nodeVisitor(node.expression, visitor, isExpression), nodesVisitor(node.typeArguments, visitor, isTypeNode)); + [SyntaxKind.ClassExpression]: function visitEachChildOfClassExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateClassExpression( + node, + nodesVisitor(node.modifiers, visitor, isModifierLike), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.heritageClauses, visitor, isHeritageClause), + nodesVisitor(node.members, visitor, isClassElement), + ); }, - [SyntaxKind.AsExpression]: function visitEachChildOfAsExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateAsExpression(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.ExpressionWithTypeArguments]: function visitEachChildOfExpressionWithTypeArguments( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExpressionWithTypeArguments( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + ); }, - [SyntaxKind.SatisfiesExpression]: function visitEachChildOfSatisfiesExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateSatisfiesExpression(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.AsExpression]: function visitEachChildOfAsExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateAsExpression( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.NonNullExpression]: function visitEachChildOfNonNullExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return isOptionalChain(node) ? - context.factory.updateNonNullChain(node, nodeVisitor(node.expression, visitor, isExpression)) : - context.factory.updateNonNullExpression(node, nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.SatisfiesExpression]: function visitEachChildOfSatisfiesExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSatisfiesExpression( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.MetaProperty]: function visitEachChildOfMetaProperty(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.NonNullExpression]: function visitEachChildOfNonNullExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return isOptionalChain(node) + ? context.factory.updateNonNullChain(node, nodeVisitor(node.expression, visitor, isExpression)) + : context.factory.updateNonNullExpression(node, nodeVisitor(node.expression, visitor, isExpression)); + }, + + [SyntaxKind.MetaProperty]: function visitEachChildOfMetaProperty( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateMetaProperty(node, nodeVisitor(node.name, visitor, isIdentifier)); }, // Misc - [SyntaxKind.TemplateSpan]: function visitEachChildOfTemplateSpan(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTemplateSpan(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail)); + [SyntaxKind.TemplateSpan]: function visitEachChildOfTemplateSpan( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTemplateSpan( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail), + ); }, // Element - [SyntaxKind.Block]: function visitEachChildOfBlock(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.Block]: function visitEachChildOfBlock( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateBlock(node, nodesVisitor(node.statements, visitor, isStatement)); }, - [SyntaxKind.VariableStatement]: function visitEachChildOfVariableStatement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateVariableStatement(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.declarationList, visitor, isVariableDeclarationList)); + [SyntaxKind.VariableStatement]: function visitEachChildOfVariableStatement( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateVariableStatement( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.declarationList, visitor, isVariableDeclarationList), + ); }, - [SyntaxKind.ExpressionStatement]: function visitEachChildOfExpressionStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.ExpressionStatement]: function visitEachChildOfExpressionStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateExpressionStatement(node, nodeVisitor(node.expression, visitor, isExpression)); }, - [SyntaxKind.IfStatement]: function visitEachChildOfIfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateIfStatement(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.thenStatement, visitor, isStatement, context.factory.liftToBlock), nodeVisitor(node.elseStatement, visitor, isStatement, context.factory.liftToBlock)); + [SyntaxKind.IfStatement]: function visitEachChildOfIfStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateIfStatement( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.thenStatement, visitor, isStatement, context.factory.liftToBlock), + nodeVisitor(node.elseStatement, visitor, isStatement, context.factory.liftToBlock), + ); }, - [SyntaxKind.DoStatement]: function visitEachChildOfDoStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateDoStatement(node, visitIterationBody(node.statement, visitor, context, nodeVisitor), nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.DoStatement]: function visitEachChildOfDoStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateDoStatement( + node, + visitIterationBody(node.statement, visitor, context, nodeVisitor), + nodeVisitor(node.expression, visitor, isExpression), + ); }, - [SyntaxKind.WhileStatement]: function visitEachChildOfWhileStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateWhileStatement(node, nodeVisitor(node.expression, visitor, isExpression), visitIterationBody(node.statement, visitor, context, nodeVisitor)); + [SyntaxKind.WhileStatement]: function visitEachChildOfWhileStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateWhileStatement( + node, + nodeVisitor(node.expression, visitor, isExpression), + visitIterationBody(node.statement, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ForStatement]: function visitEachChildOfForStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateForStatement(node, nodeVisitor(node.initializer, visitor, isForInitializer), nodeVisitor(node.condition, visitor, isExpression), nodeVisitor(node.incrementor, visitor, isExpression), visitIterationBody(node.statement, visitor, context, nodeVisitor)); + [SyntaxKind.ForStatement]: function visitEachChildOfForStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateForStatement( + node, + nodeVisitor(node.initializer, visitor, isForInitializer), + nodeVisitor(node.condition, visitor, isExpression), + nodeVisitor(node.incrementor, visitor, isExpression), + visitIterationBody(node.statement, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ForInStatement]: function visitEachChildOfForInStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateForInStatement(node, nodeVisitor(node.initializer, visitor, isForInitializer), nodeVisitor(node.expression, visitor, isExpression), visitIterationBody(node.statement, visitor, context, nodeVisitor)); + [SyntaxKind.ForInStatement]: function visitEachChildOfForInStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateForInStatement( + node, + nodeVisitor(node.initializer, visitor, isForInitializer), + nodeVisitor(node.expression, visitor, isExpression), + visitIterationBody(node.statement, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ForOfStatement]: function visitEachChildOfForOfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateForOfStatement(node, nodeVisitor(node.awaitModifier, tokenVisitor, isAwaitKeyword), nodeVisitor(node.initializer, visitor, isForInitializer), nodeVisitor(node.expression, visitor, isExpression), visitIterationBody(node.statement, visitor, context, nodeVisitor)); + [SyntaxKind.ForOfStatement]: function visitEachChildOfForOfStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateForOfStatement( + node, + nodeVisitor(node.awaitModifier, tokenVisitor, isAwaitKeyword), + nodeVisitor(node.initializer, visitor, isForInitializer), + nodeVisitor(node.expression, visitor, isExpression), + visitIterationBody(node.statement, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ContinueStatement]: function visitEachChildOfContinueStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.ContinueStatement]: function visitEachChildOfContinueStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateContinueStatement(node, nodeVisitor(node.label, visitor, isIdentifier)); }, - [SyntaxKind.BreakStatement]: function visitEachChildOfBreakStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.BreakStatement]: function visitEachChildOfBreakStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateBreakStatement(node, nodeVisitor(node.label, visitor, isIdentifier)); }, - [SyntaxKind.ReturnStatement]: function visitEachChildOfReturnStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.ReturnStatement]: function visitEachChildOfReturnStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateReturnStatement(node, nodeVisitor(node.expression, visitor, isExpression)); }, - [SyntaxKind.WithStatement]: function visitEachChildOfWithStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateWithStatement(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock)); + [SyntaxKind.WithStatement]: function visitEachChildOfWithStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateWithStatement( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock), + ); }, - [SyntaxKind.SwitchStatement]: function visitEachChildOfSwitchStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateSwitchStatement(node, nodeVisitor(node.expression, visitor, isExpression), nodeVisitor(node.caseBlock, visitor, isCaseBlock)); + [SyntaxKind.SwitchStatement]: function visitEachChildOfSwitchStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSwitchStatement( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.caseBlock, visitor, isCaseBlock), + ); }, - [SyntaxKind.LabeledStatement]: function visitEachChildOfLabeledStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateLabeledStatement(node, nodeVisitor(node.label, visitor, isIdentifier), nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock)); + [SyntaxKind.LabeledStatement]: function visitEachChildOfLabeledStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateLabeledStatement( + node, + nodeVisitor(node.label, visitor, isIdentifier), + nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock), + ); }, - [SyntaxKind.ThrowStatement]: function visitEachChildOfThrowStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.ThrowStatement]: function visitEachChildOfThrowStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateThrowStatement(node, nodeVisitor(node.expression, visitor, isExpression)); }, - [SyntaxKind.TryStatement]: function visitEachChildOfTryStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTryStatement(node, nodeVisitor(node.tryBlock, visitor, isBlock), nodeVisitor(node.catchClause, visitor, isCatchClause), nodeVisitor(node.finallyBlock, visitor, isBlock)); + [SyntaxKind.TryStatement]: function visitEachChildOfTryStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTryStatement( + node, + nodeVisitor(node.tryBlock, visitor, isBlock), + nodeVisitor(node.catchClause, visitor, isCatchClause), + nodeVisitor(node.finallyBlock, visitor, isBlock), + ); }, - [SyntaxKind.VariableDeclaration]: function visitEachChildOfVariableDeclaration(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateVariableDeclaration(node, nodeVisitor(node.name, visitor, isBindingName), nodeVisitor(node.exclamationToken, tokenVisitor, isExclamationToken), nodeVisitor(node.type, visitor, isTypeNode), nodeVisitor(node.initializer, visitor, isExpression)); + [SyntaxKind.VariableDeclaration]: function visitEachChildOfVariableDeclaration( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateVariableDeclaration( + node, + nodeVisitor(node.name, visitor, isBindingName), + nodeVisitor(node.exclamationToken, tokenVisitor, isExclamationToken), + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.initializer, visitor, isExpression), + ); }, - [SyntaxKind.VariableDeclarationList]: function visitEachChildOfVariableDeclarationList(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateVariableDeclarationList(node, nodesVisitor(node.declarations, visitor, isVariableDeclaration)); + [SyntaxKind.VariableDeclarationList]: function visitEachChildOfVariableDeclarationList( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateVariableDeclarationList( + node, + nodesVisitor(node.declarations, visitor, isVariableDeclaration), + ); }, - [SyntaxKind.FunctionDeclaration]: function visitEachChildOfFunctionDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateFunctionDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), visitFunctionBody(node.body, visitor, context, nodeVisitor)); + [SyntaxKind.FunctionDeclaration]: function visitEachChildOfFunctionDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateFunctionDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + visitFunctionBody(node.body, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ClassDeclaration]: function visitEachChildOfClassDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateClassDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.heritageClauses, visitor, isHeritageClause), nodesVisitor(node.members, visitor, isClassElement)); + [SyntaxKind.ClassDeclaration]: function visitEachChildOfClassDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateClassDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifierLike), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.heritageClauses, visitor, isHeritageClause), + nodesVisitor(node.members, visitor, isClassElement), + ); }, - [SyntaxKind.InterfaceDeclaration]: function visitEachChildOfInterfaceDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateInterfaceDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.heritageClauses, visitor, isHeritageClause), nodesVisitor(node.members, visitor, isTypeElement)); + [SyntaxKind.InterfaceDeclaration]: function visitEachChildOfInterfaceDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateInterfaceDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.heritageClauses, visitor, isHeritageClause), + nodesVisitor(node.members, visitor, isTypeElement), + ); }, - [SyntaxKind.TypeAliasDeclaration]: function visitEachChildOfTypeAliasDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeAliasDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodeVisitor(node.type, visitor, isTypeNode)); + [SyntaxKind.TypeAliasDeclaration]: function visitEachChildOfTypeAliasDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeAliasDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.EnumDeclaration]: function visitEachChildOfEnumDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateEnumDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.members, visitor, isEnumMember)); + [SyntaxKind.EnumDeclaration]: function visitEachChildOfEnumDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateEnumDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.members, visitor, isEnumMember), + ); }, - [SyntaxKind.ModuleDeclaration]: function visitEachChildOfModuleDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateModuleDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.name, visitor, isModuleName), nodeVisitor(node.body, visitor, isModuleBody)); + [SyntaxKind.ModuleDeclaration]: function visitEachChildOfModuleDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateModuleDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isModuleName), + nodeVisitor(node.body, visitor, isModuleBody), + ); }, - [SyntaxKind.ModuleBlock]: function visitEachChildOfModuleBlock(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.ModuleBlock]: function visitEachChildOfModuleBlock( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateModuleBlock(node, nodesVisitor(node.statements, visitor, isStatement)); }, - [SyntaxKind.CaseBlock]: function visitEachChildOfCaseBlock(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.CaseBlock]: function visitEachChildOfCaseBlock( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateCaseBlock(node, nodesVisitor(node.clauses, visitor, isCaseOrDefaultClause)); }, - [SyntaxKind.NamespaceExportDeclaration]: function visitEachChildOfNamespaceExportDeclaration(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateNamespaceExportDeclaration(node, nodeVisitor(node.name, visitor, isIdentifier)); + [SyntaxKind.NamespaceExportDeclaration]: function visitEachChildOfNamespaceExportDeclaration( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateNamespaceExportDeclaration( + node, + nodeVisitor(node.name, visitor, isIdentifier), + ); }, - [SyntaxKind.ImportEqualsDeclaration]: function visitEachChildOfImportEqualsDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportEqualsDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), node.isTypeOnly, nodeVisitor(node.name, visitor, isIdentifier), nodeVisitor(node.moduleReference, visitor, isModuleReference)); + [SyntaxKind.ImportEqualsDeclaration]: function visitEachChildOfImportEqualsDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportEqualsDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + node.isTypeOnly, + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.moduleReference, visitor, isModuleReference), + ); }, - [SyntaxKind.ImportDeclaration]: function visitEachChildOfImportDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.importClause, visitor, isImportClause), nodeVisitor(node.moduleSpecifier, visitor, isExpression), nodeVisitor(node.assertClause, visitor, isAssertClause)); + [SyntaxKind.ImportDeclaration]: function visitEachChildOfImportDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.importClause, visitor, isImportClause), + nodeVisitor(node.moduleSpecifier, visitor, isExpression), + nodeVisitor(node.assertClause, visitor, isAssertClause), + ); }, - [SyntaxKind.AssertClause]: function visitEachChildOfAssertClause(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateAssertClause(node, nodesVisitor(node.elements, visitor, isAssertEntry), node.multiLine); + [SyntaxKind.AssertClause]: function visitEachChildOfAssertClause( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateAssertClause( + node, + nodesVisitor(node.elements, visitor, isAssertEntry), + node.multiLine, + ); }, - [SyntaxKind.AssertEntry]: function visitEachChildOfAssertEntry(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateAssertEntry(node, nodeVisitor(node.name, visitor, isAssertionKey), nodeVisitor(node.value, visitor, isExpression)); + [SyntaxKind.AssertEntry]: function visitEachChildOfAssertEntry( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateAssertEntry( + node, + nodeVisitor(node.name, visitor, isAssertionKey), + nodeVisitor(node.value, visitor, isExpression), + ); }, - [SyntaxKind.ImportClause]: function visitEachChildOfImportClause(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportClause(node, node.isTypeOnly, nodeVisitor(node.name, visitor, isIdentifier), nodeVisitor(node.namedBindings, visitor, isNamedImportBindings)); + [SyntaxKind.ImportClause]: function visitEachChildOfImportClause( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportClause( + node, + node.isTypeOnly, + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.namedBindings, visitor, isNamedImportBindings), + ); }, - [SyntaxKind.NamespaceImport]: function visitEachChildOfNamespaceImport(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.NamespaceImport]: function visitEachChildOfNamespaceImport( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateNamespaceImport(node, nodeVisitor(node.name, visitor, isIdentifier)); }, - [SyntaxKind.NamespaceExport]: function visitEachChildOfNamespaceExport(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.NamespaceExport]: function visitEachChildOfNamespaceExport( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateNamespaceExport(node, nodeVisitor(node.name, visitor, isIdentifier)); }, - [SyntaxKind.NamedImports]: function visitEachChildOfNamedImports(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.NamedImports]: function visitEachChildOfNamedImports( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateNamedImports(node, nodesVisitor(node.elements, visitor, isImportSpecifier)); }, - [SyntaxKind.ImportSpecifier]: function visitEachChildOfImportSpecifier(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportSpecifier(node, node.isTypeOnly, nodeVisitor(node.propertyName, visitor, isIdentifier), nodeVisitor(node.name, visitor, isIdentifier)); + [SyntaxKind.ImportSpecifier]: function visitEachChildOfImportSpecifier( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportSpecifier( + node, + node.isTypeOnly, + nodeVisitor(node.propertyName, visitor, isIdentifier), + nodeVisitor(node.name, visitor, isIdentifier), + ); }, - [SyntaxKind.ExportAssignment]: function visitEachChildOfExportAssignment(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExportAssignment(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.ExportAssignment]: function visitEachChildOfExportAssignment( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExportAssignment( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.expression, visitor, isExpression), + ); }, - [SyntaxKind.ExportDeclaration]: function visitEachChildOfExportDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExportDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), node.isTypeOnly, nodeVisitor(node.exportClause, visitor, isNamedExportBindings), nodeVisitor(node.moduleSpecifier, visitor, isExpression), nodeVisitor(node.assertClause, visitor, isAssertClause)); + [SyntaxKind.ExportDeclaration]: function visitEachChildOfExportDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExportDeclaration( + node, + nodesVisitor(node.modifiers, visitor, isModifier), + node.isTypeOnly, + nodeVisitor(node.exportClause, visitor, isNamedExportBindings), + nodeVisitor(node.moduleSpecifier, visitor, isExpression), + nodeVisitor(node.assertClause, visitor, isAssertClause), + ); }, - [SyntaxKind.NamedExports]: function visitEachChildOfNamedExports(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.NamedExports]: function visitEachChildOfNamedExports( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateNamedExports(node, nodesVisitor(node.elements, visitor, isExportSpecifier)); }, - [SyntaxKind.ExportSpecifier]: function visitEachChildOfExportSpecifier(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExportSpecifier(node, node.isTypeOnly, nodeVisitor(node.propertyName, visitor, isIdentifier), nodeVisitor(node.name, visitor, isIdentifier)); + [SyntaxKind.ExportSpecifier]: function visitEachChildOfExportSpecifier( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExportSpecifier( + node, + node.isTypeOnly, + nodeVisitor(node.propertyName, visitor, isIdentifier), + nodeVisitor(node.name, visitor, isIdentifier), + ); }, // Module references - [SyntaxKind.ExternalModuleReference]: function visitEachChildOfExternalModuleReference(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExternalModuleReference(node, nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.ExternalModuleReference]: function visitEachChildOfExternalModuleReference( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExternalModuleReference( + node, + nodeVisitor(node.expression, visitor, isExpression), + ); }, // JSX - [SyntaxKind.JsxElement]: function visitEachChildOfJsxElement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxElement(node, nodeVisitor(node.openingElement, visitor, isJsxOpeningElement), nodesVisitor(node.children, visitor, isJsxChild), nodeVisitor(node.closingElement, visitor, isJsxClosingElement)); + [SyntaxKind.JsxElement]: function visitEachChildOfJsxElement( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxElement( + node, + nodeVisitor(node.openingElement, visitor, isJsxOpeningElement), + nodesVisitor(node.children, visitor, isJsxChild), + nodeVisitor(node.closingElement, visitor, isJsxClosingElement), + ); }, - [SyntaxKind.JsxSelfClosingElement]: function visitEachChildOfJsxSelfClosingElement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxSelfClosingElement(node, nodeVisitor(node.tagName, visitor, isJsxTagNameExpression), nodesVisitor(node.typeArguments, visitor, isTypeNode), nodeVisitor(node.attributes, visitor, isJsxAttributes)); + [SyntaxKind.JsxSelfClosingElement]: function visitEachChildOfJsxSelfClosingElement( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxSelfClosingElement( + node, + nodeVisitor(node.tagName, visitor, isJsxTagNameExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodeVisitor(node.attributes, visitor, isJsxAttributes), + ); }, - [SyntaxKind.JsxOpeningElement]: function visitEachChildOfJsxOpeningElement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxOpeningElement(node, nodeVisitor(node.tagName, visitor, isJsxTagNameExpression), nodesVisitor(node.typeArguments, visitor, isTypeNode), nodeVisitor(node.attributes, visitor, isJsxAttributes)); + [SyntaxKind.JsxOpeningElement]: function visitEachChildOfJsxOpeningElement( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxOpeningElement( + node, + nodeVisitor(node.tagName, visitor, isJsxTagNameExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodeVisitor(node.attributes, visitor, isJsxAttributes), + ); }, - [SyntaxKind.JsxClosingElement]: function visitEachChildOfJsxClosingElement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxClosingElement(node, nodeVisitor(node.tagName, visitor, isJsxTagNameExpression)); + [SyntaxKind.JsxClosingElement]: function visitEachChildOfJsxClosingElement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxClosingElement( + node, + nodeVisitor(node.tagName, visitor, isJsxTagNameExpression), + ); }, - [SyntaxKind.JsxFragment]: function visitEachChildOfJsxFragment(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxFragment(node, nodeVisitor(node.openingFragment, visitor, isJsxOpeningFragment), nodesVisitor(node.children, visitor, isJsxChild), nodeVisitor(node.closingFragment, visitor, isJsxClosingFragment)); + [SyntaxKind.JsxFragment]: function visitEachChildOfJsxFragment( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxFragment( + node, + nodeVisitor(node.openingFragment, visitor, isJsxOpeningFragment), + nodesVisitor(node.children, visitor, isJsxChild), + nodeVisitor(node.closingFragment, visitor, isJsxClosingFragment), + ); }, - [SyntaxKind.JsxAttribute]: function visitEachChildOfJsxAttribute(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxAttribute(node, nodeVisitor(node.name, visitor, isIdentifier), nodeVisitor(node.initializer, visitor, isStringLiteralOrJsxExpression)); + [SyntaxKind.JsxAttribute]: function visitEachChildOfJsxAttribute( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxAttribute( + node, + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.initializer, visitor, isStringLiteralOrJsxExpression), + ); }, - [SyntaxKind.JsxAttributes]: function visitEachChildOfJsxAttributes(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxAttributes(node, nodesVisitor(node.properties, visitor, isJsxAttributeLike)); + [SyntaxKind.JsxAttributes]: function visitEachChildOfJsxAttributes( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxAttributes( + node, + nodesVisitor(node.properties, visitor, isJsxAttributeLike), + ); }, - [SyntaxKind.JsxSpreadAttribute]: function visitEachChildOfJsxSpreadAttribute(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.JsxSpreadAttribute]: function visitEachChildOfJsxSpreadAttribute( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateJsxSpreadAttribute(node, nodeVisitor(node.expression, visitor, isExpression)); }, - [SyntaxKind.JsxExpression]: function visitEachChildOfJsxExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.JsxExpression]: function visitEachChildOfJsxExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateJsxExpression(node, nodeVisitor(node.expression, visitor, isExpression)); }, // Clauses - [SyntaxKind.CaseClause]: function visitEachChildOfCaseClause(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateCaseClause(node, nodeVisitor(node.expression, visitor, isExpression), nodesVisitor(node.statements, visitor, isStatement)); + [SyntaxKind.CaseClause]: function visitEachChildOfCaseClause( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateCaseClause( + node, + nodeVisitor(node.expression, visitor, isExpression), + nodesVisitor(node.statements, visitor, isStatement), + ); }, - [SyntaxKind.DefaultClause]: function visitEachChildOfDefaultClause(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.DefaultClause]: function visitEachChildOfDefaultClause( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateDefaultClause(node, nodesVisitor(node.statements, visitor, isStatement)); }, - [SyntaxKind.HeritageClause]: function visitEachChildOfHeritageClause(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateHeritageClause(node, nodesVisitor(node.types, visitor, isExpressionWithTypeArguments)); + [SyntaxKind.HeritageClause]: function visitEachChildOfHeritageClause( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateHeritageClause( + node, + nodesVisitor(node.types, visitor, isExpressionWithTypeArguments), + ); }, - [SyntaxKind.CatchClause]: function visitEachChildOfCatchClause(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateCatchClause(node, nodeVisitor(node.variableDeclaration, visitor, isVariableDeclaration), nodeVisitor(node.block, visitor, isBlock)); + [SyntaxKind.CatchClause]: function visitEachChildOfCatchClause( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateCatchClause( + node, + nodeVisitor(node.variableDeclaration, visitor, isVariableDeclaration), + nodeVisitor(node.block, visitor, isBlock), + ); }, // Property assignments - [SyntaxKind.PropertyAssignment]: function visitEachChildOfPropertyAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updatePropertyAssignment(node, nodeVisitor(node.name, visitor, isPropertyName), nodeVisitor(node.initializer, visitor, isExpression)); + [SyntaxKind.PropertyAssignment]: function visitEachChildOfPropertyAssignment( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updatePropertyAssignment( + node, + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.initializer, visitor, isExpression), + ); }, - [SyntaxKind.ShorthandPropertyAssignment]: function visitEachChildOfShorthandPropertyAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateShorthandPropertyAssignment(node, nodeVisitor(node.name, visitor, isIdentifier), nodeVisitor(node.objectAssignmentInitializer, visitor, isExpression)); + [SyntaxKind.ShorthandPropertyAssignment]: function visitEachChildOfShorthandPropertyAssignment( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateShorthandPropertyAssignment( + node, + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.objectAssignmentInitializer, visitor, isExpression), + ); }, - [SyntaxKind.SpreadAssignment]: function visitEachChildOfSpreadAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.SpreadAssignment]: function visitEachChildOfSpreadAssignment( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateSpreadAssignment(node, nodeVisitor(node.expression, visitor, isExpression)); }, // Enum - [SyntaxKind.EnumMember]: function visitEachChildOfEnumMember(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateEnumMember(node, nodeVisitor(node.name, visitor, isPropertyName), nodeVisitor(node.initializer, visitor, isExpression)); + [SyntaxKind.EnumMember]: function visitEachChildOfEnumMember( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateEnumMember( + node, + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.initializer, visitor, isExpression), + ); }, // Top-level nodes - [SyntaxKind.SourceFile]: function visitEachChildOfSourceFile(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateSourceFile(node, visitLexicalEnvironment(node.statements, visitor, context, /*start*/ undefined, /*ensureUseStrict*/ undefined, nodesVisitor)); + [SyntaxKind.SourceFile]: function visitEachChildOfSourceFile( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSourceFile( + node, + visitLexicalEnvironment( + node.statements, + visitor, + context, + /*start*/ undefined, + /*ensureUseStrict*/ undefined, + nodesVisitor, + ), + ); }, // Transformation nodes - [SyntaxKind.PartiallyEmittedExpression]: function visitEachChildOfPartiallyEmittedExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updatePartiallyEmittedExpression(node, nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.PartiallyEmittedExpression]: function visitEachChildOfPartiallyEmittedExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updatePartiallyEmittedExpression( + node, + nodeVisitor(node.expression, visitor, isExpression), + ); }, - [SyntaxKind.CommaListExpression]: function visitEachChildOfCommaListExpression(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { + [SyntaxKind.CommaListExpression]: function visitEachChildOfCommaListExpression( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { return context.factory.updateCommaListExpression(node, nodesVisitor(node.elements, visitor, isExpression)); }, }; diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index 070fb424e14ba..9575f00c48dfd 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -30,13 +30,17 @@ namespace ts { /** * @returns Whether the screen was cleared. */ - function clearScreenIfNotWatchingForFileChanges(system: System, diagnostic: Diagnostic, options: CompilerOptions): boolean { + function clearScreenIfNotWatchingForFileChanges( + system: System, + diagnostic: Diagnostic, + options: CompilerOptions, + ): boolean { if ( - system.clearScreen && - !options.preserveWatchOutput && - !options.extendedDiagnostics && - !options.diagnostics && - contains(screenStartingMessageCodes, diagnostic.code) + system.clearScreen + && !options.preserveWatchOutput + && !options.extendedDiagnostics + && !options.diagnostics + && contains(screenStartingMessageCodes, diagnostic.code) ) { system.clearScreen(); return true; @@ -60,23 +64,25 @@ namespace ts { * Get locale specific time based on whether we are in test mode */ export function getLocaleTimeString(system: System) { - return !system.now ? - new Date().toLocaleTimeString() : - system.now().toLocaleTimeString("en-US", { timeZone: "UTC" }); + return !system.now + ? new Date().toLocaleTimeString() + : system.now().toLocaleTimeString("en-US", { timeZone: "UTC" }); } /** * Create a function that reports watch status by writing to the system and handles the formatting of the diagnostic */ export function createWatchStatusReporter(system: System, pretty?: boolean): WatchStatusReporter { - return pretty ? - (diagnostic, newLine, options) => { + return pretty + ? (diagnostic, newLine, options) => { clearScreenIfNotWatchingForFileChanges(system, diagnostic, options); - let output = `[${formatColorAndReset(getLocaleTimeString(system), ForegroundColorEscapeSequences.Grey)}] `; + let output = `[${ + formatColorAndReset(getLocaleTimeString(system), ForegroundColorEscapeSequences.Grey) + }] `; output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${newLine + newLine}`; system.write(output); - } : - (diagnostic, newLine, options) => { + } + : (diagnostic, newLine, options) => { let output = ""; if (!clearScreenIfNotWatchingForFileChanges(system, diagnostic, options)) { @@ -84,17 +90,33 @@ namespace ts { } output += `${getLocaleTimeString(system)} - `; - output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${getPlainDiagnosticFollowingNewLines(diagnostic, newLine)}`; + output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${ + getPlainDiagnosticFollowingNewLines(diagnostic, newLine) + }`; system.write(output); }; } /** Parses config file using System interface */ - export function parseConfigFileWithSystem(configFileName: string, optionsToExtend: CompilerOptions, extendedConfigCache: Map | undefined, watchOptionsToExtend: WatchOptions | undefined, system: System, reportDiagnostic: DiagnosticReporter) { + export function parseConfigFileWithSystem( + configFileName: string, + optionsToExtend: CompilerOptions, + extendedConfigCache: Map | undefined, + watchOptionsToExtend: WatchOptions | undefined, + system: System, + reportDiagnostic: DiagnosticReporter, + ) { const host: ParseConfigFileHost = system as any; - host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(system, reportDiagnostic, diagnostic); - const result = getParsedCommandLineOfConfigFile(configFileName, optionsToExtend, host, extendedConfigCache, watchOptionsToExtend); + host.onUnRecoverableConfigFileDiagnostic = diagnostic => + reportUnrecoverableDiagnostic(system, reportDiagnostic, diagnostic); + const result = getParsedCommandLineOfConfigFile( + configFileName, + optionsToExtend, + host, + extendedConfigCache, + watchOptionsToExtend, + ); host.onUnRecoverableConfigFileDiagnostic = undefined!; // TODO: GH#18217 return result; } @@ -112,10 +134,16 @@ namespace ts { }, ); return filesInError.map((fileName: string) => { - const diagnosticForFileName = find(diagnostics, diagnostic => diagnostic.file !== undefined && diagnostic.file.fileName === fileName); + const diagnosticForFileName = find( + diagnostics, + diagnostic => diagnostic.file !== undefined && diagnostic.file.fileName === fileName, + ); if (diagnosticForFileName !== undefined) { - const { line } = getLineAndCharacterOfPosition(diagnosticForFileName.file!, diagnosticForFileName.start!); + const { line } = getLineAndCharacterOfPosition( + diagnosticForFileName.file!, + diagnosticForFileName.start!, + ); return { fileName, line: line + 1, @@ -125,9 +153,9 @@ namespace ts { } export function getWatchErrorSummaryDiagnosticMessage(errorCount: number) { - return errorCount === 1 ? - Diagnostics.Found_1_error_Watching_for_file_changes : - Diagnostics.Found_0_errors_Watching_for_file_changes; + return errorCount === 1 + ? Diagnostics.Found_1_error_Watching_for_file_changes + : Diagnostics.Found_0_errors_Watching_for_file_changes; } function prettyPathForFileError(error: ReportFileInError, cwd: string) { @@ -147,25 +175,27 @@ namespace ts { ) { if (errorCount === 0) return ""; const nonNilFiles = filesInError.filter(fileInError => fileInError !== undefined); - const distinctFileNamesWithLines = nonNilFiles.map(fileInError => `${fileInError!.fileName}:${fileInError!.line}`) + const distinctFileNamesWithLines = nonNilFiles.map(fileInError => + `${fileInError!.fileName}:${fileInError!.line}` + ) .filter((value, index, self) => self.indexOf(value) === index); const firstFileReference = nonNilFiles[0] && prettyPathForFileError(nonNilFiles[0], host.getCurrentDirectory()); - const d = errorCount === 1 ? - createCompilerDiagnostic( - filesInError[0] !== undefined ? - Diagnostics.Found_1_error_in_1 : - Diagnostics.Found_1_error, + const d = errorCount === 1 + ? createCompilerDiagnostic( + filesInError[0] !== undefined + ? Diagnostics.Found_1_error_in_1 + : Diagnostics.Found_1_error, errorCount, firstFileReference, - ) : - createCompilerDiagnostic( - distinctFileNamesWithLines.length === 0 ? - Diagnostics.Found_0_errors : - distinctFileNamesWithLines.length === 1 ? - Diagnostics.Found_0_errors_in_the_same_file_starting_at_Colon_1 : - Diagnostics.Found_0_errors_in_1_files, + ) + : createCompilerDiagnostic( + distinctFileNamesWithLines.length === 0 + ? Diagnostics.Found_0_errors + : distinctFileNamesWithLines.length === 1 + ? Diagnostics.Found_0_errors_in_the_same_file_starting_at_Colon_1 + : Diagnostics.Found_0_errors_in_1_files, errorCount, distinctFileNamesWithLines.length === 1 ? firstFileReference : distinctFileNamesWithLines.length, ); @@ -175,11 +205,18 @@ namespace ts { } function createTabularErrorsDisplay(filesInError: (ReportFileInError | undefined)[], host: HasCurrentDirectory) { - const distinctFiles = filesInError.filter((value, index, self) => index === self.findIndex(file => file?.fileName === value?.fileName)); + const distinctFiles = filesInError.filter((value, index, self) => + index === self.findIndex(file => file?.fileName === value?.fileName) + ); if (distinctFiles.length === 0) return ""; const numberLength = (num: number) => Math.log(num) * Math.LOG10E + 1; - const fileToErrorCount = distinctFiles.map(file => ([file, countWhere(filesInError, fileInError => fileInError!.fileName === file!.fileName)] as const)); + const fileToErrorCount = distinctFiles.map( + file => ([ + file, + countWhere(filesInError, fileInError => fileInError!.fileName === file!.fileName), + ] as const), + ); const maxErrors = fileToErrorCount.reduce((acc, value) => Math.max(acc, value[1] || 0), 0); const headerRow = Diagnostics.Errors_Files.message; @@ -192,8 +229,8 @@ namespace ts { fileToErrorCount.forEach(row => { const [file, errorCount] = row; const errorCountDigitsLength = Math.log(errorCount) * Math.LOG10E + 1 | 0; - const leftPadding = errorCountDigitsLength < leftPaddingGoal ? - " ".repeat(leftPaddingGoal - errorCountDigitsLength) + const leftPadding = errorCountDigitsLength < leftPaddingGoal + ? " ".repeat(leftPaddingGoal - errorCountDigitsLength) : ""; const fileRef = prettyPathForFileError(file!, host.getCurrentDirectory()); @@ -222,10 +259,13 @@ namespace ts { export function explainFiles(program: Program, write: (s: string) => void) { const reasons = program.getFileIncludeReasons(); const getCanonicalFileName = createGetCanonicalFileName(program.useCaseSensitiveFileNames()); - const relativeFileName = (fileName: string) => convertToRelativePath(fileName, program.getCurrentDirectory(), getCanonicalFileName); + const relativeFileName = (fileName: string) => + convertToRelativePath(fileName, program.getCurrentDirectory(), getCanonicalFileName); for (const file of program.getSourceFiles()) { write(`${toFileName(file, relativeFileName)}`); - reasons.get(file.path)?.forEach(reason => write(` ${fileIncludeReasonToDiagnostics(program, reason, relativeFileName).messageText}`)); + reasons.get(file.path)?.forEach(reason => + write(` ${fileIncludeReasonToDiagnostics(program, reason, relativeFileName).messageText}`) + ); explainIfFileIsRedirectAndImpliedFormat(file, relativeFileName)?.forEach(d => write(` ${d.messageText}`)); } } @@ -264,9 +304,9 @@ namespace ts { if (file.packageJsonScope) { (result ??= []).push(chainDiagnosticMessages( /*details*/ undefined, - file.packageJsonScope.contents.packageJsonContent.type ? - Diagnostics.File_is_CommonJS_module_because_0_has_field_type_whose_value_is_not_module : - Diagnostics.File_is_CommonJS_module_because_0_does_not_have_field_type, + file.packageJsonScope.contents.packageJsonContent.type + ? Diagnostics.File_is_CommonJS_module_because_0_has_field_type_whose_value_is_not_module + : Diagnostics.File_is_CommonJS_module_because_0_does_not_have_field_type, toFileName(last(file.packageJsonLocations!), fileNameConvertor), )); } @@ -288,8 +328,13 @@ namespace ts { const getCanonicalFileName = createGetCanonicalFileName(program.useCaseSensitiveFileNames()); const filePath = getCanonicalFileName(fileName); - const basePath = getDirectoryPath(getNormalizedAbsolutePath(configFile.fileName, program.getCurrentDirectory())); - return find(configFile.configFileSpecs.validatedFilesSpec, fileSpec => getCanonicalFileName(getNormalizedAbsolutePath(fileSpec, basePath)) === filePath); + const basePath = getDirectoryPath( + getNormalizedAbsolutePath(configFile.fileName, program.getCurrentDirectory()), + ); + return find( + configFile.configFileSpecs.validatedFilesSpec, + fileSpec => getCanonicalFileName(getNormalizedAbsolutePath(fileSpec, basePath)) === filePath, + ); } export function getMatchedIncludeSpec(program: Program, fileName: string) { @@ -300,7 +345,9 @@ namespace ts { if (configFile.configFileSpecs.isDefaultIncludeSpec) return true; const isJsonFile = fileExtensionIs(fileName, Extension.Json); - const basePath = getDirectoryPath(getNormalizedAbsolutePath(configFile.fileName, program.getCurrentDirectory())); + const basePath = getDirectoryPath( + getNormalizedAbsolutePath(configFile.fileName, program.getCurrentDirectory()), + ); const useCaseSensitiveFileNames = program.useCaseSensitiveFileNames(); return find(configFile?.configFileSpecs?.validatedIncludeSpecs, includeSpec => { if (isJsonFile && !endsWith(includeSpec, Extension.Json)) return false; @@ -309,29 +356,41 @@ namespace ts { }); } - export function fileIncludeReasonToDiagnostics(program: Program, reason: FileIncludeReason, fileNameConvertor?: (fileName: string) => string): DiagnosticMessageChain { + export function fileIncludeReasonToDiagnostics( + program: Program, + reason: FileIncludeReason, + fileNameConvertor?: (fileName: string) => string, + ): DiagnosticMessageChain { const options = program.getCompilerOptions(); if (isReferencedFile(reason)) { const referenceLocation = getReferencedFileLocation(path => program.getSourceFileByPath(path), reason); - const referenceText = isReferenceFileLocation(referenceLocation) ? referenceLocation.file.text.substring(referenceLocation.pos, referenceLocation.end) : `"${referenceLocation.text}"`; + const referenceText = isReferenceFileLocation(referenceLocation) + ? referenceLocation.file.text.substring(referenceLocation.pos, referenceLocation.end) + : `"${referenceLocation.text}"`; let message: DiagnosticMessage; - Debug.assert(isReferenceFileLocation(referenceLocation) || reason.kind === FileIncludeKind.Import, "Only synthetic references are imports"); + Debug.assert( + isReferenceFileLocation(referenceLocation) || reason.kind === FileIncludeKind.Import, + "Only synthetic references are imports", + ); switch (reason.kind) { case FileIncludeKind.Import: if (isReferenceFileLocation(referenceLocation)) { - message = referenceLocation.packageId ? - Diagnostics.Imported_via_0_from_file_1_with_packageId_2 : - Diagnostics.Imported_via_0_from_file_1; + message = referenceLocation.packageId + ? Diagnostics.Imported_via_0_from_file_1_with_packageId_2 + : Diagnostics.Imported_via_0_from_file_1; } else if (referenceLocation.text === externalHelpersModuleNameText) { - message = referenceLocation.packageId ? - Diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_importHelpers_as_specified_in_compilerOptions : - Diagnostics.Imported_via_0_from_file_1_to_import_importHelpers_as_specified_in_compilerOptions; + message = referenceLocation.packageId + ? Diagnostics + .Imported_via_0_from_file_1_with_packageId_2_to_import_importHelpers_as_specified_in_compilerOptions + : Diagnostics + .Imported_via_0_from_file_1_to_import_importHelpers_as_specified_in_compilerOptions; } else { - message = referenceLocation.packageId ? - Diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_jsx_and_jsxs_factory_functions : - Diagnostics.Imported_via_0_from_file_1_to_import_jsx_and_jsxs_factory_functions; + message = referenceLocation.packageId + ? Diagnostics + .Imported_via_0_from_file_1_with_packageId_2_to_import_jsx_and_jsxs_factory_functions + : Diagnostics.Imported_via_0_from_file_1_to_import_jsx_and_jsxs_factory_functions; } break; case FileIncludeKind.ReferenceFile: @@ -339,9 +398,9 @@ namespace ts { message = Diagnostics.Referenced_via_0_from_file_1; break; case FileIncludeKind.TypeReferenceDirective: - message = referenceLocation.packageId ? - Diagnostics.Type_library_referenced_via_0_from_file_1_with_packageId_2 : - Diagnostics.Type_library_referenced_via_0_from_file_1; + message = referenceLocation.packageId + ? Diagnostics.Type_library_referenced_via_0_from_file_1_with_packageId_2 + : Diagnostics.Type_library_referenced_via_0_from_file_1; break; case FileIncludeKind.LibReferenceDirective: Debug.assert(!referenceLocation.packageId); @@ -360,62 +419,86 @@ namespace ts { } switch (reason.kind) { case FileIncludeKind.RootFile: - if (!options.configFile?.configFileSpecs) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Root_file_specified_for_compilation); - const fileName = getNormalizedAbsolutePath(program.getRootFileNames()[reason.index], program.getCurrentDirectory()); + if (!options.configFile?.configFileSpecs) { + return chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Root_file_specified_for_compilation, + ); + } + const fileName = getNormalizedAbsolutePath( + program.getRootFileNames()[reason.index], + program.getCurrentDirectory(), + ); const matchedByFiles = getMatchedFileSpec(program, fileName); - if (matchedByFiles) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Part_of_files_list_in_tsconfig_json); + if (matchedByFiles) { + return chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Part_of_files_list_in_tsconfig_json, + ); + } const matchedByInclude = getMatchedIncludeSpec(program, fileName); - return isString(matchedByInclude) ? - chainDiagnosticMessages( + return isString(matchedByInclude) + ? chainDiagnosticMessages( /*details*/ undefined, Diagnostics.Matched_by_include_pattern_0_in_1, matchedByInclude, toFileName(options.configFile, fileNameConvertor), - ) : + ) // Could be additional files specified as roots or matched by default include - chainDiagnosticMessages( + : chainDiagnosticMessages( /*details*/ undefined, - matchedByInclude ? - Diagnostics.Matched_by_default_include_pattern_Asterisk_Asterisk_Slash_Asterisk : - Diagnostics.Root_file_specified_for_compilation, + matchedByInclude + ? Diagnostics.Matched_by_default_include_pattern_Asterisk_Asterisk_Slash_Asterisk + : Diagnostics.Root_file_specified_for_compilation, ); case FileIncludeKind.SourceFromProjectReference: case FileIncludeKind.OutputFromProjectReference: const isOutput = reason.kind === FileIncludeKind.OutputFromProjectReference; - const referencedResolvedRef = Debug.checkDefined(program.getResolvedProjectReferences()?.[reason.index]); + const referencedResolvedRef = Debug.checkDefined( + program.getResolvedProjectReferences()?.[reason.index], + ); return chainDiagnosticMessages( /*details*/ undefined, - outFile(options) ? - isOutput ? - Diagnostics.Output_from_referenced_project_0_included_because_1_specified : - Diagnostics.Source_from_referenced_project_0_included_because_1_specified : - isOutput ? - Diagnostics.Output_from_referenced_project_0_included_because_module_is_specified_as_none : - Diagnostics.Source_from_referenced_project_0_included_because_module_is_specified_as_none, + outFile(options) + ? isOutput + ? Diagnostics.Output_from_referenced_project_0_included_because_1_specified + : Diagnostics.Source_from_referenced_project_0_included_because_1_specified + : isOutput + ? Diagnostics.Output_from_referenced_project_0_included_because_module_is_specified_as_none + : Diagnostics.Source_from_referenced_project_0_included_because_module_is_specified_as_none, toFileName(referencedResolvedRef.sourceFile.fileName, fileNameConvertor), options.outFile ? "--outFile" : "--out", ); case FileIncludeKind.AutomaticTypeDirectiveFile: return chainDiagnosticMessages( /*details*/ undefined, - options.types ? - reason.packageId ? - Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1 : - Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions : - reason.packageId ? - Diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1 : - Diagnostics.Entry_point_for_implicit_type_library_0, + options.types + ? reason.packageId + ? Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1 + : Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions + : reason.packageId + ? Diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1 + : Diagnostics.Entry_point_for_implicit_type_library_0, reason.typeReference, reason.packageId && packageIdToString(reason.packageId), ); case FileIncludeKind.LibFile: - if (reason.index !== undefined) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Library_0_specified_in_compilerOptions, options.lib![reason.index]); - const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === getEmitScriptTarget(options) ? key : undefined); + if (reason.index !== undefined) { + return chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Library_0_specified_in_compilerOptions, + options.lib![reason.index], + ); + } + const target = forEachEntry( + targetOptionDeclaration.type, + (value, key) => value === getEmitScriptTarget(options) ? key : undefined, + ); return chainDiagnosticMessages( /*details*/ undefined, - target ? - Diagnostics.Default_library_for_target_0 : - Diagnostics.Default_library, + target + ? Diagnostics.Default_library_for_target_0 + : Diagnostics.Default_library, target, ); default: @@ -457,7 +540,10 @@ namespace ts { addRange(allDiagnostics, program.getGlobalDiagnostics(cancellationToken)); if (allDiagnostics.length === configFileParsingDiagnosticsLength) { - addRange(allDiagnostics, program.getSemanticDiagnostics(/*sourceFile*/ undefined, cancellationToken)); + addRange( + allDiagnostics, + program.getSemanticDiagnostics(/*sourceFile*/ undefined, cancellationToken), + ); } } } @@ -465,7 +551,13 @@ namespace ts { // Emit and report any errors we ran into. const emitResult = isListFilesOnly ? { emitSkipped: true, diagnostics: emptyArray } - : program.emit(/*targetSourceFile*/ undefined, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers); + : program.emit( + /*targetSourceFile*/ undefined, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers, + ); const { emittedFiles, diagnostics: emitDiagnostics } = emitResult; addRange(allDiagnostics, emitDiagnostics); @@ -588,15 +680,24 @@ namespace ts { writeLog: (s: string) => void; } - export function createWatchFactory(host: WatchFactoryHost & { trace?(s: string): void; }, options: { extendedDiagnostics?: boolean; diagnostics?: boolean; }) { - const watchLogLevel = host.trace ? options.extendedDiagnostics ? WatchLogLevel.Verbose : options.diagnostics ? WatchLogLevel.TriggerOnly : WatchLogLevel.None : WatchLogLevel.None; + export function createWatchFactory( + host: WatchFactoryHost & { trace?(s: string): void; }, + options: { extendedDiagnostics?: boolean; diagnostics?: boolean; }, + ) { + const watchLogLevel = host.trace + ? options.extendedDiagnostics ? WatchLogLevel.Verbose + : options.diagnostics ? WatchLogLevel.TriggerOnly : WatchLogLevel.None : WatchLogLevel.None; const writeLog: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? (s => host.trace!(s)) : noop; const result = getWatchFactory(host, watchLogLevel, writeLog) as WatchFactory; result.writeLog = writeLog; return result; } - export function createCompilerHostFromProgramHost(host: ProgramHost, getCompilerOptions: () => CompilerOptions, directoryStructureHost: DirectoryStructureHost = host): CompilerHost { + export function createCompilerHostFromProgramHost( + host: ProgramHost, + getCompilerOptions: () => CompilerOptions, + directoryStructureHost: DirectoryStructureHost = host, + ): CompilerHost { const useCaseSensitiveFileNames = host.useCaseSensitiveFileNames(); const hostGetNewLine = memoize(() => host.getNewLine()); return { @@ -637,7 +738,12 @@ namespace ts { storeFilesChangingSignatureDuringEmit: host.storeFilesChangingSignatureDuringEmit, }; - function writeFile(fileName: string, text: string, writeByteOrderMark: boolean, onError: (message: string) => void) { + function writeFile( + fileName: string, + text: string, + writeByteOrderMark: boolean, + onError: (message: string) => void, + ) { try { performance.mark("beforeIOWrite"); @@ -664,7 +770,10 @@ namespace ts { } } - export function setGetSourceFileAsHashVersioned(compilerHost: CompilerHost, host: { createHash?(data: string): string; }) { + export function setGetSourceFileAsHashVersioned( + compilerHost: CompilerHost, + host: { createHash?(data: string): string; }, + ) { const originalGetSourceFile = compilerHost.getSourceFile; const computeHash = maybeBind(host, host.createHash) || generateDjb2Hash; compilerHost.getSourceFile = (...args) => { @@ -679,7 +788,10 @@ namespace ts { /** * Creates the watch compiler host that can be extended with config file or root file names and options host */ - export function createProgramHost(system: System, createProgram: CreateProgram | undefined): ProgramHost { + export function createProgramHost( + system: System, + createProgram: CreateProgram | undefined, + ): ProgramHost { const getDefaultLibLocation = memoize(() => getDirectoryPath(normalizePath(system.getExecutingFilePath()))); return { useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames, @@ -691,7 +803,8 @@ namespace ts { readFile: (path, encoding) => system.readFile(path, encoding), directoryExists: path => system.directoryExists(path), getDirectories: path => system.getDirectories(path), - readDirectory: (path, extensions, exclude, include, depth) => system.readDirectory(path, extensions, exclude, include, depth), + readDirectory: (path, extensions, exclude, include, depth) => + system.readDirectory(path, extensions, exclude, include, depth), realpath: maybeBind(system, system.realpath), getEnvironmentVariable: maybeBind(system, system.getEnvironmentVariable), trace: s => system.write(s + system.newLine), @@ -708,7 +821,12 @@ namespace ts { /** * Creates the watch compiler host that can be extended with config file or root file names and options host */ - function createWatchCompilerHost(system = sys, createProgram: CreateProgram | undefined, reportDiagnostic: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHost { + function createWatchCompilerHost( + system = sys, + createProgram: CreateProgram | undefined, + reportDiagnostic: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, + ): WatchCompilerHost { const write = (s: string) => system.write(s + system.newLine); const result = createProgramHost(system, createProgram) as WatchCompilerHost; copyProperties(result, createWatchHost(system, reportWatchStatus)); @@ -735,7 +853,11 @@ namespace ts { /** * Report error and exit */ - function reportUnrecoverableDiagnostic(system: System, reportDiagnostic: DiagnosticReporter, diagnostic: Diagnostic) { + function reportUnrecoverableDiagnostic( + system: System, + reportDiagnostic: DiagnosticReporter, + diagnostic: Diagnostic, + ) { reportDiagnostic(diagnostic); system.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } @@ -747,7 +869,9 @@ namespace ts { reportWatchStatus?: WatchStatusReporter; } - export interface CreateWatchCompilerHostOfConfigFileInput extends CreateWatchCompilerHostInput { + export interface CreateWatchCompilerHostOfConfigFileInput + extends CreateWatchCompilerHostInput + { configFileName: string; optionsToExtend?: CompilerOptions; watchOptionsToExtend?: WatchOptions; @@ -756,7 +880,9 @@ namespace ts { /** * Creates the watch compiler host from system for config file in watch mode */ - export function createWatchCompilerHostOfConfigFile({ + export function createWatchCompilerHostOfConfigFile< + T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram, + >({ configFileName, optionsToExtend, watchOptionsToExtend, @@ -767,8 +893,14 @@ namespace ts { reportWatchStatus, }: CreateWatchCompilerHostOfConfigFileInput): WatchCompilerHostOfConfigFile { const diagnosticReporter = reportDiagnostic || createDiagnosticReporter(system); - const host = createWatchCompilerHost(system, createProgram, diagnosticReporter, reportWatchStatus) as WatchCompilerHostOfConfigFile; - host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(system, diagnosticReporter, diagnostic); + const host = createWatchCompilerHost( + system, + createProgram, + diagnosticReporter, + reportWatchStatus, + ) as WatchCompilerHostOfConfigFile; + host.onUnRecoverableConfigFileDiagnostic = diagnostic => + reportUnrecoverableDiagnostic(system, diagnosticReporter, diagnostic); host.configFileName = configFileName; host.optionsToExtend = optionsToExtend; host.watchOptionsToExtend = watchOptionsToExtend; @@ -776,7 +908,9 @@ namespace ts { return host; } - export interface CreateWatchCompilerHostOfFilesAndCompilerOptionsInput extends CreateWatchCompilerHostInput { + export interface CreateWatchCompilerHostOfFilesAndCompilerOptionsInput + extends CreateWatchCompilerHostInput + { rootFiles: string[]; options: CompilerOptions; watchOptions: WatchOptions | undefined; @@ -785,7 +919,9 @@ namespace ts { /** * Creates the watch compiler host from system for compiling root files and options in watch mode */ - export function createWatchCompilerHostOfFilesAndCompilerOptions({ + export function createWatchCompilerHostOfFilesAndCompilerOptions< + T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram, + >({ rootFiles, options, watchOptions, @@ -795,7 +931,12 @@ namespace ts { reportDiagnostic, reportWatchStatus, }: CreateWatchCompilerHostOfFilesAndCompilerOptionsInput): WatchCompilerHostOfFilesAndCompilerOptions { - const host = createWatchCompilerHost(system, createProgram, reportDiagnostic || createDiagnosticReporter(system), reportWatchStatus) as WatchCompilerHostOfFilesAndCompilerOptions; + const host = createWatchCompilerHost( + system, + createProgram, + reportDiagnostic || createDiagnosticReporter(system), + reportWatchStatus, + ) as WatchCompilerHostOfFilesAndCompilerOptions; host.rootFiles = rootFiles; host.options = options; host.watchOptions = watchOptions; @@ -822,7 +963,9 @@ namespace ts { builderProgram, input.reportDiagnostic || createDiagnosticReporter(system), s => host.trace && host.trace(s), - input.reportErrorSummary || input.options.pretty ? (errorCount, filesInError) => system.write(getErrorSummaryText(errorCount, filesInError, system.newLine, host)) : undefined, + input.reportErrorSummary || input.options.pretty + ? (errorCount, filesInError) => + system.write(getErrorSummaryText(errorCount, filesInError, system.newLine, host)) : undefined, ); if (input.afterProgramEmitAndDiagnostics) input.afterProgramEmitAndDiagnostics(builderProgram); return exitStatus; diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index 5f218abcb6454..6768755ebffa1 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -29,7 +29,10 @@ namespace ts { host.disableUseFileVersionAsSignature = system.disableUseFileVersionAsSignature; host.storeFilesChangingSignatureDuringEmit = system.storeFilesChangingSignatureDuringEmit; setGetSourceFileAsHashVersioned(host, system); - changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, host.getCurrentDirectory(), host.getCanonicalFileName)); + changeCompilerHostLikeToUseCache( + host, + fileName => toPath(fileName, host.getCurrentDirectory(), host.getCanonicalFileName), + ); return host; } @@ -56,19 +59,46 @@ namespace ts { return createProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences); } - export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions, errorCount?: number) => void; + export type WatchStatusReporter = ( + diagnostic: Diagnostic, + newLine: string, + options: CompilerOptions, + errorCount?: number, + ) => void; /** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */ - export type CreateProgram = (rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[] | undefined) => T; + export type CreateProgram = ( + rootNames: readonly string[] | undefined, + options: CompilerOptions | undefined, + host?: CompilerHost, + oldProgram?: T, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[] | undefined, + ) => T; /** Host that has watch functionality used in --watch mode */ export interface WatchHost { /** If provided, called with Diagnostic message that informs about change in watch status */ - onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions, errorCount?: number): void; + onWatchStatusChange?( + diagnostic: Diagnostic, + newLine: string, + options: CompilerOptions, + errorCount?: number, + ): void; /** Used to watch changes in source files, missing files needed to update the program or config file */ - watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; + watchFile( + path: string, + callback: FileWatcherCallback, + pollingInterval?: number, + options?: WatchOptions, + ): FileWatcher; /** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */ - watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; + watchDirectory( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher; /** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */ setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any; /** If provided, will be used to reset existing delayed compilation */ @@ -104,7 +134,13 @@ namespace ts { /** If provided, used in resolutions as well as handling directory structure */ getDirectories?(path: string): string[]; /** If provided, used to cache and handle directory structure modifications */ - readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory?( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; /** Symbol links resolution */ realpath?(path: string): string; @@ -114,9 +150,22 @@ namespace ts { getEnvironmentVariable?(name: string): string | undefined; /** If provided, used to resolve the module names, otherwise typescript's default module resolution */ - resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[]; + resolveModuleNames?( + moduleNames: string[], + containingFile: string, + reusedNames: string[] | undefined, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingSourceFile?: SourceFile, + ): (ResolvedModule | undefined)[]; /** If provided, used to resolve type reference directives, otherwise typescript's default resolution */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?( + typeReferenceDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, + ): (ResolvedTypeReferenceDirective | undefined)[]; /** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */ hasInvalidatedResolutions?(filePath: Path): boolean; /** @@ -167,7 +216,9 @@ namespace ts { /** * Host to create watch with config file */ - export interface WatchCompilerHostOfConfigFile extends WatchCompilerHost, ConfigFileDiagnosticsReporter { + export interface WatchCompilerHostOfConfigFile + extends WatchCompilerHost, ConfigFileDiagnosticsReporter + { /** Name of the config file to compile */ configFileName: string; @@ -182,7 +233,13 @@ namespace ts { * Used to generate source file names from the config file and its include, exclude, files rules * and also to cache the directory stucture */ - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; } /** @@ -221,9 +278,36 @@ namespace ts { /** * Create the watch compiler host for either configFile or fileNames and its options */ - export function createWatchCompilerHost(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, watchOptionsToExtend?: WatchOptions, extraFileExtensions?: readonly FileExtensionInfo[]): WatchCompilerHostOfConfigFile; - export function createWatchCompilerHost(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: readonly ProjectReference[], watchOptions?: WatchOptions): WatchCompilerHostOfFilesAndCompilerOptions; - export function createWatchCompilerHost(rootFilesOrConfigFileName: string | string[], options: CompilerOptions | undefined, system: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferencesOrWatchOptionsToExtend?: readonly ProjectReference[] | WatchOptions, watchOptionsOrExtraFileExtensions?: WatchOptions | readonly FileExtensionInfo[]): WatchCompilerHostOfFilesAndCompilerOptions | WatchCompilerHostOfConfigFile { + export function createWatchCompilerHost( + configFileName: string, + optionsToExtend: CompilerOptions | undefined, + system: System, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, + watchOptionsToExtend?: WatchOptions, + extraFileExtensions?: readonly FileExtensionInfo[], + ): WatchCompilerHostOfConfigFile; + export function createWatchCompilerHost( + rootFiles: string[], + options: CompilerOptions, + system: System, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, + projectReferences?: readonly ProjectReference[], + watchOptions?: WatchOptions, + ): WatchCompilerHostOfFilesAndCompilerOptions; + export function createWatchCompilerHost( + rootFilesOrConfigFileName: string | string[], + options: CompilerOptions | undefined, + system: System, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, + projectReferencesOrWatchOptionsToExtend?: readonly ProjectReference[] | WatchOptions, + watchOptionsOrExtraFileExtensions?: WatchOptions | readonly FileExtensionInfo[], + ): WatchCompilerHostOfFilesAndCompilerOptions | WatchCompilerHostOfConfigFile { if (isArray(rootFilesOrConfigFileName)) { return createWatchCompilerHostOfFilesAndCompilerOptions({ rootFiles: rootFilesOrConfigFileName, @@ -264,12 +348,18 @@ namespace ts { /** * Creates the watch from the host for root files and compiler options */ - export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptions): WatchOfFilesAndCompilerOptions; + export function createWatchProgram( + host: WatchCompilerHostOfFilesAndCompilerOptions, + ): WatchOfFilesAndCompilerOptions; /** * Creates the watch from the host for config file */ - export function createWatchProgram(host: WatchCompilerHostOfConfigFile): WatchOfConfigFile; - export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptions & WatchCompilerHostOfConfigFile): WatchOfFilesAndCompilerOptions | WatchOfConfigFile { + export function createWatchProgram( + host: WatchCompilerHostOfConfigFile, + ): WatchOfConfigFile; + export function createWatchProgram( + host: WatchCompilerHostOfFilesAndCompilerOptions & WatchCompilerHostOfConfigFile, + ): WatchOfFilesAndCompilerOptions | WatchOfConfigFile { interface FilePresentOnHost { version: string; sourceFile: SourceFile; @@ -300,14 +390,21 @@ namespace ts { const useCaseSensitiveFileNames = host.useCaseSensitiveFileNames(); const currentDirectory = host.getCurrentDirectory(); - const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {}, watchOptionsToExtend, extraFileExtensions, createProgram } = host; + const { + configFileName, + optionsToExtend: optionsToExtendForConfigFile = {}, + watchOptionsToExtend, + extraFileExtensions, + createProgram, + } = host; let { rootFiles: rootFileNames, options: compilerOptions, watchOptions, projectReferences } = host; let wildcardDirectories: MapLike | undefined; let configFileParsingDiagnostics: Diagnostic[] | undefined; let canConfigFileJsonReportNoInputFiles = false; let hasChangedConfigFileParsingErrors = false; - const cachedDirectoryStructureHost = configFileName === undefined ? undefined : createCachedDirectoryStructureHost(host, currentDirectory, useCaseSensitiveFileNames); + const cachedDirectoryStructureHost = configFileName === undefined ? undefined + : createCachedDirectoryStructureHost(host, currentDirectory, useCaseSensitiveFileNames); const directoryStructureHost: DirectoryStructureHost = cachedDirectoryStructureHost || host; const parseConfigFileHost = parseConfigHostFromCompilerHostLike(host, directoryStructureHost); @@ -331,14 +428,23 @@ namespace ts { writeLog(`Current directory: ${currentDirectory} CaseSensitiveFileNames: ${useCaseSensitiveFileNames}`); let configFileWatcher: FileWatcher | undefined; if (configFileName) { - configFileWatcher = watchFile(configFileName, scheduleProgramReload, PollingInterval.High, watchOptions, WatchType.ConfigFile); + configFileWatcher = watchFile( + configFileName, + scheduleProgramReload, + PollingInterval.High, + watchOptions, + WatchType.ConfigFile, + ); } - const compilerHost = createCompilerHostFromProgramHost(host, () => compilerOptions, directoryStructureHost) as CompilerHost & ResolutionCacheHost; + const compilerHost = createCompilerHostFromProgramHost(host, () => compilerOptions, directoryStructureHost) as + & CompilerHost + & ResolutionCacheHost; setGetSourceFileAsHashVersioned(compilerHost, host); // Members for CompilerHost const getNewSourceFile = compilerHost.getSourceFile; - compilerHost.getSourceFile = (fileName, ...args) => getVersionedSourceFileByPath(fileName, toPath(fileName), ...args); + compilerHost.getSourceFile = (fileName, ...args) => + getVersionedSourceFileByPath(fileName, toPath(fileName), ...args); compilerHost.getSourceFileByPath = getVersionedSourceFileByPath; compilerHost.getNewLine = () => newLine; compilerHost.fileExists = fileExists; @@ -348,11 +454,15 @@ namespace ts { compilerHost.toPath = toPath; compilerHost.getCompilationSettings = () => compilerOptions; compilerHost.useSourceOfProjectReferenceRedirect = maybeBind(host, host.useSourceOfProjectReferenceRedirect); - compilerHost.watchDirectoryOfFailedLookupLocation = (dir, cb, flags) => watchDirectory(dir, cb, flags, watchOptions, WatchType.FailedLookupLocations); - compilerHost.watchAffectingFileLocation = (file, cb) => watchFile(file, cb, PollingInterval.High, watchOptions, WatchType.AffectingFileLocation); - compilerHost.watchTypeRootsDirectory = (dir, cb, flags) => watchDirectory(dir, cb, flags, watchOptions, WatchType.TypeRoots); + compilerHost.watchDirectoryOfFailedLookupLocation = (dir, cb, flags) => + watchDirectory(dir, cb, flags, watchOptions, WatchType.FailedLookupLocations); + compilerHost.watchAffectingFileLocation = (file, cb) => + watchFile(file, cb, PollingInterval.High, watchOptions, WatchType.AffectingFileLocation); + compilerHost.watchTypeRootsDirectory = (dir, cb, flags) => + watchDirectory(dir, cb, flags, watchOptions, WatchType.TypeRoots); compilerHost.getCachedDirectoryStructureHost = () => cachedDirectoryStructureHost; - compilerHost.scheduleInvalidateResolutionsOfFailedLookupLocations = scheduleInvalidateResolutionsOfFailedLookupLocations; + compilerHost.scheduleInvalidateResolutionsOfFailedLookupLocations = + scheduleInvalidateResolutionsOfFailedLookupLocations; compilerHost.onInvalidatedResolution = scheduleProgramUpdate; compilerHost.onChangedAutomaticTypeDirectiveNames = scheduleProgramUpdate; compilerHost.fileIsOpen = returnFalse; @@ -363,26 +473,39 @@ namespace ts { // Cache for the module resolution const resolutionCache = createResolutionCache( compilerHost, - configFileName ? - getDirectoryPath(getNormalizedAbsolutePath(configFileName, currentDirectory)) : - currentDirectory, + configFileName + ? getDirectoryPath(getNormalizedAbsolutePath(configFileName, currentDirectory)) + : currentDirectory, /*logChangesWhenResolvingModule*/ false, ); // Resolve module using host module resolution strategy if provided otherwise use resolution cache to resolve module names - compilerHost.resolveModuleNames = host.resolveModuleNames ? - ((...args) => host.resolveModuleNames!(...args)) : - ((moduleNames, containingFile, reusedNames, redirectedReference, _options, sourceFile) => resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, sourceFile)); - compilerHost.resolveTypeReferenceDirectives = host.resolveTypeReferenceDirectives ? - ((...args) => host.resolveTypeReferenceDirectives!(...args)) : - ((typeDirectiveNames, containingFile, redirectedReference, _options, containingFileMode) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference, containingFileMode)); - compilerHost.getModuleResolutionCache = host.resolveModuleNames ? - maybeBind(host, host.getModuleResolutionCache) : - (() => resolutionCache.getModuleResolutionCache()); + compilerHost.resolveModuleNames = host.resolveModuleNames + ? ((...args) => host.resolveModuleNames!(...args)) + : ((moduleNames, containingFile, reusedNames, redirectedReference, _options, sourceFile) => + resolutionCache.resolveModuleNames( + moduleNames, + containingFile, + reusedNames, + redirectedReference, + sourceFile, + )); + compilerHost.resolveTypeReferenceDirectives = host.resolveTypeReferenceDirectives + ? ((...args) => host.resolveTypeReferenceDirectives!(...args)) + : ((typeDirectiveNames, containingFile, redirectedReference, _options, containingFileMode) => + resolutionCache.resolveTypeReferenceDirectives( + typeDirectiveNames, + containingFile, + redirectedReference, + containingFileMode, + )); + compilerHost.getModuleResolutionCache = host.resolveModuleNames + ? maybeBind(host, host.getModuleResolutionCache) + : (() => resolutionCache.getModuleResolutionCache()); const userProvidedResolution = !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives; // All resolutions are invalid if user provided resolutions and didnt supply hasInvalidatedResolutions - const customHasInvalidatedResolutions = userProvidedResolution ? - maybeBind(host, host.hasInvalidatedResolutions) || returnTrue : - returnFalse; + const customHasInvalidatedResolutions = userProvidedResolution + ? maybeBind(host, host.hasInvalidatedResolutions) || returnTrue + : returnFalse; builderProgram = readBuilderProgram(compilerOptions, compilerHost) as any as T; synchronizeProgram(); @@ -391,11 +514,18 @@ namespace ts { watchConfigFileWildCardDirectories(); // Update extended config file watch - if (configFileName) updateExtendedConfigFilesWatches(toPath(configFileName), compilerOptions, watchOptions, WatchType.ExtendedConfigFile); + if (configFileName) { + updateExtendedConfigFilesWatches( + toPath(configFileName), + compilerOptions, + watchOptions, + WatchType.ExtendedConfigFile, + ); + } - return configFileName ? - { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, close } : - { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, updateRootFileNames, close }; + return configFileName + ? { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, close } + : { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, updateRootFileNames, close }; function close() { clearInvalidateResolutionsOfFailedLookupLocations(); @@ -455,7 +585,9 @@ namespace ts { } } - const hasInvalidatedResolutions = resolutionCache.createHasInvalidatedResolutions(customHasInvalidatedResolutions); + const hasInvalidatedResolutions = resolutionCache.createHasInvalidatedResolutions( + customHasInvalidatedResolutions, + ); const { originalReadFile, originalFileExists, @@ -463,12 +595,31 @@ namespace ts { originalCreateDirectory, originalWriteFile, } = changeCompilerHostLikeToUseCache(compilerHost, toPath); - if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, getSourceVersion, fileName => compilerHost.fileExists(fileName), hasInvalidatedResolutions, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { + if ( + isProgramUptoDate( + getCurrentProgram(), + rootFileNames, + compilerOptions, + getSourceVersion, + fileName => compilerHost.fileExists(fileName), + hasInvalidatedResolutions, + hasChangedAutomaticTypeDirectiveNames, + getParsedCommandLine, + projectReferences, + ) + ) { if (hasChangedConfigFileParsingErrors) { if (reportFileChangeDetectedOnCreateProgram) { reportWatchDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation); } - builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences); + builderProgram = createProgram( + /*rootNames*/ undefined, + /*options*/ undefined, + compilerHost, + builderProgram, + configFileParsingDiagnostics, + projectReferences, + ); hasChangedConfigFileParsingErrors = false; } } @@ -507,11 +658,22 @@ namespace ts { compilerHost.hasInvalidatedResolutions = hasInvalidatedResolutions; compilerHost.hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames; const oldProgram = getCurrentProgram(); - builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences); + builderProgram = createProgram( + rootFileNames, + compilerOptions, + compilerHost, + builderProgram, + configFileParsingDiagnostics, + projectReferences, + ); resolutionCache.finishCachingPerDirectoryResolution(builderProgram.getProgram(), oldProgram); // Update watches - updateMissingFilePathsWatch(builderProgram.getProgram(), missingFilesMap || (missingFilesMap = new Map()), watchMissingFilePath); + updateMissingFilePathsWatch( + builderProgram.getProgram(), + missingFilesMap || (missingFilesMap = new Map()), + watchMissingFilePath, + ); if (needsUpdateInTypeRootWatch) { resolutionCache.updateTypeRootsWatch(); } @@ -549,7 +711,9 @@ namespace ts { return typeof hostSourceFile === "boolean"; } - function isFilePresenceUnknownOnHost(hostSourceFile: FileMayBePresentOnHost): hostSourceFile is FilePresenceUnknownOnHost { + function isFilePresenceUnknownOnHost( + hostSourceFile: FileMayBePresentOnHost, + ): hostSourceFile is FilePresenceUnknownOnHost { return typeof (hostSourceFile as FilePresenceUnknownOnHost).version === "boolean"; } @@ -564,7 +728,13 @@ namespace ts { return directoryStructureHost.fileExists(fileName); } - function getVersionedSourceFileByPath(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined { + function getVersionedSourceFileByPath( + fileName: string, + path: Path, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean, + ): SourceFile | undefined { const hostSourceFile = sourceFilesCache.get(path); // No source file on the host if (isFileMissingOnHost(hostSourceFile)) { @@ -572,7 +742,9 @@ namespace ts { } // Create new source file if requested or the versions dont match - if (hostSourceFile === undefined || shouldCreateNewSourceFile || isFilePresenceUnknownOnHost(hostSourceFile)) { + if ( + hostSourceFile === undefined || shouldCreateNewSourceFile || isFilePresenceUnknownOnHost(hostSourceFile) + ) { const sourceFile = getNewSourceFile(fileName, languageVersionOrOptions, onError); if (hostSourceFile) { if (sourceFile) { @@ -580,7 +752,14 @@ namespace ts { (hostSourceFile as FilePresentOnHost).sourceFile = sourceFile; hostSourceFile.version = sourceFile.version; if (!hostSourceFile.fileWatcher) { - hostSourceFile.fileWatcher = watchFilePath(path, fileName, onSourceFileChange, PollingInterval.Low, watchOptions, WatchType.SourceFile); + hostSourceFile.fileWatcher = watchFilePath( + path, + fileName, + onSourceFileChange, + PollingInterval.Low, + watchOptions, + WatchType.SourceFile, + ); } } else { @@ -593,7 +772,14 @@ namespace ts { } else { if (sourceFile) { - const fileWatcher = watchFilePath(path, fileName, onSourceFileChange, PollingInterval.Low, watchOptions, WatchType.SourceFile); + const fileWatcher = watchFilePath( + path, + fileName, + onSourceFileChange, + PollingInterval.Low, + watchOptions, + WatchType.SourceFile, + ); sourceFilesCache.set(path, { sourceFile, version: sourceFile.version, fileWatcher }); } else { @@ -623,7 +809,11 @@ namespace ts { return !hostSourceFile || !hostSourceFile.version ? undefined : hostSourceFile.version; } - function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions, hasSourceFileByPath: boolean) { + function onReleaseOldSourceFile( + oldSourceFile: SourceFile, + _oldOptions: CompilerOptions, + hasSourceFileByPath: boolean, + ) { const hostSourceFileInfo = sourceFilesCache.get(oldSourceFile.resolvedPath); // If this is the source file thats in the cache and new program doesnt need it, // remove the cached entry. @@ -632,7 +822,9 @@ namespace ts { if (hostSourceFileInfo !== undefined) { // record the missing file paths so they can be removed later if watchers arent tracking them if (isFileMissingOnHost(hostSourceFileInfo)) { - (missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push(oldSourceFile.path); + (missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push( + oldSourceFile.path, + ); } else if ((hostSourceFileInfo as FilePresentOnHost).sourceFile === oldSourceFile) { if (hostSourceFileInfo.fileWatcher) { @@ -648,7 +840,11 @@ namespace ts { function reportWatchDiagnostic(message: DiagnosticMessage) { if (host.onWatchStatusChange) { - host.onWatchStatusChange(createCompilerDiagnostic(message), newLine, compilerOptions || optionsToExtendForConfigFile); + host.onWatchStatusChange( + createCompilerDiagnostic(message), + newLine, + compilerOptions || optionsToExtendForConfigFile, + ); } } @@ -728,8 +924,22 @@ namespace ts { function reloadFileNamesFromConfigFile() { writeLog("Reloading new file names and options"); reloadLevel = ConfigFileProgramReloadLevel.None; - rootFileNames = getFileNamesFromConfigSpecs(compilerOptions.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), compilerOptions, parseConfigFileHost, extraFileExtensions); - if (updateErrorForNoInputFiles(rootFileNames, getNormalizedAbsolutePath(configFileName, currentDirectory), compilerOptions.configFile!.configFileSpecs!, configFileParsingDiagnostics!, canConfigFileJsonReportNoInputFiles)) { + rootFileNames = getFileNamesFromConfigSpecs( + compilerOptions.configFile!.configFileSpecs!, + getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), + compilerOptions, + parseConfigFileHost, + extraFileExtensions, + ); + if ( + updateErrorForNoInputFiles( + rootFileNames, + getNormalizedAbsolutePath(configFileName, currentDirectory), + compilerOptions.configFile!.configFileSpecs!, + configFileParsingDiagnostics!, + canConfigFileJsonReportNoInputFiles, + ) + ) { hasChangedConfigFileParsingErrors = true; } @@ -752,7 +962,12 @@ namespace ts { watchConfigFileWildCardDirectories(); // Update extended config file watch - updateExtendedConfigFilesWatches(toPath(configFileName), compilerOptions, watchOptions, WatchType.ExtendedConfigFile); + updateExtendedConfigFilesWatches( + toPath(configFileName), + compilerOptions, + watchOptions, + WatchType.ExtendedConfigFile, + ); } function parseConfigFile() { @@ -785,7 +1000,10 @@ namespace ts { if (config) { if (!config.reloadLevel) return config.parsedCommandLine; // With host implementing getParsedCommandLine we cant just update file names - if (config.parsedCommandLine && config.reloadLevel === ConfigFileProgramReloadLevel.Partial && !host.getParsedCommandLine) { + if ( + config.parsedCommandLine && config.reloadLevel === ConfigFileProgramReloadLevel.Partial + && !host.getParsedCommandLine + ) { writeLog("Reloading new file names and options"); const fileNames = getFileNamesFromConfigSpecs( config.parsedCommandLine.options.configFile!.configFileSpecs!, @@ -800,9 +1018,9 @@ namespace ts { } writeLog(`Loading config file: ${configFileName}`); - const parsedCommandLine = host.getParsedCommandLine ? - host.getParsedCommandLine(configFileName) : - getParsedCommandLineFromConfigFileHost(configFileName); + const parsedCommandLine = host.getParsedCommandLine + ? host.getParsedCommandLine(configFileName) + : getParsedCommandLineFromConfigFileHost(configFileName); if (config) { config.parsedCommandLine = parsedCommandLine; config.reloadLevel = undefined; @@ -848,7 +1066,13 @@ namespace ts { options: WatchOptions | undefined, watchType: WatchType, ): FileWatcher { - return watchFile(file, (fileName, eventKind) => callback(fileName, eventKind, path), pollingInterval, options, watchType); + return watchFile( + file, + (fileName, eventKind) => callback(fileName, eventKind, path), + pollingInterval, + options, + watchType, + ); } function onSourceFileChange(fileName: string, eventKind: FileWatcherEventKind, path: Path) { @@ -872,9 +1096,16 @@ namespace ts { function watchMissingFilePath(missingFilePath: Path) { // If watching missing referenced config file, we are already watching it so no need for separate watcher - return parsedConfigs?.has(missingFilePath) ? - noopFileWatcher : - watchFilePath(missingFilePath, missingFilePath, onMissingFileChange, PollingInterval.Medium, watchOptions, WatchType.MissingFile); + return parsedConfigs?.has(missingFilePath) + ? noopFileWatcher + : watchFilePath( + missingFilePath, + missingFilePath, + onMissingFileChange, + PollingInterval.Medium, + watchOptions, + WatchType.MissingFile, + ); } function onMissingFileChange(fileName: string, eventKind: FileWatcherEventKind, missingFilePath: Path) { @@ -949,7 +1180,12 @@ namespace ts { ); } - function updateExtendedConfigFilesWatches(forProjectPath: Path, options: CompilerOptions | undefined, watchOptions: WatchOptions | undefined, watchType: WatchTypeRegistry["ExtendedConfigFile"] | WatchTypeRegistry["ExtendedConfigOfReferencedProject"]) { + function updateExtendedConfigFilesWatches( + forProjectPath: Path, + options: CompilerOptions | undefined, + watchOptions: WatchOptions | undefined, + watchType: WatchTypeRegistry["ExtendedConfigFile"] | WatchTypeRegistry["ExtendedConfigOfReferencedProject"], + ) { updateSharedExtendedConfigFileWatcher( forProjectPath, options, @@ -960,7 +1196,13 @@ namespace ts { (_fileName, eventKind) => { updateCachedSystemWithFile(extendedConfigFileName, extendedConfigFilePath, eventKind); // Update extended config cache - if (extendedConfigCache) cleanExtendedConfigCache(extendedConfigCache, extendedConfigFilePath, toPath); + if (extendedConfigCache) { + cleanExtendedConfigCache( + extendedConfigCache, + extendedConfigFilePath, + toPath, + ); + } // Update projects const projects = sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)?.projects; // If there are no referenced projects this extended config file watcher depend on ignore @@ -1014,7 +1256,10 @@ namespace ts { const fileOrDirectoryPath = toPath(fileOrDirectory); // Since the file existence changed, update the sourceFiles cache if (cachedDirectoryStructureHost) { - cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); + cachedDirectoryStructureHost.addOrDeleteFileOrDirectory( + fileOrDirectory, + fileOrDirectoryPath, + ); } nextSourceFileVersion(fileOrDirectoryPath); diff --git a/src/compiler/watchUtilities.ts b/src/compiler/watchUtilities.ts index 1ff22d25cd202..076003cdf72ee 100644 --- a/src/compiler/watchUtilities.ts +++ b/src/compiler/watchUtilities.ts @@ -10,7 +10,13 @@ namespace ts { // TODO: GH#18217 Optional methods are frequently used as non-optional directoryExists?(path: string): boolean; getDirectories?(path: string): string[]; - readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory?( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; realpath?(path: string): string; createDirectory?(path: string): void; @@ -26,10 +32,19 @@ namespace ts { useCaseSensitiveFileNames: boolean; getDirectories(path: string): string[]; - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; /** Returns the queried result for the file exists and directory exists if at all it was done */ - addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path): FileAndDirectoryExistence | undefined; + addOrDeleteFileOrDirectory( + fileOrDirectory: string, + fileOrDirectoryPath: Path, + ): FileAndDirectoryExistence | undefined; addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind): void; clearCache(): void; } @@ -50,13 +65,19 @@ namespace ts { readonly sortedAndCanonicalizedDirectories: SortedArray; } - export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, currentDirectory: string, useCaseSensitiveFileNames: boolean): CachedDirectoryStructureHost | undefined { + export function createCachedDirectoryStructureHost( + host: DirectoryStructureHost, + currentDirectory: string, + useCaseSensitiveFileNames: boolean, + ): CachedDirectoryStructureHost | undefined { if (!host.getDirectories || !host.readDirectory) { return undefined; } const cachedReadDirectoryResult = new Map(); - const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames) as ((name: string) => Canonicalized); + const getCanonicalFileName = createGetCanonicalFileName( + useCaseSensitiveFileNames, + ) as ((name: string) => Canonicalized); return { useCaseSensitiveFileNames, fileExists, @@ -88,8 +109,11 @@ namespace ts { // If we're looking for the base directory, we're definitely going to search the entries if (!entries.sortedAndCanonicalizedFiles) { - entries.sortedAndCanonicalizedFiles = entries.files.map(getCanonicalFileName).sort() as SortedArray; - entries.sortedAndCanonicalizedDirectories = entries.directories.map(getCanonicalFileName).sort() as SortedArray; + entries.sortedAndCanonicalizedFiles = entries.files.map(getCanonicalFileName).sort() as SortedArray< + Canonicalized + >; + entries.sortedAndCanonicalizedDirectories = entries.directories.map(getCanonicalFileName) + .sort() as SortedArray; } return entries as SortedAndCanonicalizedMutableFileSystemEntries; } @@ -101,7 +125,12 @@ namespace ts { function createCachedFileSystemEntries(rootDir: string, rootDirPath: Path) { if (!host.realpath || ensureTrailingDirectorySeparator(toPath(host.realpath(rootDir))) === rootDirPath) { const resultFromHost: MutableFileSystemEntries = { - files: map(host.readDirectory!(rootDir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/ ["*.*"]), getBaseNameOfFileName) || [], + files: map( + host.readDirectory!(rootDir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/ [ + "*.*", + ]), + getBaseNameOfFileName, + ) || [], directories: host.getDirectories!(rootDir) || [], }; @@ -159,13 +188,18 @@ namespace ts { function fileExists(fileName: string): boolean { const path = toPath(fileName); const result = getCachedFileSystemEntriesForBaseDir(path); - return result && hasEntry(result.sortedAndCanonicalizedFiles, getCanonicalFileName(getBaseNameOfFileName(fileName))) || - host.fileExists(fileName); + return result + && hasEntry( + result.sortedAndCanonicalizedFiles, + getCanonicalFileName(getBaseNameOfFileName(fileName)), + ) + || host.fileExists(fileName); } function directoryExists(dirPath: string): boolean { const path = toPath(dirPath); - return cachedReadDirectoryResult.has(ensureTrailingDirectorySeparator(path)) || host.directoryExists!(dirPath); + return cachedReadDirectoryResult.has(ensureTrailingDirectorySeparator(path)) + || host.directoryExists!(dirPath); } function createDirectory(dirPath: string) { @@ -192,12 +226,28 @@ namespace ts { return host.getDirectories!(rootDir); } - function readDirectory(rootDir: string, extensions?: readonly string[], excludes?: readonly string[], includes?: readonly string[], depth?: number): string[] { + function readDirectory( + rootDir: string, + extensions?: readonly string[], + excludes?: readonly string[], + includes?: readonly string[], + depth?: number, + ): string[] { const rootDirPath = toPath(rootDir); const rootResult = tryReadDirectory(rootDir, rootDirPath); let rootSymLinkResult: FileSystemEntries | undefined; if (rootResult !== undefined) { - return matchFiles(rootDir, extensions, excludes, includes, useCaseSensitiveFileNames, currentDirectory, depth, getFileSystemEntries, realpath); + return matchFiles( + rootDir, + extensions, + excludes, + includes, + useCaseSensitiveFileNames, + currentDirectory, + depth, + getFileSystemEntries, + realpath, + ); } return host.readDirectory!(rootDir, extensions, excludes, includes, depth); @@ -207,15 +257,20 @@ namespace ts { return rootResult || getFileSystemEntriesFromHost(dir, path); } const result = tryReadDirectory(dir, path); - return result !== undefined ? - result || getFileSystemEntriesFromHost(dir, path) : - emptyFileSystemEntries; + return result !== undefined + ? result || getFileSystemEntriesFromHost(dir, path) + : emptyFileSystemEntries; } function getFileSystemEntriesFromHost(dir: string, path: Path): FileSystemEntries { if (rootSymLinkResult && path === rootDirPath) return rootSymLinkResult; const result: FileSystemEntries = { - files: map(host.readDirectory!(dir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/ ["*.*"]), getBaseNameOfFileName) || emptyArray, + files: map( + host.readDirectory!(dir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/ [ + "*.*", + ]), + getBaseNameOfFileName, + ) || emptyArray, directories: host.getDirectories!(dir) || emptyArray, }; if (path === rootDirPath) rootSymLinkResult = result; @@ -255,7 +310,10 @@ namespace ts { fileExists: host.fileExists(fileOrDirectoryPath), directoryExists: host.directoryExists(fileOrDirectoryPath), }; - if (fsQueryResult.directoryExists || hasEntry(parentResult.sortedAndCanonicalizedDirectories, getCanonicalFileName(baseName))) { + if ( + fsQueryResult.directoryExists + || hasEntry(parentResult.sortedAndCanonicalizedDirectories, getCanonicalFileName(baseName)) + ) { // Folder added or removed, clear the cache instead of updating the folder and its structure clearCache(); } @@ -273,11 +331,19 @@ namespace ts { const parentResult = getCachedFileSystemEntriesForBaseDir(filePath); if (parentResult) { - updateFilesOfFileSystemEntry(parentResult, getBaseNameOfFileName(fileName), eventKind === FileWatcherEventKind.Created); + updateFilesOfFileSystemEntry( + parentResult, + getBaseNameOfFileName(fileName), + eventKind === FileWatcherEventKind.Created, + ); } } - function updateFilesOfFileSystemEntry(parentResult: SortedAndCanonicalizedMutableFileSystemEntries, baseName: string, fileExists: boolean): void { + function updateFilesOfFileSystemEntry( + parentResult: SortedAndCanonicalizedMutableFileSystemEntries, + baseName: string, + fileExists: boolean, + ): void { const canonicalizedFiles = parentResult.sortedAndCanonicalizedFiles; const canonicalizedBaseName = getCanonicalFileName(baseName); if (fileExists) { @@ -288,10 +354,17 @@ namespace ts { } else { // Case-sensitive comparison since already canonicalized - const sortedIndex = binarySearch(canonicalizedFiles, canonicalizedBaseName, identity, compareStringsCaseSensitive); + const sortedIndex = binarySearch( + canonicalizedFiles, + canonicalizedBaseName, + identity, + compareStringsCaseSensitive, + ); if (sortedIndex >= 0) { canonicalizedFiles.splice(sortedIndex, 1); - const unsortedIndex = parentResult.files.findIndex(entry => getCanonicalFileName(entry) === canonicalizedBaseName); + const unsortedIndex = parentResult.files.findIndex(entry => + getCanonicalFileName(entry) === canonicalizedBaseName + ); parentResult.files.splice(unsortedIndex, 1); } } @@ -377,7 +450,11 @@ namespace ts { ) { if (!extendedConfigCache.delete(extendedConfigFilePath)) return; extendedConfigCache.forEach(({ extendedResult }, key) => { - if (extendedResult.extendedSourceFiles?.some(extendedFile => toPath(extendedFile) === extendedConfigFilePath)) { + if ( + extendedResult.extendedSourceFiles?.some(extendedFile => + toPath(extendedFile) === extendedConfigFilePath + ) + ) { cleanExtendedConfigCache(extendedConfigCache, key as Path, toPath); } }); @@ -456,7 +533,10 @@ namespace ts { }, ); - function createWildcardDirectoryWatcher(directory: string, flags: WatchDirectoryFlags): WildcardDirectoryWatcher { + function createWildcardDirectoryWatcher( + directory: string, + flags: WatchDirectoryFlags, + ): WildcardDirectoryWatcher { // Create new watch and recursive info return { watcher: watchDirectory(directory, flags), @@ -464,7 +544,11 @@ namespace ts { }; } - function updateWildcardDirectoryWatcher(existingWatcher: WildcardDirectoryWatcher, flags: WatchDirectoryFlags, directory: string) { + function updateWildcardDirectoryWatcher( + existingWatcher: WildcardDirectoryWatcher, + flags: WatchDirectoryFlags, + directory: string, + ) { // Watcher needs to be updated if the recursive flags dont match if (existingWatcher.flags === flags) { return; @@ -513,12 +597,25 @@ namespace ts { // If the the added or created file or directory is not supported file name, ignore the file // But when watched directory is added/removed, we need to reload the file list - if (hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, options, extraFileExtensions)) { - writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrDirectory}`); + if ( + hasExtension(fileOrDirectoryPath) + && !isSupportedSourceFileName(fileOrDirectory, options, extraFileExtensions) + ) { + writeLog( + `Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrDirectory}`, + ); return true; } - if (isExcludedFile(fileOrDirectory, options.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), useCaseSensitiveFileNames, currentDirectory)) { + if ( + isExcludedFile( + fileOrDirectory, + options.configFile!.configFileSpecs!, + getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), + useCaseSensitiveFileNames, + currentDirectory, + ) + ) { writeLog(`Project: ${configFileName} Detected excluded file: ${fileOrDirectory}`); return true; } @@ -540,11 +637,12 @@ namespace ts { // just check if sourceFile with the name exists const filePathWithoutExtension = removeFileExtension(fileOrDirectoryPath); - const realProgram = isArray(program) ? undefined : isBuilderProgram(program) ? program.getProgramOrUndefined() : program; + const realProgram = isArray(program) ? undefined + : isBuilderProgram(program) ? program.getProgramOrUndefined() : program; const builderProgram = !realProgram && !isArray(program) ? program as BuilderProgram : undefined; if ( - hasSourceFile((filePathWithoutExtension + Extension.Ts) as Path) || - hasSourceFile((filePathWithoutExtension + Extension.Tsx) as Path) + hasSourceFile((filePathWithoutExtension + Extension.Ts) as Path) + || hasSourceFile((filePathWithoutExtension + Extension.Tsx) as Path) ) { writeLog(`Project: ${configFileName} Detected output file: ${fileOrDirectory}`); return true; @@ -552,11 +650,11 @@ namespace ts { return false; function hasSourceFile(file: Path): boolean { - return realProgram ? - !!realProgram.getSourceFileByPath(file) : - builderProgram ? - builderProgram.getState().fileInfos.has(file) : - !!find(program as readonly string[], rootFile => toPath(rootFile) === file); + return realProgram + ? !!realProgram.getSourceFileByPath(file) + : builderProgram + ? builderProgram.getState().fileInfos.has(file) + : !!find(program as readonly string[], rootFile => toPath(rootFile) === file); } } @@ -579,39 +677,70 @@ namespace ts { } export interface WatchFactoryHost { - watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; - watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; + watchFile( + path: string, + callback: FileWatcherCallback, + pollingInterval?: number, + options?: WatchOptions, + ): FileWatcher; + watchDirectory( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher; getCurrentDirectory?(): string; useCaseSensitiveFileNames: boolean | (() => boolean); } export interface WatchFactory { - watchFile: (file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined, detailInfo1: X, detailInfo2?: Y) => FileWatcher; - watchDirectory: (directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags, options: WatchOptions | undefined, detailInfo1: X, detailInfo2?: Y) => FileWatcher; + watchFile: ( + file: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, + detailInfo1: X, + detailInfo2?: Y, + ) => FileWatcher; + watchDirectory: ( + directory: string, + callback: DirectoryWatcherCallback, + flags: WatchDirectoryFlags, + options: WatchOptions | undefined, + detailInfo1: X, + detailInfo2?: Y, + ) => FileWatcher; } export type GetDetailWatchInfo = (detailInfo1: X, detailInfo2: Y | undefined) => string; - export function getWatchFactory(host: WatchFactoryHost, watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo): WatchFactory { + export function getWatchFactory( + host: WatchFactoryHost, + watchLogLevel: WatchLogLevel, + log: (s: string) => void, + getDetailWatchInfo?: GetDetailWatchInfo, + ): WatchFactory { setSysLog(watchLogLevel === WatchLogLevel.Verbose ? log : noop); const plainInvokeFactory: WatchFactory = { - watchFile: (file, callback, pollingInterval, options) => host.watchFile(file, callback, pollingInterval, options), - watchDirectory: (directory, callback, flags, options) => host.watchDirectory(directory, callback, (flags & WatchDirectoryFlags.Recursive) !== 0, options), + watchFile: (file, callback, pollingInterval, options) => + host.watchFile(file, callback, pollingInterval, options), + watchDirectory: (directory, callback, flags, options) => + host.watchDirectory(directory, callback, (flags & WatchDirectoryFlags.Recursive) !== 0, options), }; - const triggerInvokingFactory: WatchFactory | undefined = watchLogLevel !== WatchLogLevel.None ? - { + const triggerInvokingFactory: WatchFactory | undefined = watchLogLevel !== WatchLogLevel.None + ? { watchFile: createTriggerLoggingAddWatch("watchFile"), watchDirectory: createTriggerLoggingAddWatch("watchDirectory"), - } : - undefined; - const factory = watchLogLevel === WatchLogLevel.Verbose ? - { + } + : undefined; + const factory = watchLogLevel === WatchLogLevel.Verbose + ? { watchFile: createFileWatcherWithLogging, watchDirectory: createDirectoryWatcherWithLogging, - } : - triggerInvokingFactory || plainInvokeFactory; - const excludeWatcherFactory = watchLogLevel === WatchLogLevel.Verbose ? - createExcludeWatcherWithLogging : - returnNoopFileWatcher; + } + : triggerInvokingFactory || plainInvokeFactory; + const excludeWatcherFactory = watchLogLevel === WatchLogLevel.Verbose + ? createExcludeWatcherWithLogging + : returnNoopFileWatcher; return { watchFile: createExcludeHandlingAddWatch("watchFile"), @@ -626,15 +755,20 @@ namespace ts { options: WatchOptions | undefined, detailInfo1: X, detailInfo2?: Y, - ) => !matchesExclude(file, key === "watchFile" ? options?.excludeFiles : options?.excludeDirectories, useCaseSensitiveFileNames(), host.getCurrentDirectory?.() || "") ? - factory[key].call(/*thisArgs*/ undefined, file, cb, flags, options, detailInfo1, detailInfo2) : - excludeWatcherFactory(file, flags, options, detailInfo1, detailInfo2); + ) => !matchesExclude( + file, + key === "watchFile" ? options?.excludeFiles : options?.excludeDirectories, + useCaseSensitiveFileNames(), + host.getCurrentDirectory?.() || "", + ) + ? factory[key].call(/*thisArgs*/ undefined, file, cb, flags, options, detailInfo1, detailInfo2) + : excludeWatcherFactory(file, flags, options, detailInfo1, detailInfo2); } function useCaseSensitiveFileNames() { - return typeof host.useCaseSensitiveFileNames === "boolean" ? - host.useCaseSensitiveFileNames : - host.useCaseSensitiveFileNames(); + return typeof host.useCaseSensitiveFileNames === "boolean" + ? host.useCaseSensitiveFileNames + : host.useCaseSensitiveFileNames(); } function createExcludeWatcherWithLogging( @@ -644,9 +778,14 @@ namespace ts { detailInfo1: X, detailInfo2?: Y, ) { - log(`ExcludeWatcher:: Added:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`); + log(`ExcludeWatcher:: Added:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`); return { - close: () => log(`ExcludeWatcher:: Close:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`), + close: () => + log(`ExcludeWatcher:: Close:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`), }; } @@ -658,11 +797,15 @@ namespace ts { detailInfo1: X, detailInfo2?: Y, ): FileWatcher { - log(`FileWatcher:: Added:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`); + log(`FileWatcher:: Added:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`); const watcher = triggerInvokingFactory!.watchFile(file, cb, flags, options, detailInfo1, detailInfo2); return { close: () => { - log(`FileWatcher:: Close:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`); + log(`FileWatcher:: Close:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`); watcher.close(); }, }; @@ -676,7 +819,9 @@ namespace ts { detailInfo1: X, detailInfo2?: Y, ): FileWatcher { - const watchInfo = `DirectoryWatcher:: Added:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`; + const watchInfo = `DirectoryWatcher:: Added:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`; log(watchInfo); const start = timestamp(); const watcher = triggerInvokingFactory!.watchDirectory(file, cb, flags, options, detailInfo1, detailInfo2); @@ -684,7 +829,9 @@ namespace ts { log(`Elapsed:: ${elapsed}ms ${watchInfo}`); return { close: () => { - const watchInfo = `DirectoryWatcher:: Close:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`; + const watchInfo = `DirectoryWatcher:: Close:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`; log(watchInfo); const start = timestamp(); watcher.close(); @@ -706,7 +853,11 @@ namespace ts { /*thisArgs*/ undefined, file, (...args: any[]) => { - const triggerredInfo = `${key === "watchFile" ? "FileWatcher" : "DirectoryWatcher"}:: Triggered with ${args[0]} ${args[1] !== undefined ? args[1] : ""}:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`; + const triggerredInfo = `${ + key === "watchFile" ? "FileWatcher" : "DirectoryWatcher" + }:: Triggered with ${args[0]} ${args[1] !== undefined ? args[1] : ""}:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`; log(triggerredInfo); const start = timestamp(); cb.call(/*thisArg*/ undefined, ...args); @@ -720,17 +871,27 @@ namespace ts { ); } - function getWatchInfo(file: string, flags: T, options: WatchOptions | undefined, detailInfo1: X, detailInfo2: Y | undefined, getDetailWatchInfo: GetDetailWatchInfo | undefined) { - return `WatchInfo: ${file} ${flags} ${JSON.stringify(options)} ${getDetailWatchInfo ? getDetailWatchInfo(detailInfo1, detailInfo2) : detailInfo2 === undefined ? detailInfo1 : `${detailInfo1} ${detailInfo2}`}`; + function getWatchInfo( + file: string, + flags: T, + options: WatchOptions | undefined, + detailInfo1: X, + detailInfo2: Y | undefined, + getDetailWatchInfo: GetDetailWatchInfo | undefined, + ) { + return `WatchInfo: ${file} ${flags} ${JSON.stringify(options)} ${ + getDetailWatchInfo ? getDetailWatchInfo(detailInfo1, detailInfo2) + : detailInfo2 === undefined ? detailInfo1 : `${detailInfo1} ${detailInfo2}` + }`; } } export function getFallbackOptions(options: WatchOptions | undefined): WatchOptions { const fallbackPolling = options?.fallbackPolling; return { - watchFile: fallbackPolling !== undefined ? - fallbackPolling as unknown as WatchFileKind : - WatchFileKind.PriorityPollingInterval, + watchFile: fallbackPolling !== undefined + ? fallbackPolling as unknown as WatchFileKind + : WatchFileKind.PriorityPollingInterval, }; } diff --git a/src/debug/dbg.ts b/src/debug/dbg.ts index 59f0ef7242d7e..41955cc1ccfed 100644 --- a/src/debug/dbg.ts +++ b/src/debug/dbg.ts @@ -193,18 +193,18 @@ namespace Debug { target: FlowGraphNode; } - const hasAntecedentFlags = FlowFlags.Assignment | - FlowFlags.Condition | - FlowFlags.SwitchClause | - FlowFlags.ArrayMutation | - FlowFlags.Call | - FlowFlags.ReduceLabel; - - const hasNodeFlags = FlowFlags.Start | - FlowFlags.Assignment | - FlowFlags.Call | - FlowFlags.Condition | - FlowFlags.ArrayMutation; + const hasAntecedentFlags = FlowFlags.Assignment + | FlowFlags.Condition + | FlowFlags.SwitchClause + | FlowFlags.ArrayMutation + | FlowFlags.Call + | FlowFlags.ReduceLabel; + + const hasNodeFlags = FlowFlags.Start + | FlowFlags.Assignment + | FlowFlags.Call + | FlowFlags.Condition + | FlowFlags.ArrayMutation; const links: Record = Object.create(/*o*/ null); // eslint-disable-line no-null/no-null const nodes: FlowGraphNode[] = []; @@ -276,7 +276,16 @@ namespace Debug { } seen.add(flowNode); if (!graphNode) { - links[id] = graphNode = { id, flowNode, edges: [], text: "", lane: -1, endLane: -1, level: -1, circular: false }; + links[id] = graphNode = { + id, + flowNode, + edges: [], + text: "", + lane: -1, + endLane: -1, + level: -1, + circular: false, + }; nodes.push(graphNode); if (hasAntecedents(flowNode)) { for (const antecedent of flowNode.antecedents) { @@ -453,7 +462,11 @@ namespace Debug { } } writeLane(lane, getBoxCharacter(connector)); - writeLane(lane, connector & Connection.Right && column < columnCount - 1 && !grid[column + 1][lane] ? BoxCharacter.lr : " "); + writeLane( + lane, + connector & Connection.Right && column < columnCount - 1 && !grid[column + 1][lane] + ? BoxCharacter.lr : " ", + ); } } diff --git a/src/deprecatedCompat/4.0/nodeFactoryTopLevelExports.ts b/src/deprecatedCompat/4.0/nodeFactoryTopLevelExports.ts index 9b27c1188aa27..dfed050cdc520 100644 --- a/src/deprecatedCompat/4.0/nodeFactoryTopLevelExports.ts +++ b/src/deprecatedCompat/4.0/nodeFactoryTopLevelExports.ts @@ -5,7 +5,12 @@ // - error: 5.0 namespace ts { // NOTE: These exports are deprecated in favor of using a `NodeFactory` instance and exist here purely for backwards compatibility reasons. - const factoryDeprecation: DeprecationOptions = { since: "4.0", warnAfter: "4.1", message: "Use the appropriate method on 'ts.factory' or the 'factory' supplied by your transformation context instead." }; + const factoryDeprecation: DeprecationOptions = { + since: "4.0", + warnAfter: "4.1", + message: + "Use the appropriate method on 'ts.factory' or the 'factory' supplied by your transformation context instead.", + }; /** @deprecated Use `factory.createNodeArray` or the factory supplied by your transformation context instead. */ export const createNodeArray = Debug.deprecate(factory.createNodeArray, factoryDeprecation); @@ -23,13 +28,17 @@ namespace ts { export const createStringLiteralFromNode = Debug.deprecate(factory.createStringLiteralFromNode, factoryDeprecation); /** @deprecated Use `factory.createRegularExpressionLiteral` or the factory supplied by your transformation context instead. */ - export const createRegularExpressionLiteral = Debug.deprecate(factory.createRegularExpressionLiteral, factoryDeprecation); + export const createRegularExpressionLiteral = Debug.deprecate( + factory.createRegularExpressionLiteral, + factoryDeprecation, + ); /** @deprecated Use `factory.createLoopVariable` or the factory supplied by your transformation context instead. */ export const createLoopVariable = Debug.deprecate(factory.createLoopVariable, factoryDeprecation); /** @deprecated Use `factory.createUniqueName` or the factory supplied by your transformation context instead. */ - export const createUniqueName: (text: string, flags?: GeneratedIdentifierFlags | undefined) => Identifier = Debug.deprecate(factory.createUniqueName, factoryDeprecation); + export const createUniqueName: (text: string, flags?: GeneratedIdentifierFlags | undefined) => Identifier = Debug + .deprecate(factory.createUniqueName, factoryDeprecation); /** @deprecated Use `factory.createPrivateIdentifier` or the factory supplied by your transformation context instead. */ export const createPrivateIdentifier = Debug.deprecate(factory.createPrivateIdentifier, factoryDeprecation); @@ -53,7 +62,10 @@ namespace ts { export const createModifier = Debug.deprecate(factory.createModifier, factoryDeprecation); /** @deprecated Use `factory.createModifiersFromModifierFlags` or the factory supplied by your transformation context instead. */ - export const createModifiersFromModifierFlags = Debug.deprecate(factory.createModifiersFromModifierFlags, factoryDeprecation); + export const createModifiersFromModifierFlags = Debug.deprecate( + factory.createModifiersFromModifierFlags, + factoryDeprecation, + ); /** @deprecated Use `factory.createQualifiedName` or the factory supplied by your transformation context instead. */ export const createQualifiedName = Debug.deprecate(factory.createQualifiedName, factoryDeprecation); @@ -68,10 +80,16 @@ namespace ts { export const updateComputedPropertyName = Debug.deprecate(factory.updateComputedPropertyName, factoryDeprecation); /** @deprecated Use `factory.createTypeParameterDeclaration` or the factory supplied by your transformation context instead. */ - export const createTypeParameterDeclaration = Debug.deprecate(factory.createTypeParameterDeclaration, factoryDeprecation); + export const createTypeParameterDeclaration = Debug.deprecate( + factory.createTypeParameterDeclaration, + factoryDeprecation, + ); /** @deprecated Use `factory.updateTypeParameterDeclaration` or the factory supplied by your transformation context instead. */ - export const updateTypeParameterDeclaration = Debug.deprecate(factory.updateTypeParameterDeclaration, factoryDeprecation); + export const updateTypeParameterDeclaration = Debug.deprecate( + factory.updateTypeParameterDeclaration, + factoryDeprecation, + ); /** @deprecated Use `factory.createParameterDeclaration` or the factory supplied by your transformation context instead. */ export const createParameter = Debug.deprecate(factory.createParameterDeclaration, factoryDeprecation); @@ -134,10 +152,16 @@ namespace ts { export const createKeywordTypeNode = Debug.deprecate(factory.createKeywordTypeNode, factoryDeprecation); /** @deprecated Use `factory.createTypePredicateNode` or the factory supplied by your transformation context instead. */ - export const createTypePredicateNodeWithModifier = Debug.deprecate(factory.createTypePredicateNode, factoryDeprecation); + export const createTypePredicateNodeWithModifier = Debug.deprecate( + factory.createTypePredicateNode, + factoryDeprecation, + ); /** @deprecated Use `factory.updateTypePredicateNode` or the factory supplied by your transformation context instead. */ - export const updateTypePredicateNodeWithModifier = Debug.deprecate(factory.updateTypePredicateNode, factoryDeprecation); + export const updateTypePredicateNodeWithModifier = Debug.deprecate( + factory.updateTypePredicateNode, + factoryDeprecation, + ); /** @deprecated Use `factory.createTypeReferenceNode` or the factory supplied by your transformation context instead. */ export const createTypeReferenceNode = Debug.deprecate(factory.createTypeReferenceNode, factoryDeprecation); @@ -414,7 +438,10 @@ namespace ts { export const createTemplateTail = Debug.deprecate(factory.createTemplateTail, factoryDeprecation); /** @deprecated Use `factory.createNoSubstitutionTemplateLiteral` or the factory supplied by your transformation context instead. */ - export const createNoSubstitutionTemplateLiteral = Debug.deprecate(factory.createNoSubstitutionTemplateLiteral, factoryDeprecation); + export const createNoSubstitutionTemplateLiteral = Debug.deprecate( + factory.createNoSubstitutionTemplateLiteral, + factoryDeprecation, + ); /** @deprecated Use `factory.updateYieldExpression` or the factory supplied by your transformation context instead. */ export const updateYield = Debug.deprecate(factory.updateYieldExpression, factoryDeprecation); @@ -576,10 +603,16 @@ namespace ts { export const createDebuggerStatement = Debug.deprecate(factory.createDebuggerStatement, factoryDeprecation); /** @deprecated Use `factory.createVariableDeclarationList` or the factory supplied by your transformation context instead. */ - export const createVariableDeclarationList = Debug.deprecate(factory.createVariableDeclarationList, factoryDeprecation); + export const createVariableDeclarationList = Debug.deprecate( + factory.createVariableDeclarationList, + factoryDeprecation, + ); /** @deprecated Use `factory.updateVariableDeclarationList` or the factory supplied by your transformation context instead. */ - export const updateVariableDeclarationList = Debug.deprecate(factory.updateVariableDeclarationList, factoryDeprecation); + export const updateVariableDeclarationList = Debug.deprecate( + factory.updateVariableDeclarationList, + factoryDeprecation, + ); /** @deprecated Use `factory.createFunctionDeclaration` or the factory supplied by your transformation context instead. */ export const createFunctionDeclaration = Debug.deprecate(factory.createFunctionDeclaration, factoryDeprecation); @@ -630,16 +663,28 @@ namespace ts { export const updateCaseBlock = Debug.deprecate(factory.updateCaseBlock, factoryDeprecation); /** @deprecated Use `factory.createNamespaceExportDeclaration` or the factory supplied by your transformation context instead. */ - export const createNamespaceExportDeclaration = Debug.deprecate(factory.createNamespaceExportDeclaration, factoryDeprecation); + export const createNamespaceExportDeclaration = Debug.deprecate( + factory.createNamespaceExportDeclaration, + factoryDeprecation, + ); /** @deprecated Use `factory.updateNamespaceExportDeclaration` or the factory supplied by your transformation context instead. */ - export const updateNamespaceExportDeclaration = Debug.deprecate(factory.updateNamespaceExportDeclaration, factoryDeprecation); + export const updateNamespaceExportDeclaration = Debug.deprecate( + factory.updateNamespaceExportDeclaration, + factoryDeprecation, + ); /** @deprecated Use `factory.createImportEqualsDeclaration` or the factory supplied by your transformation context instead. */ - export const createImportEqualsDeclaration = Debug.deprecate(factory.createImportEqualsDeclaration, factoryDeprecation); + export const createImportEqualsDeclaration = Debug.deprecate( + factory.createImportEqualsDeclaration, + factoryDeprecation, + ); /** @deprecated Use `factory.updateImportEqualsDeclaration` or the factory supplied by your transformation context instead. */ - export const updateImportEqualsDeclaration = Debug.deprecate(factory.updateImportEqualsDeclaration, factoryDeprecation); + export const updateImportEqualsDeclaration = Debug.deprecate( + factory.updateImportEqualsDeclaration, + factoryDeprecation, + ); /** @deprecated Use `factory.createImportDeclaration` or the factory supplied by your transformation context instead. */ export const createImportDeclaration = Debug.deprecate(factory.createImportDeclaration, factoryDeprecation); @@ -684,10 +729,16 @@ namespace ts { export const updateExportSpecifier = Debug.deprecate(factory.updateExportSpecifier, factoryDeprecation); /** @deprecated Use `factory.createExternalModuleReference` or the factory supplied by your transformation context instead. */ - export const createExternalModuleReference = Debug.deprecate(factory.createExternalModuleReference, factoryDeprecation); + export const createExternalModuleReference = Debug.deprecate( + factory.createExternalModuleReference, + factoryDeprecation, + ); /** @deprecated Use `factory.updateExternalModuleReference` or the factory supplied by your transformation context instead. */ - export const updateExternalModuleReference = Debug.deprecate(factory.updateExternalModuleReference, factoryDeprecation); + export const updateExternalModuleReference = Debug.deprecate( + factory.updateExternalModuleReference, + factoryDeprecation, + ); /** @deprecated Use `factory.createJSDocTypeExpression` or the factory supplied by your transformation context instead. */ export const createJSDocTypeExpression = Debug.deprecate(factory.createJSDocTypeExpression, factoryDeprecation); @@ -852,10 +903,16 @@ namespace ts { export const updatePropertyAssignment = Debug.deprecate(factory.updatePropertyAssignment, factoryDeprecation); /** @deprecated Use `factory.createShorthandPropertyAssignment` or the factory supplied by your transformation context instead. */ - export const createShorthandPropertyAssignment = Debug.deprecate(factory.createShorthandPropertyAssignment, factoryDeprecation); + export const createShorthandPropertyAssignment = Debug.deprecate( + factory.createShorthandPropertyAssignment, + factoryDeprecation, + ); /** @deprecated Use `factory.updateShorthandPropertyAssignment` or the factory supplied by your transformation context instead. */ - export const updateShorthandPropertyAssignment = Debug.deprecate(factory.updateShorthandPropertyAssignment, factoryDeprecation); + export const updateShorthandPropertyAssignment = Debug.deprecate( + factory.updateShorthandPropertyAssignment, + factoryDeprecation, + ); /** @deprecated Use `factory.createSpreadAssignment` or the factory supplied by your transformation context instead. */ export const createSpreadAssignment = Debug.deprecate(factory.createSpreadAssignment, factoryDeprecation); @@ -876,10 +933,16 @@ namespace ts { export const createNotEmittedStatement = Debug.deprecate(factory.createNotEmittedStatement, factoryDeprecation); /** @deprecated Use `factory.createPartiallyEmittedExpression` or the factory supplied by your transformation context instead. */ - export const createPartiallyEmittedExpression = Debug.deprecate(factory.createPartiallyEmittedExpression, factoryDeprecation); + export const createPartiallyEmittedExpression = Debug.deprecate( + factory.createPartiallyEmittedExpression, + factoryDeprecation, + ); /** @deprecated Use `factory.updatePartiallyEmittedExpression` or the factory supplied by your transformation context instead. */ - export const updatePartiallyEmittedExpression = Debug.deprecate(factory.updatePartiallyEmittedExpression, factoryDeprecation); + export const updatePartiallyEmittedExpression = Debug.deprecate( + factory.updatePartiallyEmittedExpression, + factoryDeprecation, + ); /** @deprecated Use `factory.createCommaListExpression` or the factory supplied by your transformation context instead. */ export const createCommaList = Debug.deprecate(factory.createCommaListExpression, factoryDeprecation); @@ -894,10 +957,16 @@ namespace ts { export const updateBundle = Debug.deprecate(factory.updateBundle, factoryDeprecation); /** @deprecated Use `factory.createImmediatelyInvokedFunctionExpression` or the factory supplied by your transformation context instead. */ - export const createImmediatelyInvokedFunctionExpression = Debug.deprecate(factory.createImmediatelyInvokedFunctionExpression, factoryDeprecation); + export const createImmediatelyInvokedFunctionExpression = Debug.deprecate( + factory.createImmediatelyInvokedFunctionExpression, + factoryDeprecation, + ); /** @deprecated Use `factory.createImmediatelyInvokedArrowFunction` or the factory supplied by your transformation context instead. */ - export const createImmediatelyInvokedArrowFunction = Debug.deprecate(factory.createImmediatelyInvokedArrowFunction, factoryDeprecation); + export const createImmediatelyInvokedArrowFunction = Debug.deprecate( + factory.createImmediatelyInvokedArrowFunction, + factoryDeprecation, + ); /** @deprecated Use `factory.createVoidZero` or the factory supplied by your transformation context instead. */ export const createVoidZero = Debug.deprecate(factory.createVoidZero, factoryDeprecation); @@ -915,9 +984,12 @@ namespace ts { export const updateNamespaceExport = Debug.deprecate(factory.updateNamespaceExport, factoryDeprecation); /** @deprecated Use `factory.createToken` or the factory supplied by your transformation context instead. */ - export const createToken = Debug.deprecate(function createToken(kind: TKind): Token { - return factory.createToken(kind); - }, factoryDeprecation); + export const createToken = Debug.deprecate( + function createToken(kind: TKind): Token { + return factory.createToken(kind); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createIdentifier` or the factory supplied by your transformation context instead. */ export const createIdentifier = Debug.deprecate(function createIdentifier(text: string) { @@ -925,62 +997,118 @@ namespace ts { }, factoryDeprecation); /** @deprecated Use `factory.createTempVariable` or the factory supplied by your transformation context instead. */ - export const createTempVariable = Debug.deprecate(function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined): Identifier { - return factory.createTempVariable(recordTempVariable, /*reserveInNestedScopes*/ undefined); - }, factoryDeprecation); + export const createTempVariable = Debug.deprecate( + function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined): Identifier { + return factory.createTempVariable(recordTempVariable, /*reserveInNestedScopes*/ undefined); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.getGeneratedNameForNode` or the factory supplied by your transformation context instead. */ - export const getGeneratedNameForNode = Debug.deprecate(function getGeneratedNameForNode(node: Node | undefined): Identifier { - return factory.getGeneratedNameForNode(node, /*flags*/ undefined); - }, factoryDeprecation); + export const getGeneratedNameForNode = Debug.deprecate( + function getGeneratedNameForNode(node: Node | undefined): Identifier { + return factory.getGeneratedNameForNode(node, /*flags*/ undefined); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createUniqueName(text, GeneratedIdentifierFlags.Optimistic)` or the factory supplied by your transformation context instead. */ - export const createOptimisticUniqueName = Debug.deprecate(function createOptimisticUniqueName(text: string): Identifier { - return factory.createUniqueName(text, GeneratedIdentifierFlags.Optimistic); - }, factoryDeprecation); + export const createOptimisticUniqueName = Debug.deprecate( + function createOptimisticUniqueName(text: string): Identifier { + return factory.createUniqueName(text, GeneratedIdentifierFlags.Optimistic); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createUniqueName(text, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)` or the factory supplied by your transformation context instead. */ - export const createFileLevelUniqueName = Debug.deprecate(function createFileLevelUniqueName(text: string): Identifier { - return factory.createUniqueName(text, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); - }, factoryDeprecation); + export const createFileLevelUniqueName = Debug.deprecate( + function createFileLevelUniqueName(text: string): Identifier { + return factory.createUniqueName( + text, + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createIndexSignature` or the factory supplied by your transformation context instead. */ - export const createIndexSignature = Debug.deprecate(function createIndexSignature(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration { - return factory.createIndexSignature(decorators, modifiers, parameters, type); - }, factoryDeprecation); + export const createIndexSignature = Debug.deprecate( + function createIndexSignature( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): IndexSignatureDeclaration { + return factory.createIndexSignature(decorators, modifiers, parameters, type); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createTypePredicateNode` or the factory supplied by your transformation context instead. */ - export const createTypePredicateNode = Debug.deprecate(function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode): TypePredicateNode { - return factory.createTypePredicateNode(/*assertsModifier*/ undefined, parameterName, type); - }, factoryDeprecation); + export const createTypePredicateNode = Debug.deprecate( + function createTypePredicateNode( + parameterName: Identifier | ThisTypeNode | string, + type: TypeNode, + ): TypePredicateNode { + return factory.createTypePredicateNode(/*assertsModifier*/ undefined, parameterName, type); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.updateTypePredicateNode` or the factory supplied by your transformation context instead. */ - export const updateTypePredicateNode = Debug.deprecate(function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode): TypePredicateNode { - return factory.updateTypePredicateNode(node, /*assertsModifier*/ undefined, parameterName, type); - }, factoryDeprecation); + export const updateTypePredicateNode = Debug.deprecate( + function updateTypePredicateNode( + node: TypePredicateNode, + parameterName: Identifier | ThisTypeNode, + type: TypeNode, + ): TypePredicateNode { + return factory.updateTypePredicateNode(node, /*assertsModifier*/ undefined, parameterName, type); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createStringLiteral`, `factory.createStringLiteralFromNode`, `factory.createNumericLiteral`, `factory.createBigIntLiteral`, `factory.createTrue`, `factory.createFalse`, or the factory supplied by your transformation context instead. */ - export const createLiteral = Debug.deprecate(function createLiteral(value: string | number | PseudoBigInt | boolean | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier): PrimaryExpression { - if (typeof value === "number") { - return factory.createNumericLiteral(value); - } - // eslint-disable-next-line local/no-in-operator - if (typeof value === "object" && "base10Value" in value) { // PseudoBigInt - return factory.createBigIntLiteral(value); - } - if (typeof value === "boolean") { - return value ? factory.createTrue() : factory.createFalse(); - } - if (typeof value === "string") { - return factory.createStringLiteral(value, /*isSingleQuote*/ undefined); - } - return factory.createStringLiteralFromNode(value); - } as { - (value: string | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier): StringLiteral; - (value: number | PseudoBigInt): NumericLiteral; - (value: boolean): BooleanLiteral; - (value: string | number | PseudoBigInt | boolean): PrimaryExpression; - }, { since: "4.0", warnAfter: "4.1", message: "Use `factory.createStringLiteral`, `factory.createStringLiteralFromNode`, `factory.createNumericLiteral`, `factory.createBigIntLiteral`, `factory.createTrue`, `factory.createFalse`, or the factory supplied by your transformation context instead." }); + export const createLiteral = Debug.deprecate( + function createLiteral( + value: + | string + | number + | PseudoBigInt + | boolean + | StringLiteral + | NoSubstitutionTemplateLiteral + | NumericLiteral + | Identifier, + ): PrimaryExpression { + if (typeof value === "number") { + return factory.createNumericLiteral(value); + } + // eslint-disable-next-line local/no-in-operator + if (typeof value === "object" && "base10Value" in value) { // PseudoBigInt + return factory.createBigIntLiteral(value); + } + if (typeof value === "boolean") { + return value ? factory.createTrue() : factory.createFalse(); + } + if (typeof value === "string") { + return factory.createStringLiteral(value, /*isSingleQuote*/ undefined); + } + return factory.createStringLiteralFromNode(value); + } as { + ( + value: string | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier, + ): StringLiteral; + (value: number | PseudoBigInt): NumericLiteral; + (value: boolean): BooleanLiteral; + (value: string | number | PseudoBigInt | boolean): PrimaryExpression; + }, + { + since: "4.0", + warnAfter: "4.1", + message: + "Use `factory.createStringLiteral`, `factory.createStringLiteralFromNode`, `factory.createNumericLiteral`, `factory.createBigIntLiteral`, `factory.createTrue`, `factory.createFalse`, or the factory supplied by your transformation context instead.", + }, + ); /** @deprecated Use `factory.createMethodSignature` or the factory supplied by your transformation context instead. */ export const createMethodSignature = Debug.deprecate(function createMethodSignature( @@ -990,7 +1118,14 @@ namespace ts { name: string | PropertyName, questionToken: QuestionToken | undefined, ) { - return factory.createMethodSignature(/*modifiers*/ undefined, name, questionToken, typeParameters, parameters, type); + return factory.createMethodSignature( + /*modifiers*/ undefined, + name, + questionToken, + typeParameters, + parameters, + type, + ); }, factoryDeprecation); /** @deprecated Use `factory.updateMethodSignature` or the factory supplied by your transformation context instead. */ @@ -1002,87 +1137,171 @@ namespace ts { name: PropertyName, questionToken: QuestionToken | undefined, ) { - return factory.updateMethodSignature(node, node.modifiers, name, questionToken, typeParameters, parameters, type); + return factory.updateMethodSignature( + node, + node.modifiers, + name, + questionToken, + typeParameters, + parameters, + type, + ); }, factoryDeprecation); /** @deprecated Use `factory.createTypeOperatorNode` or the factory supplied by your transformation context instead. */ - export const createTypeOperatorNode = Debug.deprecate(function createTypeOperatorNode(operatorOrType: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | TypeNode, type?: TypeNode) { - let operator: TypeOperatorNode["operator"]; - if (type) { - operator = operatorOrType as TypeOperatorNode["operator"]; - } - else { - type = operatorOrType as TypeNode; - operator = SyntaxKind.KeyOfKeyword; - } - return factory.createTypeOperatorNode(operator, type); - } as { - (type: TypeNode): TypeOperatorNode; - (operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode; - }, factoryDeprecation); + export const createTypeOperatorNode = Debug.deprecate( + function createTypeOperatorNode( + operatorOrType: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | TypeNode, + type?: TypeNode, + ) { + let operator: TypeOperatorNode["operator"]; + if (type) { + operator = operatorOrType as TypeOperatorNode["operator"]; + } + else { + type = operatorOrType as TypeNode; + operator = SyntaxKind.KeyOfKeyword; + } + return factory.createTypeOperatorNode(operator, type); + } as { + (type: TypeNode): TypeOperatorNode; + ( + operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, + type: TypeNode, + ): TypeOperatorNode; + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createTaggedTemplate` or the factory supplied by your transformation context instead. */ - export const createTaggedTemplate = Debug.deprecate(function createTaggedTemplate(tag: Expression, typeArgumentsOrTemplate: readonly TypeNode[] | TemplateLiteral | undefined, template?: TemplateLiteral) { - let typeArguments: readonly TypeNode[] | undefined; - if (template) { - typeArguments = typeArgumentsOrTemplate as readonly TypeNode[] | undefined; - } - else { - template = typeArgumentsOrTemplate as TemplateLiteral; - } - return factory.createTaggedTemplateExpression(tag, typeArguments, template); - } as { - (tag: Expression, template: TemplateLiteral): TaggedTemplateExpression; - (tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression; - }, factoryDeprecation); + export const createTaggedTemplate = Debug.deprecate( + function createTaggedTemplate( + tag: Expression, + typeArgumentsOrTemplate: readonly TypeNode[] | TemplateLiteral | undefined, + template?: TemplateLiteral, + ) { + let typeArguments: readonly TypeNode[] | undefined; + if (template) { + typeArguments = typeArgumentsOrTemplate as readonly TypeNode[] | undefined; + } + else { + template = typeArgumentsOrTemplate as TemplateLiteral; + } + return factory.createTaggedTemplateExpression(tag, typeArguments, template); + } as { + (tag: Expression, template: TemplateLiteral): TaggedTemplateExpression; + ( + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ): TaggedTemplateExpression; + }, + factoryDeprecation, + ); /** @deprecated Use `factory.updateTaggedTemplate` or the factory supplied by your transformation context instead. */ - export const updateTaggedTemplate = Debug.deprecate(function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, typeArgumentsOrTemplate: readonly TypeNode[] | TemplateLiteral | undefined, template?: TemplateLiteral) { - let typeArguments: readonly TypeNode[] | undefined; - if (template) { - typeArguments = typeArgumentsOrTemplate as readonly TypeNode[] | undefined; - } - else { - template = typeArgumentsOrTemplate as TemplateLiteral; - } - return factory.updateTaggedTemplateExpression(node, tag, typeArguments, template); - } as { - (node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral): TaggedTemplateExpression; - (node: TaggedTemplateExpression, tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression; - }, factoryDeprecation); + export const updateTaggedTemplate = Debug.deprecate( + function updateTaggedTemplate( + node: TaggedTemplateExpression, + tag: Expression, + typeArgumentsOrTemplate: readonly TypeNode[] | TemplateLiteral | undefined, + template?: TemplateLiteral, + ) { + let typeArguments: readonly TypeNode[] | undefined; + if (template) { + typeArguments = typeArgumentsOrTemplate as readonly TypeNode[] | undefined; + } + else { + template = typeArgumentsOrTemplate as TemplateLiteral; + } + return factory.updateTaggedTemplateExpression(node, tag, typeArguments, template); + } as { + (node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral): TaggedTemplateExpression; + ( + node: TaggedTemplateExpression, + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ): TaggedTemplateExpression; + }, + factoryDeprecation, + ); /** @deprecated Use `factory.updateBinary` or the factory supplied by your transformation context instead. */ - export const updateBinary = Debug.deprecate(function updateBinary(node: BinaryExpression, left: Expression, right: Expression, operator: BinaryOperator | BinaryOperatorToken = node.operatorToken) { - if (typeof operator === "number") { - operator = operator === node.operatorToken.kind ? node.operatorToken : factory.createToken(operator); - } - return factory.updateBinaryExpression(node, left, operator, right); - }, factoryDeprecation); + export const updateBinary = Debug.deprecate( + function updateBinary( + node: BinaryExpression, + left: Expression, + right: Expression, + operator: BinaryOperator | BinaryOperatorToken = node.operatorToken, + ) { + if (typeof operator === "number") { + operator = operator === node.operatorToken.kind ? node.operatorToken : factory.createToken(operator); + } + return factory.updateBinaryExpression(node, left, operator, right); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createConditional` or the factory supplied by your transformation context instead. */ - export const createConditional = Debug.deprecate(function createConditional(condition: Expression, questionTokenOrWhenTrue: QuestionToken | Expression, whenTrueOrWhenFalse: Expression, colonToken?: ColonToken, whenFalse?: Expression) { - return arguments.length === 5 ? factory.createConditionalExpression(condition, questionTokenOrWhenTrue as QuestionToken, whenTrueOrWhenFalse, colonToken, whenFalse!) : - arguments.length === 3 ? factory.createConditionalExpression(condition, factory.createToken(SyntaxKind.QuestionToken), questionTokenOrWhenTrue as Expression, factory.createToken(SyntaxKind.ColonToken), whenTrueOrWhenFalse) : - Debug.fail("Argument count mismatch"); - } as { - (condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression; - (condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; - }, factoryDeprecation); + export const createConditional = Debug.deprecate( + function createConditional( + condition: Expression, + questionTokenOrWhenTrue: QuestionToken | Expression, + whenTrueOrWhenFalse: Expression, + colonToken?: ColonToken, + whenFalse?: Expression, + ) { + return arguments.length === 5 + ? factory.createConditionalExpression( + condition, + questionTokenOrWhenTrue as QuestionToken, + whenTrueOrWhenFalse, + colonToken, + whenFalse!, + ) + : arguments.length === 3 + ? factory.createConditionalExpression( + condition, + factory.createToken(SyntaxKind.QuestionToken), + questionTokenOrWhenTrue as Expression, + factory.createToken(SyntaxKind.ColonToken), + whenTrueOrWhenFalse, + ) + : Debug.fail("Argument count mismatch"); + } as { + (condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression; + ( + condition: Expression, + questionToken: QuestionToken, + whenTrue: Expression, + colonToken: ColonToken, + whenFalse: Expression, + ): ConditionalExpression; + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createYield` or the factory supplied by your transformation context instead. */ - export const createYield = Debug.deprecate(function createYield(asteriskTokenOrExpression?: AsteriskToken | Expression | undefined, expression?: Expression) { - let asteriskToken: AsteriskToken | undefined; - if (expression) { - asteriskToken = asteriskTokenOrExpression as AsteriskToken; - } - else { - expression = asteriskTokenOrExpression as Expression; - } - return factory.createYieldExpression(asteriskToken, expression); - } as { - (expression?: Expression | undefined): YieldExpression; - (asteriskToken: AsteriskToken | undefined, expression: Expression): YieldExpression; - }, factoryDeprecation); + export const createYield = Debug.deprecate( + function createYield( + asteriskTokenOrExpression?: AsteriskToken | Expression | undefined, + expression?: Expression, + ) { + let asteriskToken: AsteriskToken | undefined; + if (expression) { + asteriskToken = asteriskTokenOrExpression as AsteriskToken; + } + else { + expression = asteriskTokenOrExpression as Expression; + } + return factory.createYieldExpression(asteriskToken, expression); + } as { + (expression?: Expression | undefined): YieldExpression; + (asteriskToken: AsteriskToken | undefined, expression: Expression): YieldExpression; + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createClassExpression` or the factory supplied by your transformation context instead. */ export const createClassExpression = Debug.deprecate(function createClassExpression( @@ -1092,7 +1311,14 @@ namespace ts { heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[], ) { - return factory.createClassExpression(/*decorators*/ undefined, modifiers, name, typeParameters, heritageClauses, members); + return factory.createClassExpression( + /*decorators*/ undefined, + modifiers, + name, + typeParameters, + heritageClauses, + members, + ); }, factoryDeprecation); /** @deprecated Use `factory.updateClassExpression` or the factory supplied by your transformation context instead. */ @@ -1104,7 +1330,15 @@ namespace ts { heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[], ) { - return factory.updateClassExpression(node, /*decorators*/ undefined, modifiers, name, typeParameters, heritageClauses, members); + return factory.updateClassExpression( + node, + /*decorators*/ undefined, + modifiers, + name, + typeParameters, + heritageClauses, + members, + ); }, factoryDeprecation); /** @deprecated Use `factory.createPropertySignature` or the factory supplied by your transformation context instead. */ @@ -1140,69 +1374,252 @@ namespace ts { }, factoryDeprecation); /** @deprecated Use `factory.createExpressionWithTypeArguments` or the factory supplied by your transformation context instead. */ - export const createExpressionWithTypeArguments = Debug.deprecate(function createExpressionWithTypeArguments(typeArguments: readonly TypeNode[] | undefined, expression: Expression) { - return factory.createExpressionWithTypeArguments(expression, typeArguments); - }, factoryDeprecation); + export const createExpressionWithTypeArguments = Debug.deprecate( + function createExpressionWithTypeArguments( + typeArguments: readonly TypeNode[] | undefined, + expression: Expression, + ) { + return factory.createExpressionWithTypeArguments(expression, typeArguments); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.updateExpressionWithTypeArguments` or the factory supplied by your transformation context instead. */ - export const updateExpressionWithTypeArguments = Debug.deprecate(function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, typeArguments: readonly TypeNode[] | undefined, expression: Expression) { - return factory.updateExpressionWithTypeArguments(node, expression, typeArguments); - }, factoryDeprecation); + export const updateExpressionWithTypeArguments = Debug.deprecate( + function updateExpressionWithTypeArguments( + node: ExpressionWithTypeArguments, + typeArguments: readonly TypeNode[] | undefined, + expression: Expression, + ) { + return factory.updateExpressionWithTypeArguments(node, expression, typeArguments); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createArrowFunction` or the factory supplied by your transformation context instead. */ - export const createArrowFunction = Debug.deprecate(function createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanTokenOrBody: ConciseBody | EqualsGreaterThanToken | undefined, body?: ConciseBody) { - return arguments.length === 6 ? factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanTokenOrBody as EqualsGreaterThanToken | undefined, body!) : - arguments.length === 5 ? factory.createArrowFunction(modifiers, typeParameters, parameters, type, /*equalsGreaterThanToken*/ undefined, equalsGreaterThanTokenOrBody as ConciseBody) : - Debug.fail("Argument count mismatch"); - } as { - (modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction; - (modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; - }, factoryDeprecation); + export const createArrowFunction = Debug.deprecate( + function createArrowFunction( + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + equalsGreaterThanTokenOrBody: ConciseBody | EqualsGreaterThanToken | undefined, + body?: ConciseBody, + ) { + return arguments.length === 6 + ? factory.createArrowFunction( + modifiers, + typeParameters, + parameters, + type, + equalsGreaterThanTokenOrBody as EqualsGreaterThanToken | undefined, + body!, + ) + : arguments.length === 5 + ? factory.createArrowFunction( + modifiers, + typeParameters, + parameters, + type, + /*equalsGreaterThanToken*/ undefined, + equalsGreaterThanTokenOrBody as ConciseBody, + ) + : Debug.fail("Argument count mismatch"); + } as { + ( + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + equalsGreaterThanToken: EqualsGreaterThanToken | undefined, + body: ConciseBody, + ): ArrowFunction; + ( + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: ConciseBody, + ): ArrowFunction; + }, + factoryDeprecation, + ); /** @deprecated Use `factory.updateArrowFunction` or the factory supplied by your transformation context instead. */ - export const updateArrowFunction = Debug.deprecate(function updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanTokenOrBody: EqualsGreaterThanToken | ConciseBody, body?: ConciseBody) { - return arguments.length === 7 ? factory.updateArrowFunction(node, modifiers, typeParameters, parameters, type, equalsGreaterThanTokenOrBody as EqualsGreaterThanToken, body!) : - arguments.length === 6 ? factory.updateArrowFunction(node, modifiers, typeParameters, parameters, type, node.equalsGreaterThanToken, equalsGreaterThanTokenOrBody as ConciseBody) : - Debug.fail("Argument count mismatch"); - } as { - (node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction; - (node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; - }, factoryDeprecation); + export const updateArrowFunction = Debug.deprecate( + function updateArrowFunction( + node: ArrowFunction, + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + equalsGreaterThanTokenOrBody: EqualsGreaterThanToken | ConciseBody, + body?: ConciseBody, + ) { + return arguments.length === 7 + ? factory.updateArrowFunction( + node, + modifiers, + typeParameters, + parameters, + type, + equalsGreaterThanTokenOrBody as EqualsGreaterThanToken, + body!, + ) + : arguments.length === 6 + ? factory.updateArrowFunction( + node, + modifiers, + typeParameters, + parameters, + type, + node.equalsGreaterThanToken, + equalsGreaterThanTokenOrBody as ConciseBody, + ) + : Debug.fail("Argument count mismatch"); + } as { + ( + node: ArrowFunction, + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + equalsGreaterThanToken: EqualsGreaterThanToken, + body: ConciseBody, + ): ArrowFunction; + ( + node: ArrowFunction, + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: ConciseBody, + ): ArrowFunction; + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createVariableDeclaration` or the factory supplied by your transformation context instead. */ - export const createVariableDeclaration = Debug.deprecate(function createVariableDeclaration(name: string | BindingName, exclamationTokenOrType?: ExclamationToken | TypeNode, typeOrInitializer?: TypeNode | Expression, initializer?: Expression) { - return arguments.length === 4 ? factory.createVariableDeclaration(name, exclamationTokenOrType as ExclamationToken | undefined, typeOrInitializer as TypeNode | undefined, initializer) : - arguments.length >= 1 && arguments.length <= 3 ? factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, exclamationTokenOrType as TypeNode | undefined, typeOrInitializer as Expression | undefined) : - Debug.fail("Argument count mismatch"); - } as { - (name: string | BindingName, type?: TypeNode | undefined, initializer?: Expression | undefined): VariableDeclaration; - (name: string | BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): VariableDeclaration; - }, factoryDeprecation); + export const createVariableDeclaration = Debug.deprecate( + function createVariableDeclaration( + name: string | BindingName, + exclamationTokenOrType?: ExclamationToken | TypeNode, + typeOrInitializer?: TypeNode | Expression, + initializer?: Expression, + ) { + return arguments.length === 4 + ? factory.createVariableDeclaration( + name, + exclamationTokenOrType as ExclamationToken | undefined, + typeOrInitializer as TypeNode | undefined, + initializer, + ) + : arguments.length >= 1 && arguments.length <= 3 + ? factory.createVariableDeclaration( + name, + /*exclamationToken*/ undefined, + exclamationTokenOrType as TypeNode | undefined, + typeOrInitializer as Expression | undefined, + ) + : Debug.fail("Argument count mismatch"); + } as { + ( + name: string | BindingName, + type?: TypeNode | undefined, + initializer?: Expression | undefined, + ): VariableDeclaration; + ( + name: string | BindingName, + exclamationToken: ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): VariableDeclaration; + }, + factoryDeprecation, + ); /** @deprecated Use `factory.updateVariableDeclaration` or the factory supplied by your transformation context instead. */ - export const updateVariableDeclaration = Debug.deprecate(function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationTokenOrType: ExclamationToken | TypeNode | undefined, typeOrInitializer: TypeNode | Expression | undefined, initializer?: Expression | undefined) { - return arguments.length === 5 ? factory.updateVariableDeclaration(node, name, exclamationTokenOrType as ExclamationToken | undefined, typeOrInitializer as TypeNode | undefined, initializer) : - arguments.length === 4 ? factory.updateVariableDeclaration(node, name, node.exclamationToken, exclamationTokenOrType as TypeNode | undefined, typeOrInitializer as Expression | undefined) : - Debug.fail("Argument count mismatch"); - } as { - (node: VariableDeclaration, name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined): VariableDeclaration; - (node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): VariableDeclaration; - }, factoryDeprecation); + export const updateVariableDeclaration = Debug.deprecate( + function updateVariableDeclaration( + node: VariableDeclaration, + name: BindingName, + exclamationTokenOrType: ExclamationToken | TypeNode | undefined, + typeOrInitializer: TypeNode | Expression | undefined, + initializer?: Expression | undefined, + ) { + return arguments.length === 5 + ? factory.updateVariableDeclaration( + node, + name, + exclamationTokenOrType as ExclamationToken | undefined, + typeOrInitializer as TypeNode | undefined, + initializer, + ) + : arguments.length === 4 + ? factory.updateVariableDeclaration( + node, + name, + node.exclamationToken, + exclamationTokenOrType as TypeNode | undefined, + typeOrInitializer as Expression | undefined, + ) + : Debug.fail("Argument count mismatch"); + } as { + ( + node: VariableDeclaration, + name: BindingName, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): VariableDeclaration; + ( + node: VariableDeclaration, + name: BindingName, + exclamationToken: ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): VariableDeclaration; + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createImportClause` or the factory supplied by your transformation context instead. */ - export const createImportClause = Debug.deprecate(function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly = false): ImportClause { - return factory.createImportClause(isTypeOnly, name, namedBindings); - }, factoryDeprecation); + export const createImportClause = Debug.deprecate( + function createImportClause( + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + isTypeOnly = false, + ): ImportClause { + return factory.createImportClause(isTypeOnly, name, namedBindings); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.updateImportClause` or the factory supplied by your transformation context instead. */ - export const updateImportClause = Debug.deprecate(function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly: boolean) { - return factory.updateImportClause(node, isTypeOnly, name, namedBindings); - }, factoryDeprecation); + export const updateImportClause = Debug.deprecate( + function updateImportClause( + node: ImportClause, + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + isTypeOnly: boolean, + ) { + return factory.updateImportClause(node, isTypeOnly, name, namedBindings); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createExportDeclaration` or the factory supplied by your transformation context instead. */ - export const createExportDeclaration = Debug.deprecate(function createExportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression | undefined, isTypeOnly = false) { - return factory.createExportDeclaration(decorators, modifiers, isTypeOnly, exportClause, moduleSpecifier); - }, factoryDeprecation); + export const createExportDeclaration = Debug.deprecate( + function createExportDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + exportClause: NamedExportBindings | undefined, + moduleSpecifier?: Expression | undefined, + isTypeOnly = false, + ) { + return factory.createExportDeclaration(decorators, modifiers, isTypeOnly, exportClause, moduleSpecifier); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.updateExportDeclaration` or the factory supplied by your transformation context instead. */ export const updateExportDeclaration = Debug.deprecate(function updateExportDeclaration( @@ -1213,13 +1630,36 @@ namespace ts { moduleSpecifier: Expression | undefined, isTypeOnly: boolean, ) { - return factory.updateExportDeclaration(node, decorators, modifiers, isTypeOnly, exportClause, moduleSpecifier, node.assertClause); + return factory.updateExportDeclaration( + node, + decorators, + modifiers, + isTypeOnly, + exportClause, + moduleSpecifier, + node.assertClause, + ); }, factoryDeprecation); /** @deprecated Use `factory.createJSDocParameterTag` or the factory supplied by your transformation context instead. */ - export const createJSDocParamTag = Debug.deprecate(function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression | undefined, comment?: string | undefined): JSDocParameterTag { - return factory.createJSDocParameterTag(/*tagName*/ undefined, name, isBracketed, typeExpression, /*isNameFirst*/ false, comment ? factory.createNodeArray([factory.createJSDocText(comment)]) : undefined); - }, factoryDeprecation); + export const createJSDocParamTag = Debug.deprecate( + function createJSDocParamTag( + name: EntityName, + isBracketed: boolean, + typeExpression?: JSDocTypeExpression | undefined, + comment?: string | undefined, + ): JSDocParameterTag { + return factory.createJSDocParameterTag( + /*tagName*/ undefined, + name, + isBracketed, + typeExpression, + /*isNameFirst*/ false, + comment ? factory.createNodeArray([factory.createJSDocText(comment)]) : undefined, + ); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createComma` or the factory supplied by your transformation context instead. */ export const createComma = Debug.deprecate(function createComma(left: Expression, right: Expression): Expression { @@ -1227,24 +1667,36 @@ namespace ts { }, factoryDeprecation); /** @deprecated Use `factory.createLessThan` or the factory supplied by your transformation context instead. */ - export const createLessThan = Debug.deprecate(function createLessThan(left: Expression, right: Expression): Expression { - return factory.createLessThan(left, right); - }, factoryDeprecation); + export const createLessThan = Debug.deprecate( + function createLessThan(left: Expression, right: Expression): Expression { + return factory.createLessThan(left, right); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createAssignment` or the factory supplied by your transformation context instead. */ - export const createAssignment = Debug.deprecate(function createAssignment(left: Expression, right: Expression): BinaryExpression { - return factory.createAssignment(left, right); - }, factoryDeprecation); + export const createAssignment = Debug.deprecate( + function createAssignment(left: Expression, right: Expression): BinaryExpression { + return factory.createAssignment(left, right); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createStrictEquality` or the factory supplied by your transformation context instead. */ - export const createStrictEquality = Debug.deprecate(function createStrictEquality(left: Expression, right: Expression): BinaryExpression { - return factory.createStrictEquality(left, right); - }, factoryDeprecation); + export const createStrictEquality = Debug.deprecate( + function createStrictEquality(left: Expression, right: Expression): BinaryExpression { + return factory.createStrictEquality(left, right); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createStrictInequality` or the factory supplied by your transformation context instead. */ - export const createStrictInequality = Debug.deprecate(function createStrictInequality(left: Expression, right: Expression): BinaryExpression { - return factory.createStrictInequality(left, right); - }, factoryDeprecation); + export const createStrictInequality = Debug.deprecate( + function createStrictInequality(left: Expression, right: Expression): BinaryExpression { + return factory.createStrictInequality(left, right); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createAdd` or the factory supplied by your transformation context instead. */ export const createAdd = Debug.deprecate(function createAdd(left: Expression, right: Expression): BinaryExpression { @@ -1252,38 +1704,53 @@ namespace ts { }, factoryDeprecation); /** @deprecated Use `factory.createSubtract` or the factory supplied by your transformation context instead. */ - export const createSubtract = Debug.deprecate(function createSubtract(left: Expression, right: Expression): BinaryExpression { - return factory.createSubtract(left, right); - }, factoryDeprecation); + export const createSubtract = Debug.deprecate( + function createSubtract(left: Expression, right: Expression): BinaryExpression { + return factory.createSubtract(left, right); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createLogicalAnd` or the factory supplied by your transformation context instead. */ - export const createLogicalAnd = Debug.deprecate(function createLogicalAnd(left: Expression, right: Expression): BinaryExpression { - return factory.createLogicalAnd(left, right); - }, factoryDeprecation); + export const createLogicalAnd = Debug.deprecate( + function createLogicalAnd(left: Expression, right: Expression): BinaryExpression { + return factory.createLogicalAnd(left, right); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createLogicalOr` or the factory supplied by your transformation context instead. */ - export const createLogicalOr = Debug.deprecate(function createLogicalOr(left: Expression, right: Expression): BinaryExpression { - return factory.createLogicalOr(left, right); - }, factoryDeprecation); + export const createLogicalOr = Debug.deprecate( + function createLogicalOr(left: Expression, right: Expression): BinaryExpression { + return factory.createLogicalOr(left, right); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createPostfixIncrement` or the factory supplied by your transformation context instead. */ - export const createPostfixIncrement = Debug.deprecate(function createPostfixIncrement(operand: Expression): PostfixUnaryExpression { - return factory.createPostfixIncrement(operand); - }, factoryDeprecation); + export const createPostfixIncrement = Debug.deprecate( + function createPostfixIncrement(operand: Expression): PostfixUnaryExpression { + return factory.createPostfixIncrement(operand); + }, + factoryDeprecation, + ); /** @deprecated Use `factory.createLogicalNot` or the factory supplied by your transformation context instead. */ - export const createLogicalNot = Debug.deprecate(function createLogicalNot(operand: Expression): PrefixUnaryExpression { - return factory.createLogicalNot(operand); - }, factoryDeprecation); + export const createLogicalNot = Debug.deprecate( + function createLogicalNot(operand: Expression): PrefixUnaryExpression { + return factory.createLogicalNot(operand); + }, + factoryDeprecation, + ); /** @deprecated Use an appropriate `factory` method instead. */ export const createNode = Debug.deprecate(function createNode(kind: SyntaxKind, pos = 0, end = 0): Node { return setTextRangePosEnd( - kind === SyntaxKind.SourceFile ? parseBaseNodeFactory.createBaseSourceFileNode(kind) : - kind === SyntaxKind.Identifier ? parseBaseNodeFactory.createBaseIdentifierNode(kind) : - kind === SyntaxKind.PrivateIdentifier ? parseBaseNodeFactory.createBasePrivateIdentifierNode(kind) : - !isNodeKind(kind) ? parseBaseNodeFactory.createBaseTokenNode(kind) : - parseBaseNodeFactory.createBaseNode(kind), + kind === SyntaxKind.SourceFile ? parseBaseNodeFactory.createBaseSourceFileNode(kind) + : kind === SyntaxKind.Identifier ? parseBaseNodeFactory.createBaseIdentifierNode(kind) + : kind === SyntaxKind.PrivateIdentifier ? parseBaseNodeFactory.createBasePrivateIdentifierNode(kind) + : !isNodeKind(kind) ? parseBaseNodeFactory.createBaseTokenNode(kind) + : parseBaseNodeFactory.createBaseNode(kind), pos, end, ); @@ -1302,5 +1769,10 @@ namespace ts { setTextRange(clone, node); setParent(clone, node.parent); return clone; - }, { since: "4.0", warnAfter: "4.1", message: "Use an appropriate `factory.update...` method instead, use `setCommentRange` or `setSourceMapRange`, and avoid setting `parent`." }); + }, { + since: "4.0", + warnAfter: "4.1", + message: + "Use an appropriate `factory.update...` method instead, use `setCommentRange` or `setSourceMapRange`, and avoid setting `parent`.", + }); } diff --git a/src/deprecatedCompat/4.2/abstractConstructorTypes.ts b/src/deprecatedCompat/4.2/abstractConstructorTypes.ts index 8053ab26bbb65..65d84e42550bb 100644 --- a/src/deprecatedCompat/4.2/abstractConstructorTypes.ts +++ b/src/deprecatedCompat/4.2/abstractConstructorTypes.ts @@ -6,10 +6,19 @@ namespace ts { export interface NodeFactory { /** @deprecated Use the overload that accepts 'modifiers' */ - createConstructorTypeNode(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): ConstructorTypeNode; + createConstructorTypeNode( + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): ConstructorTypeNode; /** @deprecated Use the overload that accepts 'modifiers' */ - updateConstructorTypeNode(node: ConstructorTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode): ConstructorTypeNode; + updateConstructorTypeNode( + node: ConstructorTypeNode, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode, + ): ConstructorTypeNode; } function patchNodeFactory(factory: NodeFactory) { @@ -20,11 +29,20 @@ namespace ts { factory.createConstructorTypeNode = buildOverload("createConstructorTypeNode") .overload({ - 0(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): ConstructorTypeNode { + 0( + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): ConstructorTypeNode { return createConstructorTypeNode(modifiers, typeParameters, parameters, type); }, - 1(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): ConstructorTypeNode { + 1( + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): ConstructorTypeNode { return createConstructorTypeNode(/*modifiers*/ undefined, typeParameters, parameters, type); }, }) @@ -39,11 +57,22 @@ namespace ts { factory.updateConstructorTypeNode = buildOverload("updateConstructorTypeNode") .overload({ - 0(node: ConstructorTypeNode, modifiers: readonly Modifier[] | undefined, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode) { + 0( + node: ConstructorTypeNode, + modifiers: readonly Modifier[] | undefined, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode, + ) { return updateConstructorTypeNode(node, modifiers, typeParameters, parameters, type); }, - 1(node: ConstructorTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode) { + 1( + node: ConstructorTypeNode, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode, + ) { return updateConstructorTypeNode(node, node.modifiers, typeParameters, parameters, type); }, }) diff --git a/src/deprecatedCompat/4.2/renamedNodeTests.ts b/src/deprecatedCompat/4.2/renamedNodeTests.ts index 03428e766e5c7..1e1b5f26bb660 100644 --- a/src/deprecatedCompat/4.2/renamedNodeTests.ts +++ b/src/deprecatedCompat/4.2/renamedNodeTests.ts @@ -7,11 +7,14 @@ namespace ts { /** * @deprecated Use `isMemberName` instead. */ - export const isIdentifierOrPrivateIdentifier = Debug.deprecate(function isIdentifierOrPrivateIdentifier(node: Node): node is MemberName { - return isMemberName(node); - }, { - since: "4.2", - warnAfter: "4.3", - message: "Use `isMemberName` instead.", - }); + export const isIdentifierOrPrivateIdentifier = Debug.deprecate( + function isIdentifierOrPrivateIdentifier(node: Node): node is MemberName { + return isMemberName(node); + }, + { + since: "4.2", + warnAfter: "4.3", + message: "Use `isMemberName` instead.", + }, + ); } diff --git a/src/deprecatedCompat/4.6/importTypeAssertions.ts b/src/deprecatedCompat/4.6/importTypeAssertions.ts index 23630fa3a4116..96fb6e42b8e16 100644 --- a/src/deprecatedCompat/4.6/importTypeAssertions.ts +++ b/src/deprecatedCompat/4.6/importTypeAssertions.ts @@ -6,13 +6,30 @@ namespace ts { export interface NodeFactory { // NOTE: The following overload is not deprecated, but exists to ensure we don't mark `createImportTypeNode(argument)` as deprecated due to optional parameters. - createImportTypeNode(argument: TypeNode, assertions?: ImportTypeAssertionContainer, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean): ImportTypeNode; + createImportTypeNode( + argument: TypeNode, + assertions?: ImportTypeAssertionContainer, + qualifier?: EntityName, + typeArguments?: readonly TypeNode[], + isTypeOf?: boolean, + ): ImportTypeNode; /** @deprecated Use the overload that accepts 'assertions' */ - createImportTypeNode(argument: TypeNode, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean): ImportTypeNode; + createImportTypeNode( + argument: TypeNode, + qualifier?: EntityName, + typeArguments?: readonly TypeNode[], + isTypeOf?: boolean, + ): ImportTypeNode; /** @deprecated Use the overload that accepts 'assertions' */ - updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf?: boolean): ImportTypeNode; + updateImportTypeNode( + node: ImportTypeNode, + argument: TypeNode, + qualifier: EntityName | undefined, + typeArguments: readonly TypeNode[] | undefined, + isTypeOf?: boolean, + ): ImportTypeNode; } function patchNodeFactory(factory: NodeFactory) { @@ -23,26 +40,37 @@ namespace ts { factory.createImportTypeNode = buildOverload("createImportTypeNode") .overload({ - 0(argument: TypeNode, assertions?: ImportTypeAssertionContainer, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean): ImportTypeNode { + 0( + argument: TypeNode, + assertions?: ImportTypeAssertionContainer, + qualifier?: EntityName, + typeArguments?: readonly TypeNode[], + isTypeOf?: boolean, + ): ImportTypeNode { return createImportTypeNode(argument, assertions, qualifier, typeArguments, isTypeOf); }, - 1(argument: TypeNode, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean): ImportTypeNode { + 1( + argument: TypeNode, + qualifier?: EntityName, + typeArguments?: readonly TypeNode[], + isTypeOf?: boolean, + ): ImportTypeNode { return createImportTypeNode(argument, /*assertions*/ undefined, qualifier, typeArguments, isTypeOf); }, }) .bind({ 0: ([, assertions, qualifier, typeArguments, isTypeOf]) => - (assertions === undefined || isImportTypeAssertionContainer(assertions)) && - (qualifier === undefined || !isArray(qualifier)) && - (typeArguments === undefined || isArray(typeArguments)) && - (isTypeOf === undefined || typeof isTypeOf === "boolean"), + (assertions === undefined || isImportTypeAssertionContainer(assertions)) + && (qualifier === undefined || !isArray(qualifier)) + && (typeArguments === undefined || isArray(typeArguments)) + && (isTypeOf === undefined || typeof isTypeOf === "boolean"), 1: ([, qualifier, typeArguments, isTypeOf, other]) => - (other === undefined) && - (qualifier === undefined || isEntityName(qualifier)) && - (typeArguments === undefined || isArray(typeArguments)) && - (isTypeOf === undefined || typeof isTypeOf === "boolean"), + (other === undefined) + && (qualifier === undefined || isEntityName(qualifier)) + && (typeArguments === undefined || isArray(typeArguments)) + && (isTypeOf === undefined || typeof isTypeOf === "boolean"), }) .deprecate({ 1: { since: "4.6", warnAfter: "4.7", message: "Use the overload that accepts 'assertions'" }, @@ -51,26 +79,39 @@ namespace ts { factory.updateImportTypeNode = buildOverload("updateImportTypeNode") .overload({ - 0(node: ImportTypeNode, argument: TypeNode, assertions: ImportTypeAssertionContainer | undefined, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf?: boolean): ImportTypeNode { + 0( + node: ImportTypeNode, + argument: TypeNode, + assertions: ImportTypeAssertionContainer | undefined, + qualifier: EntityName | undefined, + typeArguments: readonly TypeNode[] | undefined, + isTypeOf?: boolean, + ): ImportTypeNode { return updateImportTypeNode(node, argument, assertions, qualifier, typeArguments, isTypeOf); }, - 1(node: ImportTypeNode, argument: TypeNode, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf?: boolean): ImportTypeNode { + 1( + node: ImportTypeNode, + argument: TypeNode, + qualifier: EntityName | undefined, + typeArguments: readonly TypeNode[] | undefined, + isTypeOf?: boolean, + ): ImportTypeNode { return updateImportTypeNode(node, argument, node.assertions, qualifier, typeArguments, isTypeOf); }, }) .bind({ 0: ([, , assertions, qualifier, typeArguments, isTypeOf]) => - (assertions === undefined || isImportTypeAssertionContainer(assertions)) && - (qualifier === undefined || !isArray(qualifier)) && - (typeArguments === undefined || isArray(typeArguments)) && - (isTypeOf === undefined || typeof isTypeOf === "boolean"), + (assertions === undefined || isImportTypeAssertionContainer(assertions)) + && (qualifier === undefined || !isArray(qualifier)) + && (typeArguments === undefined || isArray(typeArguments)) + && (isTypeOf === undefined || typeof isTypeOf === "boolean"), 1: ([, , qualifier, typeArguments, isTypeOf, other]) => - (other === undefined) && - (qualifier === undefined || isEntityName(qualifier)) && - (typeArguments === undefined || isArray(typeArguments)) && - (isTypeOf === undefined || typeof isTypeOf === "boolean"), + (other === undefined) + && (qualifier === undefined || isEntityName(qualifier)) + && (typeArguments === undefined || isArray(typeArguments)) + && (isTypeOf === undefined || typeof isTypeOf === "boolean"), }) .deprecate({ 1: { since: "4.6", warnAfter: "4.7", message: "Use the overload that accepts 'assertions'" }, diff --git a/src/deprecatedCompat/4.7/typeParameterModifiers.ts b/src/deprecatedCompat/4.7/typeParameterModifiers.ts index 85bb842379a58..c3e57d173edfd 100644 --- a/src/deprecatedCompat/4.7/typeParameterModifiers.ts +++ b/src/deprecatedCompat/4.7/typeParameterModifiers.ts @@ -6,10 +6,19 @@ namespace ts { export interface NodeFactory { /** @deprecated Use the overload that accepts 'modifiers' */ - createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration; + createTypeParameterDeclaration( + name: string | Identifier, + constraint?: TypeNode, + defaultType?: TypeNode, + ): TypeParameterDeclaration; /** @deprecated Use the overload that accepts 'modifiers' */ - updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration; + updateTypeParameterDeclaration( + node: TypeParameterDeclaration, + name: Identifier, + constraint: TypeNode | undefined, + defaultType: TypeNode | undefined, + ): TypeParameterDeclaration; } function patchNodeFactory(factory: NodeFactory) { @@ -20,7 +29,12 @@ namespace ts { factory.createTypeParameterDeclaration = buildOverload("createTypeParameterDeclaration") .overload({ - 0(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + constraint?: TypeNode, + defaultType?: TypeNode, + ): TypeParameterDeclaration { return createTypeParameterDeclaration(modifiers, name, constraint, defaultType); }, @@ -40,11 +54,22 @@ namespace ts { factory.updateTypeParameterDeclaration = buildOverload("updateTypeParameterDeclaration") .overload({ - 0(node: TypeParameterDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration { + 0( + node: TypeParameterDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + constraint: TypeNode | undefined, + defaultType: TypeNode | undefined, + ): TypeParameterDeclaration { return updateTypeParameterDeclaration(node, modifiers, name, constraint, defaultType); }, - 1(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration { + 1( + node: TypeParameterDeclaration, + name: Identifier, + constraint: TypeNode | undefined, + defaultType: TypeNode | undefined, + ): TypeParameterDeclaration { return updateTypeParameterDeclaration(node, node.modifiers, name, constraint, defaultType); }, }) diff --git a/src/deprecatedCompat/4.8/mergeDecoratorsAndModifiers.ts b/src/deprecatedCompat/4.8/mergeDecoratorsAndModifiers.ts index 3c967ceb119e5..f427c76e1a394 100644 --- a/src/deprecatedCompat/4.8/mergeDecoratorsAndModifiers.ts +++ b/src/deprecatedCompat/4.8/mergeDecoratorsAndModifiers.ts @@ -63,160 +63,438 @@ namespace ts { /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - createParameterDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration; + createParameterDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken?: QuestionToken, + type?: TypeNode, + initializer?: Expression, + ): ParameterDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - updateParameterDeclaration(node: ParameterDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration; + updateParameterDeclaration( + node: ParameterDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): ParameterDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - createPropertyDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration; + createPropertyDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - updatePropertyDeclaration(node: PropertyDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration; + updatePropertyDeclaration( + node: PropertyDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - createMethodDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration; + createMethodDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - updateMethodDeclaration(node: MethodDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration; + updateMethodDeclaration( + node: MethodDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration; /** * @deprecated This node does not support Decorators. Callers should use an overload that does not accept a `decorators` parameter. */ - createConstructorDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration; + createConstructorDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration; /** * @deprecated This node does not support Decorators. Callers should use an overload that does not accept a `decorators` parameter. */ - updateConstructorDeclaration(node: ConstructorDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration; + updateConstructorDeclaration( + node: ConstructorDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - createGetAccessorDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration; + createGetAccessorDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - updateGetAccessorDeclaration(node: GetAccessorDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration; + updateGetAccessorDeclaration( + node: GetAccessorDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - createSetAccessorDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration; + createSetAccessorDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - updateSetAccessorDeclaration(node: SetAccessorDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration; + updateSetAccessorDeclaration( + node: SetAccessorDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createIndexSignature(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration; + createIndexSignature( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): IndexSignatureDeclaration; /** * @deprecated Decorators and modifiers are no longer supported for this function. Callers should use an overload that does not accept the `decorators` and `modifiers` parameters. */ - updateIndexSignature(node: IndexSignatureDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration; + updateIndexSignature( + node: IndexSignatureDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): IndexSignatureDeclaration; /** * @deprecated Decorators and modifiers are no longer supported for this function. Callers should use an overload that does not accept the `decorators` and `modifiers` parameters. */ - createClassStaticBlockDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, body: Block): ClassStaticBlockDeclaration; + createClassStaticBlockDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + body: Block, + ): ClassStaticBlockDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, body: Block): ClassStaticBlockDeclaration; + updateClassStaticBlockDeclaration( + node: ClassStaticBlockDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + body: Block, + ): ClassStaticBlockDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - createClassExpression(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression; + createClassExpression( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - updateClassExpression(node: ClassExpression, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression; + updateClassExpression( + node: ClassExpression, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createFunctionDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; + createFunctionDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateFunctionDeclaration(node: FunctionDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; + updateFunctionDeclaration( + node: FunctionDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - createClassDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; + createClassDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration; /** * @deprecated Decorators have been combined with modifiers. Callers should use an overload that does not accept a `decorators` parameter. */ - updateClassDeclaration(node: ClassDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; + updateClassDeclaration( + node: ClassDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createInterfaceDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; + createInterfaceDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateInterfaceDeclaration(node: InterfaceDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; + updateInterfaceDeclaration( + node: InterfaceDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createTypeAliasDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; + createTypeAliasDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateTypeAliasDeclaration(node: TypeAliasDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; + updateTypeAliasDeclaration( + node: TypeAliasDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createEnumDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration; + createEnumDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + members: readonly EnumMember[], + ): EnumDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateEnumDeclaration(node: EnumDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration; + updateEnumDeclaration( + node: EnumDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + members: readonly EnumMember[], + ): EnumDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createModuleDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration; + createModuleDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + flags?: NodeFlags, + ): ModuleDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateModuleDeclaration(node: ModuleDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration; + updateModuleDeclaration( + node: ModuleDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + ): ModuleDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; + createImportEqualsDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + name: string | Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; + updateImportEqualsDeclaration( + node: ImportEqualsDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + name: Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createImportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause?: AssertClause): ImportDeclaration; + createImportDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause?: AssertClause, + ): ImportDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause: AssertClause | undefined): ImportDeclaration; + updateImportDeclaration( + node: ImportDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause: AssertClause | undefined, + ): ImportDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createExportAssignment(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isExportEquals: boolean | undefined, expression: Expression): ExportAssignment; + createExportAssignment( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isExportEquals: boolean | undefined, + expression: Expression, + ): ExportAssignment; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateExportAssignment(node: ExportAssignment, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, expression: Expression): ExportAssignment; + updateExportAssignment( + node: ExportAssignment, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + expression: Expression, + ): ExportAssignment; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - createExportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, assertClause?: AssertClause): ExportDeclaration; + createExportDeclaration( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier?: Expression, + assertClause?: AssertClause, + ): ExportDeclaration; /** * @deprecated Decorators are no longer supported for this function. Callers should use an overload that does not accept a `decorators` parameter. */ - updateExportDeclaration(node: ExportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, assertClause: AssertClause | undefined): ExportDeclaration; + updateExportDeclaration( + node: ExportDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier: Expression | undefined, + assertClause: AssertClause | undefined, + ): ExportDeclaration; } - const MUST_MERGE: DeprecationOptions = { since: "4.8", warnAfter: "4.9.0-0", message: "Decorators have been combined with modifiers. Callers should switch to an overload that does not accept a 'decorators' parameter." }; - const DISALLOW_DECORATORS: DeprecationOptions = { since: "4.8", warnAfter: "4.9.0-0", message: `Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.` }; - const DISALLOW_DECORATORS_AND_MODIFIERS: DeprecationOptions = { since: "4.8", warnAfter: "4.9.0-0", message: `Decorators and modifiers are no longer supported for this function. Callers should switch to an overload that does not accept the 'decorators' and 'modifiers' parameters.` }; + const MUST_MERGE: DeprecationOptions = { + since: "4.8", + warnAfter: "4.9.0-0", + message: + "Decorators have been combined with modifiers. Callers should switch to an overload that does not accept a 'decorators' parameter.", + }; + const DISALLOW_DECORATORS: DeprecationOptions = { + since: "4.8", + warnAfter: "4.9.0-0", + message: + `Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.`, + }; + const DISALLOW_DECORATORS_AND_MODIFIERS: DeprecationOptions = { + since: "4.8", + warnAfter: "4.9.0-0", + message: + `Decorators and modifiers are no longer supported for this function. Callers should switch to an overload that does not accept the 'decorators' and 'modifiers' parameters.`, + }; function patchNodeFactory(factory: NodeFactory) { const { @@ -262,30 +540,61 @@ namespace ts { factory.createParameterDeclaration = buildOverload("createParameterDeclaration") .overload({ - 0(modifiers: readonly ModifierLike[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration { - return createParameterDeclaration(modifiers, dotDotDotToken, name, questionToken, type, initializer); - }, - - 1(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration { - return createParameterDeclaration(concatenate(decorators, modifiers), dotDotDotToken, name, questionToken, type, initializer); + 0( + modifiers: readonly ModifierLike[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken?: QuestionToken, + type?: TypeNode, + initializer?: Expression, + ): ParameterDeclaration { + return createParameterDeclaration( + modifiers, + dotDotDotToken, + name, + questionToken, + type, + initializer, + ); + }, + + 1( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken?: QuestionToken, + type?: TypeNode, + initializer?: Expression, + ): ParameterDeclaration { + return createParameterDeclaration( + concatenate(decorators, modifiers), + dotDotDotToken, + name, + questionToken, + type, + initializer, + ); }, }) .bind({ 0: ([, dotDotDotToken, name, questionToken, type, initializer, other]) => - (other === undefined) && - (dotDotDotToken === undefined || !isArray(dotDotDotToken)) && - (name === undefined || typeof name === "string" || isBindingName(name)) && - (questionToken === undefined || typeof questionToken === "object" && isQuestionToken(questionToken)) && - (type === undefined || isTypeNode(type)) && - (initializer === undefined || isExpression(initializer)), + (other === undefined) + && (dotDotDotToken === undefined || !isArray(dotDotDotToken)) + && (name === undefined || typeof name === "string" || isBindingName(name)) + && (questionToken === undefined + || typeof questionToken === "object" && isQuestionToken(questionToken)) + && (type === undefined || isTypeNode(type)) + && (initializer === undefined || isExpression(initializer)), 1: ([, modifiers, dotDotDotToken, name, questionToken, type, initializer]) => - (modifiers === undefined || isArray(modifiers)) && - (dotDotDotToken === undefined || typeof dotDotDotToken === "object" && isDotDotDotToken(dotDotDotToken)) && - (name === undefined || typeof name === "string" || isBindingName(name)) && - (questionToken === undefined || isQuestionToken(questionToken)) && - (type === undefined || isTypeNode(type)) && - (initializer === undefined || isExpression(initializer)), + (modifiers === undefined || isArray(modifiers)) + && (dotDotDotToken === undefined + || typeof dotDotDotToken === "object" && isDotDotDotToken(dotDotDotToken)) + && (name === undefined || typeof name === "string" || isBindingName(name)) + && (questionToken === undefined || isQuestionToken(questionToken)) + && (type === undefined || isTypeNode(type)) + && (initializer === undefined || isExpression(initializer)), }) .deprecate({ 1: MUST_MERGE, @@ -294,29 +603,64 @@ namespace ts { factory.updateParameterDeclaration = buildOverload("updateParameterDeclaration") .overload({ - 0(node: ParameterDeclaration, modifiers: readonly ModifierLike[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration { - return updateParameterDeclaration(node, modifiers, dotDotDotToken, name, questionToken, type, initializer); - }, - 1(node: ParameterDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration { - return updateParameterDeclaration(node, concatenate(decorators, modifiers), dotDotDotToken, name, questionToken, type, initializer); + 0( + node: ParameterDeclaration, + modifiers: readonly ModifierLike[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): ParameterDeclaration { + return updateParameterDeclaration( + node, + modifiers, + dotDotDotToken, + name, + questionToken, + type, + initializer, + ); + }, + 1( + node: ParameterDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): ParameterDeclaration { + return updateParameterDeclaration( + node, + concatenate(decorators, modifiers), + dotDotDotToken, + name, + questionToken, + type, + initializer, + ); }, }) .bind({ 0: ([, , dotDotDotToken, name, questionToken, type, initializer, other]) => - (other === undefined) && - (dotDotDotToken === undefined || !isArray(dotDotDotToken)) && - (name === undefined || typeof name === "string" || isBindingName(name)) && - (questionToken === undefined || typeof questionToken === "object" && isQuestionToken(questionToken)) && - (type === undefined || isTypeNode(type)) && - (initializer === undefined || isExpression(initializer)), + (other === undefined) + && (dotDotDotToken === undefined || !isArray(dotDotDotToken)) + && (name === undefined || typeof name === "string" || isBindingName(name)) + && (questionToken === undefined + || typeof questionToken === "object" && isQuestionToken(questionToken)) + && (type === undefined || isTypeNode(type)) + && (initializer === undefined || isExpression(initializer)), 1: ([, , modifiers, dotDotDotToken, name, questionToken, type, initializer]) => - (modifiers === undefined || isArray(modifiers)) && - (dotDotDotToken === undefined || typeof dotDotDotToken === "object" && isDotDotDotToken(dotDotDotToken)) && - (name === undefined || typeof name === "string" || isBindingName(name)) && - (questionToken === undefined || isQuestionToken(questionToken)) && - (type === undefined || isTypeNode(type)) && - (initializer === undefined || isExpression(initializer)), + (modifiers === undefined || isArray(modifiers)) + && (dotDotDotToken === undefined + || typeof dotDotDotToken === "object" && isDotDotDotToken(dotDotDotToken)) + && (name === undefined || typeof name === "string" || isBindingName(name)) + && (questionToken === undefined || isQuestionToken(questionToken)) + && (type === undefined || isTypeNode(type)) + && (initializer === undefined || isExpression(initializer)), }) .deprecate({ 1: MUST_MERGE, @@ -325,28 +669,50 @@ namespace ts { factory.createPropertyDeclaration = buildOverload("createPropertyDeclaration") .overload({ - 0(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration { + 0( + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration { return createPropertyDeclaration(modifiers, name, questionOrExclamationToken, type, initializer); }, - 1(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration { - return createPropertyDeclaration(concatenate(decorators, modifiers), name, questionOrExclamationToken, type, initializer); + 1( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration { + return createPropertyDeclaration( + concatenate(decorators, modifiers), + name, + questionOrExclamationToken, + type, + initializer, + ); }, }) .bind({ 0: ([, name, questionOrExclamationToken, type, initializer, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (questionOrExclamationToken === undefined || typeof questionOrExclamationToken === "object" && isQuestionOrExclamationToken(questionOrExclamationToken)) && - (type === undefined || isTypeNode(type)) && - (initializer === undefined || isExpression(initializer)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (questionOrExclamationToken === undefined + || typeof questionOrExclamationToken === "object" + && isQuestionOrExclamationToken(questionOrExclamationToken)) + && (type === undefined || isTypeNode(type)) + && (initializer === undefined || isExpression(initializer)), 1: ([, modifiers, name, questionOrExclamationToken, type, initializer]) => - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || typeof name === "string" || isPropertyName(name)) && - (questionOrExclamationToken === undefined || isQuestionOrExclamationToken(questionOrExclamationToken)) && - (type === undefined || isTypeNode(type)) && - (initializer === undefined || isExpression(initializer)), + (modifiers === undefined || isArray(modifiers)) + && (name === undefined || typeof name === "string" || isPropertyName(name)) + && (questionOrExclamationToken === undefined + || isQuestionOrExclamationToken(questionOrExclamationToken)) + && (type === undefined || isTypeNode(type)) + && (initializer === undefined || isExpression(initializer)), }) .deprecate({ 1: MUST_MERGE, @@ -355,28 +721,60 @@ namespace ts { factory.updatePropertyDeclaration = buildOverload("updatePropertyDeclaration") .overload({ - 0(node: PropertyDeclaration, modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration { - return updatePropertyDeclaration(node, modifiers, name, questionOrExclamationToken, type, initializer); - }, - - 1(node: PropertyDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration { - return updatePropertyDeclaration(node, concatenate(decorators, modifiers), name, questionOrExclamationToken, type, initializer); + 0( + node: PropertyDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration { + return updatePropertyDeclaration( + node, + modifiers, + name, + questionOrExclamationToken, + type, + initializer, + ); + }, + + 1( + node: PropertyDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration { + return updatePropertyDeclaration( + node, + concatenate(decorators, modifiers), + name, + questionOrExclamationToken, + type, + initializer, + ); }, }) .bind({ 0: ([, , name, questionOrExclamationToken, type, initializer, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (questionOrExclamationToken === undefined || typeof questionOrExclamationToken === "object" && isQuestionOrExclamationToken(questionOrExclamationToken)) && - (type === undefined || isTypeNode(type)) && - (initializer === undefined || isExpression(initializer)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (questionOrExclamationToken === undefined + || typeof questionOrExclamationToken === "object" + && isQuestionOrExclamationToken(questionOrExclamationToken)) + && (type === undefined || isTypeNode(type)) + && (initializer === undefined || isExpression(initializer)), 1: ([, , modifiers, name, questionOrExclamationToken, type, initializer]) => - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || typeof name === "string" || isPropertyName(name)) && - (questionOrExclamationToken === undefined || isQuestionOrExclamationToken(questionOrExclamationToken)) && - (type === undefined || isTypeNode(type)) && - (initializer === undefined || isExpression(initializer)), + (modifiers === undefined || isArray(modifiers)) + && (name === undefined || typeof name === "string" || isPropertyName(name)) + && (questionOrExclamationToken === undefined + || isQuestionOrExclamationToken(questionOrExclamationToken)) + && (type === undefined || isTypeNode(type)) + && (initializer === undefined || isExpression(initializer)), }) .deprecate({ 1: MUST_MERGE, @@ -385,34 +783,73 @@ namespace ts { factory.createMethodDeclaration = buildOverload("createMethodDeclaration") .overload({ - 0(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration { - return createMethodDeclaration(modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body); - }, - - 1(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration { - return createMethodDeclaration(concatenate(decorators, modifiers), asteriskToken, name, questionToken, typeParameters, parameters, type, body); + 0( + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration { + return createMethodDeclaration( + modifiers, + asteriskToken, + name, + questionToken, + typeParameters, + parameters, + type, + body, + ); + }, + + 1( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration { + return createMethodDeclaration( + concatenate(decorators, modifiers), + asteriskToken, + name, + questionToken, + typeParameters, + parameters, + type, + body, + ); }, }) .bind({ 0: ([, asteriskToken, name, questionToken, typeParameters, parameters, type, body, other]) => - (other === undefined) && - (asteriskToken === undefined || !isArray(asteriskToken)) && - (name === undefined || typeof name === "string" || isPropertyName(name)) && - (questionToken === undefined || typeof questionToken === "object" && isQuestionToken(questionToken)) && - (typeParameters === undefined || isArray(typeParameters)) && - (parameters === undefined || !some(parameters, isTypeParameterDeclaration)) && - (type === undefined || !isArray(type)) && - (body === undefined || isBlock(body)), + (other === undefined) + && (asteriskToken === undefined || !isArray(asteriskToken)) + && (name === undefined || typeof name === "string" || isPropertyName(name)) + && (questionToken === undefined + || typeof questionToken === "object" && isQuestionToken(questionToken)) + && (typeParameters === undefined || isArray(typeParameters)) + && (parameters === undefined || !some(parameters, isTypeParameterDeclaration)) + && (type === undefined || !isArray(type)) + && (body === undefined || isBlock(body)), 1: ([, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body]) => - (modifiers === undefined || isArray(modifiers)) && - (asteriskToken === undefined || typeof asteriskToken === "object" && isAsteriskToken(asteriskToken)) && - (name === undefined || typeof name === "string" || isPropertyName(name)) && - (questionToken === undefined || !isArray(questionToken)) && - (typeParameters === undefined || !some(typeParameters, isParameter)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || isTypeNode(type)) && - (body === undefined || isBlock(body)), + (modifiers === undefined || isArray(modifiers)) + && (asteriskToken === undefined + || typeof asteriskToken === "object" && isAsteriskToken(asteriskToken)) + && (name === undefined || typeof name === "string" || isPropertyName(name)) + && (questionToken === undefined || !isArray(questionToken)) + && (typeParameters === undefined || !some(typeParameters, isParameter)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || isTypeNode(type)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: MUST_MERGE, @@ -421,34 +858,77 @@ namespace ts { factory.updateMethodDeclaration = buildOverload("updateMethodDeclaration") .overload({ - 0(node: MethodDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration { - return updateMethodDeclaration(node, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body); - }, - - 1(node: MethodDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration { - return updateMethodDeclaration(node, concatenate(decorators, modifiers), asteriskToken, name, questionToken, typeParameters, parameters, type, body); + 0( + node: MethodDeclaration, + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration { + return updateMethodDeclaration( + node, + modifiers, + asteriskToken, + name, + questionToken, + typeParameters, + parameters, + type, + body, + ); + }, + + 1( + node: MethodDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration { + return updateMethodDeclaration( + node, + concatenate(decorators, modifiers), + asteriskToken, + name, + questionToken, + typeParameters, + parameters, + type, + body, + ); }, }) .bind({ 0: ([, , asteriskToken, name, questionToken, typeParameters, parameters, type, body, other]) => - (other === undefined) && - (asteriskToken === undefined || !isArray(asteriskToken)) && - (name === undefined || typeof name === "string" || isPropertyName(name)) && - (questionToken === undefined || typeof questionToken === "object" && isQuestionToken(questionToken)) && - (typeParameters === undefined || isArray(typeParameters)) && - (parameters === undefined || !some(parameters, isTypeParameterDeclaration)) && - (type === undefined || !isArray(type)) && - (body === undefined || isBlock(body)), + (other === undefined) + && (asteriskToken === undefined || !isArray(asteriskToken)) + && (name === undefined || typeof name === "string" || isPropertyName(name)) + && (questionToken === undefined + || typeof questionToken === "object" && isQuestionToken(questionToken)) + && (typeParameters === undefined || isArray(typeParameters)) + && (parameters === undefined || !some(parameters, isTypeParameterDeclaration)) + && (type === undefined || !isArray(type)) + && (body === undefined || isBlock(body)), 1: ([, , modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body]) => - (modifiers === undefined || isArray(modifiers)) && - (asteriskToken === undefined || typeof asteriskToken === "object" && isAsteriskToken(asteriskToken)) && - (name === undefined || typeof name === "string" || isPropertyName(name)) && - (questionToken === undefined || !isArray(questionToken)) && - (typeParameters === undefined || !some(typeParameters, isParameter)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || isTypeNode(type)) && - (body === undefined || isBlock(body)), + (modifiers === undefined || isArray(modifiers)) + && (asteriskToken === undefined + || typeof asteriskToken === "object" && isAsteriskToken(asteriskToken)) + && (name === undefined || typeof name === "string" || isPropertyName(name)) + && (questionToken === undefined || !isArray(questionToken)) + && (typeParameters === undefined || !some(typeParameters, isParameter)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || isTypeNode(type)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: MUST_MERGE, @@ -457,26 +937,35 @@ namespace ts { factory.createConstructorDeclaration = buildOverload("createConstructorDeclaration") .overload({ - 0(modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration { return createConstructorDeclaration(modifiers, parameters, body); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration { return createConstructorDeclaration(modifiers, parameters, body); }, }) .bind({ 0: ([modifiers, parameters, body, other]) => - (other === undefined) && - (modifiers === undefined || !some(modifiers, isDecorator)) && - (parameters === undefined || !some(parameters, isModifier)) && - (body === undefined || !isArray(body)), + (other === undefined) + && (modifiers === undefined || !some(modifiers, isDecorator)) + && (parameters === undefined || !some(parameters, isModifier)) + && (body === undefined || !isArray(body)), 1: ([decorators, modifiers, parameters, body]) => - (decorators === undefined || !some(decorators, isModifier)) && - (modifiers === undefined || !some(modifiers, isParameter)) && - (parameters === undefined || isArray(parameters)) && - (body === undefined || isBlock(body)), + (decorators === undefined || !some(decorators, isModifier)) + && (modifiers === undefined || !some(modifiers, isParameter)) + && (parameters === undefined || isArray(parameters)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -485,26 +974,37 @@ namespace ts { factory.updateConstructorDeclaration = buildOverload("updateConstructorDeclaration") .overload({ - 0(node: ConstructorDeclaration, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration { + 0( + node: ConstructorDeclaration, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration { return updateConstructorDeclaration(node, modifiers, parameters, body); }, - 1(node: ConstructorDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration { + 1( + node: ConstructorDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration { return updateConstructorDeclaration(node, modifiers, parameters, body); }, }) .bind({ 0: ([, modifiers, parameters, body, other]) => - (other === undefined) && - (modifiers === undefined || !some(modifiers, isDecorator)) && - (parameters === undefined || !some(parameters, isModifier)) && - (body === undefined || !isArray(body)), + (other === undefined) + && (modifiers === undefined || !some(modifiers, isDecorator)) + && (parameters === undefined || !some(parameters, isModifier)) + && (body === undefined || !isArray(body)), 1: ([, decorators, modifiers, parameters, body]) => - (decorators === undefined || !some(decorators, isModifier)) && - (modifiers === undefined || !some(modifiers, isParameter)) && - (parameters === undefined || isArray(parameters)) && - (body === undefined || isBlock(body)), + (decorators === undefined || !some(decorators, isModifier)) + && (modifiers === undefined || !some(modifiers, isParameter)) + && (parameters === undefined || isArray(parameters)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -513,28 +1013,47 @@ namespace ts { factory.createGetAccessorDeclaration = buildOverload("createGetAccessorDeclaration") .overload({ - 0(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration { + 0( + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration { return createGetAccessorDeclaration(modifiers, name, parameters, type, body); }, - 1(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration { - return createGetAccessorDeclaration(concatenate(decorators, modifiers), name, parameters, type, body); + 1( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration { + return createGetAccessorDeclaration( + concatenate(decorators, modifiers), + name, + parameters, + type, + body, + ); }, }) .bind({ 0: ([, name, parameters, type, body, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || !isArray(type)) && - (body === undefined || isBlock(body)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || !isArray(type)) + && (body === undefined || isBlock(body)), 1: ([, modifiers, name, parameters, type, body]) => - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || isTypeNode(type)) && - (body === undefined || isBlock(body)), + (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || isTypeNode(type)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: MUST_MERGE, @@ -543,28 +1062,50 @@ namespace ts { factory.updateGetAccessorDeclaration = buildOverload("updateGetAccessorDeclaration") .overload({ - 0(node: GetAccessorDeclaration, modifiers: readonly ModifierLike[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration { + 0( + node: GetAccessorDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration { return updateGetAccessorDeclaration(node, modifiers, name, parameters, type, body); }, - 1(node: GetAccessorDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration { - return updateGetAccessorDeclaration(node, concatenate(decorators, modifiers), name, parameters, type, body); + 1( + node: GetAccessorDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration { + return updateGetAccessorDeclaration( + node, + concatenate(decorators, modifiers), + name, + parameters, + type, + body, + ); }, }) .bind({ 0: ([, , name, parameters, type, body, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || !isArray(type)) && - (body === undefined || isBlock(body)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || !isArray(type)) + && (body === undefined || isBlock(body)), 1: ([, , modifiers, name, parameters, type, body]) => - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || isTypeNode(type)) && - (body === undefined || isBlock(body)), + (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || isTypeNode(type)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: MUST_MERGE, @@ -573,26 +1114,42 @@ namespace ts { factory.createSetAccessorDeclaration = buildOverload("createSetAccessorDeclaration") .overload({ - 0(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration { + 0( + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration { return createSetAccessorDeclaration(modifiers, name, parameters, body); }, - 1(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration { - return createSetAccessorDeclaration(concatenate(decorators, modifiers), name, parameters, body); + 1( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration { + return createSetAccessorDeclaration( + concatenate(decorators, modifiers), + name, + parameters, + body, + ); }, }) .bind({ 0: ([, name, parameters, body, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (parameters === undefined || isArray(parameters)) && - (body === undefined || !isArray(body)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (parameters === undefined || isArray(parameters)) + && (body === undefined || !isArray(body)), 1: ([, modifiers, name, parameters, body]) => - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (parameters === undefined || isArray(parameters)) && - (body === undefined || isBlock(body)), + (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (parameters === undefined || isArray(parameters)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: MUST_MERGE, @@ -601,26 +1158,45 @@ namespace ts { factory.updateSetAccessorDeclaration = buildOverload("updateSetAccessorDeclaration") .overload({ - 0(node: SetAccessorDeclaration, modifiers: readonly ModifierLike[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration { + 0( + node: SetAccessorDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration { return updateSetAccessorDeclaration(node, modifiers, name, parameters, body); }, - 1(node: SetAccessorDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration { - return updateSetAccessorDeclaration(node, concatenate(decorators, modifiers), name, parameters, body); + 1( + node: SetAccessorDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration { + return updateSetAccessorDeclaration( + node, + concatenate(decorators, modifiers), + name, + parameters, + body, + ); }, }) .bind({ 0: ([, , name, parameters, body, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (parameters === undefined || isArray(parameters)) && - (body === undefined || !isArray(body)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (parameters === undefined || isArray(parameters)) + && (body === undefined || !isArray(body)), 1: ([, , modifiers, name, parameters, body]) => - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (parameters === undefined || isArray(parameters)) && - (body === undefined || isBlock(body)), + (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (parameters === undefined || isArray(parameters)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: MUST_MERGE, @@ -629,26 +1205,35 @@ namespace ts { factory.createIndexSignature = buildOverload("createIndexSignature") .overload({ - 0(modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): IndexSignatureDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): IndexSignatureDeclaration { return createIndexSignature(modifiers, parameters, type); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): IndexSignatureDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): IndexSignatureDeclaration { return createIndexSignature(modifiers, parameters, type); }, }) .bind({ 0: ([modifiers, parameters, type, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (parameters === undefined || every(parameters, isParameter)) && - (type === undefined || !isArray(type)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (parameters === undefined || every(parameters, isParameter)) + && (type === undefined || !isArray(type)), 1: ([decorators, modifiers, parameters, type]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || every(modifiers, isModifier)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || isTypeNode(type)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || every(modifiers, isModifier)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || isTypeNode(type)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -657,26 +1242,37 @@ namespace ts { factory.updateIndexSignature = buildOverload("updateIndexSignature") .overload({ - 0(node: IndexSignatureDeclaration, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration { + 0( + node: IndexSignatureDeclaration, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): IndexSignatureDeclaration { return updateIndexSignature(node, modifiers, parameters, type); }, - 1(node: IndexSignatureDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration { + 1( + node: IndexSignatureDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): IndexSignatureDeclaration { return updateIndexSignature(node, modifiers, parameters, type); }, }) .bind({ 0: ([, modifiers, parameters, type, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (parameters === undefined || every(parameters, isParameter)) && - (type === undefined || !isArray(type)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (parameters === undefined || every(parameters, isParameter)) + && (type === undefined || !isArray(type)), 1: ([, decorators, modifiers, parameters, type]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || every(modifiers, isModifier)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || isTypeNode(type)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || every(modifiers, isModifier)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || isTypeNode(type)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -689,20 +1285,24 @@ namespace ts { return createClassStaticBlockDeclaration(body); }, - 1(_decorators: readonly Decorator[] | undefined, _modifiers: readonly Modifier[] | undefined, body: Block): ClassStaticBlockDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + _modifiers: readonly Modifier[] | undefined, + body: Block, + ): ClassStaticBlockDeclaration { return createClassStaticBlockDeclaration(body); }, }) .bind({ 0: ([body, other1, other2]) => - (other1 === undefined) && - (other2 === undefined) && - (body === undefined || !isArray(body)), + (other1 === undefined) + && (other2 === undefined) + && (body === undefined || !isArray(body)), 1: ([decorators, modifiers, body]) => - (decorators === undefined || isArray(decorators)) && - (modifiers === undefined || isArray(decorators)) && - (body === undefined || isBlock(body)), + (decorators === undefined || isArray(decorators)) + && (modifiers === undefined || isArray(decorators)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: DISALLOW_DECORATORS_AND_MODIFIERS, @@ -715,20 +1315,25 @@ namespace ts { return updateClassStaticBlockDeclaration(node, body); }, - 1(node: ClassStaticBlockDeclaration, _decorators: readonly Decorator[] | undefined, _modifiers: readonly Modifier[] | undefined, body: Block): ClassStaticBlockDeclaration { + 1( + node: ClassStaticBlockDeclaration, + _decorators: readonly Decorator[] | undefined, + _modifiers: readonly Modifier[] | undefined, + body: Block, + ): ClassStaticBlockDeclaration { return updateClassStaticBlockDeclaration(node, body); }, }) .bind({ 0: ([, body, other1, other2]) => - (other1 === undefined) && - (other2 === undefined) && - (body === undefined || !isArray(body)), + (other1 === undefined) + && (other2 === undefined) + && (body === undefined || !isArray(body)), 1: ([, decorators, modifiers, body]) => - (decorators === undefined || isArray(decorators)) && - (modifiers === undefined || isArray(decorators)) && - (body === undefined || isBlock(body)), + (decorators === undefined || isArray(decorators)) + && (modifiers === undefined || isArray(decorators)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: DISALLOW_DECORATORS_AND_MODIFIERS, @@ -737,28 +1342,47 @@ namespace ts { factory.createClassExpression = buildOverload("createClassExpression") .overload({ - 0(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression { + 0( + modifiers: readonly ModifierLike[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression { return createClassExpression(modifiers, name, typeParameters, heritageClauses, members); }, - 1(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression { - return createClassExpression(concatenate(decorators, modifiers), name, typeParameters, heritageClauses, members); + 1( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression { + return createClassExpression( + concatenate(decorators, modifiers), + name, + typeParameters, + heritageClauses, + members, + ); }, }) .bind({ 0: ([, name, typeParameters, heritageClauses, members, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || every(members, isClassElement)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || every(members, isClassElement)), 1: ([, modifiers, name, typeParameters, heritageClauses, members]) => - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || isArray(members)), + (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || isArray(members)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -767,28 +1391,50 @@ namespace ts { factory.updateClassExpression = buildOverload("updateClassExpression") .overload({ - 0(node: ClassExpression, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression { + 0( + node: ClassExpression, + modifiers: readonly ModifierLike[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression { return updateClassExpression(node, modifiers, name, typeParameters, heritageClauses, members); }, - 1(node: ClassExpression, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression { - return updateClassExpression(node, concatenate(decorators, modifiers), name, typeParameters, heritageClauses, members); + 1( + node: ClassExpression, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression { + return updateClassExpression( + node, + concatenate(decorators, modifiers), + name, + typeParameters, + heritageClauses, + members, + ); }, }) .bind({ 0: ([, , name, typeParameters, heritageClauses, members, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || every(members, isClassElement)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || every(members, isClassElement)), 1: ([, , modifiers, name, typeParameters, heritageClauses, members]) => - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || isArray(members)), + (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || isArray(members)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -797,32 +1443,66 @@ namespace ts { factory.createFunctionDeclaration = buildOverload("createFunctionDeclaration") .overload({ - 0(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration { - return createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body); - }, - - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration { - return createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body); + 0( + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration { + return createFunctionDeclaration( + modifiers, + asteriskToken, + name, + typeParameters, + parameters, + type, + body, + ); + }, + + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration { + return createFunctionDeclaration( + modifiers, + asteriskToken, + name, + typeParameters, + parameters, + type, + body, + ); }, }) .bind({ 0: ([, asteriskToken, name, typeParameters, parameters, type, body, other]) => - (other === undefined) && - (asteriskToken === undefined || !isArray(asteriskToken)) && - (name === undefined || typeof name === "string" || isIdentifier(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (parameters === undefined || every(parameters, isParameter)) && - (type === undefined || !isArray(type)) && - (body === undefined || isBlock(body)), + (other === undefined) + && (asteriskToken === undefined || !isArray(asteriskToken)) + && (name === undefined || typeof name === "string" || isIdentifier(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (parameters === undefined || every(parameters, isParameter)) + && (type === undefined || !isArray(type)) + && (body === undefined || isBlock(body)), 1: ([, modifiers, asteriskToken, name, typeParameters, parameters, type, body]) => - (modifiers === undefined || isArray(modifiers)) && - (asteriskToken === undefined || typeof asteriskToken !== "string" && isAsteriskToken(asteriskToken)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || isTypeNode(type)) && - (body === undefined || isBlock(body)), + (modifiers === undefined || isArray(modifiers)) + && (asteriskToken === undefined + || typeof asteriskToken !== "string" && isAsteriskToken(asteriskToken)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || isTypeNode(type)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -831,32 +1511,70 @@ namespace ts { factory.updateFunctionDeclaration = buildOverload("updateFunctionDeclaration") .overload({ - 0(node: FunctionDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration { - return updateFunctionDeclaration(node, modifiers, asteriskToken, name, typeParameters, parameters, type, body); - }, - - 1(node: FunctionDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration { - return updateFunctionDeclaration(node, modifiers, asteriskToken, name, typeParameters, parameters, type, body); + 0( + node: FunctionDeclaration, + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration { + return updateFunctionDeclaration( + node, + modifiers, + asteriskToken, + name, + typeParameters, + parameters, + type, + body, + ); + }, + + 1( + node: FunctionDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration { + return updateFunctionDeclaration( + node, + modifiers, + asteriskToken, + name, + typeParameters, + parameters, + type, + body, + ); }, }) .bind({ 0: ([, , asteriskToken, name, typeParameters, parameters, type, body, other]) => - (other === undefined) && - (asteriskToken === undefined || !isArray(asteriskToken)) && - (name === undefined || isIdentifier(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (parameters === undefined || every(parameters, isParameter)) && - (type === undefined || !isArray(type)) && - (body === undefined || isBlock(body)), + (other === undefined) + && (asteriskToken === undefined || !isArray(asteriskToken)) + && (name === undefined || isIdentifier(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (parameters === undefined || every(parameters, isParameter)) + && (type === undefined || !isArray(type)) + && (body === undefined || isBlock(body)), 1: ([, , modifiers, asteriskToken, name, typeParameters, parameters, type, body]) => - (modifiers === undefined || isArray(modifiers)) && - (asteriskToken === undefined || typeof asteriskToken !== "string" && isAsteriskToken(asteriskToken)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) && - (parameters === undefined || isArray(parameters)) && - (type === undefined || isTypeNode(type)) && - (body === undefined || isBlock(body)), + (modifiers === undefined || isArray(modifiers)) + && (asteriskToken === undefined + || typeof asteriskToken !== "string" && isAsteriskToken(asteriskToken)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) + && (parameters === undefined || isArray(parameters)) + && (type === undefined || isTypeNode(type)) + && (body === undefined || isBlock(body)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -865,21 +1583,40 @@ namespace ts { factory.createClassDeclaration = buildOverload("createClassDeclaration") .overload({ - 0(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration { + 0( + modifiers: readonly ModifierLike[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration { return createClassDeclaration(modifiers, name, typeParameters, heritageClauses, members); }, - 1(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration { - return createClassDeclaration(concatenate(decorators, modifiers), name, typeParameters, heritageClauses, members); + 1( + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration { + return createClassDeclaration( + concatenate(decorators, modifiers), + name, + typeParameters, + heritageClauses, + members, + ); }, }) .bind({ 0: ([, name, typeParameters, heritageClauses, members, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || every(members, isClassElement)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || every(members, isClassElement)), 1: () => true, }) @@ -890,28 +1627,50 @@ namespace ts { factory.updateClassDeclaration = buildOverload("updateClassDeclaration") .overload({ - 0(node: ClassDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration { + 0( + node: ClassDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration { return updateClassDeclaration(node, modifiers, name, typeParameters, heritageClauses, members); }, - 1(node: ClassDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration { - return updateClassDeclaration(node, concatenate(decorators, modifiers), name, typeParameters, heritageClauses, members); + 1( + node: ClassDeclaration, + decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration { + return updateClassDeclaration( + node, + concatenate(decorators, modifiers), + name, + typeParameters, + heritageClauses, + members, + ); }, }) .bind({ 0: ([, , name, typeParameters, heritageClauses, members, other]) => - (other === undefined) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || every(members, isClassElement)), + (other === undefined) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || every(members, isClassElement)), 1: ([, , modifiers, name, typeParameters, heritageClauses, members]) => - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || isArray(members)), + (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || isArray(members)), }) .deprecate({ 1: MUST_MERGE, @@ -920,30 +1679,43 @@ namespace ts { factory.createInterfaceDeclaration = buildOverload("createInterfaceDeclaration") .overload({ - 0(modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration { return createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration { return createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members); }, }) .bind({ 0: ([modifiers, name, typeParameters, heritageClauses, members, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || every(members, isTypeElement)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || every(members, isTypeElement)), 1: ([decorators, modifiers, name, typeParameters, heritageClauses, members]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || every(members, isTypeElement)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || every(members, isTypeElement)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -952,30 +1724,45 @@ namespace ts { factory.updateInterfaceDeclaration = buildOverload("updateInterfaceDeclaration") .overload({ - 0(node: InterfaceDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration { + 0( + node: InterfaceDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration { return updateInterfaceDeclaration(node, modifiers, name, typeParameters, heritageClauses, members); }, - 1(node: InterfaceDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration { + 1( + node: InterfaceDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration { return updateInterfaceDeclaration(node, modifiers, name, typeParameters, heritageClauses, members); }, }) .bind({ 0: ([, modifiers, name, typeParameters, heritageClauses, members, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || every(members, isTypeElement)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || every(members, isTypeElement)), 1: ([, decorators, modifiers, name, typeParameters, heritageClauses, members]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) && - (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) && - (members === undefined || every(members, isTypeElement)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || every(typeParameters, isTypeParameterDeclaration)) + && (heritageClauses === undefined || every(heritageClauses, isHeritageClause)) + && (members === undefined || every(members, isTypeElement)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -984,28 +1771,39 @@ namespace ts { factory.createTypeAliasDeclaration = buildOverload("createTypeAliasDeclaration") .overload({ - 0(modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration { return createTypeAliasDeclaration(modifiers, name, typeParameters, type); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration { return createTypeAliasDeclaration(modifiers, name, typeParameters, type); }, }) .bind({ 0: ([modifiers, name, typeParameters, type, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (type === undefined || !isArray(type)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (type === undefined || !isArray(type)), 1: ([decorators, modifiers, name, typeParameters, type]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (type === undefined || isTypeNode(type)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (type === undefined || isTypeNode(type)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1014,28 +1812,41 @@ namespace ts { factory.updateTypeAliasDeclaration = buildOverload("updateTypeAliasDeclaration") .overload({ - 0(node: TypeAliasDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration { + 0( + node: TypeAliasDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration { return updateTypeAliasDeclaration(node, modifiers, name, typeParameters, type); }, - 1(node: TypeAliasDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration { + 1( + node: TypeAliasDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration { return updateTypeAliasDeclaration(node, modifiers, name, typeParameters, type); }, }) .bind({ 0: ([, modifiers, name, typeParameters, type, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (type === undefined || !isArray(type)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (type === undefined || !isArray(type)), 1: ([, decorators, modifiers, name, typeParameters, type]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (typeParameters === undefined || isArray(typeParameters)) && - (type === undefined || isTypeNode(type)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (typeParameters === undefined || isArray(typeParameters)) + && (type === undefined || isTypeNode(type)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1044,26 +1855,35 @@ namespace ts { factory.createEnumDeclaration = buildOverload("createEnumDeclaration") .overload({ - 0(modifiers: readonly Modifier[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + members: readonly EnumMember[], + ): EnumDeclaration { return createEnumDeclaration(modifiers, name, members); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + members: readonly EnumMember[], + ): EnumDeclaration { return createEnumDeclaration(modifiers, name, members); }, }) .bind({ 0: ([modifiers, name, members, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (name === undefined || !isArray(name)) && - (members === undefined || isArray(members)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (name === undefined || !isArray(name)) + && (members === undefined || isArray(members)), 1: ([decorators, modifiers, name, members]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (members === undefined || isArray(members)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (members === undefined || isArray(members)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1072,26 +1892,37 @@ namespace ts { factory.updateEnumDeclaration = buildOverload("updateEnumDeclaration") .overload({ - 0(node: EnumDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration { + 0( + node: EnumDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + members: readonly EnumMember[], + ): EnumDeclaration { return updateEnumDeclaration(node, modifiers, name, members); }, - 1(node: EnumDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration { + 1( + node: EnumDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + members: readonly EnumMember[], + ): EnumDeclaration { return updateEnumDeclaration(node, modifiers, name, members); }, }) .bind({ 0: ([, modifiers, name, members, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (name === undefined || !isArray(name)) && - (members === undefined || isArray(members)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (name === undefined || !isArray(name)) + && (members === undefined || isArray(members)), 1: ([, decorators, modifiers, name, members]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (name === undefined || !isArray(name)) && - (members === undefined || isArray(members)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (name === undefined || !isArray(name)) + && (members === undefined || isArray(members)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1100,28 +1931,39 @@ namespace ts { factory.createModuleDeclaration = buildOverload("createModuleDeclaration") .overload({ - 0(modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + flags?: NodeFlags, + ): ModuleDeclaration { return createModuleDeclaration(modifiers, name, body, flags); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + flags?: NodeFlags, + ): ModuleDeclaration { return createModuleDeclaration(modifiers, name, body, flags); }, }) .bind({ 0: ([modifiers, name, body, flags, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (name !== undefined && !isArray(name)) && - (body === undefined || isModuleBody(body)) && - (flags === undefined || typeof flags === "number"), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (name !== undefined && !isArray(name)) + && (body === undefined || isModuleBody(body)) + && (flags === undefined || typeof flags === "number"), 1: ([decorators, modifiers, name, body, flags]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (name !== undefined && isModuleName(name)) && - (body === undefined || typeof body === "object") && - (flags === undefined || typeof flags === "number"), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (name !== undefined && isModuleName(name)) + && (body === undefined || typeof body === "object") + && (flags === undefined || typeof flags === "number"), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1130,26 +1972,37 @@ namespace ts { factory.updateModuleDeclaration = buildOverload("updateModuleDeclaration") .overload({ - 0(node: ModuleDeclaration, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration { + 0( + node: ModuleDeclaration, + modifiers: readonly Modifier[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + ): ModuleDeclaration { return updateModuleDeclaration(node, modifiers, name, body); }, - 1(node: ModuleDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration { + 1( + node: ModuleDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + ): ModuleDeclaration { return updateModuleDeclaration(node, modifiers, name, body); }, }) .bind({ 0: ([, modifiers, name, body, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (name === undefined || !isArray(name)) && - (body === undefined || isModuleBody(body)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (name === undefined || !isArray(name)) + && (body === undefined || isModuleBody(body)), 1: ([, decorators, modifiers, name, body]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (name !== undefined && isModuleName(name)) && - (body === undefined || isModuleBody(body)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (name !== undefined && isModuleName(name)) + && (body === undefined || isModuleBody(body)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1158,28 +2011,39 @@ namespace ts { factory.createImportEqualsDeclaration = buildOverload("createImportEqualsDeclaration") .overload({ - 0(modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + name: string | Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration { return createImportEqualsDeclaration(modifiers, isTypeOnly, name, moduleReference); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + name: string | Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration { return createImportEqualsDeclaration(modifiers, isTypeOnly, name, moduleReference); }, }) .bind({ 0: ([modifiers, isTypeOnly, name, moduleReference, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (isTypeOnly === undefined || typeof isTypeOnly === "boolean") && - (typeof name !== "boolean") && - (typeof moduleReference !== "string"), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (isTypeOnly === undefined || typeof isTypeOnly === "boolean") + && (typeof name !== "boolean") + && (typeof moduleReference !== "string"), 1: ([decorators, modifiers, isTypeOnly, name, moduleReference]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (isTypeOnly === undefined || typeof isTypeOnly === "boolean") && - (typeof name === "string" || isIdentifier(name)) && - (moduleReference !== undefined && isModuleReference(moduleReference)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (isTypeOnly === undefined || typeof isTypeOnly === "boolean") + && (typeof name === "string" || isIdentifier(name)) + && (moduleReference !== undefined && isModuleReference(moduleReference)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1188,28 +2052,41 @@ namespace ts { factory.updateImportEqualsDeclaration = buildOverload("updateImportEqualsDeclaration") .overload({ - 0(node: ImportEqualsDeclaration, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration { + 0( + node: ImportEqualsDeclaration, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + name: Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration { return updateImportEqualsDeclaration(node, modifiers, isTypeOnly, name, moduleReference); }, - 1(node: ImportEqualsDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration { + 1( + node: ImportEqualsDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + name: Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration { return updateImportEqualsDeclaration(node, modifiers, isTypeOnly, name, moduleReference); }, }) .bind({ 0: ([, modifiers, isTypeOnly, name, moduleReference, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (isTypeOnly === undefined || typeof isTypeOnly === "boolean") && - (typeof name !== "boolean") && - (typeof moduleReference !== "string"), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (isTypeOnly === undefined || typeof isTypeOnly === "boolean") + && (typeof name !== "boolean") + && (typeof moduleReference !== "string"), 1: ([, decorators, modifiers, isTypeOnly, name, moduleReference]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (isTypeOnly === undefined || typeof isTypeOnly === "boolean") && - (typeof name === "string" || isIdentifier(name)) && - (moduleReference !== undefined && isModuleReference(moduleReference)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (isTypeOnly === undefined || typeof isTypeOnly === "boolean") + && (typeof name === "string" || isIdentifier(name)) + && (moduleReference !== undefined && isModuleReference(moduleReference)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1218,28 +2095,39 @@ namespace ts { factory.createImportDeclaration = buildOverload("createImportDeclaration") .overload({ - 0(modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause?: AssertClause): ImportDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause?: AssertClause, + ): ImportDeclaration { return createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause?: AssertClause): ImportDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause?: AssertClause, + ): ImportDeclaration { return createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause); }, }) .bind({ 0: ([modifiers, importClause, moduleSpecifier, assertClause, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (importClause === undefined || !isArray(importClause)) && - (moduleSpecifier !== undefined && isExpression(moduleSpecifier)) && - (assertClause === undefined || isAssertClause(assertClause)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (importClause === undefined || !isArray(importClause)) + && (moduleSpecifier !== undefined && isExpression(moduleSpecifier)) + && (assertClause === undefined || isAssertClause(assertClause)), 1: ([decorators, modifiers, importClause, moduleSpecifier, assertClause]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (importClause === undefined || isImportClause(importClause)) && - (moduleSpecifier !== undefined && isExpression(moduleSpecifier)) && - (assertClause === undefined || isAssertClause(assertClause)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (importClause === undefined || isImportClause(importClause)) + && (moduleSpecifier !== undefined && isExpression(moduleSpecifier)) + && (assertClause === undefined || isAssertClause(assertClause)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1248,28 +2136,41 @@ namespace ts { factory.updateImportDeclaration = buildOverload("updateImportDeclaration") .overload({ - 0(node: ImportDeclaration, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause: AssertClause | undefined): ImportDeclaration { + 0( + node: ImportDeclaration, + modifiers: readonly Modifier[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause: AssertClause | undefined, + ): ImportDeclaration { return updateImportDeclaration(node, modifiers, importClause, moduleSpecifier, assertClause); }, - 1(node: ImportDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause: AssertClause | undefined): ImportDeclaration { + 1( + node: ImportDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause: AssertClause | undefined, + ): ImportDeclaration { return updateImportDeclaration(node, modifiers, importClause, moduleSpecifier, assertClause); }, }) .bind({ 0: ([, modifiers, importClause, moduleSpecifier, assertClause, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (importClause === undefined || !isArray(importClause)) && - (moduleSpecifier === undefined || isExpression(moduleSpecifier)) && - (assertClause === undefined || isAssertClause(assertClause)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (importClause === undefined || !isArray(importClause)) + && (moduleSpecifier === undefined || isExpression(moduleSpecifier)) + && (assertClause === undefined || isAssertClause(assertClause)), 1: ([, decorators, modifiers, importClause, moduleSpecifier, assertClause]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (importClause === undefined || isImportClause(importClause)) && - (moduleSpecifier !== undefined && isExpression(moduleSpecifier)) && - (assertClause === undefined || isAssertClause(assertClause)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (importClause === undefined || isImportClause(importClause)) + && (moduleSpecifier !== undefined && isExpression(moduleSpecifier)) + && (assertClause === undefined || isAssertClause(assertClause)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1278,26 +2179,35 @@ namespace ts { factory.createExportAssignment = buildOverload("createExportAssignment") .overload({ - 0(modifiers: readonly Modifier[] | undefined, isExportEquals: boolean | undefined, expression: Expression): ExportAssignment { + 0( + modifiers: readonly Modifier[] | undefined, + isExportEquals: boolean | undefined, + expression: Expression, + ): ExportAssignment { return createExportAssignment(modifiers, isExportEquals, expression); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isExportEquals: boolean | undefined, expression: Expression): ExportAssignment { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isExportEquals: boolean | undefined, + expression: Expression, + ): ExportAssignment { return createExportAssignment(modifiers, isExportEquals, expression); }, }) .bind({ 0: ([modifiers, isExportEquals, expression, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (isExportEquals === undefined || typeof isExportEquals === "boolean") && - (typeof expression === "object"), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (isExportEquals === undefined || typeof isExportEquals === "boolean") + && (typeof expression === "object"), 1: ([decorators, modifiers, isExportEquals, expression]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (isExportEquals === undefined || typeof isExportEquals === "boolean") && - (expression !== undefined && isExpression(expression)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (isExportEquals === undefined || typeof isExportEquals === "boolean") + && (expression !== undefined && isExpression(expression)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1306,24 +2216,33 @@ namespace ts { factory.updateExportAssignment = buildOverload("updateExportAssignment") .overload({ - 0(node: ExportAssignment, modifiers: readonly Modifier[] | undefined, expression: Expression): ExportAssignment { + 0( + node: ExportAssignment, + modifiers: readonly Modifier[] | undefined, + expression: Expression, + ): ExportAssignment { return updateExportAssignment(node, modifiers, expression); }, - 1(node: ExportAssignment, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, expression: Expression): ExportAssignment { + 1( + node: ExportAssignment, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + expression: Expression, + ): ExportAssignment { return updateExportAssignment(node, modifiers, expression); }, }) .bind({ 0: ([, modifiers, expression, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (expression !== undefined && !isArray(expression)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (expression !== undefined && !isArray(expression)), 1: ([, decorators, modifiers, expression]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (expression !== undefined && isExpression(expression)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (expression !== undefined && isExpression(expression)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1332,30 +2251,43 @@ namespace ts { factory.createExportDeclaration = buildOverload("createExportDeclaration") .overload({ - 0(modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, assertClause?: AssertClause): ExportDeclaration { + 0( + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier?: Expression, + assertClause?: AssertClause, + ): ExportDeclaration { return createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause); }, - 1(_decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, assertClause?: AssertClause): ExportDeclaration { + 1( + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier?: Expression, + assertClause?: AssertClause, + ): ExportDeclaration { return createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause); }, }) .bind({ 0: ([modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (typeof isTypeOnly === "boolean") && - (typeof exportClause !== "boolean") && - (moduleSpecifier === undefined || isExpression(moduleSpecifier)) && - (assertClause === undefined || isAssertClause(assertClause)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (typeof isTypeOnly === "boolean") + && (typeof exportClause !== "boolean") + && (moduleSpecifier === undefined || isExpression(moduleSpecifier)) + && (assertClause === undefined || isAssertClause(assertClause)), 1: ([decorators, modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (typeof isTypeOnly === "boolean") && - (exportClause === undefined || isNamedExportBindings(exportClause)) && - (moduleSpecifier === undefined || isExpression(moduleSpecifier)) && - (assertClause === undefined || isAssertClause(assertClause)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (typeof isTypeOnly === "boolean") + && (exportClause === undefined || isNamedExportBindings(exportClause)) + && (moduleSpecifier === undefined || isExpression(moduleSpecifier)) + && (assertClause === undefined || isAssertClause(assertClause)), }) .deprecate({ 1: DISALLOW_DECORATORS, @@ -1364,30 +2296,59 @@ namespace ts { factory.updateExportDeclaration = buildOverload("updateExportDeclaration") .overload({ - 0(node: ExportDeclaration, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, assertClause: AssertClause | undefined): ExportDeclaration { - return updateExportDeclaration(node, modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause); - }, - - 1(node: ExportDeclaration, _decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, assertClause: AssertClause | undefined): ExportDeclaration { - return updateExportDeclaration(node, modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause); + 0( + node: ExportDeclaration, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier: Expression | undefined, + assertClause: AssertClause | undefined, + ): ExportDeclaration { + return updateExportDeclaration( + node, + modifiers, + isTypeOnly, + exportClause, + moduleSpecifier, + assertClause, + ); + }, + + 1( + node: ExportDeclaration, + _decorators: readonly Decorator[] | undefined, + modifiers: readonly Modifier[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier: Expression | undefined, + assertClause: AssertClause | undefined, + ): ExportDeclaration { + return updateExportDeclaration( + node, + modifiers, + isTypeOnly, + exportClause, + moduleSpecifier, + assertClause, + ); }, }) .bind({ 0: ([, modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause, other]) => - (other === undefined) && - (modifiers === undefined || every(modifiers, isModifier)) && - (typeof isTypeOnly === "boolean") && - (typeof exportClause !== "boolean") && - (moduleSpecifier === undefined || isExpression(moduleSpecifier)) && - (assertClause === undefined || isAssertClause(assertClause)), + (other === undefined) + && (modifiers === undefined || every(modifiers, isModifier)) + && (typeof isTypeOnly === "boolean") + && (typeof exportClause !== "boolean") + && (moduleSpecifier === undefined || isExpression(moduleSpecifier)) + && (assertClause === undefined || isAssertClause(assertClause)), 1: ([, decorators, modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause]) => - (decorators === undefined || every(decorators, isDecorator)) && - (modifiers === undefined || isArray(modifiers)) && - (typeof isTypeOnly === "boolean") && - (exportClause === undefined || isNamedExportBindings(exportClause)) && - (moduleSpecifier === undefined || isExpression(moduleSpecifier)) && - (assertClause === undefined || isAssertClause(assertClause)), + (decorators === undefined || every(decorators, isDecorator)) + && (modifiers === undefined || isArray(modifiers)) + && (typeof isTypeOnly === "boolean") + && (exportClause === undefined || isNamedExportBindings(exportClause)) + && (moduleSpecifier === undefined || isExpression(moduleSpecifier)) + && (assertClause === undefined || isAssertClause(assertClause)), }) .deprecate({ 1: DISALLOW_DECORATORS, diff --git a/src/deprecatedCompat/deprecations.ts b/src/deprecatedCompat/deprecations.ts index 4544be2d96b34..ce032b086ee5b 100644 --- a/src/deprecatedCompat/deprecations.ts +++ b/src/deprecatedCompat/deprecations.ts @@ -22,7 +22,9 @@ namespace ts { type OverloadKeys = Extract; /** Extracts a union of the potential parameter lists for each overload. */ - type OverloadParameters = Parameters<{ [P in OverloadKeys]: T[P]; }[OverloadKeys]>; + type OverloadParameters = Parameters< + { [P in OverloadKeys]: T[P]; }[OverloadKeys] + >; // NOTE: the following doesn't work in TS 4.4 (the current LKG in main), so we have to use UnionToIntersection for now /** Constructs an intersection of each overload in a set of overload definitions. */ @@ -33,12 +35,19 @@ namespace ts { type OverloadFunction = UnionToIntersection; /** Maps each ordinal in a set of overload definitions to a function that can be used to bind its arguments. */ - type OverloadBinders = { [P in OverloadKeys]: (args: OverloadParameters) => boolean | undefined; }; + type OverloadBinders = { + [P in OverloadKeys]: (args: OverloadParameters) => boolean | undefined; + }; /** Defines deprecations for specific overloads by ordinal. */ type OverloadDeprecations = { [P in OverloadKeys]?: DeprecationOptions; }; - export function createOverload(name: string, overloads: T, binder: OverloadBinders, deprecations?: OverloadDeprecations) { + export function createOverload( + name: string, + overloads: T, + binder: OverloadBinders, + deprecations?: OverloadDeprecations, + ) { Object.defineProperty(call, "name", { ...Object.getOwnPropertyDescriptor(call, "name"), value: name }); if (deprecations) { diff --git a/src/executeCommandLine/executeCommandLine.ts b/src/executeCommandLine/executeCommandLine.ts index e0496960969aa..19eca1b1b4713 100644 --- a/src/executeCommandLine/executeCommandLine.ts +++ b/src/executeCommandLine/executeCommandLine.ts @@ -60,9 +60,9 @@ namespace ts { existing: DiagnosticReporter, options: CompilerOptions | BuildOptions, ): DiagnosticReporter { - return shouldBePretty(sys, options) ? - createDiagnosticReporter(sys, /*pretty*/ true) : - existing; + return shouldBePretty(sys, options) + ? createDiagnosticReporter(sys, /*pretty*/ true) + : existing; } function defaultIsPretty(sys: System) { @@ -78,9 +78,9 @@ namespace ts { function getOptionsForHelp(commandLine: ParsedCommandLine) { // Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch") - return !!commandLine.options.all ? - sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) : - filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView); + return !!commandLine.options.all + ? sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) + : filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView); } function printVersion(sys: System) { @@ -102,9 +102,11 @@ namespace ts { return `\x1b[1m${str}\x1b[22m`; } - const isWindows = sys.getEnvironmentVariable("OS") && stringContains(sys.getEnvironmentVariable("OS").toLowerCase(), "windows"); + const isWindows = sys.getEnvironmentVariable("OS") + && stringContains(sys.getEnvironmentVariable("OS").toLowerCase(), "windows"); const isWindowsTerminal = sys.getEnvironmentVariable("WT_SESSION"); - const isVSCode = sys.getEnvironmentVariable("TERM_PROGRAM") && sys.getEnvironmentVariable("TERM_PROGRAM") === "vscode"; + const isVSCode = sys.getEnvironmentVariable("TERM_PROGRAM") + && sys.getEnvironmentVariable("TERM_PROGRAM") === "vscode"; function blue(str: string) { // Effectively Powershell and Command prompt users use cyan instead @@ -119,7 +121,8 @@ namespace ts { // There are ~3 types of terminal color support: 16 colors, 256 and 16m colors // If there is richer color support, e.g. 256+ we can use extended ANSI codes which are not just generic 'blue' // but a 'lighter blue' which is closer to the blue in the TS logo. - const supportsRicherColors = sys.getEnvironmentVariable("COLORTERM") === "truecolor" || sys.getEnvironmentVariable("TERM") === "xterm-256color"; + const supportsRicherColors = sys.getEnvironmentVariable("COLORTERM") === "truecolor" + || sys.getEnvironmentVariable("TERM") === "xterm-256color"; function blueBackground(str: string) { if (supportsRicherColors) { return `\x1B[48;5;68m${str}\x1B[39;49m`; @@ -143,7 +146,12 @@ namespace ts { return `--${option.name}${option.shortName ? `, -${option.shortName}` : ""}`; } - function generateOptionOutput(sys: System, option: CommandLineOption, rightAlignOfLeft: number, leftAlignOfRight: number) { + function generateOptionOutput( + sys: System, + option: CommandLineOption, + rightAlignOfLeft: number, + leftAlignOfRight: number, + ) { interface ValueCandidate { // "one or more" or "any of" valueType: string; @@ -172,13 +180,43 @@ namespace ts { if (option.description) { description = getDiagnosticText(option.description); } - text.push(...getPrettyOutput(name, description, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ true), sys.newLine); + text.push( + ...getPrettyOutput( + name, + description, + rightAlignOfLeft, + leftAlignOfRight, + terminalWidth, + /*colorLeft*/ true, + ), + sys.newLine, + ); if (showAdditionalInfoOutput(valueCandidates, option)) { if (valueCandidates) { - text.push(...getPrettyOutput(valueCandidates.valueType, valueCandidates.possibleValues, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ false), sys.newLine); + text.push( + ...getPrettyOutput( + valueCandidates.valueType, + valueCandidates.possibleValues, + rightAlignOfLeft, + leftAlignOfRight, + terminalWidth, + /*colorLeft*/ false, + ), + sys.newLine, + ); } if (defaultValueDescription) { - text.push(...getPrettyOutput(getDiagnosticText(Diagnostics.default_Colon), defaultValueDescription, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ false), sys.newLine); + text.push( + ...getPrettyOutput( + getDiagnosticText(Diagnostics.default_Colon), + defaultValueDescription, + rightAlignOfLeft, + leftAlignOfRight, + terminalWidth, + /*colorLeft*/ false, + ), + sys.newLine, + ); } } text.push(sys.newLine); @@ -219,19 +257,32 @@ namespace ts { : String(defaultValue); } - function showAdditionalInfoOutput(valueCandidates: ValueCandidate | undefined, option: CommandLineOption): boolean { + function showAdditionalInfoOutput( + valueCandidates: ValueCandidate | undefined, + option: CommandLineOption, + ): boolean { const ignoreValues = ["string"]; const ignoredDescriptions = [undefined, "false", "n/a"]; const defaultValueDescription = option.defaultValueDescription; if (option.category === Diagnostics.Command_line_Options) return false; - if (contains(ignoreValues, valueCandidates?.possibleValues) && contains(ignoredDescriptions, defaultValueDescription)) { + if ( + contains(ignoreValues, valueCandidates?.possibleValues) + && contains(ignoredDescriptions, defaultValueDescription) + ) { return false; } return true; } - function getPrettyOutput(left: string, right: string, rightAlignOfLeft: number, leftAlignOfRight: number, terminalWidth: number, colorLeft: boolean) { + function getPrettyOutput( + left: string, + right: string, + rightAlignOfLeft: number, + leftAlignOfRight: number, + terminalWidth: number, + colorLeft: boolean, + ) { const res = []; let isFirstLine = true; let remainRight = right; @@ -341,7 +392,14 @@ namespace ts { return lines; } - function generateSectionOptionsOutput(sys: System, sectionName: string, options: readonly CommandLineOption[], subCategory: boolean, beforeOptionsDescription?: string, afterOptionsDescription?: string) { + function generateSectionOptionsOutput( + sys: System, + sectionName: string, + options: readonly CommandLineOption[], + subCategory: boolean, + beforeOptionsDescription?: string, + afterOptionsDescription?: string, + ) { let res: string[] = []; res.push(createColors(sys).bold(sectionName) + sys.newLine + sys.newLine); if (beforeOptionsDescription) { @@ -376,24 +434,66 @@ namespace ts { function printEasyHelp(sys: System, simpleOptions: readonly CommandLineOption[]) { const colors = createColors(sys); - let output: string[] = [...getHeader(sys, `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)]; + let output: string[] = [ + ...getHeader( + sys, + `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${ + getDiagnosticText(Diagnostics.Version_0, version) + }`, + ), + ]; output.push(colors.bold(getDiagnosticText(Diagnostics.COMMON_COMMANDS)) + sys.newLine + sys.newLine); example("tsc", Diagnostics.Compiles_the_current_project_tsconfig_json_in_the_working_directory); - example("tsc app.ts util.ts", Diagnostics.Ignoring_tsconfig_json_compiles_the_specified_files_with_default_compiler_options); + example( + "tsc app.ts util.ts", + Diagnostics.Ignoring_tsconfig_json_compiles_the_specified_files_with_default_compiler_options, + ); example("tsc -b", Diagnostics.Build_a_composite_project_in_the_working_directory); - example("tsc --init", Diagnostics.Creates_a_tsconfig_json_with_the_recommended_settings_in_the_working_directory); - example("tsc -p ./path/to/tsconfig.json", Diagnostics.Compiles_the_TypeScript_project_located_at_the_specified_path); - example("tsc --help --all", Diagnostics.An_expanded_version_of_this_information_showing_all_possible_compiler_options); - example(["tsc --noEmit", "tsc --target esnext"], Diagnostics.Compiles_the_current_project_with_additional_settings); + example( + "tsc --init", + Diagnostics.Creates_a_tsconfig_json_with_the_recommended_settings_in_the_working_directory, + ); + example( + "tsc -p ./path/to/tsconfig.json", + Diagnostics.Compiles_the_TypeScript_project_located_at_the_specified_path, + ); + example( + "tsc --help --all", + Diagnostics.An_expanded_version_of_this_information_showing_all_possible_compiler_options, + ); + example( + ["tsc --noEmit", "tsc --target esnext"], + Diagnostics.Compiles_the_current_project_with_additional_settings, + ); - const cliCommands = simpleOptions.filter(opt => opt.isCommandLineOnly || opt.category === Diagnostics.Command_line_Options); + const cliCommands = simpleOptions.filter(opt => + opt.isCommandLineOnly || opt.category === Diagnostics.Command_line_Options + ); const configOpts = simpleOptions.filter(opt => !contains(cliCommands, opt)); output = [ ...output, - ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.COMMAND_LINE_FLAGS), cliCommands, /*subCategory*/ false, /* beforeOptionsDescription */ undefined, /* afterOptionsDescription*/ undefined), - ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.COMMON_COMPILER_OPTIONS), configOpts, /*subCategory*/ false, /* beforeOptionsDescription */ undefined, formatMessage(/*_dummy*/ undefined, Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc")), + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.COMMAND_LINE_FLAGS), + cliCommands, + /*subCategory*/ false, + /* beforeOptionsDescription */ undefined, + /* afterOptionsDescription*/ undefined, + ), + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.COMMON_COMPILER_OPTIONS), + configOpts, + /*subCategory*/ false, + /* beforeOptionsDescription */ undefined, + formatMessage( + /*_dummy*/ undefined, + Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, + "https://aka.ms/tsc", + ), + ), ]; for (const line of output) { @@ -409,19 +509,92 @@ namespace ts { } } - function printAllHelp(sys: System, compilerOptions: readonly CommandLineOption[], buildOptions: readonly CommandLineOption[], watchOptions: readonly CommandLineOption[]) { - let output: string[] = [...getHeader(sys, `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)]; - output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.ALL_COMPILER_OPTIONS), compilerOptions, /*subCategory*/ true, /* beforeOptionsDescription */ undefined, formatMessage(/*_dummy*/ undefined, Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc"))]; - output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.WATCH_OPTIONS), watchOptions, /*subCategory*/ false, getDiagnosticText(Diagnostics.Including_watch_w_will_start_watching_the_current_project_for_the_file_changes_Once_set_you_can_config_watch_mode_with_Colon))]; - output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), buildOptions, /*subCategory*/ false, formatMessage(/*_dummy*/ undefined, Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))]; + function printAllHelp( + sys: System, + compilerOptions: readonly CommandLineOption[], + buildOptions: readonly CommandLineOption[], + watchOptions: readonly CommandLineOption[], + ) { + let output: string[] = [ + ...getHeader( + sys, + `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${ + getDiagnosticText(Diagnostics.Version_0, version) + }`, + ), + ]; + output = [ + ...output, + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.ALL_COMPILER_OPTIONS), + compilerOptions, + /*subCategory*/ true, + /* beforeOptionsDescription */ undefined, + formatMessage( + /*_dummy*/ undefined, + Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, + "https://aka.ms/tsc", + ), + ), + ]; + output = [ + ...output, + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.WATCH_OPTIONS), + watchOptions, + /*subCategory*/ false, + getDiagnosticText( + Diagnostics + .Including_watch_w_will_start_watching_the_current_project_for_the_file_changes_Once_set_you_can_config_watch_mode_with_Colon, + ), + ), + ]; + output = [ + ...output, + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.BUILD_OPTIONS), + buildOptions, + /*subCategory*/ false, + formatMessage( + /*_dummy*/ undefined, + Diagnostics + .Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, + "https://aka.ms/tsc-composite-builds", + ), + ), + ]; for (const line of output) { sys.write(line); } } function printBuildHelp(sys: System, buildOptions: readonly CommandLineOption[]) { - let output: string[] = [...getHeader(sys, `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)]; - output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), buildOptions, /*subCategory*/ false, formatMessage(/*_dummy*/ undefined, Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))]; + let output: string[] = [ + ...getHeader( + sys, + `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${ + getDiagnosticText(Diagnostics.Version_0, version) + }`, + ), + ]; + output = [ + ...output, + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.BUILD_OPTIONS), + buildOptions, + /*subCategory*/ false, + formatMessage( + /*_dummy*/ undefined, + Diagnostics + .Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, + "https://aka.ms/tsc-composite-builds", + ), + ), + ]; for (const line of output) { sys.write(line); } @@ -466,7 +639,9 @@ namespace ts { ) { let reportDiagnostic = createDiagnosticReporter(sys); if (commandLine.options.build) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_build_must_be_the_first_command_line_argument)); + reportDiagnostic( + createCompilerDiagnostic(Diagnostics.Option_build_must_be_the_first_command_line_argument), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } @@ -499,13 +674,19 @@ namespace ts { } if (commandLine.options.watch && commandLine.options.listFilesOnly) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "listFilesOnly")); + reportDiagnostic( + createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "listFilesOnly"), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (commandLine.options.project) { if (commandLine.fileNames.length !== 0) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line)); + reportDiagnostic( + createCompilerDiagnostic( + Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line, + ), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } @@ -513,14 +694,24 @@ namespace ts { if (!fileOrDirectory /* current directory "." */ || sys.directoryExists(fileOrDirectory)) { configFileName = combinePaths(fileOrDirectory, "tsconfig.json"); if (!sys.fileExists(configFileName)) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, commandLine.options.project)); + reportDiagnostic( + createCompilerDiagnostic( + Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, + commandLine.options.project, + ), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } } else { configFileName = fileOrDirectory; if (!sys.fileExists(configFileName)) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, commandLine.options.project)); + reportDiagnostic( + createCompilerDiagnostic( + Diagnostics.The_specified_path_does_not_exist_Colon_0, + commandLine.options.project, + ), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } } @@ -532,7 +723,12 @@ namespace ts { if (commandLine.fileNames.length === 0 && !configFileName) { if (commandLine.options.showConfig) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_current_directory_Colon_0, normalizePath(sys.getCurrentDirectory()))); + reportDiagnostic( + createCompilerDiagnostic( + Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_current_directory_Colon_0, + normalizePath(sys.getCurrentDirectory()), + ), + ); } else { printVersion(sys); @@ -548,7 +744,14 @@ namespace ts { ); if (configFileName) { const extendedConfigCache = new Map(); - const configParseResult = parseConfigFileWithSystem(configFileName, commandLineOptions, extendedConfigCache, commandLine.watchOptions, sys, reportDiagnostic)!; // TODO: GH#18217 + const configParseResult = parseConfigFileWithSystem( + configFileName, + commandLineOptions, + extendedConfigCache, + commandLine.watchOptions, + sys, + reportDiagnostic, + )!; // TODO: GH#18217 if (commandLineOptions.showConfig) { if (configParseResult.errors.length !== 0) { reportDiagnostic = updateReportDiagnostic( @@ -560,7 +763,9 @@ namespace ts { return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } // eslint-disable-next-line no-null/no-null - sys.write(JSON.stringify(convertToTSConfig(configParseResult, configFileName, sys), null, 4) + sys.newLine); + sys.write( + JSON.stringify(convertToTSConfig(configParseResult, configFileName, sys), null, 4) + sys.newLine, + ); return sys.exit(ExitStatus.Success); } reportDiagnostic = updateReportDiagnostic( @@ -600,7 +805,13 @@ namespace ts { else { if (commandLineOptions.showConfig) { // eslint-disable-next-line no-null/no-null - sys.write(JSON.stringify(convertToTSConfig(commandLine, combinePaths(currentDirectory, "tsconfig.json"), sys), null, 4) + sys.newLine); + sys.write( + JSON.stringify( + convertToTSConfig(commandLine, combinePaths(currentDirectory, "tsconfig.json"), sys), + null, + 4, + ) + sys.newLine, + ); return sys.exit(ExitStatus.Success); } reportDiagnostic = updateReportDiagnostic( @@ -640,7 +851,9 @@ namespace ts { export function isBuild(commandLineArgs: readonly string[]) { if (commandLineArgs.length > 0 && commandLineArgs[0].charCodeAt(0) === CharacterCodes.minus) { - const firstOption = commandLineArgs[0].slice(commandLineArgs[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase(); + const firstOption = commandLineArgs[0].slice( + commandLineArgs[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1, + ).toLowerCase(); return firstOption === "build" || firstOption === "b"; } return false; @@ -693,7 +906,9 @@ namespace ts { function reportWatchModeWithoutSysSupport(sys: System, reportDiagnostic: DiagnosticReporter) { if (!sys.watchFile || !sys.watchDirectory) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch")); + reportDiagnostic( + createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), + ); sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); return true; } @@ -737,7 +952,9 @@ namespace ts { } if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build")); + reportDiagnostic( + createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } @@ -756,8 +973,8 @@ namespace ts { buildHost.onWatchStatusChange = (d, newLine, options, errorCount) => { onWatchStatusChange?.(d, newLine, options, errorCount); if ( - d.code === Diagnostics.Found_0_errors_Watching_for_file_changes.code || - d.code === Diagnostics.Found_1_error_Watching_for_file_changes.code + d.code === Diagnostics.Found_0_errors_Watching_for_file_changes.code + || d.code === Diagnostics.Found_1_error_Watching_for_file_changes.code ) { reportSolutionBuilderTimes(builder, solutionPerformance); } @@ -783,10 +1000,13 @@ namespace ts { return sys.exit(exitStatus); } - function createReportErrorSummary(sys: System, options: CompilerOptions | BuildOptions): ReportEmitErrorSummary | undefined { - return shouldBePretty(sys, options) ? - (errorCount, filesInError) => sys.write(getErrorSummaryText(errorCount, filesInError, sys.newLine, sys)) : - undefined; + function createReportErrorSummary( + sys: System, + options: CompilerOptions | BuildOptions, + ): ReportEmitErrorSummary | undefined { + return shouldBePretty(sys, options) + ? (errorCount, filesInError) => sys.write(getErrorSummaryText(errorCount, filesInError, sys.newLine, sys)) + : undefined; } function performCompilation( @@ -861,14 +1081,32 @@ namespace ts { buildHost.afterEmitBundle = cb; } - function updateCreateProgram(sys: System, host: { createProgram: CreateProgram; }, isBuildMode: boolean) { + function updateCreateProgram( + sys: System, + host: { createProgram: CreateProgram; }, + isBuildMode: boolean, + ) { const compileUsingBuilder = host.createProgram; - host.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) => { + host.createProgram = ( + rootNames, + options, + host, + oldProgram, + configFileParsingDiagnostics, + projectReferences, + ) => { Debug.assert(rootNames !== undefined || (options === undefined && !!oldProgram)); if (options !== undefined) { enableStatisticsAndTracing(sys, options, isBuildMode); } - return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences); + return compileUsingBuilder( + rootNames, + options, + host, + oldProgram, + configFileParsingDiagnostics, + projectReferences, + ); }; } @@ -981,13 +1219,21 @@ namespace ts { if (!solutionPerformance) return; if (!performance.isEnabled()) { - sys.write(Diagnostics.Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found.message + "\n"); + sys.write( + Diagnostics + .Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found + .message + "\n", + ); return; } const statistics: Statistic[] = []; statistics.push( - { name: "Projects in scope", value: getBuildOrderFromAnyBuildOrder(builder.getBuildOrder()).length, type: StatisticType.count }, + { + name: "Projects in scope", + value: getBuildOrderFromAnyBuildOrder(builder.getBuildOrder()).length, + type: StatisticType.count, + }, ); reportSolutionBuilderCountStatistic("SolutionBuilder::Projects built"); reportSolutionBuilderCountStatistic("SolutionBuilder::Timestamps only updates"); @@ -997,7 +1243,13 @@ namespace ts { statistics.push(s); }); performance.forEachMeasure((name, duration) => { - if (isSolutionMarkOrMeasure(name)) statistics.push({ name: `${getNameFromSolutionBuilderMarkOrMeasure(name)} time`, value: duration, type: StatisticType.time }); + if (isSolutionMarkOrMeasure(name)) { + statistics.push({ + name: `${getNameFromSolutionBuilderMarkOrMeasure(name)} time`, + value: duration, + type: StatisticType.time, + }); + } }); performance.disable(); performance.enable(); @@ -1007,7 +1259,11 @@ namespace ts { function reportSolutionBuilderCountStatistic(name: string) { const value = performance.getCount(name); if (value) { - statistics.push({ name: getNameFromSolutionBuilderMarkOrMeasure(name), value, type: StatisticType.count }); + statistics.push({ + name: getNameFromSolutionBuilderMarkOrMeasure(name), + value, + type: StatisticType.count, + }); } } @@ -1030,7 +1286,11 @@ namespace ts { } if (canTrace(system, compilerOptions)) { - startTracing(isBuildMode ? "build" : "project", compilerOptions.generateTrace!, compilerOptions.configFilePath); + startTracing( + isBuildMode ? "build" : "project", + compilerOptions.generateTrace!, + compilerOptions.configFilePath, + ); } } @@ -1067,7 +1327,10 @@ namespace ts { reportCountStatistic("Instantiations", program.getInstantiationCount()); if (memoryUsed >= 0) { - reportStatisticalValue({ name: "Memory used", value: memoryUsed, type: StatisticType.memory }, /*aggregate*/ true); + reportStatisticalValue( + { name: "Memory used", value: memoryUsed, type: StatisticType.memory }, + /*aggregate*/ true, + ); } const isPerformanceEnabled = performance.isEnabled(); @@ -1083,7 +1346,9 @@ namespace ts { reportCountStatistic("Strict subtype cache size", caches.strictSubtype); if (isPerformanceEnabled) { performance.forEachMeasure((name, duration) => { - if (!isSolutionMarkOrMeasure(name)) reportTimeStatistic(`${name} time`, duration, /*aggregate*/ true); + if (!isSolutionMarkOrMeasure(name)) { + reportTimeStatistic(`${name} time`, duration, /*aggregate*/ true); + } }); } } @@ -1104,7 +1369,11 @@ namespace ts { } reportAllStatistics(sys, statistics); if (!isPerformanceEnabled) { - sys.write(Diagnostics.Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found.message + "\n"); + sys.write( + Diagnostics + .Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found + .message + "\n", + ); } else { if (solutionPerformance) { @@ -1151,7 +1420,9 @@ namespace ts { } for (const s of statistics) { - sys.write(padRight(s.name + ":", nameSize + 2) + padLeft(statisticValue(s).toString(), valueSize) + sys.newLine); + sys.write( + padRight(s.name + ":", nameSize + 2) + padLeft(statisticValue(s).toString(), valueSize) + sys.newLine, + ); } } @@ -1177,7 +1448,9 @@ namespace ts { const currentDirectory = sys.getCurrentDirectory(); const file = normalizePath(combinePaths(currentDirectory, "tsconfig.json")); if (sys.fileExists(file)) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file)); + reportDiagnostic( + createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file), + ); } else { sys.writeFile(file, generateTSConfig(options, fileNames, sys.newLine)); diff --git a/src/harness/client.ts b/src/harness/client.ts index b4fea41e94b2f..7273a814f3a30 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -22,14 +22,20 @@ namespace ts.server { Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response."); const contentLengthText = lines[0]; - Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header."); + Debug.assert( + contentLengthText.indexOf(contentLengthPrefix) === 0, + "Malformed response: Response text did not contain content-length header.", + ); const contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length)); // Read the body const responseBody = lines[2]; // Verify content length - Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length."); + Debug.assert( + responseBody.length + 1 === contentLength, + "Malformed response: Content length did not match the response's body length.", + ); return responseBody; } @@ -107,7 +113,10 @@ namespace ts.server { } } catch (e) { - throw new Error("Malformed response: Failed to parse server response: " + lastMessage + ". \r\n Error details: " + e.message); + throw new Error( + "Malformed response: Failed to parse server response: " + lastMessage + + ". \r\n Error details: " + e.message, + ); } } @@ -116,7 +125,10 @@ namespace ts.server { throw new Error("Error " + response.message); } - Debug.assert(response.request_seq === request.seq, "Malformed response: response sequence number did not match request sequence number."); + Debug.assert( + response.request_seq === request.seq, + "Malformed response: response sequence number did not match request sequence number.", + ); Debug.assert(expectEmptyBody || !!response.body, "Malformed response: Unexpected empty response body."); Debug.assert(!expectEmptyBody || !response.body, "Malformed response: Unexpected non-empty response body."); @@ -155,7 +167,12 @@ namespace ts.server { this.processRequest(CommandNames.Close, args); } - createChangeFileRequestArgs(fileName: string, start: number, end: number, insertString: string): protocol.ChangeRequestArgs { + createChangeFileRequestArgs( + fileName: string, + start: number, + end: number, + insertString: string, + ): protocol.ChangeRequestArgs { return { ...this.createFileLocationRequestArgsWithEndLineAndOffset(fileName, start, end), insertString }; } @@ -182,7 +199,8 @@ namespace ts.server { kindModifiers: body.kindModifiers, textSpan: this.decodeSpan(body, fileName), displayParts: [{ kind: "text", text: body.displayString }], - documentation: typeof body.documentation === "string" ? [{ kind: "text", text: body.documentation }] : body.documentation, + documentation: typeof body.documentation === "string" ? [{ kind: "text", text: body.documentation }] + : body.documentation, tags: this.decodeLinkDisplayParts(body.tags), }; } @@ -199,7 +217,11 @@ namespace ts.server { }; } - getCompletionsAtPosition(fileName: string, position: number, _preferences: UserPreferences | undefined): CompletionInfo { + getCompletionsAtPosition( + fileName: string, + position: number, + _preferences: UserPreferences | undefined, + ): CompletionInfo { // Not passing along 'preferences' because server should already have those from the 'configure' command const args: protocol.CompletionsRequestArgs = this.createFileLocationRequestArgs(fileName, position); @@ -212,7 +234,11 @@ namespace ts.server { isNewIdentifierLocation: response.body!.isNewIdentifierLocation, entries: response.body!.entries.map(entry => { // TODO: GH#18217 if (entry.replacementSpan !== undefined) { - const res: CompletionEntry = { ...entry, data: entry.data as any, replacementSpan: this.decodeSpan(entry.replacementSpan, fileName) }; + const res: CompletionEntry = { + ...entry, + data: entry.data as any, + replacementSpan: this.decodeSpan(entry.replacementSpan, fileName), + }; return res; } @@ -221,10 +247,24 @@ namespace ts.server { }; } - getCompletionEntryDetails(fileName: string, position: number, entryName: string, _options: FormatCodeOptions | FormatCodeSettings | undefined, source: string | undefined, _preferences: UserPreferences | undefined, data: unknown): CompletionEntryDetails { - const args: protocol.CompletionDetailsRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), entryNames: [{ name: entryName, source, data }] }; + getCompletionEntryDetails( + fileName: string, + position: number, + entryName: string, + _options: FormatCodeOptions | FormatCodeSettings | undefined, + source: string | undefined, + _preferences: UserPreferences | undefined, + data: unknown, + ): CompletionEntryDetails { + const args: protocol.CompletionDetailsRequestArgs = { + ...this.createFileLocationRequestArgs(fileName, position), + entryNames: [{ name: entryName, source, data }], + }; - const request = this.processRequest(CommandNames.CompletionDetailsFull, args); + const request = this.processRequest( + CommandNames.CompletionDetailsFull, + args, + ); const response = this.processResponse(request); Debug.assert(response.body.length === 1, "Unexpected length of completion details response body."); return response.body[0]; @@ -256,8 +296,17 @@ namespace ts.server { })); } - getFormattingEditsForRange(file: string, start: number, end: number, _options: FormatCodeOptions): TextChange[] { - const args: protocol.FormatRequestArgs = this.createFileLocationRequestArgsWithEndLineAndOffset(file, start, end); + getFormattingEditsForRange( + file: string, + start: number, + end: number, + _options: FormatCodeOptions, + ): TextChange[] { + const args: protocol.FormatRequestArgs = this.createFileLocationRequestArgsWithEndLineAndOffset( + file, + start, + end, + ); // TODO: handle FormatCodeOptions const request = this.processRequest(CommandNames.Format, args); @@ -267,11 +316,24 @@ namespace ts.server { } getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[] { - return this.getFormattingEditsForRange(fileName, 0, this.host.getScriptSnapshot(fileName)!.getLength(), options); + return this.getFormattingEditsForRange( + fileName, + 0, + this.host.getScriptSnapshot(fileName)!.getLength(), + options, + ); } - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, _options: FormatCodeOptions): TextChange[] { - const args: protocol.FormatOnKeyRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), key }; + getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + _options: FormatCodeOptions, + ): TextChange[] { + const args: protocol.FormatOnKeyRequestArgs = { + ...this.createFileLocationRequestArgs(fileName, position), + key, + }; // TODO: handle FormatCodeOptions const request = this.processRequest(CommandNames.Formatonkey, args); @@ -299,7 +361,10 @@ namespace ts.server { getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan { const args: protocol.FileLocationRequestArgs = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(CommandNames.DefinitionAndBoundSpan, args); + const request = this.processRequest( + CommandNames.DefinitionAndBoundSpan, + args, + ); const response = this.processResponse(request); const body = Debug.checkDefined(response.body); // TODO: GH#18217 @@ -335,7 +400,10 @@ namespace ts.server { getSourceDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfo[] { const args: protocol.FileLocationRequestArgs = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(CommandNames.FindSourceDefinition, args); + const request = this.processRequest( + CommandNames.FindSourceDefinition, + args, + ); const response = this.processResponse(request); const body = Debug.checkDefined(response.body); // TODO: GH#18217 @@ -386,7 +454,9 @@ namespace ts.server { } getFileReferences(fileName: string): ReferenceEntry[] { - const request = this.processRequest(CommandNames.FileReferences, { file: fileName }); + const request = this.processRequest(CommandNames.FileReferences, { + file: fileName, + }); const response = this.processResponse(request); return response.body!.refs.map(entry => ({ // TODO: GH#18217 @@ -414,13 +484,26 @@ namespace ts.server { } private getDiagnostics(file: string, command: CommandNames): DiagnosticWithLocation[] { - const request = this.processRequest(command, { file, includeLinePosition: true }); - const response = this.processResponse(request); + const request = this.processRequest< + | protocol.SyntacticDiagnosticsSyncRequest + | protocol.SemanticDiagnosticsSyncRequest + | protocol.SuggestionDiagnosticsSyncRequest + >(command, { file, includeLinePosition: true }); + const response = this.processResponse< + | protocol.SyntacticDiagnosticsSyncResponse + | protocol.SemanticDiagnosticsSyncResponse + | protocol.SuggestionDiagnosticsSyncResponse + >(request); const sourceText = getSnapshotText(this.host.getScriptSnapshot(file)!); const fakeSourceFile = { fileName: file, text: sourceText } as SourceFile; // Warning! This is a huge lie! return (response.body as protocol.DiagnosticWithLinePosition[]).map((entry): DiagnosticWithLocation => { - const category = firstDefined(Object.keys(DiagnosticCategory), id => isString(id) && entry.category === id.toLowerCase() ? (DiagnosticCategory as any)[id] : undefined); + const category = firstDefined( + Object.keys(DiagnosticCategory), + id => + isString(id) && entry.category === id.toLowerCase() ? (DiagnosticCategory as any)[id] + : undefined, + ); return { file: fakeSourceFile, start: entry.start, @@ -438,9 +521,19 @@ namespace ts.server { return notImplemented(); } - getRenameInfo(fileName: string, position: number, _preferences: UserPreferences, findInStrings?: boolean, findInComments?: boolean): RenameInfo { + getRenameInfo( + fileName: string, + position: number, + _preferences: UserPreferences, + findInStrings?: boolean, + findInComments?: boolean, + ): RenameInfo { // Not passing along 'options' because server should already have those from the 'configure' command - const args: protocol.RenameRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), findInStrings, findInComments }; + const args: protocol.RenameRequestArgs = { + ...this.createFileLocationRequestArgs(fileName, position), + findInStrings, + findInComments, + }; const request = this.processRequest(CommandNames.Rename, args); const response = this.processResponse(request); @@ -452,9 +545,9 @@ namespace ts.server { locations.push({ textSpan: this.decodeSpan({ start, end }, fileName), fileName, - ...(contextStart !== undefined ? - { contextSpan: this.decodeSpan({ start: contextStart, end: contextEnd! }, fileName) } : - undefined), + ...(contextStart !== undefined + ? { contextSpan: this.decodeSpan({ start: contextStart, end: contextEnd! }, fileName) } + : undefined), ...prefixSuffixText, }); } @@ -470,7 +563,10 @@ namespace ts.server { kindModifiers: body.info.kindModifiers, triggerSpan: createTextSpanFromBounds(position, position), }) - : identity({ canRename: false, localizedErrorMessage: body.info.localizedErrorMessage }); + : identity({ + canRename: false, + localizedErrorMessage: body.info.localizedErrorMessage, + }); this.lastRenameEntry = { renameInfo, inputs: { @@ -488,13 +584,19 @@ namespace ts.server { return notImplemented(); } - findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): RenameLocation[] { + findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + providePrefixAndSuffixTextForRename?: boolean, + ): RenameLocation[] { if ( - !this.lastRenameEntry || - this.lastRenameEntry.inputs.fileName !== fileName || - this.lastRenameEntry.inputs.position !== position || - this.lastRenameEntry.inputs.findInStrings !== findInStrings || - this.lastRenameEntry.inputs.findInComments !== findInComments + !this.lastRenameEntry + || this.lastRenameEntry.inputs.fileName !== fileName + || this.lastRenameEntry.inputs.position !== position + || this.lastRenameEntry.inputs.findInStrings !== findInStrings + || this.lastRenameEntry.inputs.findInComments !== findInComments ) { if (providePrefixAndSuffixTextForRename !== undefined) { // User preferences have to be set through the `Configure` command @@ -514,7 +616,11 @@ namespace ts.server { return this.lastRenameEntry!.locations; } - private decodeNavigationBarItems(items: protocol.NavigationBarItem[] | undefined, fileName: string, lineMap: number[]): NavigationBarItem[] { + private decodeNavigationBarItems( + items: protocol.NavigationBarItem[] | undefined, + fileName: string, + lineMap: number[], + ): NavigationBarItem[] { if (!items) { return []; } @@ -539,7 +645,11 @@ namespace ts.server { return this.decodeNavigationBarItems(response.body, file, lineMap); } - private decodeNavigationTree(tree: protocol.NavigationTree, fileName: string, lineMap: number[]): NavigationTree { + private decodeNavigationTree( + tree: protocol.NavigationTree, + fileName: string, + lineMap: number[], + ): NavigationTree { return { text: tree.text, kind: tree.kind, @@ -560,7 +670,11 @@ namespace ts.server { private decodeSpan(span: protocol.TextSpan & { file: string; }): TextSpan; private decodeSpan(span: protocol.TextSpan, fileName: string, lineMap?: number[]): TextSpan; - private decodeSpan(span: protocol.TextSpan & { file: string; }, fileName?: string, lineMap?: number[]): TextSpan { + private decodeSpan( + span: protocol.TextSpan & { file: string; }, + fileName?: string, + lineMap?: number[], + ): TextSpan { if (span.start.line === 1 && span.start.offset === 1 && span.end.line === 1 && span.end.offset === 1) { return { start: 0, length: 0 }; } @@ -599,10 +713,19 @@ namespace ts.server { return undefined; } - const { items: encodedItems, applicableSpan: encodedApplicableSpan, selectedItemIndex, argumentIndex, argumentCount } = response.body; + const { + items: encodedItems, + applicableSpan: encodedApplicableSpan, + selectedItemIndex, + argumentIndex, + argumentCount, + } = response.body; const applicableSpan = encodedApplicableSpan as unknown as TextSpan; - const items = (encodedItems as (SignatureHelpItem | protocol.SignatureHelpItem)[]).map(item => ({ ...item, tags: this.decodeLinkDisplayParts(item.tags) })); + const items = (encodedItems as (SignatureHelpItem | protocol.SignatureHelpItem)[]).map(item => ({ + ...item, + tags: this.decodeLinkDisplayParts(item.tags), + })); return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount }; } @@ -621,9 +744,15 @@ namespace ts.server { } getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] { - const args: protocol.DocumentHighlightsRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), filesToSearch }; + const args: protocol.DocumentHighlightsRequestArgs = { + ...this.createFileLocationRequestArgs(fileName, position), + filesToSearch, + }; - const request = this.processRequest(CommandNames.DocumentHighlights, args); + const request = this.processRequest( + CommandNames.DocumentHighlights, + args, + ); const response = this.processResponse(request); return response.body!.map(item => ({ // TODO: GH#18217 @@ -636,7 +765,9 @@ namespace ts.server { } getOutliningSpans(file: string): OutliningSpan[] { - const request = this.processRequest(CommandNames.GetOutliningSpans, { file }); + const request = this.processRequest(CommandNames.GetOutliningSpans, { + file, + }); const response = this.processResponse(request); return response.body!.map(item => ({ @@ -652,7 +783,11 @@ namespace ts.server { return notImplemented(); } - getDocCommentTemplateAtPosition(_fileName: string, _position: number, _options?: DocCommentTemplateOptions): TextInsertion { + getDocCommentTemplateAtPosition( + _fileName: string, + _position: number, + _options?: DocCommentTemplateOptions, + ): TextInsertion { return notImplemented(); } @@ -668,14 +803,31 @@ namespace ts.server { return notImplemented(); } - getCodeFixesAtPosition(file: string, start: number, end: number, errorCodes: readonly number[]): readonly CodeFixAction[] { - const args: protocol.CodeFixRequestArgs = { ...this.createFileRangeRequestArgs(file, start, end), errorCodes }; + getCodeFixesAtPosition( + file: string, + start: number, + end: number, + errorCodes: readonly number[], + ): readonly CodeFixAction[] { + const args: protocol.CodeFixRequestArgs = { + ...this.createFileRangeRequestArgs(file, start, end), + errorCodes, + }; const request = this.processRequest(CommandNames.GetCodeFixes, args); const response = this.processResponse(request); - return response.body!.map(({ fixName, description, changes, commands, fixId, fixAllDescription }) => // TODO: GH#18217 - ({ fixName, description, changes: this.convertChanges(changes, file), commands: commands as CodeActionCommand[], fixId, fixAllDescription })); + return response.body!.map(( + { fixName, description, changes, commands, fixId, fixAllDescription }, + ) => // TODO: GH#18217 + ({ + fixName, + description, + changes: this.convertChanges(changes, file), + commands: commands as CodeActionCommand[], + fixId, + fixAllDescription, + })); } getCombinedCodeFix = notImplemented; @@ -696,7 +848,10 @@ namespace ts.server { })); } - private createFileLocationOrRangeRequestArgs(positionOrRange: number | TextRange, fileName: string): protocol.FileLocationOrRangeRequestArgs { + private createFileLocationOrRangeRequestArgs( + positionOrRange: number | TextRange, + fileName: string, + ): protocol.FileLocationOrRangeRequestArgs { return typeof positionOrRange === "number" ? this.createFileLocationRequestArgs(fileName, positionOrRange) : this.createFileRangeRequestArgs(fileName, positionOrRange.pos, positionOrRange.end); @@ -713,7 +868,11 @@ namespace ts.server { return { file, startLine, startOffset, endLine, endOffset }; } - private createFileLocationRequestArgsWithEndLineAndOffset(file: string, start: number, end: number): protocol.FileLocationRequestArgs & { endLine: number; endOffset: number; } { + private createFileLocationRequestArgsWithEndLineAndOffset( + file: string, + start: number, + end: number, + ): protocol.FileLocationRequestArgs & { endLine: number; endOffset: number; } { const { line, offset } = this.positionToOneBasedLineOffset(file, start); const { line: endLine, offset: endOffset } = this.positionToOneBasedLineOffset(file, end); return { file, line, offset, endLine, endOffset }; @@ -722,7 +881,10 @@ namespace ts.server { getApplicableRefactors(fileName: string, positionOrRange: number | TextRange): ApplicableRefactorInfo[] { const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName); - const request = this.processRequest(CommandNames.GetApplicableRefactors, args); + const request = this.processRequest( + CommandNames.GetApplicableRefactors, + args, + ); const response = this.processResponse(request); return response.body!; // TODO: GH#18217 } @@ -734,11 +896,17 @@ namespace ts.server { refactorName: string, actionName: string, ): RefactorEditInfo { - const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName) as protocol.GetEditsForRefactorRequestArgs; + const args = this.createFileLocationOrRangeRequestArgs( + positionOrRange, + fileName, + ) as protocol.GetEditsForRefactorRequestArgs; args.refactor = refactorName; args.action = actionName; - const request = this.processRequest(CommandNames.GetEditsForRefactor, args); + const request = this.processRequest( + CommandNames.GetEditsForRefactor, + args, + ); const response = this.processResponse(request); if (!response.body) { @@ -781,7 +949,9 @@ namespace ts.server { private convertChanges(changes: protocol.FileCodeEdits[], fileName: string): FileTextChanges[] { return changes.map(change => ({ fileName: change.fileName, - textChanges: change.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, fileName)), + textChanges: change.textChanges.map(textChange => + this.convertTextChangeToCodeEdit(textChange, fileName) + ), })); } @@ -802,7 +972,10 @@ namespace ts.server { } configurePlugin(pluginName: string, configuration: any): void { - const request = this.processRequest("configurePlugin", { pluginName, configuration }); + const request = this.processRequest("configurePlugin", { + pluginName, + configuration, + }); this.processResponse(request, /*expectEmptyBody*/ true); } @@ -822,8 +995,15 @@ namespace ts.server { return notImplemented(); } - getEncodedSemanticClassifications(file: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications { - const request = this.processRequest(protocol.CommandTypes.EncodedSemanticClassificationsFull, { file, start: span.start, length: span.length, format }); + getEncodedSemanticClassifications( + file: string, + span: TextSpan, + format?: SemanticClassificationFormat, + ): Classifications { + const request = this.processRequest( + protocol.CommandTypes.EncodedSemanticClassificationsFull, + { file, start: span.start, length: span.length, format }, + ); const r = this.processResponse(request); return r.body!; } @@ -842,7 +1022,10 @@ namespace ts.server { prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined { const args = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(CommandNames.PrepareCallHierarchy, args); + const request = this.processRequest( + CommandNames.PrepareCallHierarchy, + args, + ); const response = this.processResponse(request); return response.body && mapOneOrMany(response.body, item => this.convertCallHierarchyItem(item)); } @@ -856,12 +1039,18 @@ namespace ts.server { provideCallHierarchyIncomingCalls(fileName: string, position: number) { const args = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(CommandNames.ProvideCallHierarchyIncomingCalls, args); + const request = this.processRequest( + CommandNames.ProvideCallHierarchyIncomingCalls, + args, + ); const response = this.processResponse(request); return response.body.map(item => this.convertCallHierarchyIncomingCall(item)); } - private convertCallHierarchyOutgoingCall(file: string, item: protocol.CallHierarchyOutgoingCall): CallHierarchyOutgoingCall { + private convertCallHierarchyOutgoingCall( + file: string, + item: protocol.CallHierarchyOutgoingCall, + ): CallHierarchyOutgoingCall { return { to: this.convertCallHierarchyItem(item.to), fromSpans: item.fromSpans.map(span => this.decodeSpan(span, file)), @@ -870,7 +1059,10 @@ namespace ts.server { provideCallHierarchyOutgoingCalls(fileName: string, position: number) { const args = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(CommandNames.ProvideCallHierarchyOutgoingCalls, args); + const request = this.processRequest( + CommandNames.ProvideCallHierarchyOutgoingCalls, + args, + ); const response = this.processResponse(request); return response.body.map(item => this.convertCallHierarchyOutgoingCall(fileName, item)); } @@ -887,7 +1079,10 @@ namespace ts.server { throw new Error("Program objects are not serializable through the server protocol."); } - updateIsDefinitionOfReferencedSymbols(_referencedSymbols: readonly ReferencedSymbol[], _knownSymbolSpans: Set): boolean { + updateIsDefinitionOfReferencedSymbols( + _referencedSymbols: readonly ReferencedSymbol[], + _knownSymbolSpans: Set, + ): boolean { return notImplemented(); } diff --git a/src/harness/collectionsImpl.ts b/src/harness/collectionsImpl.ts index a2a1cf627f140..b473cc2b459a5 100644 --- a/src/harness/collectionsImpl.ts +++ b/src/harness/collectionsImpl.ts @@ -320,7 +320,8 @@ namespace collections { } private static _unescapeKey(text: string) { - return (text.length >= 3 && text.charAt(0) === "_" && text.charAt(1) === "_" && text.charAt(2) === "_" ? text.slice(1) : text); + return (text.length >= 3 && text.charAt(0) === "_" && text.charAt(1) === "_" && text.charAt(2) === "_" + ? text.slice(1) : text); } } } diff --git a/src/harness/compilerImpl.ts b/src/harness/compilerImpl.ts index 008e2f2ab45a6..28b6f1c4d2901 100644 --- a/src/harness/compilerImpl.ts +++ b/src/harness/compilerImpl.ts @@ -8,13 +8,18 @@ namespace compiler { errors?: ts.Diagnostic[]; } - export function readProject(host: fakes.ParseConfigHost, project: string | undefined, existingOptions?: ts.CompilerOptions): Project | undefined { + export function readProject( + host: fakes.ParseConfigHost, + project: string | undefined, + existingOptions?: ts.CompilerOptions, + ): Project | undefined { if (project) { project = vpath.isTsConfigFile(project) ? project : vpath.combine(project, "tsconfig.json"); } else { [project] = host.vfs.scanSync(".", "ancestors-or-self", { - accept: (path, stats) => stats.isFile() && host.vfs.stringComparer(vpath.basename(path), "tsconfig.json") === 0, + accept: (path, stats) => + stats.isFile() && host.vfs.stringComparer(vpath.basename(path), "tsconfig.json") === 0, }); } @@ -29,7 +34,12 @@ namespace compiler { } // parse the config file - const config = ts.parseJsonConfigFileContent(readResult.config, host, vpath.dirname(project), existingOptions); + const config = ts.parseJsonConfigFileContent( + readResult.config, + host, + vpath.dirname(project), + existingOptions, + ); return { file: project, errors: config.errors, config }; } } @@ -58,7 +68,13 @@ namespace compiler { private _inputs: documents.TextDocument[] = []; private _inputsAndOutputs: collections.SortedMap; - constructor(host: fakes.CompilerHost, options: ts.CompilerOptions, program: ts.Program | undefined, result: ts.EmitResult | undefined, diagnostics: readonly ts.Diagnostic[]) { + constructor( + host: fakes.CompilerHost, + options: ts.CompilerOptions, + program: ts.Program | undefined, + result: ts.EmitResult | undefined, + diagnostics: readonly ts.Diagnostic[], + ) { this.host = host; this.program = program; this.result = result; @@ -66,9 +82,18 @@ namespace compiler { this.options = program ? program.getCompilerOptions() : options; // collect outputs - const js = this.js = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); - const dts = this.dts = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); - const maps = this.maps = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); + const js = this.js = new collections.SortedMap({ + comparer: this.vfs.stringComparer, + sort: "insertion", + }); + const dts = this.dts = new collections.SortedMap({ + comparer: this.vfs.stringComparer, + sort: "insertion", + }); + const maps = this.maps = new collections.SortedMap({ + comparer: this.vfs.stringComparer, + sort: "insertion", + }); for (const document of this.host.outputs) { if (vpath.isJavaScript(document.file) || ts.fileExtensionIs(document.file, ts.Extension.Json)) { js.set(document.file, document); @@ -82,7 +107,10 @@ namespace compiler { } // correlate inputs and outputs - this._inputsAndOutputs = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); + this._inputsAndOutputs = new collections.SortedMap({ + comparer: this.vfs.stringComparer, + sort: "insertion", + }); if (program) { if (this.options.out || this.options.outFile) { const outFile = vpath.resolve(this.vfs.cwd(), this.options.outFile || this.options.out); @@ -122,7 +150,12 @@ namespace compiler { const outputs: CompilationOutput = { inputs: [input], js: js.get(this.getOutputPath(sourceFile.fileName, extname)), - dts: dts.get(this.getOutputPath(sourceFile.fileName, ts.getDeclarationEmitExtensionForPath(sourceFile.fileName))), + dts: dts.get( + this.getOutputPath( + sourceFile.fileName, + ts.getDeclarationEmitExtensionForPath(sourceFile.fileName), + ), + ), map: maps.get(this.getOutputPath(sourceFile.fileName, extname + ".map")), }; @@ -183,7 +216,12 @@ namespace compiler { public getSourceMapRecord(): string | undefined { const maps = this.result!.sourceMaps; if (maps && maps.length > 0) { - return Harness.SourceMapRecorder.getSourceMapRecord(maps, this.program!, Array.from(this.js.values()).filter(d => !ts.fileExtensionIs(d.file, ts.Extension.Json)), Array.from(this.dts.values())); + return Harness.SourceMapRecorder.getSourceMapRecord( + maps, + this.program!, + Array.from(this.js.values()).filter(d => !ts.fileExtensionIs(d.file, ts.Extension.Json)), + Array.from(this.dts.values()), + ); } } @@ -205,7 +243,8 @@ namespace compiler { } else { path = vpath.resolve(this.vfs.cwd(), path); - const outDir = ext === ".d.ts" || ext === ".json.d.ts" || ext === ".d.mts" || ext === ".d.cts" ? this.options.declarationDir || this.options.outDir : this.options.outDir; + const outDir = ext === ".d.ts" || ext === ".json.d.ts" || ext === ".d.mts" || ext === ".d.cts" + ? this.options.declarationDir || this.options.outDir : this.options.outDir; if (outDir) { const common = this.commonSourceDirectory; if (common) { @@ -233,12 +272,22 @@ namespace compiler { } } - export function compileFiles(host: fakes.CompilerHost, rootFiles: string[] | undefined, compilerOptions: ts.CompilerOptions): CompilationResult { + export function compileFiles( + host: fakes.CompilerHost, + rootFiles: string[] | undefined, + compilerOptions: ts.CompilerOptions, + ): CompilationResult { if (compilerOptions.project || !rootFiles || rootFiles.length === 0) { const project = readProject(host.parseConfigHost, compilerOptions.project, compilerOptions); if (project) { if (project.errors && project.errors.length > 0) { - return new CompilationResult(host, compilerOptions, /*program*/ undefined, /*result*/ undefined, project.errors); + return new CompilationResult( + host, + compilerOptions, + /*program*/ undefined, + /*result*/ undefined, + project.errors, + ); } if (project.config) { rootFiles = project.config.fileNames; @@ -249,16 +298,25 @@ namespace compiler { } // establish defaults (aligns with old harness) - if (compilerOptions.target === undefined && compilerOptions.module !== ts.ModuleKind.Node16 && compilerOptions.module !== ts.ModuleKind.NodeNext) compilerOptions.target = ts.ScriptTarget.ES3; + if ( + compilerOptions.target === undefined && compilerOptions.module !== ts.ModuleKind.Node16 + && compilerOptions.module !== ts.ModuleKind.NodeNext + ) compilerOptions.target = ts.ScriptTarget.ES3; if (compilerOptions.newLine === undefined) compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed; if (compilerOptions.skipDefaultLibCheck === undefined) compilerOptions.skipDefaultLibCheck = true; if (compilerOptions.noErrorTruncation === undefined) compilerOptions.noErrorTruncation = true; // pre-emit/post-emit error comparison requires declaration emit twice, which can be slow. If it's unlikely to flag any error consistency issues // and if the test is running `skipLibCheck` - an indicator that we want the tets to run quickly - skip the before/after error comparison, too - const skipErrorComparison = ts.length(rootFiles) >= 100 || (!!compilerOptions.skipLibCheck && !!compilerOptions.declaration); - - const preProgram = !skipErrorComparison ? ts.createProgram(rootFiles || [], { ...compilerOptions, configFile: compilerOptions.configFile, traceResolution: false }, host) : undefined; + const skipErrorComparison = ts.length(rootFiles) >= 100 + || (!!compilerOptions.skipLibCheck && !!compilerOptions.declaration); + + const preProgram = !skipErrorComparison + ? ts.createProgram(rootFiles || [], { + ...compilerOptions, + configFile: compilerOptions.configFile, + traceResolution: false, + }, host) : undefined; const preErrors = preProgram && ts.getPreEmitDiagnostics(preProgram); const program = ts.createProgram(rootFiles || [], compilerOptions, host); @@ -273,7 +331,8 @@ namespace compiler { category: ts.DiagnosticCategory.Error, code: -1, key: "-1", - message: `Pre-emit (${preErrors.length}) and post-emit (${postErrors.length}) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here!`, + message: + `Pre-emit (${preErrors.length}) and post-emit (${postErrors.length}) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here!`, }), ts.createCompilerDiagnostic({ category: ts.DiagnosticCategory.Error, @@ -281,7 +340,10 @@ namespace compiler { key: "-1", message: `The excess diagnostics are:`, }), - ...ts.filter(longerErrors!, p => !ts.some(shorterErrors, p2 => ts.compareDiagnostics(p, p2) === ts.Comparison.EqualTo)), + ...ts.filter( + longerErrors!, + p => !ts.some(shorterErrors, p2 => ts.compareDiagnostics(p, p2) === ts.Comparison.EqualTo), + ), ), ] : postErrors; return new CompilationResult(host, compilerOptions, program, emitResult, errors); diff --git a/src/harness/documentsUtil.ts b/src/harness/documentsUtil.ts index 359761826876a..c5db510081411 100644 --- a/src/harness/documentsUtil.ts +++ b/src/harness/documentsUtil.ts @@ -111,7 +111,14 @@ namespace documents { sourceColumn += segment[3]; } - const mapping: Mapping = { mappingIndex: mappings.length, emittedLine, emittedColumn, sourceIndex, sourceLine, sourceColumn }; + const mapping: Mapping = { + mappingIndex: mappings.length, + emittedLine, + emittedColumn, + sourceIndex, + sourceLine, + sourceColumn, + }; if (segment.length === 5) { nameIndex += segment[4]; mapping.nameIndex = nameIndex; @@ -119,11 +126,14 @@ namespace documents { mappings.push(mapping); - const mappingsForEmittedLine = this._emittedLineMappings[mapping.emittedLine] || (this._emittedLineMappings[mapping.emittedLine] = []); + const mappingsForEmittedLine = this._emittedLineMappings[mapping.emittedLine] + || (this._emittedLineMappings[mapping.emittedLine] = []); mappingsForEmittedLine.push(mapping); - const mappingsForSource = this._sourceLineMappings[mapping.sourceIndex] || (this._sourceLineMappings[mapping.sourceIndex] = []); - const mappingsForSourceLine = mappingsForSource[mapping.sourceLine] || (mappingsForSource[mapping.sourceLine] = []); + const mappingsForSource = this._sourceLineMappings[mapping.sourceIndex] + || (this._sourceLineMappings[mapping.sourceIndex] = []); + const mappingsForSourceLine = mappingsForSource[mapping.sourceLine] + || (mappingsForSource[mapping.sourceLine] = []); mappingsForSourceLine.push(mapping); } else if (match[2]) { diff --git a/src/harness/evaluatorImpl.ts b/src/harness/evaluatorImpl.ts index a94ffd305c5f2..b9e333bfa49e8 100644 --- a/src/harness/evaluatorImpl.ts +++ b/src/harness/evaluatorImpl.ts @@ -13,10 +13,21 @@ namespace evaluator { } // Add "asyncIterator" if missing - if (!ts.hasProperty(FakeSymbol, "asyncIterator")) Object.defineProperty(FakeSymbol, "asyncIterator", { value: Symbol.for("Symbol.asyncIterator"), configurable: true }); + if (!ts.hasProperty(FakeSymbol, "asyncIterator")) { + Object.defineProperty(FakeSymbol, "asyncIterator", { + value: Symbol.for("Symbol.asyncIterator"), + configurable: true, + }); + } - export function evaluateTypeScript(source: string | { files: vfs.FileSet; rootFiles: string[]; main: string; }, options?: ts.CompilerOptions, globals?: Record) { - if (typeof source === "string") source = { files: { [sourceFile]: source }, rootFiles: [sourceFile], main: sourceFile }; + export function evaluateTypeScript( + source: string | { files: vfs.FileSet; rootFiles: string[]; main: string; }, + options?: ts.CompilerOptions, + globals?: Record, + ) { + if (typeof source === "string") { + source = { files: { [sourceFile]: source }, rootFiles: [sourceFile], main: sourceFile }; + } const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { files: source.files }); const compilerOptions: ts.CompilerOptions = { target: ts.ScriptTarget.ES5, @@ -50,7 +61,11 @@ namespace evaluator { return new CommonJsLoader(fs, globals).import(sourceFile); } - function getLoader(compilerOptions: ts.CompilerOptions, fs: vfs.FileSystem, globals: Record): Loader { + function getLoader( + compilerOptions: ts.CompilerOptions, + fs: vfs.FileSystem, + globals: Record, + ): Loader { const moduleKind = ts.getEmitModuleKind(compilerOptions); switch (moduleKind) { case ts.ModuleKind.UMD: @@ -170,10 +185,27 @@ namespace evaluator { } const base = vpath.dirname(file); const localRequire = (id: string) => this.import(id, base); - const evaluateText = `(function (module, exports, require, __dirname, __filename, ${globalNames.join(", ")}) { ${text} })`; + const evaluateText = `(function (module, exports, require, __dirname, __filename, ${ + globalNames.join(", ") + }) { ${text} })`; // eslint-disable-next-line no-eval - const evaluateThunk = (void 0, eval)(evaluateText) as (module: any, exports: any, require: (id: string) => any, dirname: string, filename: string, ...globalArgs: any[]) => void; - evaluateThunk.call(this.globals, module, module.exports, localRequire, vpath.dirname(file), file, ...globalArgs); + const evaluateThunk = (void 0, eval)(evaluateText) as ( + module: any, + exports: any, + require: (id: string) => any, + dirname: string, + filename: string, + ...globalArgs: any[] + ) => void; + evaluateThunk.call( + this.globals, + module, + module.exports, + localRequire, + vpath.dirname(file), + file, + ...globalArgs, + ); } } @@ -218,7 +250,10 @@ namespace evaluator { meta: any; } - type SystemModuleRegisterCallback = (exporter: SystemModuleExporter, context: SystemModuleContext) => SystemModuleDeclaration; + type SystemModuleRegisterCallback = ( + exporter: SystemModuleExporter, + context: SystemModuleContext, + ) => SystemModuleDeclaration; type SystemModuleDependencySetter = (dependency: any) => void; interface SystemModuleDeclaration { @@ -292,7 +327,11 @@ namespace evaluator { } } - private instantiateModule(module: SystemModule, dependencies: string[], registration?: SystemModuleRegisterCallback) { + private instantiateModule( + module: SystemModule, + dependencies: string[], + registration?: SystemModuleRegisterCallback, + ) { function exporter(name: string, value: T): T; function exporter(value: T): T; function exporter(...args: [string, T] | [T]) { @@ -318,7 +357,12 @@ namespace evaluator { throw new Error("Dynamic import not implemented."); }, meta: { - url: ts.isUrl(module.file) ? module.file : `file:///${ts.normalizeSlashes(module.file).replace(/^\//, "").split("/").map(encodeURIComponent).join("/")}`, + url: ts.isUrl(module.file) ? module.file + : `file:///${ + ts.normalizeSlashes(module.file).replace(/^\//, "").split("/").map(encodeURIComponent).join( + "/", + ) + }`, }, }; diff --git a/src/harness/fakesHosts.ts b/src/harness/fakesHosts.ts index 792ad079499eb..97a58f5e01e50 100644 --- a/src/harness/fakesHosts.ts +++ b/src/harness/fakesHosts.ts @@ -94,8 +94,24 @@ namespace fakes { return result; } - public readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { - return ts.matchFiles(path, extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), depth, path => this.getAccessibleFileSystemEntries(path), path => this.realpath(path)); + public readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { + return ts.matchFiles( + path, + extensions, + exclude, + include, + this.useCaseSensitiveFileNames, + this.getCurrentDirectory(), + depth, + path => this.getAccessibleFileSystemEntries(path), + path => this.realpath(path), + ); } public getAccessibleFileSystemEntries(path: string): ts.FileSystemEntries { @@ -209,7 +225,13 @@ namespace fakes { return this.sys.readFile(path); } - public readDirectory(path: string, extensions: string[], excludes: string[], includes: string[], depth: number): string[] { + public readDirectory( + path: string, + extensions: string[], + excludes: string[], + includes: string[], + depth: number, + ): string[] { return this.sys.readDirectory(path, extensions, excludes, includes, depth); } } @@ -235,7 +257,10 @@ namespace fakes { this.sys = sys; this.defaultLibLocation = sys.vfs.meta.get("defaultLibLocation") || ""; this._newLine = ts.getNewLineCharacter(options, () => this.sys.newLine); - this._sourceFiles = new collections.SortedMap({ comparer: sys.vfs.stringComparer, sort: "insertion" }); + this._sourceFiles = new collections.SortedMap({ + comparer: sys.vfs.stringComparer, + sort: "insertion", + }); this._setParentNodes = setParentNodes; this._outputsMap = new collections.SortedMap(this.vfs.stringComparer); } @@ -288,7 +313,13 @@ namespace fakes { return this.sys.getDirectories(path); } - public readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { + public readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { return this.sys.readDirectory(path, extensions, exclude, include, depth); } @@ -340,7 +371,8 @@ namespace fakes { // reused across multiple tests. In that case, we cache the SourceFile we parse // so that it can be reused across multiple tests to avoid the cost of // repeatedly parsing the same file over and over (such as lib.d.ts). - const cacheKey = this.vfs.shadowRoot && `SourceFile[languageVersion=${languageVersion},setParentNodes=${this._setParentNodes}]`; + const cacheKey = this.vfs.shadowRoot + && `SourceFile[languageVersion=${languageVersion},setParentNodes=${this._setParentNodes}]`; if (cacheKey) { const meta = this.vfs.filemeta(canonicalFileName); const sourceFileFromMetadata = meta.get(cacheKey) as ts.SourceFile | undefined; @@ -350,7 +382,12 @@ namespace fakes { } } - const parsed = ts.createSourceFile(fileName, content, languageVersion, this._setParentNodes || this.shouldAssertInvariants); + const parsed = ts.createSourceFile( + fileName, + content, + languageVersion, + this._setParentNodes || this.shouldAssertInvariants, + ); if (this.shouldAssertInvariants) { Utils.assertInvariants(parsed, /*parent*/ undefined); } @@ -364,11 +401,12 @@ namespace fakes { let fs = this.vfs; while (fs.shadowRoot) { try { - const shadowRootStats = fs.shadowRoot.existsSync(canonicalFileName) ? fs.shadowRoot.statSync(canonicalFileName) : undefined!; // TODO: GH#18217 + const shadowRootStats = fs.shadowRoot.existsSync(canonicalFileName) + ? fs.shadowRoot.statSync(canonicalFileName) : undefined!; // TODO: GH#18217 if ( - shadowRootStats.dev !== stats.dev || - shadowRootStats.ino !== stats.ino || - shadowRootStats.mtimeMs !== stats.mtimeMs + shadowRootStats.dev !== stats.dev + || shadowRootStats.ino !== stats.ino + || shadowRootStats.mtimeMs !== stats.mtimeMs ) { break; } @@ -446,7 +484,9 @@ ${indentText}${text}`; return text; } - function expectedDiagnosticRelatedInformationToText({ location, ...diagnosticMessage }: ExpectedDiagnosticRelatedInformation) { + function expectedDiagnosticRelatedInformationToText( + { location, ...diagnosticMessage }: ExpectedDiagnosticRelatedInformation, + ) { const text = expectedDiagnosticMessageChainToText(diagnosticMessage); if (location) { const { file, start, length } = location; @@ -455,8 +495,12 @@ ${indentText}${text}`; return text; } - function expectedErrorDiagnosticToText({ relatedInformation, ...diagnosticRelatedInformation }: ExpectedErrorDiagnostic) { - let text = `${DiagnosticKind.Error}!: ${expectedDiagnosticRelatedInformationToText(diagnosticRelatedInformation)}`; + function expectedErrorDiagnosticToText( + { relatedInformation, ...diagnosticRelatedInformation }: ExpectedErrorDiagnostic, + ) { + let text = `${DiagnosticKind.Error}!: ${ + expectedDiagnosticRelatedInformationToText(diagnosticRelatedInformation) + }`; if (relatedInformation) { for (const kid of relatedInformation) { text += ` @@ -467,9 +511,9 @@ ${indentText}${text}`; } function expectedDiagnosticToText(errorOrStatus: ExpectedDiagnostic) { - return ts.isArray(errorOrStatus) ? - `${DiagnosticKind.Status}!: ${expectedDiagnosticMessageToText(errorOrStatus)}` : - expectedErrorDiagnosticToText(errorOrStatus); + return ts.isArray(errorOrStatus) + ? `${DiagnosticKind.Status}!: ${expectedDiagnosticMessageToText(errorOrStatus)}` + : expectedErrorDiagnosticToText(errorOrStatus); } function diagnosticMessageChainToText({ messageText, next }: ts.DiagnosticMessageChain, indent = 0) { @@ -482,15 +526,17 @@ ${indentText}${text}`; } function diagnosticRelatedInformationToText({ file, start, length, messageText }: ts.DiagnosticRelatedInformation) { - const text = typeof messageText === "string" ? - messageText : - diagnosticMessageChainToText(messageText); - return file ? - `${file.fileName}(${start}:${length}):: ${text}` : - text; + const text = typeof messageText === "string" + ? messageText + : diagnosticMessageChainToText(messageText); + return file + ? `${file.fileName}(${start}:${length}):: ${text}` + : text; } - function diagnosticToText({ kind, diagnostic: { relatedInformation, ...diagnosticRelatedInformation } }: SolutionBuilderDiagnostic) { + function diagnosticToText( + { kind, diagnostic: { relatedInformation, ...diagnosticRelatedInformation } }: SolutionBuilderDiagnostic, + ) { let text = `${kind}!: ${diagnosticRelatedInformationToText(diagnosticRelatedInformation)}`; if (relatedInformation) { for (const kid of relatedInformation) { @@ -537,12 +583,22 @@ ${indentText}${text}`; export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost { createProgram: ts.CreateProgram; - private constructor(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram) { + private constructor( + sys: System | vfs.FileSystem, + options?: ts.CompilerOptions, + setParentNodes?: boolean, + createProgram?: ts.CreateProgram, + ) { super(sys, options, setParentNodes); this.createProgram = createProgram || ts.createEmitAndSemanticDiagnosticsBuilderProgram; } - static create(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram) { + static create( + sys: System | vfs.FileSystem, + options?: ts.CompilerOptions, + setParentNodes?: boolean, + createProgram?: ts.CreateProgram, + ) { const host = new SolutionBuilderHost(sys, options, setParentNodes, createProgram); patchHostForBuildInfoReadWrite(host.sys); return host; diff --git a/src/harness/findUpDir.ts b/src/harness/findUpDir.ts index 64c0b1829a36b..013ac51ef0a08 100644 --- a/src/harness/findUpDir.ts +++ b/src/harness/findUpDir.ts @@ -16,5 +16,6 @@ namespace Utils { } } - export const findUpRoot: { (): string; cached?: string; } = () => findUpRoot.cached ||= dirname(findUpFile("Gulpfile.mjs")); + export const findUpRoot: { (): string; cached?: string; } = () => + findUpRoot.cached ||= dirname(findUpFile("Gulpfile.mjs")); } diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 83e1f664e8ad5..176f561914bf4 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -88,9 +88,16 @@ namespace FourSlash { } // List of allowed metadata names - const fileMetadataNames = [MetadataOptionNames.fileName, MetadataOptionNames.emitThisFile, MetadataOptionNames.resolveReference, MetadataOptionNames.symlink]; - - function convertGlobalOptionsToCompilerOptions(globalOptions: Harness.TestCaseParser.CompilerSettings): ts.CompilerOptions { + const fileMetadataNames = [ + MetadataOptionNames.fileName, + MetadataOptionNames.emitThisFile, + MetadataOptionNames.resolveReference, + MetadataOptionNames.symlink, + ]; + + function convertGlobalOptionsToCompilerOptions( + globalOptions: Harness.TestCaseParser.CompilerSettings, + ): ts.CompilerOptions { const settings: ts.CompilerOptions = { target: ts.ScriptTarget.ES5 }; Harness.Compiler.setCompilerOptionsFromHarnessSetting(globalOptions, settings); return settings; @@ -139,7 +146,9 @@ namespace FourSlash { throw new Error("Operation should be cancelled"); } - export function ignoreInterpolations(diagnostic: string | ts.DiagnosticMessage): FourSlashInterface.DiagnosticIgnoredInterpolations { + export function ignoreInterpolations( + diagnostic: string | ts.DiagnosticMessage, + ): FourSlashInterface.DiagnosticIgnoredInterpolations { return { template: typeof diagnostic === "string" ? diagnostic : diagnostic.message }; } @@ -216,22 +225,45 @@ namespace FourSlash { } } - private getLanguageServiceAdapter(testType: FourSlashTestType, cancellationToken: TestCancellationToken, compilationOptions: ts.CompilerOptions): Harness.LanguageService.LanguageServiceAdapter { + private getLanguageServiceAdapter( + testType: FourSlashTestType, + cancellationToken: TestCancellationToken, + compilationOptions: ts.CompilerOptions, + ): Harness.LanguageService.LanguageServiceAdapter { switch (testType) { case FourSlashTestType.Native: - return new Harness.LanguageService.NativeLanguageServiceAdapter(cancellationToken, compilationOptions); + return new Harness.LanguageService.NativeLanguageServiceAdapter( + cancellationToken, + compilationOptions, + ); case FourSlashTestType.Shims: - return new Harness.LanguageService.ShimLanguageServiceAdapter(/*preprocessToResolve*/ false, cancellationToken, compilationOptions); + return new Harness.LanguageService.ShimLanguageServiceAdapter( + /*preprocessToResolve*/ false, + cancellationToken, + compilationOptions, + ); case FourSlashTestType.ShimsWithPreprocess: - return new Harness.LanguageService.ShimLanguageServiceAdapter(/*preprocessToResolve*/ true, cancellationToken, compilationOptions); + return new Harness.LanguageService.ShimLanguageServiceAdapter( + /*preprocessToResolve*/ true, + cancellationToken, + compilationOptions, + ); case FourSlashTestType.Server: - return new Harness.LanguageService.ServerLanguageServiceAdapter(cancellationToken, compilationOptions); + return new Harness.LanguageService.ServerLanguageServiceAdapter( + cancellationToken, + compilationOptions, + ); default: throw new Error("Unknown FourSlash test type: "); } } - constructor(private originalInputFileName: string, private basePath: string, private testType: FourSlashTestType, public testData: FourSlashData) { + constructor( + private originalInputFileName: string, + private basePath: string, + private testType: FourSlashTestType, + public testData: FourSlashData, + ) { // Create a new Services Adapter this.cancellationToken = new TestCancellationToken(); let compilationOptions = convertGlobalOptionsToCompilerOptions(this.testData.globalOptions); @@ -253,7 +285,11 @@ namespace FourSlash { // Extend our existing compiler options so that we can also support tsconfig only options if (configJson.config.compilerOptions) { const baseDirectory = ts.normalizePath(ts.getDirectoryPath(file.fileName)); - const tsConfig = ts.convertCompilerOptionsFromJson(configJson.config.compilerOptions, baseDirectory, file.fileName); + const tsConfig = ts.convertCompilerOptionsFromJson( + configJson.config.compilerOptions, + baseDirectory, + file.fileName, + ); if (!tsConfig.errors || !tsConfig.errors.length) { compilationOptions = ts.extend(tsConfig.options, compilationOptions); @@ -267,7 +303,9 @@ namespace FourSlash { } else if (startResolveFileRef) { // If entry point for resolving file references is already specified, report duplication error - throw new Error("There exists a Fourslash file which has resolveReference flag specified; remove duplicated resolveReference flag"); + throw new Error( + "There exists a Fourslash file which has resolveReference flag specified; remove duplicated resolveReference flag", + ); } } @@ -282,26 +320,47 @@ namespace FourSlash { const fs = new vfs.FileSystem(/*ignoreCase*/ true, { cwd: baseDir, files }); const host = new fakes.ParseConfigHost(fs); const jsonSourceFile = ts.parseJsonText(configFileName, this.inputFiles.get(configFileName)!); - configParseResult = ts.parseJsonSourceFileConfigFileContent(jsonSourceFile, host, baseDir, compilationOptions, configFileName); + configParseResult = ts.parseJsonSourceFileConfigFileContent( + jsonSourceFile, + host, + baseDir, + compilationOptions, + configFileName, + ); compilationOptions = configParseResult.options; } if (compilationOptions.typeRoots) { - compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => ts.getNormalizedAbsolutePath(p, this.basePath)); + compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => + ts.getNormalizedAbsolutePath(p, this.basePath) + ); } - const languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions); + const languageServiceAdapter = this.getLanguageServiceAdapter( + testType, + this.cancellationToken, + compilationOptions, + ); this.languageServiceAdapterHost = languageServiceAdapter.getHost(); this.languageService = memoWrap(languageServiceAdapter.getLanguageService(), this); // Wrap the LS to cache some expensive operations certain tests call repeatedly if (this.testType === FourSlashTestType.Server) { - this.assertTextConsistent = fileName => (languageServiceAdapter as Harness.LanguageService.ServerLanguageServiceAdapter).assertTextConsistent(fileName); + this.assertTextConsistent = fileName => + (languageServiceAdapter as Harness.LanguageService.ServerLanguageServiceAdapter) + .assertTextConsistent(fileName); } if (startResolveFileRef) { // Add the entry-point file itself into the languageServiceShimHost - this.languageServiceAdapterHost.addScript(startResolveFileRef.fileName, startResolveFileRef.content, /*isRootFile*/ true); + this.languageServiceAdapterHost.addScript( + startResolveFileRef.fileName, + startResolveFileRef.content, + /*isRootFile*/ true, + ); - const resolvedResult = languageServiceAdapter.getPreProcessedFileInfo(startResolveFileRef.fileName, startResolveFileRef.content); + const resolvedResult = languageServiceAdapter.getPreProcessedFileInfo( + startResolveFileRef.fileName, + startResolveFileRef.content, + ); const referencedFiles: ts.FileReference[] = resolvedResult.referencedFiles; const importedFiles: ts.FileReference[] = resolvedResult.importedFiles; @@ -323,7 +382,11 @@ namespace FourSlash { // Check if no-default-lib flag is false and if so add default library if (!resolvedResult.isLibFile) { - this.languageServiceAdapterHost.addScript(Harness.Compiler.defaultLibFileName, Harness.Compiler.getDefaultLibrarySourceFile()!.text, /*isRootFile*/ false); + this.languageServiceAdapterHost.addScript( + Harness.Compiler.defaultLibFileName, + Harness.Compiler.getDefaultLibrarySourceFile()!.text, + /*isRootFile*/ false, + ); compilationOptions.lib?.forEach(fileName => { const libFile = Harness.Compiler.getDefaultLibrarySourceFile(fileName); @@ -339,9 +402,10 @@ namespace FourSlash { this.inputFiles.forEach((file, fileName) => { if (!Harness.isDefaultLibraryFile(fileName)) { // all files if config file not specified, otherwise root files from the config and typings cache files are root files - const isRootFile = !configParseResult || - ts.contains(configParseResult.fileNames, fileName) || - (ts.isDeclarationFileName(fileName) && ts.containsPath("/Library/Caches/typescript", fileName)); + const isRootFile = !configParseResult + || ts.contains(configParseResult.fileNames, fileName) + || (ts.isDeclarationFileName(fileName) + && ts.containsPath("/Library/Caches/typescript", fileName)); this.languageServiceAdapterHost.addScript(fileName, file, isRootFile); } }); @@ -398,7 +462,14 @@ namespace FourSlash { continue; } const memo = Utils.memoize( - (_version: number, _active: string, _caret: number, _selectEnd: number, _marker: string | undefined, ...args: any[]) => (ls[key] as Function)(...args), + ( + _version: number, + _active: string, + _caret: number, + _selectEnd: number, + _marker: string | undefined, + ...args: any[] + ) => (ls[key] as Function)(...args), (...args) => args.map(a => a && typeof a === "object" ? JSON.stringify(a) : a).join("|,|"), ); proxy[key] = (...args: any[]) => @@ -467,7 +538,10 @@ namespace FourSlash { public goToPosition(positionOrLineAndCharacter: number | ts.LineAndCharacter) { const pos = typeof positionOrLineAndCharacter === "number" ? positionOrLineAndCharacter - : this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, positionOrLineAndCharacter); + : this.languageServiceAdapterHost.lineAndCharacterToPosition( + this.activeFile.fileName, + positionOrLineAndCharacter, + ); this.currentCaretPosition = pos; this.selectionEnd = -1; } @@ -494,14 +568,20 @@ namespace FourSlash { } public selectLine(index: number) { - const lineStart = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { line: index, character: 0 }); + const lineStart = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { + line: index, + character: 0, + }); const lineEnd = lineStart + this.getLineContent(index).length; this.selectRange({ fileName: this.activeFile.fileName, pos: lineStart, end: lineEnd }); } public moveCaretRight(count = 1) { this.currentCaretPosition += count; - this.currentCaretPosition = Math.min(this.currentCaretPosition, this.getFileContent(this.activeFile.fileName).length); + this.currentCaretPosition = Math.min( + this.currentCaretPosition, + this.getFileContent(this.activeFile.fileName).length, + ); this.selectionEnd = -1; } @@ -517,18 +597,27 @@ namespace FourSlash { public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, shouldExist: boolean) { const startMarker = this.getMarkerByName(startMarkerName); const endMarker = this.getMarkerByName(endMarkerName); - const predicate = (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false; + const predicate = (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => + ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false; const exists = this.anyErrorInRange(predicate, startMarker, endMarker); if (exists !== shouldExist) { this.printErrorLog(shouldExist, this.getAllDiagnostics()); - throw new Error(`${shouldExist ? "Expected" : "Did not expect"} failure between markers: '${startMarkerName}', '${endMarkerName}'`); + throw new Error( + `${ + shouldExist ? "Expected" : "Did not expect" + } failure between markers: '${startMarkerName}', '${endMarkerName}'`, + ); } } public verifyOrganizeImports(newContent: string, mode?: ts.OrganizeImportsMode) { - const changes = this.languageService.organizeImports({ fileName: this.activeFile.fileName, type: "file", mode }, this.formatCodeSettings, ts.emptyOptions); + const changes = this.languageService.organizeImports( + { fileName: this.activeFile.fileName, type: "file", mode }, + this.formatCodeSettings, + ts.emptyOptions, + ); this.applyChanges(changes); this.verifyFileContent(this.activeFile.fileName, newContent); } @@ -538,7 +627,8 @@ namespace FourSlash { } private messageAtLastKnownMarker(message: string) { - const locationDescription = this.lastKnownMarker !== undefined ? this.lastKnownMarker : this.getLineColStringAtPosition(this.currentCaretPosition); + const locationDescription = this.lastKnownMarker !== undefined ? this.lastKnownMarker + : this.getLineColStringAtPosition(this.currentCaretPosition); return `At marker '${locationDescription}': ${message}`; } @@ -573,10 +663,12 @@ namespace FourSlash { let predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean; if (after) { - predicate = (errorMinChar: number, errorLimChar: number, startPos: number) => ((errorMinChar >= startPos) && (errorLimChar >= startPos)) ? true : false; + predicate = (errorMinChar: number, errorLimChar: number, startPos: number) => + ((errorMinChar >= startPos) && (errorLimChar >= startPos)) ? true : false; } else { - predicate = (errorMinChar: number, errorLimChar: number, startPos: number) => ((errorMinChar <= startPos) && (errorLimChar <= startPos)) ? true : false; + predicate = (errorMinChar: number, errorLimChar: number, startPos: number) => + ((errorMinChar <= startPos) && (errorLimChar <= startPos)) ? true : false; } const exists = this.anyErrorInRange(predicate, marker); @@ -588,8 +680,24 @@ namespace FourSlash { } } - private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number | undefined) => boolean, startMarker: Marker, endMarker?: Marker): boolean { - return this.getDiagnostics(startMarker.fileName).some(({ start, length }) => predicate(start!, start! + length!, startMarker.position, endMarker === undefined ? undefined : endMarker.position)); // TODO: GH#18217 + private anyErrorInRange( + predicate: ( + errorMinChar: number, + errorLimChar: number, + startPos: number, + endPos: number | undefined, + ) => boolean, + startMarker: Marker, + endMarker?: Marker, + ): boolean { + return this.getDiagnostics(startMarker.fileName).some(({ start, length }) => + predicate( + start!, + start! + length!, + startMarker.position, + endMarker === undefined ? undefined : endMarker.position, + ) + ); // TODO: GH#18217 } private printErrorLog(expectErrors: boolean, errors: readonly ts.Diagnostic[]): void { @@ -602,15 +710,17 @@ namespace FourSlash { for (const { start, length, messageText, file } of errors) { Harness.IO.log( - " " + this.formatRange(file, start!, length!) + // TODO: GH#18217 - ", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n", + " " + this.formatRange(file, start!, length!) // TODO: GH#18217 + + ", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n", ); } } private formatRange(file: ts.SourceFile | undefined, start: number, length: number) { if (file) { - return `from: ${this.formatLineAndCharacterOfPosition(file, start)}, to: ${this.formatLineAndCharacterOfPosition(file, start + length)}`; + return `from: ${this.formatLineAndCharacterOfPosition(file, start)}, to: ${ + this.formatLineAndCharacterOfPosition(file, start + length) + }`; } return "global"; } @@ -636,14 +746,19 @@ namespace FourSlash { !ts.isAnySupportedFileExtension(fileName) || Harness.getConfigNameFromFileName(fileName) // Can't get a Program in Server tests - || this.testType !== FourSlashTestType.Server && !ts.getAllowJSCompilerOption(this.getProgram().getCompilerOptions()) && !ts.resolutionExtensionIsTSOrJson(ts.extensionFromPath(fileName)) + || this.testType !== FourSlashTestType.Server + && !ts.getAllowJSCompilerOption(this.getProgram().getCompilerOptions()) + && !ts.resolutionExtensionIsTSOrJson(ts.extensionFromPath(fileName)) || ts.getBaseFileName(fileName) === "package.json" ) return; - const errors = this.getDiagnostics(fileName).filter(e => e.category !== ts.DiagnosticCategory.Suggestion); + const errors = this.getDiagnostics(fileName).filter(e => + e.category !== ts.DiagnosticCategory.Suggestion + ); if (errors.length) { this.printErrorLog(/*expectErrors*/ false, errors); const error = errors[0]; - const message = typeof error.messageText === "string" ? error.messageText : error.messageText.messageText; + const message = typeof error.messageText === "string" ? error.messageText + : error.messageText.messageText; this.raiseError(`Found an error: ${this.formatPosition(error.file!, error.start!)}: ${message}`); } }); @@ -654,10 +769,10 @@ namespace FourSlash { const hasMatchingError = ts.some( this.getDiagnostics(range.fileName), ({ code, messageText, start, length }) => - code === code && - (!expectedMessage || expectedMessage === messageText) && - ts.isNumber(start) && ts.isNumber(length) && - ts.textSpansEqual(span, { start, length }), + code === code + && (!expectedMessage || expectedMessage === messageText) + && ts.isNumber(start) && ts.isNumber(length) + && ts.textSpansEqual(span, { start, length }), ); if (!hasMatchingError) { @@ -671,7 +786,8 @@ namespace FourSlash { if (actual !== expected) { this.printErrorLog(/*expectErrors*/ false, errors); - const errorMsg = "Actual number of errors (" + actual + ") does not match expected number (" + expected + ")"; + const errorMsg = "Actual number of errors (" + actual + ") does not match expected number (" + expected + + ")"; Harness.IO.log(errorMsg); this.raiseError(errorMsg); } @@ -685,7 +801,9 @@ namespace FourSlash { const evaluation = new Function(`${emit.outputFiles[0].text};\r\nreturn (${expr});`)(); // eslint-disable-line no-new-func if (evaluation !== value) { - this.raiseError(`Expected evaluation of expression "${expr}" to equal "${value}", but got "${evaluation}"`); + this.raiseError( + `Expected evaluation of expression "${expr}" to equal "${value}", but got "${evaluation}"`, + ); } } @@ -693,15 +811,35 @@ namespace FourSlash { this.verifyGoToXWorker(/*startMarker*/ undefined, toArray(endMarker), () => this.getGoToDefinition()); } - public verifyGoToDefinition(arg0: any, endMarkerNames?: ArrayOrSingle | { file: string; unverified?: boolean; }) { + public verifyGoToDefinition( + arg0: any, + endMarkerNames?: ArrayOrSingle | { + file: string; + unverified?: boolean; + }, + ) { this.verifyGoToX(arg0, endMarkerNames, () => this.getGoToDefinitionAndBoundSpan()); } - public verifyGoToSourceDefinition(startMarkerNames: ArrayOrSingle, end?: ArrayOrSingle | { file: string; unverified?: boolean; }) { + public verifyGoToSourceDefinition( + startMarkerNames: ArrayOrSingle, + end?: ArrayOrSingle | { + file: string; + unverified?: boolean; + }, + ) { if (this.testType !== FourSlashTestType.Server) { this.raiseError("goToSourceDefinition may only be used in fourslash/server tests."); } - this.verifyGoToX(startMarkerNames, end, () => (this.languageService as ts.server.SessionClient).getSourceDefinitionAndBoundSpan(this.activeFile.fileName, this.currentCaretPosition)!); + this.verifyGoToX( + startMarkerNames, + end, + () => + (this.languageService as ts.server.SessionClient).getSourceDefinitionAndBoundSpan( + this.activeFile.fileName, + this.currentCaretPosition, + )!, + ); } private getGoToDefinition(): readonly ts.DefinitionInfo[] { @@ -713,10 +851,25 @@ namespace FourSlash { } public verifyGoToType(arg0: any, endMarkerNames?: ArrayOrSingle) { - this.verifyGoToX(arg0, endMarkerNames, () => this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition)); + this.verifyGoToX( + arg0, + endMarkerNames, + () => + this.languageService.getTypeDefinitionAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ), + ); } - private verifyGoToX(arg0: any, endMarkerNames: ArrayOrSingle | { file: string; unverified?: boolean; } | undefined, getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { + private verifyGoToX( + arg0: any, + endMarkerNames: ArrayOrSingle | { + file: string; + unverified?: boolean; + } | undefined, + getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined, + ) { if (endMarkerNames) { this.verifyGoToXPlain(arg0, endMarkerNames, getDefs); } @@ -736,7 +889,14 @@ namespace FourSlash { } } - private verifyGoToXPlain(startMarkerNames: ArrayOrSingle, endMarkerNames: ArrayOrSingle | { file: string; unverified?: boolean; }, getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { + private verifyGoToXPlain( + startMarkerNames: ArrayOrSingle, + endMarkerNames: ArrayOrSingle | { + file: string; + unverified?: boolean; + }, + getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined, + ) { for (const start of toArray(startMarkerNames)) { this.verifyGoToXSingle(start, endMarkerNames, getDefs); } @@ -744,16 +904,32 @@ namespace FourSlash { public verifyGoToDefinitionForMarkers(markerNames: string[]) { for (const markerName of markerNames) { - this.verifyGoToXSingle(`${markerName}Reference`, `${markerName}Definition`, () => this.getGoToDefinition()); + this.verifyGoToXSingle( + `${markerName}Reference`, + `${markerName}Definition`, + () => this.getGoToDefinition(), + ); } } - private verifyGoToXSingle(startMarkerName: string, endMarkerNames: ArrayOrSingle | { file: string; unverified?: boolean; }, getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { + private verifyGoToXSingle( + startMarkerName: string, + endMarkerNames: ArrayOrSingle | { + file: string; + unverified?: boolean; + }, + getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined, + ) { this.goToMarker(startMarkerName); this.verifyGoToXWorker(startMarkerName, toArray(endMarkerNames), getDefs, startMarkerName); } - private verifyGoToXWorker(startMarker: string | undefined, endMarkers: readonly (string | { marker?: string; file?: string; unverified?: boolean; })[], getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined, startMarkerName?: string) { + private verifyGoToXWorker( + startMarker: string | undefined, + endMarkers: readonly (string | { marker?: string; file?: string; unverified?: boolean; })[], + getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined, + startMarkerName?: string, + ) { const defs = getDefs(); let definitions: readonly ts.DefinitionInfo[]; let testName: string; @@ -770,28 +946,56 @@ namespace FourSlash { } if (endMarkers.length !== definitions.length) { - const markers = definitions.map(d => ({ text: "HERE", fileName: d.fileName, position: d.textSpan.start })); + const markers = definitions.map(d => ({ + text: "HERE", + fileName: d.fileName, + position: d.textSpan.start, + })); const actual = this.renderMarkers(markers); - this.raiseError(`${testName} failed - expected to find ${endMarkers.length} definitions but got ${definitions.length}\n\n${actual}`); + this.raiseError( + `${testName} failed - expected to find ${endMarkers.length} definitions but got ${definitions.length}\n\n${actual}`, + ); } ts.zipWith(endMarkers, definitions, (endMarkerOrFileResult, definition, i) => { - const markerName = typeof endMarkerOrFileResult === "string" ? endMarkerOrFileResult : endMarkerOrFileResult.marker; + const markerName = typeof endMarkerOrFileResult === "string" ? endMarkerOrFileResult + : endMarkerOrFileResult.marker; const marker = markerName !== undefined ? this.getMarkerByName(markerName) : undefined; - const expectedFileName = marker?.fileName || typeof endMarkerOrFileResult !== "string" && endMarkerOrFileResult.file; + const expectedFileName = marker?.fileName + || typeof endMarkerOrFileResult !== "string" && endMarkerOrFileResult.file; ts.Debug.assert(typeof expectedFileName === "string"); const expectedPosition = marker?.position || 0; - if (ts.comparePaths(expectedFileName, definition.fileName, /*ignoreCase*/ true) !== ts.Comparison.EqualTo || expectedPosition !== definition.textSpan.start) { - const markers = [{ text: "EXPECTED", fileName: expectedFileName, position: expectedPosition }, { text: "ACTUAL", fileName: definition.fileName, position: definition.textSpan.start }]; + if ( + ts.comparePaths(expectedFileName, definition.fileName, /*ignoreCase*/ true) + !== ts.Comparison.EqualTo || expectedPosition !== definition.textSpan.start + ) { + const markers = [{ text: "EXPECTED", fileName: expectedFileName, position: expectedPosition }, { + text: "ACTUAL", + fileName: definition.fileName, + position: definition.textSpan.start, + }]; const text = this.renderMarkers(markers); - this.raiseError(`${testName} failed for definition ${markerName || expectedFileName} (${i}): expected ${expectedFileName} at ${expectedPosition}, got ${definition.fileName} at ${definition.textSpan.start}\n\n${text}\n`); + this.raiseError( + `${testName} failed for definition ${ + markerName || expectedFileName + } (${i}): expected ${expectedFileName} at ${expectedPosition}, got ${definition.fileName} at ${definition.textSpan.start}\n\n${text}\n`, + ); } - if (definition.unverified && (typeof endMarkerOrFileResult === "string" || !endMarkerOrFileResult.unverified)) { + if ( + definition.unverified + && (typeof endMarkerOrFileResult === "string" || !endMarkerOrFileResult.unverified) + ) { const isFileResult = typeof endMarkerOrFileResult !== "string" && !!endMarkerOrFileResult.file; this.raiseError( - `${testName} failed for definition ${markerName || expectedFileName} (${i}): The actual definition was an \`unverified\` result. Use:\n\n` + - ` verify.goToDefinition(${startMarker === undefined ? "startMarker" : `"${startMarker}"`}, { ${isFileResult ? `file: "${expectedFileName}"` : `marker: "${markerName}"`}, unverified: true })\n\n` + - `if this is expected.`, + `${testName} failed for definition ${ + markerName || expectedFileName + } (${i}): The actual definition was an \`unverified\` result. Use:\n\n` + + ` verify.goToDefinition(${ + startMarker === undefined ? "startMarker" : `"${startMarker}"` + }, { ${ + isFileResult ? `file: "${expectedFileName}"` : `marker: "${markerName}"` + }, unverified: true })\n\n` + + `if this is expected.`, ); } }); @@ -800,10 +1004,13 @@ namespace FourSlash { private renderMarkers(markers: { text: string; fileName: string; position: number; }[]) { const filesToDisplay = ts.deduplicate(markers.map(m => m.fileName), ts.equateValues); return filesToDisplay.map(fileName => { - const markersToRender = markers.filter(m => m.fileName === fileName).sort((a, b) => b.position - a.position); + const markersToRender = markers.filter(m => m.fileName === fileName).sort((a, b) => + b.position - a.position + ); let fileContent = this.tryGetFileContent(fileName) || ""; for (const marker of markersToRender) { - fileContent = fileContent.slice(0, marker.position) + `\x1b[1;4m/*${marker.text}*/\x1b[0;31m` + fileContent.slice(marker.position); + fileContent = fileContent.slice(0, marker.position) + `\x1b[1;4m/*${marker.text}*/\x1b[0;31m` + + fileContent.slice(marker.position); } return `// @Filename: ${fileName}\n${fileContent}`; }).join("\n\n"); @@ -821,9 +1028,12 @@ namespace FourSlash { const startFile = marker.fileName; const fileContent = this.getFileContent(startFile); const spanContent = fileContent.slice(defs.textSpan.start, ts.textSpanEnd(defs.textSpan)); - const spanContentWithMarker = spanContent.slice(0, marker.position - defs.textSpan.start) + `/*${startMarkerName}*/` + spanContent.slice(marker.position - defs.textSpan.start); - const suggestedFileContent = (fileContent.slice(0, defs.textSpan.start) + `\x1b[1;4m[|${spanContentWithMarker}|]\x1b[0;31m` + fileContent.slice(ts.textSpanEnd(defs.textSpan))) - .split(/\r?\n/).map(line => " ".repeat(6) + line).join(ts.sys.newLine); + const spanContentWithMarker = spanContent.slice(0, marker.position - defs.textSpan.start) + + `/*${startMarkerName}*/` + spanContent.slice(marker.position - defs.textSpan.start); + const suggestedFileContent = + (fileContent.slice(0, defs.textSpan.start) + `\x1b[1;4m[|${spanContentWithMarker}|]\x1b[0;31m` + + fileContent.slice(ts.textSpanEnd(defs.textSpan))) + .split(/\r?\n/).map(line => " ".repeat(6) + line).join(ts.sys.newLine); this.raiseError( `goToDefinitionsAndBoundSpan failed. Found a starting TextSpan around '${spanContent}' in '${startFile}' (at position ${defs.textSpan.start}). ` + `If this is the correct input span, put a fourslash range around it: \n\n${suggestedFileContent}\n`, @@ -854,7 +1064,11 @@ namespace FourSlash { }); } - public verifyInlayHints(expected: readonly FourSlashInterface.VerifyInlayHintsOptions[], span: ts.TextSpan = { start: 0, length: this.activeFile.content.length }, preference?: ts.UserPreferences) { + public verifyInlayHints( + expected: readonly FourSlashInterface.VerifyInlayHintsOptions[], + span: ts.TextSpan = { start: 0, length: this.activeFile.content.length }, + preference?: ts.UserPreferences, + ) { const hints = this.languageService.provideInlayHints(this.activeFile.fileName, span, preference); assert.equal(hints.length, expected.length, "Number of hints"); @@ -883,20 +1097,35 @@ namespace FourSlash { } private verifyCompletionsWorker(options: FourSlashInterface.VerifyCompletionsOptions): void { - const actualCompletions = this.getCompletionListAtCaret({ ...options.preferences, triggerCharacter: options.triggerCharacter })!; + const actualCompletions = this.getCompletionListAtCaret({ + ...options.preferences, + triggerCharacter: options.triggerCharacter, + })!; if (!actualCompletions) { - if (ts.hasProperty(options, "exact") && (options.exact === undefined || ts.isArray(options.exact) && !options.exact.length)) { + if ( + ts.hasProperty(options, "exact") + && (options.exact === undefined || ts.isArray(options.exact) && !options.exact.length) + ) { return; } this.raiseError(`No completions at position '${this.currentCaretPosition}'.`); } if (actualCompletions.isNewIdentifierLocation !== (options.isNewIdentifierLocation || false)) { - this.raiseError(`Expected 'isNewIdentifierLocation' to be ${options.isNewIdentifierLocation || false}, got ${actualCompletions.isNewIdentifierLocation}`); + this.raiseError( + `Expected 'isNewIdentifierLocation' to be ${ + options.isNewIdentifierLocation || false + }, got ${actualCompletions.isNewIdentifierLocation}`, + ); } - if (ts.hasProperty(options, "isGlobalCompletion") && actualCompletions.isGlobalCompletion !== options.isGlobalCompletion) { - this.raiseError(`Expected 'isGlobalCompletion to be ${options.isGlobalCompletion}, got ${actualCompletions.isGlobalCompletion}`); + if ( + ts.hasProperty(options, "isGlobalCompletion") + && actualCompletions.isGlobalCompletion !== options.isGlobalCompletion + ) { + this.raiseError( + `Expected 'isGlobalCompletion to be ${options.isGlobalCompletion}, got ${actualCompletions.isGlobalCompletion}`, + ); } if (ts.hasProperty(options, "optionalReplacementSpan")) { @@ -916,11 +1145,11 @@ namespace FourSlash { else { if ( entries.some(e => - e.source === entry.source && - e.data?.exportName === entry.data?.exportName && - e.data?.fileName === entry.data?.fileName && - e.data?.moduleSpecifier === entry.data?.moduleSpecifier && - e.data?.ambientModuleName === entry.data?.ambientModuleName + e.source === entry.source + && e.data?.exportName === entry.data?.exportName + && e.data?.fileName === entry.data?.fileName + && e.data?.moduleSpecifier === entry.data?.moduleSpecifier + && e.data?.ambientModuleName === entry.data?.ambientModuleName ) ) { this.raiseError(`Duplicate completions for ${entry.name}`); @@ -930,7 +1159,10 @@ namespace FourSlash { } if (ts.hasProperty(options, "exact")) { - ts.Debug.assert(!ts.hasProperty(options, "includes") && !ts.hasProperty(options, "excludes") && !ts.hasProperty(options, "unsorted")); + ts.Debug.assert( + !ts.hasProperty(options, "includes") && !ts.hasProperty(options, "excludes") + && !ts.hasProperty(options, "unsorted"), + ); if (options.exact === undefined) throw this.raiseError("Expected no completions"); this.verifyCompletionsAreExactly(actualCompletions.entries, options.exact, options.marker); } @@ -940,7 +1172,9 @@ namespace FourSlash { const name = typeof expectedEntry === "string" ? expectedEntry : expectedEntry.name; const found = nameToEntries.get(name); if (!found) throw this.raiseError(`Unsorted: completion '${name}' not found.`); - if (!found.length) throw this.raiseError(`Unsorted: no completions with name '${name}' remain unmatched.`); + if (!found.length) { + throw this.raiseError(`Unsorted: no completions with name '${name}' remain unmatched.`); + } this.verifyCompletionEntry(found.shift()!, expectedEntry); } if (actualCompletions.entries.length !== options.unsorted.length) { @@ -957,7 +1191,9 @@ namespace FourSlash { const name = typeof include === "string" ? include : include.name; const found = nameToEntries.get(name); if (!found) throw this.raiseError(`Includes: completion '${name}' not found.`); - if (!found.length) throw this.raiseError(`Includes: no completions with name '${name}' remain unmatched.`); + if (!found.length) { + throw this.raiseError(`Includes: no completions with name '${name}' remain unmatched.`); + } this.verifyCompletionEntry(found.shift()!, include); } } @@ -972,74 +1208,170 @@ namespace FourSlash { } } - private verifyCompletionEntry(actual: ts.CompletionEntry, expected: FourSlashInterface.ExpectedCompletionEntry) { + private verifyCompletionEntry( + actual: ts.CompletionEntry, + expected: FourSlashInterface.ExpectedCompletionEntry, + ) { expected = typeof expected === "string" ? { name: expected } : expected; if (actual.insertText !== expected.insertText) { - this.raiseError(`At entry ${actual.name}: Completion insert text did not match: ${showTextDiff(expected.insertText || "", actual.insertText || "")}`); + this.raiseError( + `At entry ${actual.name}: Completion insert text did not match: ${ + showTextDiff(expected.insertText || "", actual.insertText || "") + }`, + ); } - const convertedReplacementSpan = expected.replacementSpan && ts.createTextSpanFromRange(expected.replacementSpan); + const convertedReplacementSpan = expected.replacementSpan + && ts.createTextSpanFromRange(expected.replacementSpan); if (convertedReplacementSpan?.length) { try { assert.deepEqual(actual.replacementSpan, convertedReplacementSpan); } catch { - this.raiseError(`At entry ${actual.name}: Expected completion replacementSpan to be ${stringify(convertedReplacementSpan)}, got ${stringify(actual.replacementSpan)}`); + this.raiseError( + `At entry ${actual.name}: Expected completion replacementSpan to be ${ + stringify(convertedReplacementSpan) + }, got ${stringify(actual.replacementSpan)}`, + ); } } if (expected.kind !== undefined || expected.kindModifiers !== undefined) { - assert.equal(actual.kind, expected.kind, `At entry ${actual.name}: Expected 'kind' for ${actual.name} to match`); - assert.equal(actual.kindModifiers, expected.kindModifiers || "", `At entry ${actual.name}: Expected 'kindModifiers' for ${actual.name} to match`); + assert.equal( + actual.kind, + expected.kind, + `At entry ${actual.name}: Expected 'kind' for ${actual.name} to match`, + ); + assert.equal( + actual.kindModifiers, + expected.kindModifiers || "", + `At entry ${actual.name}: Expected 'kindModifiers' for ${actual.name} to match`, + ); } if (expected.isFromUncheckedFile !== undefined) { - assert.equal(actual.isFromUncheckedFile, expected.isFromUncheckedFile, `At entry ${actual.name}: Expected 'isFromUncheckedFile' properties to match`); + assert.equal( + actual.isFromUncheckedFile, + expected.isFromUncheckedFile, + `At entry ${actual.name}: Expected 'isFromUncheckedFile' properties to match`, + ); } if (expected.isPackageJsonImport !== undefined) { - assert.equal(actual.isPackageJsonImport, expected.isPackageJsonImport, `At entry ${actual.name}: Expected 'isPackageJsonImport' properties to match`); + assert.equal( + actual.isPackageJsonImport, + expected.isPackageJsonImport, + `At entry ${actual.name}: Expected 'isPackageJsonImport' properties to match`, + ); } - assert.equal(actual.labelDetails?.description, expected.labelDetails?.description, `At entry ${actual.name}: Expected 'labelDetails.description' properties to match`); - assert.equal(actual.labelDetails?.detail, expected.labelDetails?.detail, `At entry ${actual.name}: Expected 'labelDetails.detail' properties to match`); - assert.equal(actual.hasAction, expected.hasAction, `At entry ${actual.name}: Expected 'hasAction' properties to match`); - assert.equal(actual.isRecommended, expected.isRecommended, `At entry ${actual.name}: Expected 'isRecommended' properties to match'`); - assert.equal(actual.isSnippet, expected.isSnippet, `At entry ${actual.name}: Expected 'isSnippet' properties to match`); + assert.equal( + actual.labelDetails?.description, + expected.labelDetails?.description, + `At entry ${actual.name}: Expected 'labelDetails.description' properties to match`, + ); + assert.equal( + actual.labelDetails?.detail, + expected.labelDetails?.detail, + `At entry ${actual.name}: Expected 'labelDetails.detail' properties to match`, + ); + assert.equal( + actual.hasAction, + expected.hasAction, + `At entry ${actual.name}: Expected 'hasAction' properties to match`, + ); + assert.equal( + actual.isRecommended, + expected.isRecommended, + `At entry ${actual.name}: Expected 'isRecommended' properties to match'`, + ); + assert.equal( + actual.isSnippet, + expected.isSnippet, + `At entry ${actual.name}: Expected 'isSnippet' properties to match`, + ); assert.equal(actual.source, expected.source, `At entry ${actual.name}: Expected 'source' values to match`); - assert.equal(actual.sortText, expected.sortText || ts.Completions.SortText.LocationPriority, `At entry ${actual.name}: Expected 'sortText' properties to match`); + assert.equal( + actual.sortText, + expected.sortText || ts.Completions.SortText.LocationPriority, + `At entry ${actual.name}: Expected 'sortText' properties to match`, + ); if (expected.sourceDisplay && actual.sourceDisplay) { - assert.equal(ts.displayPartsToString(actual.sourceDisplay), expected.sourceDisplay, `At entry ${actual.name}: Expected 'sourceDisplay' properties to match`); + assert.equal( + ts.displayPartsToString(actual.sourceDisplay), + expected.sourceDisplay, + `At entry ${actual.name}: Expected 'sourceDisplay' properties to match`, + ); } if (expected.text !== undefined) { - const actualDetails = ts.Debug.checkDefined(this.getCompletionEntryDetails(actual.name, actual.source, actual.data), `No completion details available for name '${actual.name}' and source '${actual.source}'`); - assert.equal(ts.displayPartsToString(actualDetails.displayParts), expected.text, "Expected 'text' property to match 'displayParts' string"); - assert.equal(ts.displayPartsToString(actualDetails.documentation), expected.documentation || "", "Expected 'documentation' property to match 'documentation' display parts string"); + const actualDetails = ts.Debug.checkDefined( + this.getCompletionEntryDetails(actual.name, actual.source, actual.data), + `No completion details available for name '${actual.name}' and source '${actual.source}'`, + ); + assert.equal( + ts.displayPartsToString(actualDetails.displayParts), + expected.text, + "Expected 'text' property to match 'displayParts' string", + ); + assert.equal( + ts.displayPartsToString(actualDetails.documentation), + expected.documentation || "", + "Expected 'documentation' property to match 'documentation' display parts string", + ); // TODO: GH#23587 // assert.equal(actualDetails.kind, actual.kind); - assert.equal(actualDetails.kindModifiers, actual.kindModifiers, "Expected 'kindModifiers' properties to match"); - assert.equal(actualDetails.source && ts.displayPartsToString(actualDetails.source), expected.sourceDisplay, "Expected 'sourceDisplay' property to match 'source' display parts string"); + assert.equal( + actualDetails.kindModifiers, + actual.kindModifiers, + "Expected 'kindModifiers' properties to match", + ); + assert.equal( + actualDetails.source && ts.displayPartsToString(actualDetails.source), + expected.sourceDisplay, + "Expected 'sourceDisplay' property to match 'source' display parts string", + ); if (!actual.sourceDisplay) { - assert.equal(actualDetails.sourceDisplay && ts.displayPartsToString(actualDetails.sourceDisplay), expected.sourceDisplay, "Expected 'sourceDisplay' property to match 'sourceDisplay' display parts string"); + assert.equal( + actualDetails.sourceDisplay && ts.displayPartsToString(actualDetails.sourceDisplay), + expected.sourceDisplay, + "Expected 'sourceDisplay' property to match 'sourceDisplay' display parts string", + ); } assert.deepEqual(actualDetails.tags, expected.tags); } else { - assert(expected.documentation === undefined && expected.tags === undefined, "If specifying completion details, should specify 'text'"); + assert( + expected.documentation === undefined && expected.tags === undefined, + "If specifying completion details, should specify 'text'", + ); } } - private verifyCompletionsAreExactly(actual: readonly ts.CompletionEntry[], expected: ArrayOrSingle | FourSlashInterface.ExpectedExactCompletionsPlus, marker?: ArrayOrSingle) { + private verifyCompletionsAreExactly( + actual: readonly ts.CompletionEntry[], + expected: + | ArrayOrSingle + | FourSlashInterface.ExpectedExactCompletionsPlus, + marker?: ArrayOrSingle, + ) { if (!ts.isArray(expected)) { expected = [expected]; } // First pass: test that names are right. Then we'll test details. - assert.deepEqual(actual.map(a => a.name), expected.map(e => typeof e === "string" ? e : e.name), marker ? "At marker " + JSON.stringify(marker) : undefined); + assert.deepEqual( + actual.map(a => a.name), + expected.map(e => typeof e === "string" ? e : e.name), + marker ? "At marker " + JSON.stringify(marker) : undefined, + ); ts.zipWith(actual, expected, (completion, expectedCompletion, index) => { const name = typeof expectedCompletion === "string" ? expectedCompletion : expectedCompletion.name; if (completion.name !== name) { - this.raiseError(`${marker ? JSON.stringify(marker) : ""} Expected completion at index ${index} to be ${name}, got ${completion.name}`); + this.raiseError( + `${ + marker ? JSON.stringify(marker) : "" + } Expected completion at index ${index} to be ${name}, got ${completion.name}`, + ); } this.verifyCompletionEntry(completion, expectedCompletion); }); @@ -1102,7 +1434,9 @@ namespace FourSlash { private verifySymbol(symbol: ts.Symbol, declarationRanges: Range[]) { const { declarations } = symbol; if (declarations?.length !== declarationRanges.length) { - this.raiseError(`Expected to get ${declarationRanges.length} declarations, got ${declarations?.length}`); + this.raiseError( + `Expected to get ${declarationRanges.length} declarations, got ${declarations?.length}`, + ); } ts.zipWith(declarations, declarationRanges, (decl, range) => { @@ -1121,7 +1455,10 @@ namespace FourSlash { public symbolsInScope(range: Range): ts.Symbol[] { const node = this.goToAndGetNode(range); - return this.getChecker().getSymbolsInScope(node, ts.SymbolFlags.Value | ts.SymbolFlags.Type | ts.SymbolFlags.Namespace); + return this.getChecker().getSymbolsInScope( + node, + ts.SymbolFlags.Value | ts.SymbolFlags.Type | ts.SymbolFlags.Namespace, + ); } public setTypesRegistry(map: ts.MapLike): void { @@ -1140,13 +1477,19 @@ namespace FourSlash { } public verifyBaselineFindAllReferences(...markerNames: string[]) { - ts.Debug.assert(markerNames.length > 0, "Must pass at least one marker name to `verifyBaselineFindAllReferences()`"); + ts.Debug.assert( + markerNames.length > 0, + "Must pass at least one marker name to `verifyBaselineFindAllReferences()`", + ); this.verifyBaselineFindAllReferencesWorker("", markerNames); } // Used when a single test needs to produce multiple baselines public verifyBaselineFindAllReferencesMulti(seq: number, ...markerNames: string[]) { - ts.Debug.assert(markerNames.length > 0, "Must pass at least one marker name to `baselineFindAllReferences()`"); + ts.Debug.assert( + markerNames.length > 0, + "Must pass at least one marker name to `baselineFindAllReferences()`", + ); this.verifyBaselineFindAllReferencesWorker(`.${seq}`, markerNames); } @@ -1156,7 +1499,13 @@ namespace FourSlash { const marker = this.getMarkerByName(markerName); const references = this.languageService.findReferences(marker.fileName, marker.position); const refsByFile = references - ? ts.group(ts.sort(ts.flatMap(references, r => r.references), (a, b) => a.textSpan.start - b.textSpan.start), ref => ref.fileName) + ? ts.group( + ts.sort( + ts.flatMap(references, r => r.references), + (a, b) => a.textSpan.start - b.textSpan.start, + ), + ref => ref.fileName, + ) : ts.emptyArray; // Write input files @@ -1165,7 +1514,10 @@ namespace FourSlash { // Write response JSON return baselineContent + JSON.stringify(references, undefined, 2); }).join("\n\n"); - Harness.Baseline.runBaseline(this.getBaselineFileNameForContainingTestFile(`${suffix}.baseline.jsonc`), baseline); + Harness.Baseline.runBaseline( + this.getBaselineFileNameForContainingTestFile(`${suffix}.baseline.jsonc`), + baseline, + ); } public verifyBaselineGetFileReferences(fileName: string) { @@ -1179,10 +1531,16 @@ namespace FourSlash { // Write response JSON baselineContent += JSON.stringify(references, undefined, 2); - Harness.Baseline.runBaseline(this.getBaselineFileNameForContainingTestFile(".baseline.jsonc"), baselineContent); + Harness.Baseline.runBaseline( + this.getBaselineFileNameForContainingTestFile(".baseline.jsonc"), + baselineContent, + ); } - private getBaselineContentForGroupedReferences(refsByFile: readonly (readonly ts.ReferenceEntry[])[], markerName?: string) { + private getBaselineContentForGroupedReferences( + refsByFile: readonly (readonly ts.ReferenceEntry[])[], + markerName?: string, + ) { const marker = markerName !== undefined ? this.getMarkerByName(markerName) : undefined; let baselineContent = ""; for (const group of refsByFile) { @@ -1235,7 +1593,11 @@ namespace FourSlash { private assertObjectsEqual(fullActual: T, fullExpected: T, msgPrefix = ""): void { const recur = (actual: U, expected: U, path: string) => { const fail = (msg: string) => { - this.raiseError(`${msgPrefix} At ${path}: ${msg} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`); + this.raiseError( + `${msgPrefix} At ${path}: ${msg} ${ + displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual)) + }`, + ); }; if ((actual === undefined) !== (expected === undefined)) { @@ -1267,7 +1629,9 @@ namespace FourSlash { if (fullActual === fullExpected) { return; } - this.raiseError(`${msgPrefix} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`); + this.raiseError( + `${msgPrefix} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`, + ); } recur(fullActual, fullExpected, ""); } @@ -1282,7 +1646,11 @@ namespace FourSlash { this.raiseError("More than one referenced symbol found"); } - assert.equal(TestState.getDisplayPartsJson(referencedSymbols[0].definition.displayParts), TestState.getDisplayPartsJson(expected), this.messageAtLastKnownMarker("referenced symbol definition display parts")); + assert.equal( + TestState.getDisplayPartsJson(referencedSymbols[0].definition.displayParts), + TestState.getDisplayPartsJson(expected), + this.messageAtLastKnownMarker("referenced symbol definition display parts"), + ); } private configure(preferences: ts.UserPreferences) { @@ -1303,11 +1671,24 @@ namespace FourSlash { ); } - private getCompletionEntryDetails(entryName: string, source: string | undefined, data: ts.CompletionEntryData | undefined, preferences?: ts.UserPreferences): ts.CompletionEntryDetails | undefined { + private getCompletionEntryDetails( + entryName: string, + source: string | undefined, + data: ts.CompletionEntryData | undefined, + preferences?: ts.UserPreferences, + ): ts.CompletionEntryDetails | undefined { if (preferences) { this.configure(preferences); } - return this.languageService.getCompletionEntryDetails(this.activeFile.fileName, this.currentCaretPosition, entryName, this.formatCodeSettings, source, preferences, data); + return this.languageService.getCompletionEntryDetails( + this.activeFile.fileName, + this.currentCaretPosition, + entryName, + this.formatCodeSettings, + source, + preferences, + data, + ); } private findReferencesAtCaret() { @@ -1325,16 +1706,26 @@ namespace FourSlash { } public getSuggestionDiagnostics(expected: readonly FourSlashInterface.Diagnostic[]): void { - this.testDiagnostics(expected, this.languageService.getSuggestionDiagnostics(this.activeFile.fileName), "suggestion"); + this.testDiagnostics( + expected, + this.languageService.getSuggestionDiagnostics(this.activeFile.fileName), + "suggestion", + ); } - private testDiagnostics(expected: readonly FourSlashInterface.Diagnostic[], diagnostics: readonly ts.Diagnostic[], category: string) { + private testDiagnostics( + expected: readonly FourSlashInterface.Diagnostic[], + diagnostics: readonly ts.Diagnostic[], + category: string, + ) { assert.deepEqual( ts.realizeDiagnostics(diagnostics, "\n"), expected.map((e): ts.RealizedDiagnostic => { const range = e.range || this.getRangesInFile()[0]; if (!range) { - this.raiseError("Must provide a range for each expected diagnostic, or have one range in the fourslash source."); + this.raiseError( + "Must provide a range for each expected diagnostic, or have one range in the fourslash source.", + ); } return { message: e.message, @@ -1348,7 +1739,12 @@ namespace FourSlash { ); } - public verifyQuickInfoAt(markerName: string | Range, expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) { + public verifyQuickInfoAt( + markerName: string | Range, + expectedText: string, + expectedDocumentation?: string, + expectedTags?: { name: string; text: string; }[], + ) { if (typeof markerName === "string") this.goToMarker(markerName); else this.goToRangeStart(markerName); @@ -1371,17 +1767,31 @@ namespace FourSlash { } } - public verifyQuickInfoString(expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) { + public verifyQuickInfoString( + expectedText: string, + expectedDocumentation?: string, + expectedTags?: { name: string; text: string; }[], + ) { if (expectedDocumentation === "") { throw new Error("Use 'undefined' instead of empty string for `expectedDocumentation`"); } - const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const actualQuickInfo = this.languageService.getQuickInfoAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); const actualQuickInfoText = ts.displayPartsToString(actualQuickInfo?.displayParts); const actualQuickInfoDocumentation = ts.displayPartsToString(actualQuickInfo?.documentation); - const actualQuickInfoTags = actualQuickInfo?.tags?.map(tag => ({ name: tag.name, text: ts.displayPartsToString(tag.text) })); + const actualQuickInfoTags = actualQuickInfo?.tags?.map(tag => ({ + name: tag.name, + text: ts.displayPartsToString(tag.text), + })); assert.equal(actualQuickInfoText, expectedText, this.messageAtLastKnownMarker("quick info text")); - assert.equal(actualQuickInfoDocumentation, expectedDocumentation || "", this.assertionMessageAtLastKnownMarker("quick info doc")); + assert.equal( + actualQuickInfoDocumentation, + expectedDocumentation || "", + this.assertionMessageAtLastKnownMarker("quick info doc"), + ); if (!expectedTags) { // Skip if `expectedTags` is not given } @@ -1391,18 +1801,48 @@ namespace FourSlash { else { ts.zipWith(expectedTags, actualQuickInfoTags, (expectedTag, actualTag) => { assert.equal(expectedTag.name, actualTag.name); - assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name)); + assert.equal( + expectedTag.text, + actualTag.text, + this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name), + ); }); } } - public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: TextSpan, displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], tags: ts.JSDocTagInfo[] | undefined) { - const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition)!; + public verifyQuickInfoDisplayParts( + kind: string, + kindModifiers: string, + textSpan: TextSpan, + displayParts: ts.SymbolDisplayPart[], + documentation: ts.SymbolDisplayPart[], + tags: ts.JSDocTagInfo[] | undefined, + ) { + const actualQuickInfo = this.languageService.getQuickInfoAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + )!; assert.equal(actualQuickInfo.kind, kind, this.messageAtLastKnownMarker("QuickInfo kind")); - assert.equal(actualQuickInfo.kindModifiers, kindModifiers, this.messageAtLastKnownMarker("QuickInfo kindModifiers")); - assert.equal(JSON.stringify(actualQuickInfo.textSpan), JSON.stringify(textSpan), this.messageAtLastKnownMarker("QuickInfo textSpan")); - assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.displayParts), TestState.getDisplayPartsJson(displayParts), this.messageAtLastKnownMarker("QuickInfo displayParts")); - assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.documentation), TestState.getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation")); + assert.equal( + actualQuickInfo.kindModifiers, + kindModifiers, + this.messageAtLastKnownMarker("QuickInfo kindModifiers"), + ); + assert.equal( + JSON.stringify(actualQuickInfo.textSpan), + JSON.stringify(textSpan), + this.messageAtLastKnownMarker("QuickInfo textSpan"), + ); + assert.equal( + TestState.getDisplayPartsJson(actualQuickInfo.displayParts), + TestState.getDisplayPartsJson(displayParts), + this.messageAtLastKnownMarker("QuickInfo displayParts"), + ); + assert.equal( + TestState.getDisplayPartsJson(actualQuickInfo.documentation), + TestState.getDisplayPartsJson(documentation), + this.messageAtLastKnownMarker("QuickInfo documentation"), + ); if (!actualQuickInfo.tags || !tags) { assert.equal(actualQuickInfo.tags, tags, this.messageAtLastKnownMarker("QuickInfo tags")); } @@ -1410,12 +1850,18 @@ namespace FourSlash { assert.equal(actualQuickInfo.tags.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags")); ts.zipWith(tags, actualQuickInfo.tags, (expectedTag, actualTag) => { assert.equal(expectedTag.name, actualTag.name); - assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name)); + assert.equal( + expectedTag.text, + actualTag.text, + this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name), + ); }); } } - public verifyRangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean; findInComments?: boolean; ranges?: Range[]; }) { + public verifyRangesAreRenameLocations( + options?: Range[] | { findInStrings?: boolean; findInComments?: boolean; ranges?: Range[]; }, + ) { if (ts.isArray(options)) { this.verifyRenameLocations(options, options); } @@ -1425,15 +1871,28 @@ namespace FourSlash { } } - public verifyRenameLocations(startRanges: ArrayOrSingle, options: FourSlashInterface.RenameLocationsOptions) { + public verifyRenameLocations( + startRanges: ArrayOrSingle, + options: FourSlashInterface.RenameLocationsOptions, + ) { interface RangeMarkerData { id?: string; contextRangeIndex?: number; contextRangeDelta?: number; contextRangeId?: string; } - const { findInStrings = false, findInComments = false, ranges = this.getRanges(), providePrefixAndSuffixTextForRename = true } = ts.isArray(options) - ? { findInStrings: false, findInComments: false, ranges: options, providePrefixAndSuffixTextForRename: true } + const { + findInStrings = false, + findInComments = false, + ranges = this.getRanges(), + providePrefixAndSuffixTextForRename = true, + } = ts.isArray(options) + ? { + findInStrings: false, + findInComments: false, + ranges: options, + providePrefixAndSuffixTextForRename: true, + } : options; const _startRanges = toArray(startRanges); @@ -1441,7 +1900,11 @@ namespace FourSlash { for (const startRange of _startRanges) { this.goToRangeStart(startRange); - const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition, { providePrefixAndSuffixTextForRename }); + const renameInfo = this.languageService.getRenameInfo( + this.activeFile.fileName, + this.currentCaretPosition, + { providePrefixAndSuffixTextForRename }, + ); if (!renameInfo.canRename) { this.raiseError("Expected rename to succeed, but it actually failed."); break; @@ -1455,12 +1918,18 @@ namespace FourSlash { providePrefixAndSuffixTextForRename, ); - const sort = (locations: readonly ts.RenameLocation[] | undefined) => locations && ts.sort(locations, (r1, r2) => ts.compareStringsCaseSensitive(r1.fileName, r2.fileName) || r1.textSpan.start - r2.textSpan.start); + const sort = (locations: readonly ts.RenameLocation[] | undefined) => + locations + && ts.sort(locations, (r1, r2) => + ts.compareStringsCaseSensitive(r1.fileName, r2.fileName) + || r1.textSpan.start - r2.textSpan.start); assert.deepEqual( sort(references), sort(ranges.map((rangeOrOptions): ts.RenameLocation => { - const { range, ...prefixSuffixText } = "range" in rangeOrOptions ? rangeOrOptions : { range: rangeOrOptions }; // eslint-disable-line local/no-in-operator - const { contextRangeIndex, contextRangeDelta, contextRangeId } = (range.marker && range.marker.data || {}) as RangeMarkerData; + const { range, ...prefixSuffixText } = "range" in rangeOrOptions ? rangeOrOptions + : { range: rangeOrOptions }; // eslint-disable-line local/no-in-operator + const { contextRangeIndex, contextRangeDelta, contextRangeId } = + (range.marker && range.marker.data || {}) as RangeMarkerData; let contextSpan: ts.TextSpan | undefined; if (contextRangeDelta !== undefined) { const allRanges = this.getRanges(); @@ -1471,7 +1940,10 @@ namespace FourSlash { } else if (contextRangeId !== undefined) { const allRanges = this.getRanges(); - const contextRange = ts.find(allRanges, range => (range.marker?.data as RangeMarkerData)?.id === contextRangeId); + const contextRange = ts.find( + allRanges, + range => (range.marker?.data as RangeMarkerData)?.id === contextRangeId, + ); if (contextRange) { contextSpan = ts.createTextSpanFromRange(contextRange); } @@ -1510,10 +1982,11 @@ namespace FourSlash { const sortedRenames = ts.sort(renames, (a, b) => b.textSpan.start - a.textSpan.start); let baselineFileContent = this.getFileContent(fileName); for (const { textSpan } of sortedRenames) { - const isOriginalSpan = fileName === this.activeFile.fileName && ts.textSpanIntersectsWithPosition(textSpan, position); - baselineFileContent = baselineFileContent.slice(0, textSpan.start) + - (isOriginalSpan ? "[|RENAME|]" : "RENAME") + - baselineFileContent.slice(textSpan.start + textSpan.length); + const isOriginalSpan = fileName === this.activeFile.fileName + && ts.textSpanIntersectsWithPosition(textSpan, position); + baselineFileContent = baselineFileContent.slice(0, textSpan.start) + + (isOriginalSpan ? "[|RENAME|]" : "RENAME") + + baselineFileContent.slice(textSpan.start + textSpan.length); } return `/*====== ${fileName} ======*/\n\n${baselineFileContent}`; }).join("\n\n") + "\n"; @@ -1522,7 +1995,10 @@ namespace FourSlash { } public verifyQuickInfoExists(negative: boolean) { - const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const actualQuickInfo = this.languageService.getQuickInfoAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); if (negative) { if (actualQuickInfo) { this.raiseError("verifyQuickInfoExists failed. Expected quick info NOT to exist"); @@ -1535,7 +2011,11 @@ namespace FourSlash { } } - public verifySignatureHelpPresence(expectPresent: boolean, triggerReason: ts.SignatureHelpTriggerReason | undefined, markers: readonly (string | Marker)[]) { + public verifySignatureHelpPresence( + expectPresent: boolean, + triggerReason: ts.SignatureHelpTriggerReason | undefined, + markers: readonly (string | Marker)[], + ) { if (markers.length) { for (const marker of markers) { this.goToMarker(marker); @@ -1576,17 +2056,29 @@ namespace FourSlash { const selectedItem = help.items[options.overrideSelectedItemIndex ?? help.selectedItemIndex]; // Argument index may exceed number of parameters - const currentParameter = selectedItem.parameters[help.argumentIndex] as ts.SignatureHelpParameter | undefined; - - assert.equal(help.items.length, options.overloadsCount || 1, this.assertionMessageAtLastKnownMarker("signature help overloads count")); + const currentParameter = selectedItem.parameters[help.argumentIndex] as + | ts.SignatureHelpParameter + | undefined; + + assert.equal( + help.items.length, + options.overloadsCount || 1, + this.assertionMessageAtLastKnownMarker("signature help overloads count"), + ); - assert.equal(ts.displayPartsToString(selectedItem.documentation), options.docComment || "", this.assertionMessageAtLastKnownMarker("current signature help doc comment")); + assert.equal( + ts.displayPartsToString(selectedItem.documentation), + options.docComment || "", + this.assertionMessageAtLastKnownMarker("current signature help doc comment"), + ); if (options.text !== undefined) { assert.equal( - ts.displayPartsToString(selectedItem.prefixDisplayParts) + - selectedItem.parameters.map(p => ts.displayPartsToString(p.displayParts)).join(ts.displayPartsToString(selectedItem.separatorDisplayParts)) + - ts.displayPartsToString(selectedItem.suffixDisplayParts), + ts.displayPartsToString(selectedItem.prefixDisplayParts) + + selectedItem.parameters.map(p => ts.displayPartsToString(p.displayParts)).join( + ts.displayPartsToString(selectedItem.separatorDisplayParts), + ) + + ts.displayPartsToString(selectedItem.suffixDisplayParts), options.text, ); } @@ -1597,7 +2089,11 @@ namespace FourSlash { assert.equal(ts.displayPartsToString(currentParameter!.displayParts), options.parameterSpan); } if (currentParameter) { - assert.equal(ts.displayPartsToString(currentParameter.documentation), options.parameterDocComment || "", this.assertionMessageAtLastKnownMarker("current parameter Help DocComment")); + assert.equal( + ts.displayPartsToString(currentParameter.documentation), + options.parameterDocComment || "", + this.assertionMessageAtLastKnownMarker("current parameter Help DocComment"), + ); } if (options.parameterCount !== undefined) { assert.equal(selectedItem.parameters.length, options.parameterCount); @@ -1609,10 +2105,18 @@ namespace FourSlash { assert.equal(selectedItem.isVariadic, !!options.isVariadic); const actualTags = selectedItem.tags; - assert.equal(actualTags.length, (options.tags || ts.emptyArray).length, this.assertionMessageAtLastKnownMarker("signature help tags")); + assert.equal( + actualTags.length, + (options.tags || ts.emptyArray).length, + this.assertionMessageAtLastKnownMarker("signature help tags"), + ); ts.zipWith(options.tags || ts.emptyArray, actualTags, (expectedTag, actualTag) => { assert.equal(actualTag.name, expectedTag.name); - assert.deepEqual(actualTag.text, expectedTag.text, this.assertionMessageAtLastKnownMarker("signature help tag " + actualTag.name)); + assert.deepEqual( + actualTag.text, + expectedTag.text, + this.assertionMessageAtLastKnownMarker("signature help tag " + actualTag.name), + ); }); const allKeys: readonly (keyof FourSlashInterface.VerifySignatureHelpOptions)[] = [ @@ -1652,7 +2156,11 @@ namespace FourSlash { expectedRange: Range | undefined, preferences: ts.UserPreferences | undefined, ): void { - const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition, preferences || { allowRenameOfImportPath: true }); + const renameInfo = this.languageService.getRenameInfo( + this.activeFile.fileName, + this.currentCaretPosition, + preferences || { allowRenameOfImportPath: true }, + ); if (!renameInfo.canRename) { throw this.raiseError("Rename did not succeed"); } @@ -1671,19 +2179,23 @@ namespace FourSlash { } if ( - renameInfo.triggerSpan.start !== expectedRange.pos || - ts.textSpanEnd(renameInfo.triggerSpan) !== expectedRange.end + renameInfo.triggerSpan.start !== expectedRange.pos + || ts.textSpanEnd(renameInfo.triggerSpan) !== expectedRange.end ) { this.raiseError( - "Expected triggerSpan [" + expectedRange.pos + "," + expectedRange.end + "). Got [" + - renameInfo.triggerSpan.start + "," + ts.textSpanEnd(renameInfo.triggerSpan) + ") instead.", + "Expected triggerSpan [" + expectedRange.pos + "," + expectedRange.end + "). Got [" + + renameInfo.triggerSpan.start + "," + ts.textSpanEnd(renameInfo.triggerSpan) + ") instead.", ); } } public verifyRenameInfoFailed(message?: string, preferences?: ts.UserPreferences) { - const allowRenameOfImportPath = preferences?.allowRenameOfImportPath === undefined ? true : preferences.allowRenameOfImportPath; - const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition, { ...preferences, allowRenameOfImportPath }); + const allowRenameOfImportPath = preferences?.allowRenameOfImportPath === undefined ? true + : preferences.allowRenameOfImportPath; + const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition, { + ...preferences, + allowRenameOfImportPath, + }); if (renameInfo.canRename) { throw this.raiseError("Rename was expected to fail"); } @@ -1692,7 +2204,11 @@ namespace FourSlash { private alignmentForExtraInfo = 50; - private spanLines(file: FourSlashFile, spanInfo: ts.TextSpan, { selection = false, fullLines = false, lineNumbers = false } = {}) { + private spanLines( + file: FourSlashFile, + spanInfo: ts.TextSpan, + { selection = false, fullLines = false, lineNumbers = false } = {}, + ) { if (selection) { fullLines = true; } @@ -1741,24 +2257,36 @@ namespace FourSlash { contextLineMap = ts.computeLineStarts(contextString); contextStart = { line: 0, character: 0 }; contextEnd = { line: contextLineMap.length - 1, character: 0 }; - selectionStart = selection ? ts.computeLineAndCharacterOfPosition(contextLineMap, spanInfo.start - contextStartPos) : contextStart; - selectionEnd = selection ? ts.computeLineAndCharacterOfPosition(contextLineMap, ts.textSpanEnd(spanInfo) - contextStartPos) : contextEnd; + selectionStart = selection + ? ts.computeLineAndCharacterOfPosition(contextLineMap, spanInfo.start - contextStartPos) + : contextStart; + selectionEnd = selection + ? ts.computeLineAndCharacterOfPosition(contextLineMap, ts.textSpanEnd(spanInfo) - contextStartPos) + : contextEnd; lineNumberPrefixLength = 0; } const output: string[] = []; for (let lineNumber = contextStart.line; lineNumber <= contextEnd.line; lineNumber++) { const spanLine = contextString.substring(contextLineMap[lineNumber], contextLineMap[lineNumber + 1]); - output.push(lineNumbers ? `${ts.padLeft(`${lineNumber + 1}: `, lineNumberPrefixLength)}${spanLine}` : spanLine); + output.push( + lineNumbers ? `${ts.padLeft(`${lineNumber + 1}: `, lineNumberPrefixLength)}${spanLine}` : spanLine, + ); if (selection) { if (lineNumber < selectionStart.line || lineNumber > selectionEnd.line) { continue; } - const isEmpty = selectionStart.line === selectionEnd.line && selectionStart.character === selectionEnd.character; + const isEmpty = selectionStart.line === selectionEnd.line + && selectionStart.character === selectionEnd.character; const selectionPadLength = lineNumber === selectionStart.line ? selectionStart.character : 0; const selectionPad = " ".repeat(selectionPadLength + lineNumberPrefixLength); - const selectionLength = isEmpty ? 0 : Math.max(lineNumber < selectionEnd.line ? spanLine.trimRight().length - selectionPadLength : selectionEnd.character - selectionPadLength, 1); + const selectionLength = isEmpty ? 0 + : Math.max( + lineNumber < selectionEnd.line ? spanLine.trimRight().length - selectionPadLength + : selectionEnd.character - selectionPadLength, + 1, + ); const selectionLine = isEmpty ? "<" : "^".repeat(selectionLength); output.push(`${selectionPad}${selectionLine}`); } @@ -1776,7 +2304,8 @@ namespace FourSlash { } resultString += prefixString + spanLines[i]; } - resultString += "\n" + prefixString + ":=> (" + this.getLineColStringAtPosition(spanInfo.start, file) + ") to (" + this.getLineColStringAtPosition(ts.textSpanEnd(spanInfo), file) + ")"; + resultString += "\n" + prefixString + ":=> (" + this.getLineColStringAtPosition(spanInfo.start, file) + + ") to (" + this.getLineColStringAtPosition(ts.textSpanEnd(spanInfo), file) + ")"; } return resultString; @@ -1797,7 +2326,10 @@ namespace FourSlash { if (previousSpanInfo) { resultString += currentLine; let thisLineMarker = ts.repeatString(" ", startColumn!) + ts.repeatString("~", length!); - thisLineMarker += ts.repeatString(" ", this.alignmentForExtraInfo - thisLineMarker.length - prefixString.length + 1); + thisLineMarker += ts.repeatString( + " ", + this.alignmentForExtraInfo - thisLineMarker.length - prefixString.length + 1, + ); resultString += thisLineMarker; resultString += "=> Pos: (" + (pos - length!) + " to " + (pos - 1) + ") "; resultString += " " + previousSpanInfo; @@ -1812,7 +2344,8 @@ namespace FourSlash { if (resultString.length) { resultString += "\n--------------------------------"; } - currentLine = "\n" + nextLine.toString() + ts.repeatString(" ", 3 - nextLine.toString().length) + ">" + this.activeFile.content.substring(pos, fileLineMap[nextLine]) + "\n "; + currentLine = "\n" + nextLine.toString() + ts.repeatString(" ", 3 - nextLine.toString().length) + + ">" + this.activeFile.content.substring(pos, fileLineMap[nextLine]) + "\n "; startColumn = 0; length = 0; } @@ -1837,8 +2370,14 @@ namespace FourSlash { } public baselineCurrentFileBreakpointLocations() { - const baselineFile = this.getBaselineFileNameForInternalFourslashFile().replace("breakpointValidation", "bpSpan"); - Harness.Baseline.runBaseline(baselineFile, this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos)!)); + const baselineFile = this.getBaselineFileNameForInternalFourslashFile().replace( + "breakpointValidation", + "bpSpan", + ); + Harness.Baseline.runBaseline( + baselineFile, + this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos)!), + ); } private getEmitFiles(): readonly FourSlashFile[] { @@ -1862,7 +2401,10 @@ namespace FourSlash { } public verifyGetEmitOutput(expectedOutputFiles: readonly string[]): void { - const outputFiles = ts.flatMap(this.getEmitFiles(), e => this.languageService.getEmitOutput(e.fileName).outputFiles); + const outputFiles = ts.flatMap( + this.getEmitFiles(), + e => this.languageService.getEmitOutput(e.fileName).outputFiles, + ); assert.deepEqual(outputFiles.map(f => f.name), expectedOutputFiles); @@ -1902,7 +2444,10 @@ namespace FourSlash { resultString += Harness.IO.newLine(); } - Harness.Baseline.runBaseline(ts.Debug.checkDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]), resultString); + Harness.Baseline.runBaseline( + ts.Debug.checkDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]), + resultString, + ); } private flattenChainedMessage(diag: ts.DiagnosticMessageChain, indent = " ") { @@ -1967,7 +2512,11 @@ namespace FourSlash { const baselineFile = this.getBaselineFileNameForContainingTestFile(); const result = ts.arrayFrom(this.testData.markerPositions.entries(), ([name, marker]) => ({ marker: { ...marker, name }, - signatureHelp: this.languageService.getSignatureHelpItems(marker.fileName, marker.position, /*options*/ undefined), + signatureHelp: this.languageService.getSignatureHelpItems( + marker.fileName, + marker.position, + /*options*/ undefined, + ), })); Harness.Baseline.runBaseline(baselineFile, stringify(result)); } @@ -1997,8 +2546,13 @@ namespace FourSlash { const markers = this.getMarkers(); const fileContent = this.activeFile.content; const text = markers.map(marker => { - const baselineContent = [fileContent.slice(0, marker.position) + "/**/" + fileContent.slice(marker.position) + n]; - let selectionRange: ts.SelectionRange | undefined = this.languageService.getSmartSelectionRange(this.activeFile.fileName, marker.position); + const baselineContent = [ + fileContent.slice(0, marker.position) + "/**/" + fileContent.slice(marker.position) + n, + ]; + let selectionRange: ts.SelectionRange | undefined = this.languageService.getSmartSelectionRange( + this.activeFile.fileName, + marker.position, + ); while (selectionRange) { const { textSpan } = selectionRange; let masked = Array.from(fileContent).map((char, index) => { @@ -2009,7 +2563,8 @@ namespace FourSlash { return ts.isLineBreak(charCode) ? char : " "; }).join(""); masked = masked.replace(/^\s*$\r?\n?/gm, ""); // Remove blank lines - const isRealCharacter = (char: string) => char !== "•" && char !== "↲" && !ts.isWhiteSpaceLike(char.charCodeAt(0)); + const isRealCharacter = (char: string) => + char !== "•" && char !== "↲" && !ts.isWhiteSpaceLike(char.charCodeAt(0)); const leadingWidth = Array.from(masked).findIndex(isRealCharacter); const trailingWidth = ts.findLastIndex(Array.from(masked), isRealCharacter); masked = masked.slice(0, leadingWidth) @@ -2025,7 +2580,9 @@ namespace FourSlash { } public printBreakpointLocation(pos: number) { - Harness.IO.log("\n**Pos: " + pos + " " + this.spanInfoToString(this.getBreakpointStatementLocation(pos)!, " ")); + Harness.IO.log( + "\n**Pos: " + pos + " " + this.spanInfoToString(this.getBreakpointStatementLocation(pos)!, " "), + ); } public printBreakpointAtCurrentLocation() { @@ -2033,12 +2590,19 @@ namespace FourSlash { } public printCurrentParameterHelp() { - const help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition, /*options*/ undefined); + const help = this.languageService.getSignatureHelpItems( + this.activeFile.fileName, + this.currentCaretPosition, + /*options*/ undefined, + ); Harness.IO.log(stringify(help)); } public printCurrentQuickInfo() { - const quickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition)!; + const quickInfo = this.languageService.getQuickInfoAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + )!; Harness.IO.log("Quick Info: " + quickInfo.displayParts!.map(part => part.text).join("")); } @@ -2051,9 +2615,9 @@ namespace FourSlash { if (errorList.length) { errorList.forEach(err => { Harness.IO.log( - "start: " + err.start + - ", length: " + err.length + - ", message: " + ts.flattenDiagnosticMessageText(err.messageText, Harness.IO.newLine()), + "start: " + err.start + + ", length: " + err.length + + ", message: " + ts.flattenDiagnosticMessageText(err.messageText, Harness.IO.newLine()), ); }); } @@ -2065,7 +2629,8 @@ namespace FourSlash { Harness.IO.log(`=== Script (${file.fileName}) ${(active ? "(active, cursor at |)" : "")} ===`); let content = this.getFileContent(file.fileName); if (active) { - content = content.substr(0, this.currentCaretPosition) + (makeCaretVisible ? "|" : "") + content.substr(this.currentCaretPosition); + content = content.substr(0, this.currentCaretPosition) + (makeCaretVisible ? "|" : "") + + content.substr(this.currentCaretPosition); } if (showWhitespace) { content = makeWhitespaceVisible(content); @@ -2080,16 +2645,18 @@ namespace FourSlash { } private getBaselineFileNameForInternalFourslashFile(ext = ".baseline") { - return this.testData.globalOptions[MetadataOptionNames.baselineFile] || - ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ext); + return this.testData.globalOptions[MetadataOptionNames.baselineFile] + || ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ext); } private getBaselineFileNameForContainingTestFile(ext = ".baseline") { - return this.testData.globalOptions[MetadataOptionNames.baselineFile] || - ts.getBaseFileName(this.originalInputFileName).replace(ts.Extension.Ts, ext); + return this.testData.globalOptions[MetadataOptionNames.baselineFile] + || ts.getBaseFileName(this.originalInputFileName).replace(ts.Extension.Ts, ext); } - private getSignatureHelp({ triggerReason }: FourSlashInterface.VerifySignatureHelpOptions): ts.SignatureHelpItems | undefined { + private getSignatureHelp( + { triggerReason }: FourSlashInterface.VerifySignatureHelpOptions, + ): ts.SignatureHelpItems | undefined { return this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition, { triggerReason, }); @@ -2112,8 +2679,15 @@ namespace FourSlash { } const longestNameLength = max(entries, m => m.name.length); const longestKindLength = max(entries, m => m.kind.length); - entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0); - const membersString = entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers} ${m.isRecommended ? "recommended " : ""}${m.source === undefined ? "" : m.source}`).join("\n"); + entries.sort((m, n) => + m.sortText > n.sortText ? 1 + : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0 + ); + const membersString = entries.map(m => + `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers} ${ + m.isRecommended ? "recommended " : "" + }${m.source === undefined ? "" : m.source}` + ).join("\n"); Harness.IO.log(membersString); } @@ -2136,7 +2710,12 @@ namespace FourSlash { // Handle post-keystroke formatting if (this.enableFormatting) { - const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsAfterKeystroke( + this.activeFile.fileName, + offset, + ch, + this.formatCodeSettings, + ); if (edits.length) { offset += this.applyEdits(this.activeFile.fileName, edits); } @@ -2152,8 +2731,14 @@ namespace FourSlash { } public deleteLineRange(startIndex: number, endIndexInclusive: number) { - const startPos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { line: startIndex, character: 0 }); - const endPos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { line: endIndexInclusive + 1, character: 0 }); + const startPos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { + line: startIndex, + character: 0, + }); + const endPos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { + line: endIndexInclusive + 1, + character: 0, + }); this.replace(startPos, endPos - startPos, ""); } @@ -2207,7 +2792,11 @@ namespace FourSlash { } else if (prevChar === " " && /A-Za-z_/.test(ch)) { /* Completions */ - this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset, ts.emptyOptions); + this.languageService.getCompletionsAtPosition( + this.activeFile.fileName, + offset, + ts.emptyOptions, + ); } if (i % checkCadence === 0) { @@ -2217,7 +2806,12 @@ namespace FourSlash { // Handle post-keystroke formatting if (this.enableFormatting) { - const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsAfterKeystroke( + this.activeFile.fileName, + offset, + ch, + this.formatCodeSettings, + ); if (edits.length) { offset += this.applyEdits(this.activeFile.fileName, edits); } @@ -2230,13 +2824,23 @@ namespace FourSlash { // Enters text as if the user had pasted it public paste(text: string) { const start = this.currentCaretPosition; - this.editScriptAndUpdateMarkers(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition, text); + this.editScriptAndUpdateMarkers( + this.activeFile.fileName, + this.currentCaretPosition, + this.currentCaretPosition, + text, + ); this.checkPostEditInvariants(); const offset = this.currentCaretPosition += text.length; // Handle formatting if (this.enableFormatting) { - const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsForRange( + this.activeFile.fileName, + start, + offset, + this.formatCodeSettings, + ); if (edits.length) { this.applyEdits(this.activeFile.fileName, edits); } @@ -2263,12 +2867,18 @@ namespace FourSlash { const options: ts.CreateSourceFileOptions = { languageVersion: ts.ScriptTarget.Latest, impliedNodeFormat: ts.getImpliedNodeFormatForFile( - ts.toPath(this.activeFile.fileName, this.languageServiceAdapterHost.sys.getCurrentDirectory(), ts.hostGetCanonicalFileName(this.languageServiceAdapterHost)), + ts.toPath( + this.activeFile.fileName, + this.languageServiceAdapterHost.sys.getCurrentDirectory(), + ts.hostGetCanonicalFileName(this.languageServiceAdapterHost), + ), /*cache*/ undefined, this.languageServiceAdapterHost, this.languageService.getProgram()?.getCompilerOptions() || {}, ), - setExternalModuleIndicator: ts.getSetExternalModuleIndicator(this.languageService.getProgram()?.getCompilerOptions() || {}), + setExternalModuleIndicator: ts.getSetExternalModuleIndicator( + this.languageService.getProgram()?.getCompilerOptions() || {}, + ), }; const referenceSourceFile = ts.createLanguageServiceSourceFile( this.activeFile.fileName, @@ -2315,7 +2925,9 @@ namespace FourSlash { return ts.clone(this.formatCodeSettings); } - public setFormatOptions(formatCodeOptions: ts.FormatCodeOptions | ts.FormatCodeSettings): ts.FormatCodeSettings { + public setFormatOptions( + formatCodeOptions: ts.FormatCodeOptions | ts.FormatCodeSettings, + ): ts.FormatCodeSettings { const oldFormatCodeOptions = this.formatCodeSettings; this.formatCodeSettings = ts.toEditorSettings(formatCodeOptions); if (this.testType === FourSlashTestType.Server) { @@ -2325,17 +2937,30 @@ namespace FourSlash { } public formatDocument() { - const edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsForDocument( + this.activeFile.fileName, + this.formatCodeSettings, + ); this.applyEdits(this.activeFile.fileName, edits); } public formatSelection(start: number, end: number) { - const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, end, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsForRange( + this.activeFile.fileName, + start, + end, + this.formatCodeSettings, + ); this.applyEdits(this.activeFile.fileName, edits); } public formatOnType(pos: number, key: string) { - const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, pos, key, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsAfterKeystroke( + this.activeFile.fileName, + pos, + key, + this.formatCodeSettings, + ); this.applyEdits(this.activeFile.fileName, edits); } @@ -2378,13 +3003,20 @@ namespace FourSlash { } public goToTypeDefinition(definitionIndex: number) { - const definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition)!; + const definitions = this.languageService.getTypeDefinitionAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + )!; if (!definitions || !definitions.length) { - this.raiseError("goToTypeDefinition failed - expected to find at least one definition location but got 0"); + this.raiseError( + "goToTypeDefinition failed - expected to find at least one definition location but got 0", + ); } if (definitionIndex >= definitions.length) { - this.raiseError(`goToTypeDefinition failed - definitionIndex value (${definitionIndex}) exceeds definition list size (${definitions.length})`); + this.raiseError( + `goToTypeDefinition failed - definitionIndex value (${definitionIndex}) exceeds definition list size (${definitions.length})`, + ); } const definition = definitions[definitionIndex]; @@ -2395,38 +3027,64 @@ namespace FourSlash { public verifyTypeDefinitionsCount(negative: boolean, expectedCount: number) { const assertFn = negative ? assert.notEqual : assert.equal; - const definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const definitions = this.languageService.getTypeDefinitionAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); const actualCount = definitions && definitions.length || 0; assertFn(actualCount, expectedCount, this.messageAtLastKnownMarker("Type definitions Count")); } public verifyImplementationListIsEmpty(negative: boolean) { - const implementations = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const implementations = this.languageService.getImplementationAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); if (negative) { - assert.isTrue(implementations && implementations.length > 0, "Expected at least one implementation but got 0"); + assert.isTrue( + implementations && implementations.length > 0, + "Expected at least one implementation but got 0", + ); } else { - assert.isUndefined(implementations, "Expected implementation list to be empty but implementations returned"); + assert.isUndefined( + implementations, + "Expected implementation list to be empty but implementations returned", + ); } } public verifyGoToDefinitionName(expectedName: string, expectedContainerName: string) { - const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const definitions = this.languageService.getDefinitionAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); const actualDefinitionName = definitions && definitions.length ? definitions[0].name : ""; const actualDefinitionContainerName = definitions && definitions.length ? definitions[0].containerName : ""; assert.equal(actualDefinitionName, expectedName, this.messageAtLastKnownMarker("Definition Info Name")); - assert.equal(actualDefinitionContainerName, expectedContainerName, this.messageAtLastKnownMarker("Definition Info Container Name")); + assert.equal( + actualDefinitionContainerName, + expectedContainerName, + this.messageAtLastKnownMarker("Definition Info Container Name"), + ); } public goToImplementation() { - const implementations = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition)!; + const implementations = this.languageService.getImplementationAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + )!; if (!implementations || !implementations.length) { - this.raiseError("goToImplementation failed - expected to find at least one implementation location but got 0"); + this.raiseError( + "goToImplementation failed - expected to find at least one implementation location but got 0", + ); } if (implementations.length > 1) { - this.raiseError(`goToImplementation failed - more than 1 implementation returned (${implementations.length})`); + this.raiseError( + `goToImplementation failed - more than 1 implementation returned (${implementations.length})`, + ); } const implementation = implementations[0]; @@ -2436,21 +3094,30 @@ namespace FourSlash { public verifyRangesInImplementationList(markerName: string) { this.goToMarker(markerName); - const implementations: readonly ImplementationLocationInformation[] = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition)!; + const implementations: readonly ImplementationLocationInformation[] = this.languageService + .getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition)!; if (!implementations || !implementations.length) { - this.raiseError("verifyRangesInImplementationList failed - expected to find at least one implementation location but got 0"); + this.raiseError( + "verifyRangesInImplementationList failed - expected to find at least one implementation location but got 0", + ); } const duplicate = findDuplicatedElement(implementations, ts.documentSpansEqual); if (duplicate) { const { textSpan, fileName } = duplicate; - this.raiseError(`Duplicate implementations returned for range (${textSpan.start}, ${ts.textSpanEnd(textSpan)}) in ${fileName}`); + this.raiseError( + `Duplicate implementations returned for range (${textSpan.start}, ${ + ts.textSpanEnd(textSpan) + }) in ${fileName}`, + ); } const ranges = this.getRanges(); if (!ranges || !ranges.length) { - this.raiseError("verifyRangesInImplementationList failed - expected to find at least one range in test source"); + this.raiseError( + "verifyRangesInImplementationList failed - expected to find at least one range in test source", + ); } const unsatisfiedRanges: Range[] = []; @@ -2458,24 +3125,51 @@ namespace FourSlash { const delayedErrors: string[] = []; for (const range of ranges) { const length = range.end - range.pos; - const matchingImpl = ts.find(implementations, impl => range.fileName === impl.fileName && range.pos === impl.textSpan.start && length === impl.textSpan.length); + const matchingImpl = ts.find( + implementations, + impl => + range.fileName === impl.fileName && range.pos === impl.textSpan.start + && length === impl.textSpan.length, + ); if (matchingImpl) { if (range.marker && range.marker.data) { - const expected = range.marker.data as { displayParts?: ts.SymbolDisplayPart[]; parts: string[]; kind?: string; }; + const expected = range.marker.data as { + displayParts?: ts.SymbolDisplayPart[]; + parts: string[]; + kind?: string; + }; if (expected.displayParts) { - if (!ts.arrayIsEqualTo(expected.displayParts, matchingImpl.displayParts, displayPartIsEqualTo)) { - delayedErrors.push(`Mismatched display parts: expected ${JSON.stringify(expected.displayParts)}, actual ${JSON.stringify(matchingImpl.displayParts)}`); + if ( + !ts.arrayIsEqualTo( + expected.displayParts, + matchingImpl.displayParts, + displayPartIsEqualTo, + ) + ) { + delayedErrors.push( + `Mismatched display parts: expected ${ + JSON.stringify(expected.displayParts) + }, actual ${JSON.stringify(matchingImpl.displayParts)}`, + ); } } else if (expected.parts) { const actualParts = matchingImpl.displayParts.map(p => p.text); if (!ts.arrayIsEqualTo(expected.parts, actualParts)) { - delayedErrors.push(`Mismatched non-tagged display parts: expected ${JSON.stringify(expected.parts)}, actual ${JSON.stringify(actualParts)}`); + delayedErrors.push( + `Mismatched non-tagged display parts: expected ${ + JSON.stringify(expected.parts) + }, actual ${JSON.stringify(actualParts)}`, + ); } } if (expected.kind !== undefined) { if (expected.kind !== matchingImpl.kind) { - delayedErrors.push(`Mismatched kind: expected ${JSON.stringify(expected.kind)}, actual ${JSON.stringify(matchingImpl.kind)}`); + delayedErrors.push( + `Mismatched kind: expected ${JSON.stringify(expected.kind)}, actual ${ + JSON.stringify(matchingImpl.kind) + }`, + ); } } } @@ -2504,7 +3198,9 @@ namespace FourSlash { error += "\nUnmatched implementations:"; for (const impl of unmatchedImplementations) { const end = impl.textSpan.start + impl.textSpan.length; - error += `\n (${impl.textSpan.start}, ${end}) in ${impl.fileName}: ${this.getFileContent(impl.fileName).slice(impl.textSpan.start, end)}`; + error += `\n (${impl.textSpan.start}, ${end}) in ${impl.fileName}: ${ + this.getFileContent(impl.fileName).slice(impl.textSpan.start, end) + }`; } } this.raiseError(error); @@ -2550,40 +3246,72 @@ namespace FourSlash { public verifyCaretAtMarker(markerName = "") { const pos = this.getMarkerByName(markerName); if (pos.fileName !== this.activeFile.fileName) { - throw new Error(`verifyCaretAtMarker failed - expected to be in file "${pos.fileName}", but was in file "${this.activeFile.fileName}"`); + throw new Error( + `verifyCaretAtMarker failed - expected to be in file "${pos.fileName}", but was in file "${this.activeFile.fileName}"`, + ); } if (pos.position !== this.currentCaretPosition) { - throw new Error(`verifyCaretAtMarker failed - expected to be at marker "/*${markerName}*/, but was at position ${this.currentCaretPosition}(${this.getLineColStringAtPosition(this.currentCaretPosition)})`); + throw new Error( + `verifyCaretAtMarker failed - expected to be at marker "/*${markerName}*/, but was at position ${this.currentCaretPosition}(${ + this.getLineColStringAtPosition(this.currentCaretPosition) + })`, + ); } } - private getIndentation(fileName: string, position: number, indentStyle: ts.IndentStyle, baseIndentSize: number): number { + private getIndentation( + fileName: string, + position: number, + indentStyle: ts.IndentStyle, + baseIndentSize: number, + ): number { const formatOptions = ts.clone(this.formatCodeSettings); formatOptions.indentStyle = indentStyle; formatOptions.baseIndentSize = baseIndentSize; return this.languageService.getIndentationAtPosition(fileName, position, formatOptions); } - public verifyIndentationAtCurrentPosition(numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) { - const actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition, indentStyle, baseIndentSize); + public verifyIndentationAtCurrentPosition( + numberOfSpaces: number, + indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, + baseIndentSize = 0, + ) { + const actual = this.getIndentation( + this.activeFile.fileName, + this.currentCaretPosition, + indentStyle, + baseIndentSize, + ); const lineCol = this.getLineColStringAtPosition(this.currentCaretPosition); if (actual !== numberOfSpaces) { - this.raiseError(`verifyIndentationAtCurrentPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`); + this.raiseError( + `verifyIndentationAtCurrentPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`, + ); } } - public verifyIndentationAtPosition(fileName: string, position: number, numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) { + public verifyIndentationAtPosition( + fileName: string, + position: number, + numberOfSpaces: number, + indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, + baseIndentSize = 0, + ) { const actual = this.getIndentation(fileName, position, indentStyle, baseIndentSize); const lineCol = this.getLineColStringAtPosition(position); if (actual !== numberOfSpaces) { - this.raiseError(`verifyIndentationAtPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`); + this.raiseError( + `verifyIndentationAtPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`, + ); } } public verifyCurrentLineContent(text: string) { const actual = this.getCurrentLineContent(); if (actual !== text) { - throw new Error("verifyCurrentLineContent\n" + displayExpectedAndActualString(text, actual, /* quoted */ true)); + throw new Error( + "verifyCurrentLineContent\n" + displayExpectedAndActualString(text, actual, /* quoted */ true), + ); } } @@ -2606,21 +3334,36 @@ namespace FourSlash { } public verifyTextAtCaretIs(text: string) { - const actual = this.getFileContent(this.activeFile.fileName).substring(this.currentCaretPosition, this.currentCaretPosition + text.length); + const actual = this.getFileContent(this.activeFile.fileName).substring( + this.currentCaretPosition, + this.currentCaretPosition + text.length, + ); if (actual !== text) { - throw new Error("verifyTextAtCaretIs\n" + displayExpectedAndActualString(text, actual, /* quoted */ true)); + throw new Error( + "verifyTextAtCaretIs\n" + displayExpectedAndActualString(text, actual, /* quoted */ true), + ); } } public verifyCurrentNameOrDottedNameSpanText(text: string) { - const span = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition); + const span = this.languageService.getNameOrDottedNameSpan( + this.activeFile.fileName, + this.currentCaretPosition, + this.currentCaretPosition, + ); if (!span) { - return this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + displayExpectedAndActualString('"' + text + '"', "undefined")); + return this.raiseError( + "verifyCurrentNameOrDottedNameSpanText\n" + + displayExpectedAndActualString('"' + text + '"', "undefined"), + ); } const actual = this.getFileContent(this.activeFile.fileName).substring(span.start, ts.textSpanEnd(span)); if (actual !== text) { - this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + displayExpectedAndActualString(text, actual, /* quoted */ true)); + this.raiseError( + "verifyCurrentNameOrDottedNameSpanText\n" + + displayExpectedAndActualString(text, actual, /* quoted */ true), + ); } } @@ -2679,25 +3422,31 @@ namespace FourSlash { return [tokenTypes[typeIdx], ...tokenModifiers.filter((_, i) => modSet & 1 << i)].join("."); } - private verifyClassifications(expected: { classificationType: string | number; text?: string; textSpan?: TextSpan; }[], actual: (ts.ClassifiedSpan | ts.ClassifiedSpan2020)[], sourceFileText: string) { + private verifyClassifications( + expected: { classificationType: string | number; text?: string; textSpan?: TextSpan; }[], + actual: (ts.ClassifiedSpan | ts.ClassifiedSpan2020)[], + sourceFileText: string, + ) { if (actual.length !== expected.length) { this.raiseError( - "verifyClassifications failed - expected total classifications to be " + expected.length + - ", but was " + actual.length + - jsonMismatchString(), + "verifyClassifications failed - expected total classifications to be " + expected.length + + ", but was " + actual.length + + jsonMismatchString(), ); } ts.zipWith(expected, actual, (expectedClassification, actualClassification) => { const expectedType = expectedClassification.classificationType; - const actualType = typeof actualClassification.classificationType === "number" ? this.classificationToIdentifier(actualClassification.classificationType) : actualClassification.classificationType; + const actualType = typeof actualClassification.classificationType === "number" + ? this.classificationToIdentifier(actualClassification.classificationType) + : actualClassification.classificationType; if (expectedType !== actualType) { this.raiseError( - "verifyClassifications failed - expected classifications type to be " + - expectedType + ", but was " + - actualType + - jsonMismatchString(), + "verifyClassifications failed - expected classifications type to be " + + expectedType + ", but was " + + actualType + + jsonMismatchString(), ); } @@ -2709,10 +3458,10 @@ namespace FourSlash { if (expectedSpan.start !== actualSpan.start || expectedLength !== actualSpan.length) { this.raiseError( - "verifyClassifications failed - expected span of text to be " + - "{start=" + expectedSpan.start + ", length=" + expectedLength + "}, but was " + - "{start=" + actualSpan.start + ", length=" + actualSpan.length + "}" + - jsonMismatchString(), + "verifyClassifications failed - expected span of text to be " + + "{start=" + expectedSpan.start + ", length=" + expectedLength + "}, but was " + + "{start=" + actualSpan.start + ", length=" + actualSpan.length + "}" + + jsonMismatchString(), ); } } @@ -2720,19 +3469,22 @@ namespace FourSlash { const actualText = this.activeFile.content.substr(actualSpan.start, actualSpan.length); if (expectedClassification.text !== actualText) { this.raiseError( - "verifyClassifications failed - expected classified text to be " + - expectedClassification.text + ", but was " + - actualText + - jsonMismatchString(), + "verifyClassifications failed - expected classified text to be " + + expectedClassification.text + ", but was " + + actualText + + jsonMismatchString(), ); } }); function jsonMismatchString() { - const showActual = actual.map(({ classificationType, textSpan }) => ({ classificationType, text: sourceFileText.slice(textSpan.start, textSpan.start + textSpan.length) })); - return Harness.IO.newLine() + - "expected: '" + Harness.IO.newLine() + stringify(expected) + "'" + Harness.IO.newLine() + - "actual: '" + Harness.IO.newLine() + stringify(showActual) + "'"; + const showActual = actual.map(({ classificationType, textSpan }) => ({ + classificationType, + text: sourceFileText.slice(textSpan.start, textSpan.start + textSpan.length), + })); + return Harness.IO.newLine() + + "expected: '" + Harness.IO.newLine() + stringify(expected) + "'" + Harness.IO.newLine() + + "actual: '" + Harness.IO.newLine() + stringify(showActual) + "'"; } } @@ -2752,7 +3504,11 @@ namespace FourSlash { } public replaceWithSemanticClassifications(format: ts.SemanticClassificationFormat.TwentyTwenty) { - const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format); + const actual = this.languageService.getSemanticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + format, + ); const replacement = [`const c2 = classification("2020");`, `verify.semanticClassificationsAre("2020",`]; for (const a of actual) { const identifier = this.classificationToIdentifier(a.classificationType as number); @@ -2761,7 +3517,9 @@ namespace FourSlash { } replacement.push(");"); - throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications"); + throw new Error( + "You need to change the source code of fourslash test to use replaceWithSemanticClassifications", + ); // const fs = require("fs"); // const testfilePath = this.originalInputFileName.slice(1); @@ -2771,26 +3529,47 @@ namespace FourSlash { } public verifyEncodedSyntacticClassificationsLength(expected: number) { - const actual = this.languageService.getEncodedSyntacticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length)); + const actual = this.languageService.getEncodedSyntacticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + ); if (actual.spans.length !== expected) { - this.raiseError(`encodedSyntacticClassificationsLength failed - expected total spans to be ${expected} got ${actual.spans.length}`); + this.raiseError( + `encodedSyntacticClassificationsLength failed - expected total spans to be ${expected} got ${actual.spans.length}`, + ); } } public verifyEncodedSemanticClassificationsLength(format: ts.SemanticClassificationFormat, expected: number) { - const actual = this.languageService.getEncodedSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format); + const actual = this.languageService.getEncodedSemanticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + format, + ); if (actual.spans.length !== expected) { - this.raiseError(`encodedSemanticClassificationsLength failed - expected total spans to be ${expected} got ${actual.spans.length}`); + this.raiseError( + `encodedSemanticClassificationsLength failed - expected total spans to be ${expected} got ${actual.spans.length}`, + ); } } - public verifySemanticClassifications(format: ts.SemanticClassificationFormat, expected: { classificationType: string | number; text?: string; }[]) { - const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format); + public verifySemanticClassifications( + format: ts.SemanticClassificationFormat, + expected: { classificationType: string | number; text?: string; }[], + ) { + const actual = this.languageService.getSemanticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + format, + ); this.verifyClassifications(expected, actual, this.activeFile.content); } public verifySyntacticClassifications(expected: { classificationType: string; text: string; }[]) { - const actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length)); + const actual = this.languageService.getSyntacticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + ); this.verifyClassifications(expected, actual, this.activeFile.content); } @@ -2822,15 +3601,30 @@ namespace FourSlash { const filterActual = ts.filter(actual, f => kind === undefined ? true : f.kind === kind); if (filterActual.length !== spans.length) { - this.raiseError(`verifyOutliningSpans failed - expected total spans to be ${spans.length}, but was ${actual.length}\n\nFound Spans:\n\n${this.printOutliningSpansInline(actual)}`); + this.raiseError( + `verifyOutliningSpans failed - expected total spans to be ${spans.length}, but was ${actual.length}\n\nFound Spans:\n\n${ + this.printOutliningSpansInline(actual) + }`, + ); } ts.zipWith(spans, filterActual, (expectedSpan, actualSpan, i) => { - if (expectedSpan.pos !== actualSpan.textSpan.start || expectedSpan.end !== ts.textSpanEnd(actualSpan.textSpan)) { - return this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualSpan.textSpan.start},${ts.textSpanEnd(actualSpan.textSpan)})`); + if ( + expectedSpan.pos !== actualSpan.textSpan.start + || expectedSpan.end !== ts.textSpanEnd(actualSpan.textSpan) + ) { + return this.raiseError( + `verifyOutliningSpans failed - span ${(i + + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualSpan.textSpan.start},${ + ts.textSpanEnd(actualSpan.textSpan) + })`, + ); } if (kind !== undefined && actualSpan.kind !== kind) { - return this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected kind: ('${kind}'), actual: ('${actualSpan.kind}')`); + return this.raiseError( + `verifyOutliningSpans failed - span ${(i + + 1)} expected kind: ('${kind}'), actual: ('${actualSpan.kind}')`, + ); } }); } @@ -2839,28 +3633,51 @@ namespace FourSlash { const actual = this.languageService.getOutliningSpans(this.activeFile.fileName); if (actual.length !== spans.length) { - this.raiseError(`verifyOutliningHintSpans failed - expected total spans to be ${spans.length}, but was ${actual.length}`); + this.raiseError( + `verifyOutliningHintSpans failed - expected total spans to be ${spans.length}, but was ${actual.length}`, + ); } ts.zipWith(spans, actual, (expectedSpan, actualSpan, i) => { - if (expectedSpan.pos !== actualSpan.hintSpan.start || expectedSpan.end !== ts.textSpanEnd(actualSpan.hintSpan)) { - return this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualSpan.hintSpan.start},${ts.textSpanEnd(actualSpan.hintSpan)})`); + if ( + expectedSpan.pos !== actualSpan.hintSpan.start + || expectedSpan.end !== ts.textSpanEnd(actualSpan.hintSpan) + ) { + return this.raiseError( + `verifyOutliningSpans failed - span ${(i + + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualSpan.hintSpan.start},${ + ts.textSpanEnd(actualSpan.hintSpan) + })`, + ); } }); } public verifyTodoComments(descriptors: string[], spans: Range[]) { - const actual = this.languageService.getTodoComments(this.activeFile.fileName, descriptors.map(d => ({ text: d, priority: 0 }))); + const actual = this.languageService.getTodoComments( + this.activeFile.fileName, + descriptors.map(d => ({ text: d, priority: 0 })), + ); if (actual.length !== spans.length) { - this.raiseError(`verifyTodoComments failed - expected total spans to be ${spans.length}, but was ${actual.length}`); + this.raiseError( + `verifyTodoComments failed - expected total spans to be ${spans.length}, but was ${actual.length}`, + ); } ts.zipWith(spans, actual, (expectedSpan, actualComment, i) => { const actualCommentSpan = ts.createTextSpan(actualComment.position, actualComment.message.length); - if (expectedSpan.pos !== actualCommentSpan.start || expectedSpan.end !== ts.textSpanEnd(actualCommentSpan)) { - this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualCommentSpan.start},${ts.textSpanEnd(actualCommentSpan)})`); + if ( + expectedSpan.pos !== actualCommentSpan.start + || expectedSpan.end !== ts.textSpanEnd(actualCommentSpan) + ) { + this.raiseError( + `verifyOutliningSpans failed - span ${(i + + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualCommentSpan.start},${ + ts.textSpanEnd(actualCommentSpan) + })`, + ); } }); } @@ -2876,30 +3693,48 @@ namespace FourSlash { const fixes = this.getCodeFixes(fileName, errorCode); if (index === undefined) { if (!(fixes && fixes.length === 1)) { - this.raiseError(`Should find exactly one codefix, but ${fixes ? fixes.length : "none"} found. ${fixes ? fixes.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`); + this.raiseError( + `Should find exactly one codefix, but ${fixes ? fixes.length : "none"} found. ${ + fixes ? fixes.map(a => `${Harness.IO.newLine()} "${a.description}"`) : "" + }`, + ); } index = 0; } else { if (!(fixes && fixes.length >= index + 1)) { - this.raiseError(`Should find at least ${index + 1} codefix(es), but ${fixes ? fixes.length : "none"} found.`); + this.raiseError( + `Should find at least ${index + 1} codefix(es), but ${fixes ? fixes.length : "none"} found.`, + ); } } this.applyChanges(fixes[index].changes); } - public applyCodeActionFromCompletion(markerName: string, options: FourSlashInterface.VerifyCompletionActionOptions) { + public applyCodeActionFromCompletion( + markerName: string, + options: FourSlashInterface.VerifyCompletionActionOptions, + ) { this.goToMarker(markerName); - const details = this.getCompletionEntryDetails(options.name, options.source, options.data, options.preferences); + const details = this.getCompletionEntryDetails( + options.name, + options.source, + options.data, + options.preferences, + ); if (!details) { const completions = this.getCompletionListAtCaret(options.preferences)?.entries; const matchingName = completions?.filter(e => e.name === options.name); const detailMessage = matchingName?.length - ? `\n Found ${matchingName.length} with name '${options.name}' from source(s) ${matchingName.map(e => `'${e.source}'`).join(", ")}.` + ? `\n Found ${matchingName.length} with name '${options.name}' from source(s) ${ + matchingName.map(e => `'${e.source}'`).join(", ") + }.` : ` (In fact, there were no completions with name '${options.name}' at all.)`; - return this.raiseError(`No completions were found for the given name, source/data, and preferences.` + detailMessage); + return this.raiseError( + `No completions were found for the given name, source/data, and preferences.` + detailMessage, + ); } const codeActions = details.codeActions; if (codeActions?.length !== 1) { @@ -2908,7 +3743,9 @@ namespace FourSlash { const codeAction = ts.first(codeActions); if (codeAction.description !== options.description) { - this.raiseError(`Expected description to be:\n${options.description}\ngot:\n${codeActions[0].description}`); + this.raiseError( + `Expected description to be:\n${options.description}\ngot:\n${codeActions[0].description}`, + ); } this.applyChanges(codeAction.changes); @@ -2930,7 +3767,9 @@ namespace FourSlash { private verifyTextMatches(actualText: string, includeWhitespace: boolean, expectedText: string) { const removeWhitespace = (s: string): string => includeWhitespace ? s : this.removeWhitespace(s); if (removeWhitespace(actualText) !== removeWhitespace(expectedText)) { - this.raiseError(`Actual range text doesn't match expected text.\n${showTextDiff(expectedText, actualText)}`); + this.raiseError( + `Actual range text doesn't match expected text.\n${showTextDiff(expectedText, actualText)}`, + ); } } @@ -2939,17 +3778,40 @@ namespace FourSlash { * (ie: [|...|]) in the file after applying the codefix sole codefix * in the source file. */ - public verifyRangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number) { + public verifyRangeAfterCodeFix( + expectedText: string, + includeWhiteSpace?: boolean, + errorCode?: number, + index?: number, + ) { this.getAndApplyCodeActions(errorCode, index); this.verifyRangeIs(expectedText, includeWhiteSpace); } - public verifyCodeFixAll({ fixId, fixAllDescription, newFileContent, commands: expectedCommands }: FourSlashInterface.VerifyCodeFixAllOptions): void { + public verifyCodeFixAll( + { fixId, fixAllDescription, newFileContent, commands: expectedCommands }: + FourSlashInterface.VerifyCodeFixAllOptions, + ): void { const fixWithId = ts.find(this.getCodeFixes(this.activeFile.fileName), a => a.fixId === fixId); - ts.Debug.assert(fixWithId !== undefined, "No available code fix has the expected id. Fix All is not available if there is only one potentially fixable diagnostic present.", () => `Expected '${fixId}'. Available actions:\n${ts.mapDefined(this.getCodeFixes(this.activeFile.fileName), a => `${a.fixName} (${a.fixId || "no fix id"})`).join("\n")}`); + ts.Debug.assert( + fixWithId !== undefined, + "No available code fix has the expected id. Fix All is not available if there is only one potentially fixable diagnostic present.", + () => + `Expected '${fixId}'. Available actions:\n${ + ts.mapDefined( + this.getCodeFixes(this.activeFile.fileName), + a => `${a.fixName} (${a.fixId || "no fix id"})`, + ).join("\n") + }`, + ); ts.Debug.assertEqual(fixWithId.fixAllDescription, fixAllDescription); - const { changes, commands } = this.languageService.getCombinedCodeFix({ type: "file", fileName: this.activeFile.fileName }, fixId, this.formatCodeSettings, ts.emptyOptions); + const { changes, commands } = this.languageService.getCombinedCodeFix( + { type: "file", fileName: this.activeFile.fileName }, + fixId, + this.formatCodeSettings, + ts.emptyOptions, + ); assert.deepEqual(commands, expectedCommands); this.verifyNewContent({ newFileContent }, changes); } @@ -2960,13 +3822,21 @@ namespace FourSlash { let index = options.index; if (index === undefined) { if (!(actions && actions.length === 1)) { - this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`); + this.raiseError( + `Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${ + actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : "" + }`, + ); } index = 0; } else { if (!(actions && actions.length >= index + 1)) { - this.raiseError(`Should find at least ${index + 1} codefix(es), but ${actions ? actions.length : "none"} found.`); + this.raiseError( + `Should find at least ${index + 1} codefix(es), but ${ + actions ? actions.length : "none" + } found.`, + ); } } @@ -2995,13 +3865,22 @@ namespace FourSlash { } } - private verifyNewContent({ newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, changes: readonly ts.FileTextChanges[]): void { + private verifyNewContent( + { newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, + changes: readonly ts.FileTextChanges[], + ): void { if (newRangeContent !== undefined) { assert(newFileContent === undefined); - assert(changes.length === 1, "Affected 0 or more than 1 file, must use 'newFileContent' instead of 'newRangeContent'"); + assert( + changes.length === 1, + "Affected 0 or more than 1 file, must use 'newFileContent' instead of 'newRangeContent'", + ); const change = ts.first(changes); assert(change.fileName = this.activeFile.fileName); - const newText = ts.textChanges.applyChanges(this.getFileContent(this.activeFile.fileName), change.textChanges); + const newText = ts.textChanges.applyChanges( + this.getFileContent(this.activeFile.fileName), + change.textChanges, + ); const newRange = updateTextRangeForTextChanges(this.getOnlyRange(), change.textChanges); const actualText = newText.slice(newRange.pos, newRange.end); this.verifyTextMatches(actualText, /*includeWhitespace*/ true, newRangeContent); @@ -3016,16 +3895,24 @@ namespace FourSlash { } const oldText = this.tryGetFileContent(change.fileName); ts.Debug.assert(!!change.isNewFile === (oldText === undefined)); - const newContent = change.isNewFile ? ts.first(change.textChanges).newText : ts.textChanges.applyChanges(oldText!, change.textChanges); + const newContent = change.isNewFile ? ts.first(change.textChanges).newText + : ts.textChanges.applyChanges(oldText!, change.textChanges); this.verifyTextMatches(newContent, /*includeWhitespace*/ true, expectedNewContent); } for (const newFileName in newFileContent) { - ts.Debug.assert(changes.some(c => c.fileName === newFileName), "No change in file", () => newFileName); + ts.Debug.assert( + changes.some(c => c.fileName === newFileName), + "No change in file", + () => newFileName, + ); } } } - private verifyNewContentAfterChange({ newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, changedFiles: readonly string[]) { + private verifyNewContentAfterChange( + { newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, + changedFiles: readonly string[], + ) { const assertedChangedFiles = !newFileContent || typeof newFileContent === "string" ? [this.activeFile.fileName] : ts.getOwnKeys(newFileContent); @@ -3051,12 +3938,19 @@ namespace FourSlash { * Rerieves a codefix satisfying the parameters, or undefined if no such codefix is found. * @param fileName Path to file where error should be retrieved from. */ - private getCodeFixes(fileName: string, errorCode?: number, preferences: ts.UserPreferences = ts.emptyOptions, position?: number): readonly ts.CodeFixAction[] { - const diagnosticsForCodeFix = this.getDiagnostics(fileName, /*includeSuggestions*/ true).map(diagnostic => ({ - start: diagnostic.start, - length: diagnostic.length, - code: diagnostic.code, - })); + private getCodeFixes( + fileName: string, + errorCode?: number, + preferences: ts.UserPreferences = ts.emptyOptions, + position?: number, + ): readonly ts.CodeFixAction[] { + const diagnosticsForCodeFix = this.getDiagnostics(fileName, /*includeSuggestions*/ true).map( + diagnostic => ({ + start: diagnostic.start, + length: diagnostic.length, + code: diagnostic.code, + }), + ); return ts.flatMap(ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties), diagnostic => { if (errorCode !== undefined && errorCode !== diagnostic.code) { @@ -3068,7 +3962,14 @@ namespace FourSlash { return; } } - return this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start!, diagnostic.start! + diagnostic.length!, [diagnostic.code], this.formatCodeSettings, preferences); + return this.languageService.getCodeFixesAtPosition( + fileName, + diagnostic.start!, + diagnostic.start! + diagnostic.length!, + [diagnostic.code], + this.formatCodeSettings, + preferences, + ); }); } @@ -3078,7 +3979,11 @@ namespace FourSlash { } } - public verifyImportFixAtPosition(expectedTextArray: string[], errorCode: number | undefined, preferences: ts.UserPreferences | undefined) { + public verifyImportFixAtPosition( + expectedTextArray: string[], + errorCode: number | undefined, + preferences: ts.UserPreferences | undefined, + ) { const { fileName } = this.activeFile; const ranges = this.getRanges().filter(r => r.fileName === fileName); if (ranges.length > 1) { @@ -3090,7 +3995,9 @@ namespace FourSlash { this.configure(preferences); } - const codeFixes = this.getCodeFixes(fileName, errorCode, preferences).filter(f => f.fixName === ts.codefix.importFixName); + const codeFixes = this.getCodeFixes(fileName, errorCode, preferences).filter(f => + f.fixName === ts.codefix.importFixName + ); if (codeFixes.length === 0) { if (expectedTextArray.length !== 0) { @@ -3117,7 +4024,11 @@ namespace FourSlash { this.editScriptAndUpdateMarkers(fileName, span.start, span.start + insertedText.length, deletedText); } if (expectedTextArray.length !== actualTextArray.length) { - this.raiseError(`Expected ${expectedTextArray.length} import fixes, got ${actualTextArray.length}:\n\n${actualTextArray.join("\n\n" + "-".repeat(20) + "\n\n")}`); + this.raiseError( + `Expected ${expectedTextArray.length} import fixes, got ${actualTextArray.length}:\n\n${ + actualTextArray.join("\n\n" + "-".repeat(20) + "\n\n") + }`, + ); } ts.zipWith(expectedTextArray, actualTextArray, (expected, actual, index) => { if (expected !== actual) { @@ -3126,7 +4037,11 @@ namespace FourSlash { }); } - public verifyImportFixModuleSpecifiers(markerName: string, moduleSpecifiers: string[], preferences?: ts.UserPreferences) { + public verifyImportFixModuleSpecifiers( + markerName: string, + moduleSpecifiers: string[], + preferences?: ts.UserPreferences, + ) { const marker = this.getMarkerByName(markerName); const codeFixes = this.getCodeFixes(marker.fileName, ts.Diagnostics.Cannot_find_name_0.code, { includeCompletionsForModuleExports: true, @@ -3144,28 +4059,43 @@ namespace FourSlash { assert.deepEqual(actualModuleSpecifiers, moduleSpecifiers); } - public verifyDocCommentTemplate(expected: ts.TextInsertion | undefined, options?: ts.DocCommentTemplateOptions) { + public verifyDocCommentTemplate( + expected: ts.TextInsertion | undefined, + options?: ts.DocCommentTemplateOptions, + ) { const name = "verifyDocCommentTemplate"; - const actual = this.languageService.getDocCommentTemplateAtPosition(this.activeFile.fileName, this.currentCaretPosition, options || { generateReturnInDocTemplate: true })!; + const actual = this.languageService.getDocCommentTemplateAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + options || { generateReturnInDocTemplate: true }, + )!; if (expected === undefined) { if (actual) { - this.raiseError(`${name} failed - expected no template but got {newText: "${actual.newText}", caretOffset: ${actual.caretOffset}}`); + this.raiseError( + `${name} failed - expected no template but got {newText: "${actual.newText}", caretOffset: ${actual.caretOffset}}`, + ); } return; } else { if (actual === undefined) { - this.raiseError(`${name} failed - expected the template {newText: "${expected.newText}", caretOffset: "${expected.caretOffset}"} but got nothing instead`); + this.raiseError( + `${name} failed - expected the template {newText: "${expected.newText}", caretOffset: "${expected.caretOffset}"} but got nothing instead`, + ); } if (actual.newText !== expected.newText) { - this.raiseError(`${name} failed for expected insertion.\n${showTextDiff(expected.newText, actual.newText)}`); + this.raiseError( + `${name} failed for expected insertion.\n${showTextDiff(expected.newText, actual.newText)}`, + ); } if (actual.caretOffset !== expected.caretOffset) { - this.raiseError(`${name} failed - expected caretOffset: ${expected.caretOffset}\nactual caretOffset:${actual.caretOffset}`); + this.raiseError( + `${name} failed - expected caretOffset: ${expected.caretOffset}\nactual caretOffset:${actual.caretOffset}`, + ); } } } @@ -3189,7 +4119,11 @@ namespace FourSlash { const position = this.currentCaretPosition; - const validBraceCompletion = this.languageService.isValidBraceCompletionAtPosition(this.activeFile.fileName, position, charCode); + const validBraceCompletion = this.languageService.isValidBraceCompletionAtPosition( + this.activeFile.fileName, + position, + charCode, + ); if (!negative && !validBraceCompletion) { this.raiseError(`${position} is not a valid brace completion position for ${openingBrace}`); @@ -3203,7 +4137,10 @@ namespace FourSlash { public verifyJsxClosingTag(map: { [markerName: string]: ts.JsxClosingTagInfo | undefined; }): void { for (const markerName in map) { this.goToMarker(markerName); - const actual = this.languageService.getJsxClosingTagAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const actual = this.languageService.getJsxClosingTagAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); assert.deepEqual(actual, map[markerName], markerName); } } @@ -3212,7 +4149,9 @@ namespace FourSlash { const actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition); if (actual.length !== 2) { - this.raiseError(`verifyMatchingBracePosition failed - expected result to contain 2 spans, but it had ${actual.length}`); + this.raiseError( + `verifyMatchingBracePosition failed - expected result to contain 2 spans, but it had ${actual.length}`, + ); } let actualMatchPosition = -1; @@ -3223,11 +4162,17 @@ namespace FourSlash { actualMatchPosition = actual[0].start; } else { - this.raiseError(`verifyMatchingBracePosition failed - could not find the brace position: ${bracePosition} in the returned list: (${actual[0].start},${ts.textSpanEnd(actual[0])}) and (${actual[1].start},${ts.textSpanEnd(actual[1])})`); + this.raiseError( + `verifyMatchingBracePosition failed - could not find the brace position: ${bracePosition} in the returned list: (${ + actual[0].start + },${ts.textSpanEnd(actual[0])}) and (${actual[1].start},${ts.textSpanEnd(actual[1])})`, + ); } if (actualMatchPosition !== expectedMatchPosition) { - this.raiseError(`verifyMatchingBracePosition failed - expected: ${actualMatchPosition}, actual: ${expectedMatchPosition}`); + this.raiseError( + `verifyMatchingBracePosition failed - expected: ${actualMatchPosition}, actual: ${expectedMatchPosition}`, + ); } } @@ -3243,8 +4188,16 @@ namespace FourSlash { const expected = !negative; const position = this.currentCaretPosition; const fileName = this.activeFile.fileName; - const actual = !!this.languageService.getSpanOfEnclosingComment(fileName, position, /*onlyMultiLine*/ false); - const actualOnlyMultiLine = !!this.languageService.getSpanOfEnclosingComment(fileName, position, /*onlyMultiLine*/ true); + const actual = !!this.languageService.getSpanOfEnclosingComment( + fileName, + position, + /*onlyMultiLine*/ false, + ); + const actualOnlyMultiLine = !!this.languageService.getSpanOfEnclosingComment( + fileName, + position, + /*onlyMultiLine*/ true, + ); if (expected !== actual || onlyMultiLineDiverges === (actual === actualOnlyMultiLine)) { this.raiseError(`verifySpanOfEnclosingComment failed: position: '${position}' @@ -3277,16 +4230,33 @@ namespace FourSlash { } public verifyNavigationBar(json: any, options: { checkSpans?: boolean; } | undefined) { - this.verifyNavigationTreeOrBar(json, this.languageService.getNavigationBarItems(this.activeFile.fileName), "Bar", options); + this.verifyNavigationTreeOrBar( + json, + this.languageService.getNavigationBarItems(this.activeFile.fileName), + "Bar", + options, + ); } public verifyNavigationTree(json: any, options: { checkSpans?: boolean; } | undefined) { - this.verifyNavigationTreeOrBar(json, this.languageService.getNavigationTree(this.activeFile.fileName), "Tree", options); + this.verifyNavigationTreeOrBar( + json, + this.languageService.getNavigationTree(this.activeFile.fileName), + "Tree", + options, + ); } - private verifyNavigationTreeOrBar(json: any, tree: any, name: "Tree" | "Bar", options: { checkSpans?: boolean; } | undefined) { + private verifyNavigationTreeOrBar( + json: any, + tree: any, + name: "Tree" | "Bar", + options: { checkSpans?: boolean; } | undefined, + ) { if (JSON.stringify(tree, replacer) !== JSON.stringify(json)) { - this.raiseError(`verifyNavigation${name} failed - \n${showTextDiff(stringify(json), stringify(tree, replacer))}`); + this.raiseError( + `verifyNavigation${name} failed - \n${showTextDiff(stringify(json), stringify(tree, replacer))}`, + ); } function replacer(key: string, value: any) { @@ -3311,7 +4281,9 @@ namespace FourSlash { const items = this.languageService.getNavigateToItems(searchValue); Harness.IO.log(`NavigationItems list (${items.length} items)`); for (const item of items) { - Harness.IO.log(`name: ${item.name}, kind: ${item.kind}, parentName: ${item.containerName}, fileName: ${item.fileName}`); + Harness.IO.log( + `name: ${item.name}, kind: ${item.kind}, parentName: ${item.containerName}, fileName: ${item.fileName}`, + ); } } @@ -3319,7 +4291,11 @@ namespace FourSlash { const items = this.languageService.getNavigationBarItems(this.activeFile.fileName); Harness.IO.log(`Navigation bar (${items.length} items)`); for (const item of items) { - Harness.IO.log(`${ts.repeatString(" ", item.indent)}name: ${item.text}, kind: ${item.kind}, childItems: ${item.childItems.map(child => child.text)}`); + Harness.IO.log( + `${ts.repeatString(" ", item.indent)}name: ${item.text}, kind: ${item.kind}, childItems: ${ + item.childItems.map(child => child.text) + }`, + ); } } @@ -3327,37 +4303,59 @@ namespace FourSlash { return this.languageService.getOccurrencesAtPosition(this.activeFile.fileName, this.currentCaretPosition); } - public verifyOccurrencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean) { + public verifyOccurrencesAtPositionListContains( + fileName: string, + start: number, + end: number, + isWriteAccess?: boolean, + ) { const occurrences = this.getOccurrencesAtCurrentPosition(); if (!occurrences || occurrences.length === 0) { - return this.raiseError("verifyOccurrencesAtPositionListContains failed - found 0 references, expected at least one."); + return this.raiseError( + "verifyOccurrencesAtPositionListContains failed - found 0 references, expected at least one.", + ); } for (const occurrence of occurrences) { - if (occurrence && occurrence.fileName === fileName && occurrence.textSpan.start === start && ts.textSpanEnd(occurrence.textSpan) === end) { + if ( + occurrence && occurrence.fileName === fileName && occurrence.textSpan.start === start + && ts.textSpanEnd(occurrence.textSpan) === end + ) { if (typeof isWriteAccess !== "undefined" && occurrence.isWriteAccess !== isWriteAccess) { - this.raiseError(`verifyOccurrencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ${occurrence.isWriteAccess}, expected: ${isWriteAccess}.`); + this.raiseError( + `verifyOccurrencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ${occurrence.isWriteAccess}, expected: ${isWriteAccess}.`, + ); } return; } } const missingItem = { fileName, start, end, isWriteAccess }; - this.raiseError(`verifyOccurrencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(occurrences)})`); + this.raiseError( + `verifyOccurrencesAtPositionListContains failed - could not find the item: ${ + stringify(missingItem) + } in the returned list: (${stringify(occurrences)})`, + ); } public verifyOccurrencesAtPositionListCount(expectedCount: number) { const occurrences = this.getOccurrencesAtCurrentPosition(); const actualCount = occurrences ? occurrences.length : 0; if (expectedCount !== actualCount) { - this.raiseError(`verifyOccurrencesAtPositionListCount failed - actual: ${actualCount}, expected:${expectedCount}`); + this.raiseError( + `verifyOccurrencesAtPositionListCount failed - actual: ${actualCount}, expected:${expectedCount}`, + ); } } private getDocumentHighlightsAtCurrentPosition(fileNamesToSearch: readonly string[]) { const filesToSearch = fileNamesToSearch.map(name => ts.combinePaths(this.basePath, name)); - return this.languageService.getDocumentHighlights(this.activeFile.fileName, this.currentCaretPosition, filesToSearch); + return this.languageService.getDocumentHighlights( + this.activeFile.fileName, + this.currentCaretPosition, + filesToSearch, + ); } public verifyRangesAreOccurrences(isWriteAccess?: boolean, ranges?: Range[]) { @@ -3382,16 +4380,25 @@ namespace FourSlash { } public verifyRangesWithSameTextAreDocumentHighlights() { - this.rangesByText().forEach(ranges => this.verifyRangesAreDocumentHighlights(ranges, /*options*/ undefined)); + this.rangesByText().forEach(ranges => + this.verifyRangesAreDocumentHighlights(ranges, /*options*/ undefined) + ); } - public verifyDocumentHighlightsOf(startRange: Range, ranges: Range[], options: FourSlashInterface.VerifyDocumentHighlightsOptions | undefined) { + public verifyDocumentHighlightsOf( + startRange: Range, + ranges: Range[], + options: FourSlashInterface.VerifyDocumentHighlightsOptions | undefined, + ) { const fileNames = options && options.filesToSearch || unique(ranges, range => range.fileName); this.goToRangeStart(startRange); this.verifyDocumentHighlights(ranges, fileNames); } - public verifyRangesAreDocumentHighlights(ranges: Range[] | undefined, options: FourSlashInterface.VerifyDocumentHighlightsOptions | undefined) { + public verifyRangesAreDocumentHighlights( + ranges: Range[] | undefined, + options: FourSlashInterface.VerifyDocumentHighlightsOptions | undefined, + ) { ranges = ranges || this.getRanges(); assert(ranges.length); const fileNames = options && options.filesToSearch || unique(ranges, range => range.fileName); @@ -3410,34 +4417,52 @@ namespace FourSlash { } } - private verifyDocumentHighlights(expectedRanges: Range[], fileNames: readonly string[] = [this.activeFile.fileName]) { + private verifyDocumentHighlights( + expectedRanges: Range[], + fileNames: readonly string[] = [this.activeFile.fileName], + ) { fileNames = ts.map(fileNames, ts.normalizePath); const documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNames) || []; for (const dh of documentHighlights) { if (fileNames.indexOf(dh.fileName) === -1) { - this.raiseError(`verifyDocumentHighlights failed - got highlights in unexpected file name ${dh.fileName}`); + this.raiseError( + `verifyDocumentHighlights failed - got highlights in unexpected file name ${dh.fileName}`, + ); } } for (const fileName of fileNames) { const expectedRangesInFile = expectedRanges.filter(r => ts.normalizePath(r.fileName) === fileName); const highlights = ts.find(documentHighlights, dh => dh.fileName === fileName); - const spansInFile = highlights ? highlights.highlightSpans.sort((s1, s2) => s1.textSpan.start - s2.textSpan.start) : []; + const spansInFile = highlights ? highlights.highlightSpans.sort((s1, s2) => + s1.textSpan.start - s2.textSpan.start + ) : []; if (expectedRangesInFile.length !== spansInFile.length) { - this.raiseError(`verifyDocumentHighlights failed - In ${fileName}, expected ${expectedRangesInFile.length} highlights, got ${spansInFile.length}`); + this.raiseError( + `verifyDocumentHighlights failed - In ${fileName}, expected ${expectedRangesInFile.length} highlights, got ${spansInFile.length}`, + ); } ts.zipWith(expectedRangesInFile, spansInFile, (expectedRange, span) => { - if (span.textSpan.start !== expectedRange.pos || ts.textSpanEnd(span.textSpan) !== expectedRange.end) { - this.raiseError(`verifyDocumentHighlights failed - span does not match, actual: ${stringify(span.textSpan)}, expected: ${expectedRange.pos}--${expectedRange.end}`); + if ( + span.textSpan.start !== expectedRange.pos || ts.textSpanEnd(span.textSpan) !== expectedRange.end + ) { + this.raiseError( + `verifyDocumentHighlights failed - span does not match, actual: ${ + stringify(span.textSpan) + }, expected: ${expectedRange.pos}--${expectedRange.end}`, + ); } }); } } - public verifyCodeFixAvailable(negative: boolean, expected: FourSlashInterface.VerifyCodeFixAvailableOptions[] | string | undefined): void { + public verifyCodeFixAvailable( + negative: boolean, + expected: FourSlashInterface.VerifyCodeFixAvailableOptions[] | string | undefined, + ): void { const codeFixes = this.getCodeFixes(this.activeFile.fileName); if (negative) { if (typeof expected === "undefined") { @@ -3449,14 +4474,20 @@ namespace FourSlash { } } else { - assert(typeof expected === "undefined" || typeof expected === "string", "With a negated assertion, 'expected' must be undefined or a string value of a codefix name."); + assert( + typeof expected === "undefined" || typeof expected === "string", + "With a negated assertion, 'expected' must be undefined or a string value of a codefix name.", + ); } } else if (typeof expected === "string") { this.assertObjectsEqual(codeFixes.map(fix => fix.fixName), [expected]); } else { - const actuals = codeFixes.map((fix): FourSlashInterface.VerifyCodeFixAvailableOptions => ({ description: fix.description, commands: fix.commands })); + const actuals = codeFixes.map((fix): FourSlashInterface.VerifyCodeFixAvailableOptions => ({ + description: fix.description, + commands: fix.commands, + })); this.assertObjectsEqual(actuals, negative ? ts.emptyArray : expected); } } @@ -3473,9 +4504,12 @@ namespace FourSlash { } this.raiseError( - `Expected to find a fix with the name '${fixName}', but none exists.` + - availableFixes.length - ? ` Available fixes: ${availableFixes.map(fix => `${fix.fixName} (${fix.fixId ? "with" : "without"} fix-all)`).join(", ")}` + `Expected to find a fix with the name '${fixName}', but none exists.` + + availableFixes.length + ? ` Available fixes: ${ + availableFixes.map(fix => `${fix.fixName} (${fix.fixId ? "with" : "without"} fix-all)`) + .join(", ") + }` : "", ); } @@ -3484,10 +4518,14 @@ namespace FourSlash { public verifyApplicableRefactorAvailableAtMarker(negative: boolean, markerName: string) { const isAvailable = this.getApplicableRefactors(this.getMarkerByName(markerName)).length > 0; if (negative && isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableAtMarker failed - expected no refactor at marker ${markerName} but found some.`); + this.raiseError( + `verifyApplicableRefactorAvailableAtMarker failed - expected no refactor at marker ${markerName} but found some.`, + ); } if (!negative && !isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableAtMarker failed - expected a refactor at marker ${markerName} but found none.`); + this.raiseError( + `verifyApplicableRefactorAvailableAtMarker failed - expected a refactor at marker ${markerName} but found none.`, + ); } } @@ -3498,7 +4536,13 @@ namespace FourSlash { }; } - public verifyRefactorAvailable(negative: boolean, triggerReason: ts.RefactorTriggerReason, name: string, actionName?: string, actionDescription?: string) { + public verifyRefactorAvailable( + negative: boolean, + triggerReason: ts.RefactorTriggerReason, + name: string, + actionName?: string, + actionDescription?: string, + ) { let refactors = this.getApplicableRefactorsAtSelection(triggerReason); refactors = refactors.filter(r => r.name === name); @@ -3516,15 +4560,23 @@ namespace FourSlash { if (negative) { if (isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found: ${refactors.map(r => r.name).join(", ")}`); + this.raiseError( + `verifyApplicableRefactorAvailableForRange failed - expected no refactor but found: ${ + refactors.map(r => r.name).join(", ") + }`, + ); } } else { if (!isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`); + this.raiseError( + `verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`, + ); } if (refactors.length > 1) { - this.raiseError(`${refactors.length} available refactors both have name ${name} and action ${actionName}`); + this.raiseError( + `${refactors.length} available refactors both have name ${name} and action ${actionName}`, + ); } } } @@ -3547,30 +4599,59 @@ namespace FourSlash { const isAvailable = this.getApplicableRefactors(ts.first(ranges)).length > 0; if (negative && isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found some.`); + this.raiseError( + `verifyApplicableRefactorAvailableForRange failed - expected no refactor but found some.`, + ); } if (!negative && !isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`); + this.raiseError( + `verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`, + ); } } - public applyRefactor({ refactorName, actionName, actionDescription, newContent: newContentWithRenameMarker, triggerReason }: FourSlashInterface.ApplyRefactorOptions) { + public applyRefactor( + { refactorName, actionName, actionDescription, newContent: newContentWithRenameMarker, triggerReason }: + FourSlashInterface.ApplyRefactorOptions, + ) { const range = this.getSelection(); const refactors = this.getApplicableRefactorsAtSelection(triggerReason); const refactorsWithName = refactors.filter(r => r.name === refactorName); if (refactorsWithName.length === 0) { - this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.\nAvailable refactors: ${refactors.map(r => r.name)}`); + this.raiseError( + `The expected refactor: ${refactorName} is not available at the marker location.\nAvailable refactors: ${ + refactors.map(r => r.name) + }`, + ); } - const action = ts.firstDefined(refactorsWithName, refactor => refactor.actions.find(a => a.name === actionName)); + const action = ts.firstDefined( + refactorsWithName, + refactor => refactor.actions.find(a => a.name === actionName), + ); if (!action) { - throw this.raiseError(`The expected action: ${actionName} is not included in: ${ts.flatMap(refactorsWithName, r => r.actions.map(a => a.name))}`); + throw this.raiseError( + `The expected action: ${actionName} is not included in: ${ + ts.flatMap(refactorsWithName, r => r.actions.map(a => a.name)) + }`, + ); } if (action.description !== actionDescription) { - this.raiseError(`Expected action description to be ${JSON.stringify(actionDescription)}, got: ${JSON.stringify(action.description)}`); + this.raiseError( + `Expected action description to be ${JSON.stringify(actionDescription)}, got: ${ + JSON.stringify(action.description) + }`, + ); } - const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName, ts.emptyOptions)!; + const editInfo = this.languageService.getEditsForRefactor( + this.activeFile.fileName, + this.formatCodeSettings, + range, + refactorName, + actionName, + ts.emptyOptions, + )!; for (const edit of editInfo.edits) { this.applyEdits(edit.fileName, edit.textChanges); } @@ -3578,7 +4659,8 @@ namespace FourSlash { let renameFilename: string | undefined; let renamePosition: number | undefined; - const newFileContents = typeof newContentWithRenameMarker === "string" ? { [this.activeFile.fileName]: newContentWithRenameMarker } : newContentWithRenameMarker; + const newFileContents = typeof newContentWithRenameMarker === "string" + ? { [this.activeFile.fileName]: newContentWithRenameMarker } : newContentWithRenameMarker; for (const fileName in newFileContents) { const { renamePosition: rp, newContent } = TestState.parseNewContent(newFileContents[fileName]); if (renamePosition === undefined) { @@ -3599,18 +4681,23 @@ namespace FourSlash { else { this.assertObjectsEqual(editInfo.renameFilename, renameFilename); if (renamePosition !== editInfo.renameLocation) { - this.raiseError(`Expected rename position of ${renamePosition}, but got ${editInfo.renameLocation}`); + this.raiseError( + `Expected rename position of ${renamePosition}, but got ${editInfo.renameLocation}`, + ); } } } - private static parseNewContent(newContentWithRenameMarker: string): { readonly renamePosition: number | undefined; readonly newContent: string; } { + private static parseNewContent( + newContentWithRenameMarker: string, + ): { readonly renamePosition: number | undefined; readonly newContent: string; } { const renamePosition = newContentWithRenameMarker.indexOf("/*RENAME*/"); if (renamePosition === -1) { return { renamePosition: undefined, newContent: newContentWithRenameMarker }; } else { - const newContent = newContentWithRenameMarker.slice(0, renamePosition) + newContentWithRenameMarker.slice(renamePosition + "/*RENAME*/".length); + const newContent = newContentWithRenameMarker.slice(0, renamePosition) + + newContentWithRenameMarker.slice(renamePosition + "/*RENAME*/".length); return { renamePosition, newContent }; } } @@ -3628,22 +4715,41 @@ namespace FourSlash { } public moveToNewFile(options: FourSlashInterface.MoveToNewFileOptions): void { - assert(this.getRanges().length === 1, "Must have exactly one fourslash range (source enclosed between '[|' and '|]' delimiters) in the source file"); + assert( + this.getRanges().length === 1, + "Must have exactly one fourslash range (source enclosed between '[|' and '|]' delimiters) in the source file", + ); const range = this.getRanges()[0]; - const refactor = ts.find(this.getApplicableRefactors(range, { allowTextChangesInNewFiles: true }), r => r.name === "Move to a new file")!; + const refactor = ts.find( + this.getApplicableRefactors(range, { allowTextChangesInNewFiles: true }), + r => r.name === "Move to a new file", + )!; assert(refactor.actions.length === 1); const action = ts.first(refactor.actions); assert(action.name === "Move to a new file" && action.description === "Move to a new file"); - const editInfo = this.languageService.getEditsForRefactor(range.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions)!; + const editInfo = this.languageService.getEditsForRefactor( + range.fileName, + this.formatCodeSettings, + range, + refactor.name, + action.name, + options.preferences || ts.emptyOptions, + )!; this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits); } - private testNewFileContents(edits: readonly ts.FileTextChanges[], newFileContents: { [fileName: string]: string; }, description: string): void { + private testNewFileContents( + edits: readonly ts.FileTextChanges[], + newFileContents: { [fileName: string]: string; }, + description: string, + ): void { for (const { fileName, textChanges } of edits) { const newContent = newFileContents[fileName]; if (newContent === undefined) { - this.raiseError(`${description} - There was an edit in ${fileName} but new content was not specified.`); + this.raiseError( + `${description} - There was an edit in ${fileName} but new content was not specified.`, + ); } const fileContent = this.tryGetFileContent(fileName); @@ -3677,14 +4783,30 @@ namespace FourSlash { formattingOptions = formattingOptions || this.formatCodeSettings; const marker = this.getMarkerByName(markerName); - const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, marker.position, ts.emptyOptions); - const applicableRefactorToApply = ts.find(applicableRefactors, refactor => refactor.name === refactorNameToApply); + const applicableRefactors = this.languageService.getApplicableRefactors( + this.activeFile.fileName, + marker.position, + ts.emptyOptions, + ); + const applicableRefactorToApply = ts.find( + applicableRefactors, + refactor => refactor.name === refactorNameToApply, + ); if (!applicableRefactorToApply) { - this.raiseError(`The expected refactor: ${refactorNameToApply} is not available at the marker location.`); + this.raiseError( + `The expected refactor: ${refactorNameToApply} is not available at the marker location.`, + ); } - const editInfo = this.languageService.getEditsForRefactor(marker.fileName, formattingOptions, marker.position, refactorNameToApply, actionName, ts.emptyOptions)!; + const editInfo = this.languageService.getEditsForRefactor( + marker.fileName, + formattingOptions, + marker.position, + refactorNameToApply, + actionName, + ts.emptyOptions, + )!; for (const edit of editInfo.edits) { this.applyEdits(edit.fileName, edit.textChanges); @@ -3692,7 +4814,9 @@ namespace FourSlash { const actualContent = this.getFileContent(marker.fileName); if (actualContent !== expectedContent) { - this.raiseError(`verifyFileAfterApplyingRefactors failed:\n${showTextDiff(expectedContent, actualContent)}`); + this.raiseError( + `verifyFileAfterApplyingRefactors failed:\n${showTextDiff(expectedContent, actualContent)}`, + ); } } @@ -3701,12 +4825,22 @@ namespace FourSlash { Harness.IO.log(stringify(codeFixes)); } - private formatCallHierarchyItemSpan(file: FourSlashFile, span: ts.TextSpan, prefix: string, trailingPrefix = prefix) { + private formatCallHierarchyItemSpan( + file: FourSlashFile, + span: ts.TextSpan, + prefix: string, + trailingPrefix = prefix, + ) { const startLc = this.languageServiceAdapterHost.positionToLineAndCharacter(file.fileName, span.start); - const endLc = this.languageServiceAdapterHost.positionToLineAndCharacter(file.fileName, ts.textSpanEnd(span)); + const endLc = this.languageServiceAdapterHost.positionToLineAndCharacter( + file.fileName, + ts.textSpanEnd(span), + ); const lines = this.spanLines(file, span, { fullLines: true, lineNumbers: true, selection: true }); let text = ""; - text += `${prefix}╭ ${file.fileName}:${startLc.line + 1}:${startLc.character + 1}-${endLc.line + 1}:${endLc.character + 1}\n`; + text += `${prefix}╭ ${file.fileName}:${startLc.line + 1}:${startLc.character + 1}-${endLc.line + 1}:${ + endLc.character + 1 + }\n`; for (const line of lines) { text += `${prefix}│ ${line.trimRight()}\n`; } @@ -3714,26 +4848,55 @@ namespace FourSlash { return text; } - private formatCallHierarchyItemSpans(file: FourSlashFile, spans: ts.TextSpan[], prefix: string, trailingPrefix = prefix) { + private formatCallHierarchyItemSpans( + file: FourSlashFile, + spans: ts.TextSpan[], + prefix: string, + trailingPrefix = prefix, + ) { let text = ""; for (let i = 0; i < spans.length; i++) { - text += this.formatCallHierarchyItemSpan(file, spans[i], prefix, i < spans.length - 1 ? prefix : trailingPrefix); + text += this.formatCallHierarchyItemSpan( + file, + spans[i], + prefix, + i < spans.length - 1 ? prefix : trailingPrefix, + ); } return text; } - private formatCallHierarchyItem(file: FourSlashFile, callHierarchyItem: ts.CallHierarchyItem, direction: CallHierarchyItemDirection, seen: ts.ESMap, prefix: string, trailingPrefix: string = prefix) { + private formatCallHierarchyItem( + file: FourSlashFile, + callHierarchyItem: ts.CallHierarchyItem, + direction: CallHierarchyItemDirection, + seen: ts.ESMap, + prefix: string, + trailingPrefix: string = prefix, + ) { const key = `${callHierarchyItem.file}|${JSON.stringify(callHierarchyItem.span)}|${direction}`; const alreadySeen = seen.has(key); seen.set(key, true); - const incomingCalls = direction === CallHierarchyItemDirection.Outgoing ? { result: "skip" } as const : - alreadySeen ? { result: "seen" } as const : - { result: "show", values: this.languageService.provideCallHierarchyIncomingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const; - - const outgoingCalls = direction === CallHierarchyItemDirection.Incoming ? { result: "skip" } as const : - alreadySeen ? { result: "seen" } as const : - { result: "show", values: this.languageService.provideCallHierarchyOutgoingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const; + const incomingCalls = direction === CallHierarchyItemDirection.Outgoing ? { result: "skip" } as const + : alreadySeen ? { result: "seen" } as const + : { + result: "show", + values: this.languageService.provideCallHierarchyIncomingCalls( + callHierarchyItem.file, + callHierarchyItem.selectionSpan.start, + ), + } as const; + + const outgoingCalls = direction === CallHierarchyItemDirection.Incoming ? { result: "skip" } as const + : alreadySeen ? { result: "seen" } as const + : { + result: "show", + values: this.languageService.provideCallHierarchyOutgoingCalls( + callHierarchyItem.file, + callHierarchyItem.selectionSpan.start, + ), + } as const; let text = ""; text += `${prefix}╭ name: ${callHierarchyItem.name}\n`; @@ -3749,8 +4912,8 @@ namespace FourSlash { file, callHierarchyItem.selectionSpan, `${prefix}│ `, - incomingCalls.result !== "skip" || outgoingCalls.result !== "skip" ? `${prefix}│ ` : - `${trailingPrefix}╰ `, + incomingCalls.result !== "skip" || outgoingCalls.result !== "skip" ? `${prefix}│ ` + : `${trailingPrefix}╰ `, ); if (incomingCalls.result === "seen") { @@ -3776,15 +4939,21 @@ namespace FourSlash { const incomingCall = incomingCalls.values[i]; const file = this.findFile(incomingCall.from.file); text += `${prefix}│ ╭ from:\n`; - text += this.formatCallHierarchyItem(file, incomingCall.from, CallHierarchyItemDirection.Incoming, seen, `${prefix}│ │ `); + text += this.formatCallHierarchyItem( + file, + incomingCall.from, + CallHierarchyItemDirection.Incoming, + seen, + `${prefix}│ │ `, + ); text += `${prefix}│ ├ fromSpans:\n`; text += this.formatCallHierarchyItemSpans( file, incomingCall.fromSpans, `${prefix}│ │ `, - i < incomingCalls.values.length - 1 ? `${prefix}│ ╰ ` : - outgoingCalls.result !== "skip" ? `${prefix}│ ╰ ` : - `${trailingPrefix}╰ ╰ `, + i < incomingCalls.values.length - 1 ? `${prefix}│ ╰ ` + : outgoingCalls.result !== "skip" ? `${prefix}│ ╰ ` + : `${trailingPrefix}╰ ╰ `, ); } } @@ -3802,14 +4971,20 @@ namespace FourSlash { for (let i = 0; i < outgoingCalls.values.length; i++) { const outgoingCall = outgoingCalls.values[i]; text += `${prefix}│ ╭ to:\n`; - text += this.formatCallHierarchyItem(this.findFile(outgoingCall.to.file), outgoingCall.to, CallHierarchyItemDirection.Outgoing, seen, `${prefix}│ │ `); + text += this.formatCallHierarchyItem( + this.findFile(outgoingCall.to.file), + outgoingCall.to, + CallHierarchyItemDirection.Outgoing, + seen, + `${prefix}│ │ `, + ); text += `${prefix}│ ├ fromSpans:\n`; text += this.formatCallHierarchyItemSpans( file, outgoingCall.fromSpans, `${prefix}│ │ `, - i < outgoingCalls.values.length - 1 ? `${prefix}│ ╰ ` : - `${trailingPrefix}╰ ╰ `, + i < outgoingCalls.values.length - 1 ? `${prefix}│ ╰ ` + : `${trailingPrefix}╰ ╰ `, ); } } @@ -3821,27 +4996,45 @@ namespace FourSlash { let text = ""; if (callHierarchyItem) { const file = this.findFile(callHierarchyItem.file); - text += this.formatCallHierarchyItem(file, callHierarchyItem, CallHierarchyItemDirection.Root, new ts.Map(), ""); + text += this.formatCallHierarchyItem( + file, + callHierarchyItem, + CallHierarchyItemDirection.Root, + new ts.Map(), + "", + ); } return text; } public baselineCallHierarchy() { const baselineFile = this.getBaselineFileNameForContainingTestFile(".callHierarchy.txt"); - const callHierarchyItem = this.languageService.prepareCallHierarchy(this.activeFile.fileName, this.currentCaretPosition); - const text = callHierarchyItem ? ts.mapOneOrMany(callHierarchyItem, item => this.formatCallHierarchy(item), result => result.join("")) : "none"; + const callHierarchyItem = this.languageService.prepareCallHierarchy( + this.activeFile.fileName, + this.currentCaretPosition, + ); + const text = callHierarchyItem + ? ts.mapOneOrMany(callHierarchyItem, item => this.formatCallHierarchy(item), result => result.join("")) + : "none"; Harness.Baseline.runBaseline(baselineFile, text); } private assertTextSpanEqualsRange(span: ts.TextSpan, range: Range, message?: string) { if (!textSpanEqualsRange(span, range)) { - this.raiseError(`${prefixMessage(message)}Expected to find TextSpan ${JSON.stringify({ start: range.pos, length: range.end - range.pos })} but got ${JSON.stringify(span)} instead.`); + this.raiseError( + `${prefixMessage(message)}Expected to find TextSpan ${ + JSON.stringify({ start: range.pos, length: range.end - range.pos }) + } but got ${JSON.stringify(span)} instead.`, + ); } } private getLineContent(index: number) { const text = this.getFileContent(this.activeFile.fileName); - const pos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { line: index, character: 0 }); + const pos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { + line: index, + character: 0, + }); let startPos = pos, endPos = pos; while (startPos > 0) { @@ -3880,7 +5073,9 @@ namespace FourSlash { if (typeof indexOrName === "number") { const index = indexOrName; if (index >= this.testData.files.length) { - throw new Error(`File index (${index}) in openFile was out of range. There are only ${this.testData.files.length} files in this test.`); + throw new Error( + `File index (${index}) in openFile was out of range. There are only ${this.testData.files.length} files in this test.`, + ); } else { return this.testData.files[index]; @@ -3889,7 +5084,11 @@ namespace FourSlash { else if (ts.isString(indexOrName)) { const { file, availableNames } = this.tryFindFileWorker(indexOrName); if (!file) { - throw new Error(`No test file named "${indexOrName}" exists. Available file names are: ${availableNames.join(", ")}`); + throw new Error( + `No test file named "${indexOrName}" exists. Available file names are: ${ + availableNames.join(", ") + }`, + ); } return file; } @@ -3898,7 +5097,9 @@ namespace FourSlash { } } - private tryFindFileWorker(name: string): { readonly file: FourSlashFile | undefined; readonly availableNames: readonly string[]; } { + private tryFindFileWorker( + name: string, + ): { readonly file: FourSlashFile | undefined; readonly availableNames: readonly string[]; } { name = ts.normalizePath(name); // names are stored in the compiler with this relative path, this allows people to use goTo.file on just the fileName name = name.indexOf("/") === -1 ? (this.basePath + "/" + name) : name; @@ -3928,7 +5129,11 @@ namespace FourSlash { public getMarkerByName(markerName: string) { const markerPos = this.testData.markerPositions.get(markerName); if (markerPos === undefined) { - throw new Error(`Unknown marker "${markerName}" Available markers: ${this.getMarkerNames().map(m => '"' + m + '"').join(", ")}`); + throw new Error( + `Unknown marker "${markerName}" Available markers: ${ + this.getMarkerNames().map(m => '"' + m + '"').join(", ") + }`, + ); } else { return markerPos; @@ -3943,9 +5148,16 @@ namespace FourSlash { this.cancellationToken.resetCancelled(); } - public getEditsForFileRename({ oldPath, newPath, newFileContents, preferences }: FourSlashInterface.GetEditsForFileRenameOptions): void { + public getEditsForFileRename( + { oldPath, newPath, newFileContents, preferences }: FourSlashInterface.GetEditsForFileRenameOptions, + ): void { const test = (fileContents: { readonly [fileName: string]: string; }, description: string): void => { - const changes = this.languageService.getEditsForFileRename(oldPath, newPath, this.formatCodeSettings, preferences); + const changes = this.languageService.getEditsForFileRename( + oldPath, + newPath, + this.formatCodeSettings, + preferences, + ); this.testNewFileContents(changes, fileContents, description); }; @@ -3955,18 +5167,56 @@ namespace FourSlash { this.languageServiceAdapterHost.renameFileOrDirectory(oldPath, newPath); this.languageService.cleanupSemanticCache(); - const pathUpdater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ false), /*sourceMapper*/ undefined); + const pathUpdater = ts.getPathUpdater( + oldPath, + newPath, + ts.createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ false), + /*sourceMapper*/ undefined, + ); test(renameKeys(newFileContents, key => pathUpdater(key) || key), "with file moved"); } - private getApplicableRefactorsAtSelection(triggerReason: ts.RefactorTriggerReason = "implicit", kind?: string, preferences = ts.emptyOptions) { - return this.getApplicableRefactorsWorker(this.getSelection(), this.activeFile.fileName, preferences, triggerReason, kind); - } - private getApplicableRefactors(rangeOrMarker: Range | Marker, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason = "implicit", kind?: string): readonly ts.ApplicableRefactorInfo[] { - return this.getApplicableRefactorsWorker("position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, rangeOrMarker.fileName, preferences, triggerReason, kind); // eslint-disable-line local/no-in-operator + private getApplicableRefactorsAtSelection( + triggerReason: ts.RefactorTriggerReason = "implicit", + kind?: string, + preferences = ts.emptyOptions, + ) { + return this.getApplicableRefactorsWorker( + this.getSelection(), + this.activeFile.fileName, + preferences, + triggerReason, + kind, + ); } - private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason, kind?: string): readonly ts.ApplicableRefactorInfo[] { - return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences, triggerReason, kind) || ts.emptyArray; + private getApplicableRefactors( + rangeOrMarker: Range | Marker, + preferences = ts.emptyOptions, + triggerReason: ts.RefactorTriggerReason = "implicit", + kind?: string, + ): readonly ts.ApplicableRefactorInfo[] { + return this.getApplicableRefactorsWorker( + "position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, + rangeOrMarker.fileName, + preferences, + triggerReason, + kind, + ); // eslint-disable-line local/no-in-operator + } + private getApplicableRefactorsWorker( + positionOrRange: number | ts.TextRange, + fileName: string, + preferences = ts.emptyOptions, + triggerReason: ts.RefactorTriggerReason, + kind?: string, + ): readonly ts.ApplicableRefactorInfo[] { + return this.languageService.getApplicableRefactors( + fileName, + positionOrRange, + preferences, + triggerReason, + kind, + ) || ts.emptyArray; } public configurePlugin(pluginName: string, configuration: any): void { @@ -3992,7 +5242,10 @@ namespace FourSlash { public toggleMultilineComment(newFileContent: string): void { const changes: ts.TextChange[] = []; for (const range of this.getRanges()) { - changes.push.apply(changes, this.languageService.toggleMultilineComment(this.activeFile.fileName, range)); + changes.push.apply( + changes, + this.languageService.toggleMultilineComment(this.activeFile.fileName, range), + ); } this.applyEdits(this.activeFile.fileName, changes); @@ -4031,9 +5284,13 @@ namespace FourSlash { return span.start === range.pos && span.length === range.end - range.pos; } - function updateTextRangeForTextChanges({ pos, end }: ts.TextRange, textChanges: readonly ts.TextChange[]): ts.TextRange { + function updateTextRangeForTextChanges( + { pos, end }: ts.TextRange, + textChanges: readonly ts.TextChange[], + ): ts.TextRange { forEachTextChange(textChanges, change => { - const update = (p: number): number => updatePosition(p, change.span.start, ts.textSpanEnd(change.span), change.newText); + const update = (p: number): number => + updatePosition(p, change.span.start, ts.textSpanEnd(change.span), change.newText); pos = update(pos); end = update(end); }); @@ -4061,7 +5318,10 @@ namespace FourSlash { return position <= editStart ? position : position < editEnd ? -1 : position + length - +(editEnd - editStart); } - function renameKeys(obj: { readonly [key: string]: T; }, renameKey: (key: string) => string): { readonly [key: string]: T; } { + function renameKeys( + obj: { readonly [key: string]: T; }, + renameKey: (key: string) => string, + ): { readonly [key: string]: T; } { const res: { [key: string]: T; } = {}; for (const key in obj) { res[renameKey(key)] = obj[key]; @@ -4074,7 +5334,12 @@ namespace FourSlash { runFourSlashTestContent(basePath, testType, content, fileName); } - export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): void { + export function runFourSlashTestContent( + basePath: string, + testType: FourSlashTestType, + content: string, + fileName: string, + ): void { // Give file paths an absolute path for the virtual file system const absoluteBasePath = ts.combinePaths(Harness.virtualFileSystemRoot, basePath); const absoluteFileName = ts.combinePaths(Harness.virtualFileSystemRoot, fileName); @@ -4083,7 +5348,11 @@ namespace FourSlash { const testData = parseTestData(absoluteBasePath, content, absoluteFileName); const state = new TestState(absoluteFileName, absoluteBasePath, testType, testData); const actualFileName = Harness.IO.resolvePath(fileName) || absoluteFileName; - const output = ts.transpileModule(content, { reportDiagnostics: true, fileName: actualFileName, compilerOptions: { target: ts.ScriptTarget.ES2015, inlineSourceMap: true, inlineSources: true } }); + const output = ts.transpileModule(content, { + reportDiagnostics: true, + fileName: actualFileName, + compilerOptions: { target: ts.ScriptTarget.ES2015, inlineSourceMap: true, inlineSources: true }, + }); if (output.diagnostics!.length > 0) { throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`); } @@ -4093,7 +5362,10 @@ namespace FourSlash { function runCode(code: string, state: TestState, fileName: string): void { // Compile and execute the test const generatedFile = ts.changeExtension(fileName, ".js"); - const wrappedCode = `(function(test, goTo, plugins, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled) {${code}\n//# sourceURL=${ts.getBaseFileName(generatedFile)}\n})`; + const wrappedCode = + `(function(test, goTo, plugins, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled) {${code}\n//# sourceURL=${ + ts.getBaseFileName(generatedFile) + }\n})`; type SourceMapSupportModule = typeof import("source-map-support") & { // TODO(rbuckton): This is missing from the DT definitions and needs to be added. @@ -4112,8 +5384,8 @@ namespace FourSlash { sourceMapSupportModule?.install({ retrieveFile: path => { - return path === generatedFile ? wrappedCode : - undefined!; + return path === generatedFile ? wrappedCode + : undefined!; }, }); @@ -4128,7 +5400,19 @@ namespace FourSlash { const cancellation = new FourSlashInterface.Cancellation(state); // eslint-disable-next-line no-eval const f = eval(wrappedCode); - f(test, goTo, config, verify, edit, debug, format, cancellation, FourSlashInterface.classification, FourSlashInterface.Completion, verifyOperationIsCancelled); + f( + test, + goTo, + config, + verify, + edit, + debug, + format, + cancellation, + FourSlashInterface.classification, + FourSlashInterface.Completion, + verifyOperationIsCancelled, + ); } catch (err) { // ensure 'source-map-support' is triggered while we still have the handler attached by accessing `error.stack`. @@ -4307,14 +5591,25 @@ namespace FourSlash { throw new Error(errorMessage); } - function recordObjectMarker(fileName: string, location: LocationInformation, text: string, markerMap: ts.ESMap, markers: Marker[]): Marker | undefined { + function recordObjectMarker( + fileName: string, + location: LocationInformation, + text: string, + markerMap: ts.ESMap, + markers: Marker[], + ): Marker | undefined { let markerValue: any; try { // Attempt to parse the marker value as JSON markerValue = JSON.parse("{ " + text + " }"); } catch (e) { - reportError(fileName, location.sourceLine, location.sourceColumn, "Unable to parse marker text " + e.message); + reportError( + fileName, + location.sourceLine, + location.sourceColumn, + "Unable to parse marker text " + e.message, + ); } if (markerValue === undefined) { @@ -4338,7 +5633,13 @@ namespace FourSlash { return marker; } - function recordMarker(fileName: string, location: LocationInformation, name: string, markerMap: ts.ESMap, markers: Marker[]): Marker | undefined { + function recordMarker( + fileName: string, + location: LocationInformation, + name: string, + markerMap: ts.ESMap, + markers: Marker[], + ): Marker | undefined { const marker: Marker = { fileName, position: location.position, @@ -4357,7 +5658,13 @@ namespace FourSlash { } } - function parseFileContent(content: string, fileName: string, markerMap: ts.ESMap, markers: Marker[], ranges: Range[]): FourSlashFile { + function parseFileContent( + content: string, + fileName: string, + markerMap: ts.ESMap, + markers: Marker[], + ranges: Range[], + ): FourSlashFile { content = chompLeadingSpace(content); // Any slash-star comment with a character not in this string is not a marker. @@ -4389,7 +5696,11 @@ namespace FourSlash { let column = 1; const flush = (lastSafeCharIndex: number | undefined) => { - output = output + content.substr(lastNormalCharPosition, lastSafeCharIndex === undefined ? undefined : lastSafeCharIndex - lastNormalCharPosition); + output = output + + content.substr( + lastNormalCharPosition, + lastSafeCharIndex === undefined ? undefined : lastSafeCharIndex - lastNormalCharPosition, + ); }; if (content.length > 0) { @@ -4458,8 +5769,15 @@ namespace FourSlash { // Object markers are only ever terminated by |} and have no content restrictions if (previousChar === "|" && currentChar === "}") { // Record the marker - const objectMarkerNameText = content.substring(openMarker!.sourcePosition + 2, i - 1).trim(); - const marker = recordObjectMarker(fileName, openMarker!, objectMarkerNameText, markerMap, markers); + const objectMarkerNameText = content.substring(openMarker!.sourcePosition + 2, i - 1) + .trim(); + const marker = recordObjectMarker( + fileName, + openMarker!, + objectMarkerNameText, + markerMap, + markers, + ); if (openRanges.length > 0) { openRanges[openRanges.length - 1].marker = marker; @@ -4570,7 +5888,10 @@ namespace FourSlash { } function makeWhitespaceVisible(text: string) { - return text.replace(/ /g, "\u00B7").replace(/\r/g, "\u00B6").replace(/\n/g, "\u2193\n").replace(/\t/g, "\u2192\ "); + return text.replace(/ /g, "\u00B7").replace(/\r/g, "\u00B6").replace(/\n/g, "\u2193\n").replace( + /\t/g, + "\u2192\ ", + ); } function showTextDiff(expected: string, actual: string): string { @@ -4605,7 +5926,9 @@ namespace FourSlash { const actualMsg = "\x1b[1mActual\x1b[0m\x1b[31m"; const expectedString = quoted ? '"' + expected + '"' : expected; const actualString = quoted ? '"' + actual + '"' : actual; - return `\n${expectMsg}:\n${expectedString}\n\n${actualMsg}:\n${highlightDifferenceBetweenStrings(expected, actualString)}`; + return `\n${expectMsg}:\n${expectedString}\n\n${actualMsg}:\n${ + highlightDifferenceBetweenStrings(expected, actualString) + }`; } function templateToRegExp(template: string) { diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 8d182ec230c53..96574250c4684 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -73,8 +73,12 @@ namespace FourSlashInterface { public eachMarker(markers: readonly string[], action: (marker: FourSlash.Marker, index: number) => void): void; public eachMarker(action: (marker: FourSlash.Marker, index: number) => void): void; - public eachMarker(a: readonly string[] | ((marker: FourSlash.Marker, index: number) => void), b?: (marker: FourSlash.Marker, index: number) => void): void { - const markers = typeof a === "function" ? this.state.getMarkers() : a.map(m => this.state.getMarkerByName(m)); + public eachMarker( + a: readonly string[] | ((marker: FourSlash.Marker, index: number) => void), + b?: (marker: FourSlash.Marker, index: number) => void, + ): void { + const markers = typeof a === "function" ? this.state.getMarkers() + : a.map(m => this.state.getMarkerByName(m)); this.state.goToEachMarker(markers, typeof a === "function" ? a : b!); } @@ -98,7 +102,10 @@ namespace FourSlashInterface { this.state.goToImplementation(); } - public position(positionOrLineAndCharacter: number | ts.LineAndCharacter, fileNameOrIndex?: string | number): void { + public position( + positionOrLineAndCharacter: number | ts.LineAndCharacter, + fileNameOrIndex?: string | number, + ): void { if (fileNameOrIndex !== undefined) { this.file(fileNameOrIndex); } @@ -142,11 +149,17 @@ namespace FourSlashInterface { this.state.verifySignatureHelpPresence(/*expectPresent*/ false, /*triggerReason*/ undefined, markers); } - public noSignatureHelpForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void { + public noSignatureHelpForTriggerReason( + reason: ts.SignatureHelpTriggerReason, + ...markers: (string | FourSlash.Marker)[] + ): void { this.state.verifySignatureHelpPresence(/*expectPresent*/ false, reason, markers); } - public signatureHelpPresentForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void { + public signatureHelpPresentForTriggerReason( + reason: ts.SignatureHelpTriggerReason, + ...markers: (string | FourSlash.Marker)[] + ): void { this.state.verifySignatureHelpPresence(/*expectPresent*/ true, reason, markers); } @@ -218,7 +231,11 @@ namespace FourSlashInterface { this.state.verifyRefactorAvailable(this.negative, "implicit", name, actionName, actionDescription); } - public refactorAvailableForTriggerReason(triggerReason: ts.RefactorTriggerReason, name: string, actionName?: string) { + public refactorAvailableForTriggerReason( + triggerReason: ts.RefactorTriggerReason, + name: string, + actionName?: string, + ) { this.state.verifyRefactorAvailable(this.negative, triggerReason, name, actionName); } @@ -254,15 +271,28 @@ namespace FourSlashInterface { } } - public getInlayHints(expected: readonly VerifyInlayHintsOptions[], span: ts.TextSpan, preference?: ts.UserPreferences) { + public getInlayHints( + expected: readonly VerifyInlayHintsOptions[], + span: ts.TextSpan, + preference?: ts.UserPreferences, + ) { this.state.verifyInlayHints(expected, span, preference); } - public quickInfoIs(expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) { + public quickInfoIs( + expectedText: string, + expectedDocumentation?: string, + expectedTags?: { name: string; text: string; }[], + ) { this.state.verifyQuickInfoString(expectedText, expectedDocumentation, expectedTags); } - public quickInfoAt(markerName: string | FourSlash.Range, expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) { + public quickInfoAt( + markerName: string | FourSlash.Range, + expectedText: string, + expectedDocumentation?: string, + expectedTags?: { name: string; text: string; }[], + ) { this.state.verifyQuickInfoAt(markerName, expectedText, expectedDocumentation, expectedTags); } @@ -278,7 +308,13 @@ namespace FourSlashInterface { this.state.verifyIndentationAtCurrentPosition(numberOfSpaces); } - public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) { + public indentationAtPositionIs( + fileName: string, + position: number, + numberOfSpaces: number, + indentStyle = ts.IndentStyle.Smart, + baseIndentSize = 0, + ) { this.state.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle, baseIndentSize); } @@ -311,19 +347,34 @@ namespace FourSlashInterface { this.state.verifyGoToDefinitionIs(endMarkers); } - public goToDefinition(startMarkerName: ArrayOrSingle, endMarkerName: ArrayOrSingle, range?: FourSlash.Range): void; - public goToDefinition(startsAndEnds: [ArrayOrSingle, ArrayOrSingle][] | { [startMarkerName: string]: ArrayOrSingle; }): void; + public goToDefinition( + startMarkerName: ArrayOrSingle, + endMarkerName: ArrayOrSingle, + range?: FourSlash.Range, + ): void; + public goToDefinition( + startsAndEnds: [ArrayOrSingle, ArrayOrSingle][] | { + [startMarkerName: string]: ArrayOrSingle; + }, + ): void; public goToDefinition(arg0: any, endMarkerName?: ArrayOrSingle) { this.state.verifyGoToDefinition(arg0, endMarkerName); } public goToType(startMarkerName: ArrayOrSingle, endMarkerName: ArrayOrSingle): void; - public goToType(startsAndEnds: [ArrayOrSingle, ArrayOrSingle][] | { [startMarkerName: string]: ArrayOrSingle; }): void; + public goToType( + startsAndEnds: [ArrayOrSingle, ArrayOrSingle][] | { + [startMarkerName: string]: ArrayOrSingle; + }, + ): void; public goToType(arg0: any, endMarkerName?: ArrayOrSingle) { this.state.verifyGoToType(arg0, endMarkerName); } - public goToSourceDefinition(startMarkerNames: ArrayOrSingle, end: { file: string; } | ArrayOrSingle) { + public goToSourceDefinition( + startMarkerNames: ArrayOrSingle, + end: { file: string; } | ArrayOrSingle, + ) { this.state.verifyGoToSourceDefinition(startMarkerNames, end); } @@ -443,9 +494,17 @@ namespace FourSlashInterface { this.state.verifyNoMatchingBracePosition(bracePosition); } - public docCommentTemplateAt(marker: string | FourSlash.Marker, expectedOffset: number, expectedText: string, options?: ts.DocCommentTemplateOptions) { + public docCommentTemplateAt( + marker: string | FourSlash.Marker, + expectedOffset: number, + expectedText: string, + options?: ts.DocCommentTemplateOptions, + ) { this.state.goToMarker(marker); - this.state.verifyDocCommentTemplate({ newText: expectedText.replace(/\r?\n/g, "\r\n"), caretOffset: expectedOffset }, options); + this.state.verifyDocCommentTemplate({ + newText: expectedText.replace(/\r?\n/g, "\r\n"), + caretOffset: expectedOffset, + }, options); } public noDocCommentTemplateAt(marker: string | FourSlash.Marker) { @@ -453,7 +512,12 @@ namespace FourSlashInterface { this.state.verifyDocCommentTemplate(/*expected*/ undefined); } - public rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void { + public rangeAfterCodeFix( + expectedText: string, + includeWhiteSpace?: boolean, + errorCode?: number, + index?: number, + ): void { this.state.verifyRangeAfterCodeFix(expectedText, includeWhiteSpace, errorCode, index); } @@ -461,8 +525,20 @@ namespace FourSlashInterface { this.state.verifyCodeFixAll(options); } - public fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: ts.FormatCodeSettings): void { - this.state.verifyFileAfterApplyingRefactorAtMarker(markerName, expectedContent, refactorNameToApply, actionName, formattingOptions); + public fileAfterApplyingRefactorAtMarker( + markerName: string, + expectedContent: string, + refactorNameToApply: string, + actionName: string, + formattingOptions?: ts.FormatCodeSettings, + ): void { + this.state.verifyFileAfterApplyingRefactorAtMarker( + markerName, + expectedContent, + refactorNameToApply, + actionName, + formattingOptions, + ); } public rangeIs(expectedText: string, includeWhiteSpace?: boolean): void { @@ -477,7 +553,11 @@ namespace FourSlashInterface { this.state.applyCodeActionFromCompletion(markerName, options); } - public importFixAtPosition(expectedTextArray: string[], errorCode?: number, preferences?: ts.UserPreferences): void { + public importFixAtPosition( + expectedTextArray: string[], + errorCode?: number, + preferences?: ts.UserPreferences, + ): void { this.state.verifyImportFixAtPosition(expectedTextArray, errorCode, preferences); } @@ -513,7 +593,14 @@ namespace FourSlashInterface { this.state.verifyRangesWithSameTextAreRenameLocations(...texts); } - public rangesAreRenameLocations(options?: FourSlash.Range[] | { findInStrings?: boolean; findInComments?: boolean; ranges?: FourSlash.Range[]; providePrefixAndSuffixTextForRename?: boolean; }) { + public rangesAreRenameLocations( + options?: FourSlash.Range[] | { + findInStrings?: boolean; + findInComments?: boolean; + ranges?: FourSlash.Range[]; + providePrefixAndSuffixTextForRename?: boolean; + }, + ) { this.state.verifyRangesAreRenameLocations(options); } @@ -525,7 +612,11 @@ namespace FourSlashInterface { this.state.verifyRangesWithSameTextAreDocumentHighlights(); } - public documentHighlightsOf(startRange: FourSlash.Range, ranges: FourSlash.Range[], options?: VerifyDocumentHighlightsOptions) { + public documentHighlightsOf( + startRange: FourSlash.Range, + ranges: FourSlash.Range[], + options?: VerifyDocumentHighlightsOptions, + ) { this.state.verifyDocumentHighlightsOf(startRange, ranges, options); } @@ -551,7 +642,10 @@ namespace FourSlashInterface { /** * This method *requires* an ordered stream of classifications for a file, and spans are highly recommended. */ - public semanticClassificationsAre(format: ts.SemanticClassificationFormat, ...classifications: Classification[]) { + public semanticClassificationsAre( + format: ts.SemanticClassificationFormat, + ...classifications: Classification[] + ) { this.state.verifySemanticClassifications(format, classifications); } @@ -568,7 +662,15 @@ namespace FourSlashInterface { expectedRange?: FourSlash.Range, preferences?: ts.UserPreferences, ) { - this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange, preferences); + this.state.verifyRenameInfoSucceeded( + displayName, + fullDisplayName, + kind, + kindModifiers, + fileToRename, + expectedRange, + preferences, + ); } public renameInfoFailed(message?: string, preferences?: ts.UserPreferences) { @@ -583,7 +685,14 @@ namespace FourSlashInterface { this.state.baselineRename(marker, options); } - public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: FourSlash.TextSpan, displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], tags: ts.JSDocTagInfo[]) { + public verifyQuickInfoDisplayParts( + kind: string, + kindModifiers: string, + textSpan: FourSlash.TextSpan, + displayParts: ts.SymbolDisplayPart[], + documentation: ts.SymbolDisplayPart[], + tags: ts.JSDocTagInfo[], + ) { this.state.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation, tags); } @@ -781,7 +890,10 @@ namespace FourSlashInterface { } public selection(startMarker: string, endMarker: string) { - this.state.formatSelection(this.state.getMarkerByName(startMarker).position, this.state.getMarkerByName(endMarker).position); + this.state.formatSelection( + this.state.getMarkerByName(startMarker).position, + this.state.getMarkerByName(endMarker).position, + ); } public onType(posMarker: string, key: string) { @@ -929,7 +1041,11 @@ namespace FourSlashInterface { return getClassification(ts.ClassificationTypeNames.jsxAttributeStringLiteralValue, text, position); } - function getClassification(classificationType: ts.ClassificationTypeNames, text: string, position?: number): Classification { + function getClassification( + classificationType: ts.ClassificationTypeNames, + text: string, + position?: number, + ): Classification { const textSpan = position === undefined ? undefined : { start: position, end: position + text.length }; return { classificationType, text, textSpan }; } @@ -1062,7 +1178,9 @@ namespace FourSlashInterface { }); } export const keywordsWithUndefined: readonly ExpectedCompletionEntryObject[] = res; - export const keywords: readonly ExpectedCompletionEntryObject[] = keywordsWithUndefined.filter(k => k.name !== "undefined"); + export const keywords: readonly ExpectedCompletionEntryObject[] = keywordsWithUndefined.filter(k => + k.name !== "undefined" + ); export const typeKeywords: readonly ExpectedCompletionEntryObject[] = [ "any", @@ -1100,7 +1218,10 @@ namespace FourSlashInterface { providedByHarness: readonly ExpectedCompletionEntry[], providedByTest: readonly ExpectedCompletionEntry[], ): ExpectedExactCompletionsPlus { - return Object.assign(sorted([...providedByHarness, ...providedByTest]), { plusFunctionName: functionName, plusArgument: providedByTest }); + return Object.assign(sorted([...providedByHarness, ...providedByTest]), { + plusFunctionName: functionName, + plusArgument: providedByTest, + }); } export function typeKeywordsPlus(plus: readonly ExpectedCompletionEntry[]) { @@ -1227,9 +1348,13 @@ namespace FourSlashInterface { ); } - export const typeAssertionKeywords: readonly ExpectedCompletionEntry[] = globalTypesPlus([keywordEntry("const")]); + export const typeAssertionKeywords: readonly ExpectedCompletionEntry[] = globalTypesPlus([ + keywordEntry("const"), + ]); - function getInJsKeywords(keywords: readonly ExpectedCompletionEntryObject[]): readonly ExpectedCompletionEntryObject[] { + function getInJsKeywords( + keywords: readonly ExpectedCompletionEntryObject[], + ): readonly ExpectedCompletionEntryObject[] { return keywords.filter(keyword => { switch (keyword.name) { case "enum": @@ -1284,7 +1409,13 @@ namespace FourSlashInterface { export const classElementInJsKeywords = getInJsKeywords(classElementKeywords); - export const constructorParameterKeywords: readonly ExpectedCompletionEntryObject[] = ["override", "private", "protected", "public", "readonly"].map((name): ExpectedCompletionEntryObject => ({ + export const constructorParameterKeywords: readonly ExpectedCompletionEntryObject[] = [ + "override", + "private", + "protected", + "public", + "readonly", + ].map((name): ExpectedCompletionEntryObject => ({ name, kind: "keyword", sortText: SortText.GlobalsOrKeywords, @@ -1296,7 +1427,12 @@ namespace FourSlashInterface { methodEntry("bind"), methodEntry("toString"), propertyEntry("length"), - { name: "arguments", kind: "property", kindModifiers: "declare", text: "(property) Function.arguments: any" }, + { + name: "arguments", + kind: "property", + kindModifiers: "declare", + text: "(property) Function.arguments: any", + }, propertyEntry("caller"), ].sort(compareExpectedCompletionEntries); @@ -1405,21 +1541,23 @@ namespace FourSlashInterface { "yield", ].map(keywordEntry); - export const statementKeywords: readonly ExpectedCompletionEntryObject[] = statementKeywordsWithTypes.filter(k => { - const name = k.name; - switch (name) { - case "false": - case "true": - case "null": - case "void": - return true; - case "declare": - case "module": - return false; - default: - return !ts.contains(typeKeywords, k); - } - }); + export const statementKeywords: readonly ExpectedCompletionEntryObject[] = statementKeywordsWithTypes.filter( + k => { + const name = k.name; + switch (name) { + case "false": + case "true": + case "null": + case "void": + return true; + case "declare": + case "module": + return false; + default: + return !ts.contains(typeKeywords, k); + } + }, + ); export const statementInJsKeywords = getInJsKeywords(statementKeywords); @@ -1522,7 +1660,10 @@ namespace FourSlashInterface { const bSortText = typeof b !== "string" && b.sortText || ts.Completions.SortText.LocationPriority; const bySortText = ts.compareStringsCaseSensitiveUI(aSortText, bSortText); if (bySortText !== ts.Comparison.EqualTo) return bySortText; - return ts.compareStringsCaseSensitiveUI(typeof a === "string" ? a : a.name, typeof b === "string" ? b : b.name); + return ts.compareStringsCaseSensitiveUI( + typeof a === "string" ? a : a.name, + typeof b === "string" ? b : b.name, + ); } export const undefinedVarEntry: ExpectedCompletionEntryObject = { @@ -1531,7 +1672,10 @@ namespace FourSlashInterface { sortText: SortText.GlobalsOrKeywords, }; // TODO: many of these are inappropriate to always provide - export const globalsInsideFunction = (plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean; }): readonly ExpectedCompletionEntry[] => + export const globalsInsideFunction = ( + plus: readonly ExpectedCompletionEntry[], + options?: { noLib?: boolean; }, + ): readonly ExpectedCompletionEntry[] => [ { name: "arguments", kind: "local var" }, ...plus, @@ -1544,7 +1688,10 @@ namespace FourSlashInterface { const globalInJsKeywordsInsideFunction = getInJsKeywords(globalKeywordsInsideFunction); // TODO: many of these are inappropriate to always provide - export const globalsInJsInsideFunction = (plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean; }): readonly ExpectedCompletionEntry[] => + export const globalsInJsInsideFunction = ( + plus: readonly ExpectedCompletionEntry[], + options?: { noLib?: boolean; }, + ): readonly ExpectedCompletionEntry[] => [ { name: "arguments", kind: "local var" }, globalThisEntry, @@ -1899,7 +2046,11 @@ namespace FourSlashInterface { export interface DiagnosticIgnoredInterpolations { template: string; } - export type RenameLocationOptions = FourSlash.Range | { readonly range: FourSlash.Range; readonly prefixText?: string; readonly suffixText?: string; }; + export type RenameLocationOptions = FourSlash.Range | { + readonly range: FourSlash.Range; + readonly prefixText?: string; + readonly suffixText?: string; + }; export interface RenameOptions { readonly findInStrings?: boolean; readonly findInComments?: boolean; diff --git a/src/harness/harnessIO.ts b/src/harness/harnessIO.ts index 442e106a4af8f..6b1ab3cbaa257 100644 --- a/src/harness/harnessIO.ts +++ b/src/harness/harnessIO.ts @@ -20,7 +20,13 @@ namespace Harness { getExecutingFilePath(): string; getWorkspaceRoot(): string; exit(exitCode?: number): void; - readDirectory(path: string, extension?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): readonly string[]; + readDirectory( + path: string, + extension?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): readonly string[]; getAccessibleFileSystemEntries(dirname: string): ts.FileSystemEntries; tryEnableSourceMapsForHost?(): void; getEnvironmentVariable?(name: string): string; @@ -96,7 +102,10 @@ namespace Harness { function getAccessibleFileSystemEntries(dirname: string): ts.FileSystemEntries { try { - const entries: string[] = fs.readdirSync(dirname || ".").sort(ts.sys.useCaseSensitiveFileNames ? ts.compareStringsCaseSensitive : ts.compareStringsCaseInsensitive); + const entries: string[] = fs.readdirSync(dirname || ".").sort( + ts.sys.useCaseSensitiveFileNames ? ts.compareStringsCaseSensitive + : ts.compareStringsCaseInsensitive, + ); const files: string[] = []; const directories: string[] = []; for (const entry of entries) { @@ -157,7 +166,8 @@ namespace Harness { getExecutingFilePath: () => ts.sys.getExecutingFilePath(), getWorkspaceRoot: () => workspaceRoot, exit: exitCode => ts.sys.exit(exitCode), - readDirectory: (path, extension, exclude, include, depth) => ts.sys.readDirectory(path, extension, exclude, include, depth), + readDirectory: (path, extension, exclude, include, depth) => + ts.sys.readDirectory(path, extension, exclude, include, depth), getAccessibleFileSystemEntries, tryEnableSourceMapsForHost: () => ts.sys.tryEnableSourceMapsForHost && ts.sys.tryEnableSourceMapsForHost(), getMemoryUsage: () => ts.sys.getMemoryUsage && ts.sys.getMemoryUsage(), @@ -237,7 +247,12 @@ namespace Harness { const shouldAssertInvariants = !lightMode; // Only set the parent nodes if we're asserting invariants. We don't need them otherwise. - const result = ts.createSourceFile(fileName, sourceText, languageVersion, /*setParentNodes:*/ shouldAssertInvariants); + const result = ts.createSourceFile( + fileName, + sourceText, + languageVersion, + /*setParentNodes:*/ shouldAssertInvariants, + ); if (shouldAssertInvariants) { Utils.assertInvariants(result, /*parent:*/ undefined); @@ -259,13 +274,24 @@ namespace Harness { if (!libFileNameSourceFileMap) { libFileNameSourceFileMap = new ts.Map(ts.getEntries({ - [defaultLibFileName]: createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.es5.d.ts")!, /*languageVersion*/ ts.ScriptTarget.Latest), + [defaultLibFileName]: createSourceFileAndAssertInvariants( + defaultLibFileName, + IO.readFile(libFolder + "lib.es5.d.ts")!, + /*languageVersion*/ ts.ScriptTarget.Latest, + ), })); } let sourceFile = libFileNameSourceFileMap.get(fileName); if (!sourceFile) { - libFileNameSourceFileMap.set(fileName, sourceFile = createSourceFileAndAssertInvariants(fileName, IO.readFile(libFolder + fileName)!, ts.ScriptTarget.Latest)); + libFileNameSourceFileMap.set( + fileName, + sourceFile = createSourceFileAndAssertInvariants( + fileName, + IO.readFile(libFolder + fileName)!, + ts.ScriptTarget.Latest, + ), + ); } return sourceFile; } @@ -332,7 +358,10 @@ namespace Harness { return optionsIndex.get(name.toLowerCase()); } - export function setCompilerOptionsFromHarnessSetting(settings: TestCaseParser.CompilerSettings, options: ts.CompilerOptions & HarnessOptions): void { + export function setCompilerOptionsFromHarnessSetting( + settings: TestCaseParser.CompilerSettings, + options: ts.CompilerOptions & HarnessOptions, + ): void { for (const name in settings) { if (ts.hasProperty(settings, name)) { const value = settings[name]; @@ -390,11 +419,13 @@ namespace Harness { currentDirectory: string | undefined, symlinks?: vfs.FileSet, ): compiler.CompilationResult { - const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.cloneCompilerOptions(compilerOptions) : { noResolve: false }; + const options: ts.CompilerOptions & HarnessOptions = compilerOptions + ? ts.cloneCompilerOptions(compilerOptions) : { noResolve: false }; options.target = ts.getEmitScriptTarget(options); options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed; options.noErrorTruncation = true; - options.skipDefaultLibCheck = typeof options.skipDefaultLibCheck === "undefined" ? true : options.skipDefaultLibCheck; + options.skipDefaultLibCheck = typeof options.skipDefaultLibCheck === "undefined" ? true + : options.skipDefaultLibCheck; if (typeof currentDirectory === "undefined") { currentDirectory = vfs.srcFolder; @@ -408,8 +439,11 @@ namespace Harness { options.rootDirs = ts.map(options.rootDirs, d => ts.getNormalizedAbsolutePath(d, currentDirectory)); } - const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined ? options.useCaseSensitiveFileNames : true; - const programFileNames = inputFiles.map(file => file.unitName).filter(fileName => !ts.fileExtensionIs(fileName, ts.Extension.Json)); + const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined + ? options.useCaseSensitiveFileNames : true; + const programFileNames = inputFiles.map(file => file.unitName).filter(fileName => + !ts.fileExtensionIs(fileName, ts.Extension.Json) + ); // Files from built\local that are requested by test "@includeBuiltFiles" to be in the context. // Treat them as library files, so include them in build, but not in baselines. @@ -425,7 +459,10 @@ namespace Harness { } const docs = inputFiles.concat(otherFiles).map(documents.TextDocument.fromTestFile); - const fs = vfs.createFromFileSystem(IO, !useCaseSensitiveFileNames, { documents: docs, cwd: currentDirectory }); + const fs = vfs.createFromFileSystem(IO, !useCaseSensitiveFileNames, { + documents: docs, + cwd: currentDirectory, + }); if (symlinks) { fs.apply(symlinks); } @@ -459,7 +496,9 @@ namespace Harness { } } else if (result.dts.size !== result.getNumberOfJsFiles(/*includeJson*/ false)) { - throw new Error("There were no errors and declFiles generated did not match number of js files generated"); + throw new Error( + "There were no errors and declFiles generated did not match number of js files generated", + ); } } @@ -470,16 +509,27 @@ namespace Harness { if (options.declaration && result.diagnostics.length === 0 && result.dts.size > 0) { ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles)); ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles)); - return { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory: currentDirectory || harnessSettings.currentDirectory }; + return { + declInputFiles, + declOtherFiles, + harnessSettings, + options, + currentDirectory: currentDirectory || harnessSettings.currentDirectory, + }; } function addDtsFile(file: TestFile, dtsFiles: TestFile[]) { if (vpath.isDeclaration(file.unitName) || vpath.isJson(file.unitName)) { dtsFiles.push(file); } - else if (vpath.isTypeScript(file.unitName) || (vpath.isJavaScript(file.unitName) && ts.getAllowJSCompilerOption(options))) { + else if ( + vpath.isTypeScript(file.unitName) + || (vpath.isJavaScript(file.unitName) && ts.getAllowJSCompilerOption(options)) + ) { const declFile = findResultCodeFile(file.unitName); - if (declFile && !findUnit(declFile.file, declInputFiles) && !findUnit(declFile.file, declOtherFiles)) { + if ( + declFile && !findUnit(declFile.file, declInputFiles) && !findUnit(declFile.file, declOtherFiles) + ) { dtsFiles.push({ unitName: declFile.file, content: Utils.removeByteOrderMark(declFile.text) }); } } @@ -506,7 +556,8 @@ namespace Harness { sourceFileName = outFile; } - const dTsFileName = ts.removeFileExtension(sourceFileName) + ts.getDeclarationEmitExtensionForPath(sourceFileName); + const dTsFileName = ts.removeFileExtension(sourceFileName) + + ts.getDeclarationEmitExtensionForPath(sourceFileName); return result.dts.get(dTsFileName); } @@ -515,12 +566,22 @@ namespace Harness { } } - export function compileDeclarationFiles(context: DeclarationCompilationContext | undefined, symlinks: vfs.FileSet | undefined) { + export function compileDeclarationFiles( + context: DeclarationCompilationContext | undefined, + symlinks: vfs.FileSet | undefined, + ) { if (!context) { return; } const { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory } = context; - const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory, symlinks); + const output = compileFiles( + declInputFiles, + declOtherFiles, + harnessSettings, + options, + currentDirectory, + symlinks, + ); return { declInputFiles, declOtherFiles, declResult: output }; } @@ -529,7 +590,11 @@ namespace Harness { return (pretty ? ts.formatDiagnosticsWithColorAndContext : ts.formatDiagnostics)(diagnostics, host); } - export function getErrorBaseline(inputFiles: readonly TestFile[], diagnostics: readonly ts.Diagnostic[], pretty?: boolean) { + export function getErrorBaseline( + inputFiles: readonly TestFile[], + diagnostics: readonly ts.Diagnostic[], + pretty?: boolean, + ) { let outputLines = ""; const gen = iterateErrorBaseline(inputFiles, diagnostics, { pretty }); for (let { done, value } = gen.next(); !done; { done, value } = gen.next()) { @@ -537,14 +602,23 @@ namespace Harness { outputLines += content; } if (pretty) { - outputLines += ts.getErrorSummaryText(ts.getErrorCountForSummary(diagnostics), ts.getFilesInErrorForSummary(diagnostics), IO.newLine(), { getCurrentDirectory: () => "" }); + outputLines += ts.getErrorSummaryText( + ts.getErrorCountForSummary(diagnostics), + ts.getFilesInErrorForSummary(diagnostics), + IO.newLine(), + { getCurrentDirectory: () => "" }, + ); } return outputLines; } export const diagnosticSummaryMarker = "__diagnosticSummary"; export const globalErrorsMarker = "__globalErrors"; - export function* iterateErrorBaseline(inputFiles: readonly TestFile[], diagnostics: readonly ts.Diagnostic[], options?: { pretty?: boolean; caseSensitive?: boolean; currentDirectory?: string; }): IterableIterator<[string, string, number]> { + export function* iterateErrorBaseline( + inputFiles: readonly TestFile[], + diagnostics: readonly ts.Diagnostic[], + options?: { pretty?: boolean; caseSensitive?: boolean; currentDirectory?: string; }, + ): IterableIterator<[string, string, number]> { diagnostics = ts.sort(diagnostics, ts.compareDiagnostics); let outputLines = ""; // Count up all errors that were found in files other than lib.d.ts so we don't miss any @@ -564,7 +638,9 @@ namespace Harness { const formatDiagnsoticHost = { getCurrentDirectory: () => options && options.currentDirectory ? options.currentDirectory : "", getNewLine: () => IO.newLine(), - getCanonicalFileName: ts.createGetCanonicalFileName(options && options.caseSensitive !== undefined ? options.caseSensitive : true), + getCanonicalFileName: ts.createGetCanonicalFileName( + options && options.caseSensitive !== undefined ? options.caseSensitive : true, + ), }; function outputErrorText(error: ts.Diagnostic) { @@ -577,7 +653,13 @@ namespace Harness { .map(s => "!!! " + ts.diagnosticCategoryName(error) + " TS" + error.code + ": " + s); if (error.relatedInformation) { for (const info of error.relatedInformation) { - errLines.push(`!!! related TS${info.code}${info.file ? " " + ts.formatLocation(info.file, info.start!, formatDiagnsoticHost, ts.identity) : ""}: ${ts.flattenDiagnosticMessageText(info.messageText, IO.newLine())}`); + errLines.push( + `!!! related TS${info.code}${ + info.file + ? " " + ts.formatLocation(info.file, info.start!, formatDiagnsoticHost, ts.identity) + : "" + }: ${ts.flattenDiagnosticMessageText(info.messageText, IO.newLine())}`, + ); } } errLines.forEach(e => outputLines += newLine() + e); @@ -593,7 +675,12 @@ namespace Harness { } } - yield [diagnosticSummaryMarker, Utils.removeTestPathPrefixes(minimalDiagnosticsToString(diagnostics, options && options.pretty)) + IO.newLine() + IO.newLine(), diagnostics.length]; + yield [ + diagnosticSummaryMarker, + Utils.removeTestPathPrefixes(minimalDiagnosticsToString(diagnostics, options && options.pretty)) + + IO.newLine() + IO.newLine(), + diagnostics.length, + ]; // Report global errors const globalErrors = diagnostics.filter(err => !err.file); @@ -608,7 +695,13 @@ namespace Harness { // Filter down to the errors in the file const fileErrors = diagnostics.filter((e): e is ts.DiagnosticWithLocation => { const errFn = e.file; - return !!errFn && ts.comparePaths(Utils.removeTestPathPrefixes(errFn.fileName), Utils.removeTestPathPrefixes(inputFile.unitName), options && options.currentDirectory || "", !(options && options.caseSensitive)) === ts.Comparison.EqualTo; + return !!errFn + && ts.comparePaths( + Utils.removeTestPathPrefixes(errFn.fileName), + Utils.removeTestPathPrefixes(inputFile.unitName), + options && options.currentDirectory || "", + !(options && options.caseSensitive), + ) === ts.Comparison.EqualTo; }); // Header @@ -646,7 +739,9 @@ namespace Harness { const err = errDiagnostic as ts.TextSpan; // TODO: GH#18217 // Does any error start or continue on to this line? Emit squiggles const end = ts.textSpanEnd(err); - if ((end >= thisLineStart) && ((err.start < nextLineStart) || (lineIndex === lines.length - 1))) { + if ( + (end >= thisLineStart) && ((err.start < nextLineStart) || (lineIndex === lines.length - 1)) + ) { // How many characters from the start of this line the error starts at (could be positive or negative) const relativeOffset = err.start - thisLineStart; // How many characters of the error are on this line (might be longer than this line in reality) @@ -654,7 +749,8 @@ namespace Harness { // Calculate the start of the squiggle const squiggleStart = Math.max(0, relativeOffset); // TODO/REVIEW: this doesn't work quite right in the browser if a multi file test has files whose names are just the right length relative to one another - outputLines += newLine() + " " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"); + outputLines += newLine() + " " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"); // If the error ended here, or we're at the end of the file, emit its message if ((lineIndex === lines.length - 1) || nextLineStart > end) { @@ -683,7 +779,8 @@ namespace Harness { } const numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => { - return !!diagnostic.file && (isDefaultLibraryFile(diagnostic.file.fileName) || isBuiltFile(diagnostic.file.fileName)); + return !!diagnostic.file + && (isDefaultLibraryFile(diagnostic.file.fileName) || isBuiltFile(diagnostic.file.fileName)); }); const numTest262HarnessDiagnostics = ts.countWhere(diagnostics, diagnostic => { @@ -692,14 +789,35 @@ namespace Harness { }); // Verify we didn't miss any errors in total - assert.equal(totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length, "total number of errors"); + assert.equal( + totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, + diagnostics.length, + "total number of errors", + ); } - export function doErrorBaseline(baselinePath: string, inputFiles: readonly TestFile[], errors: readonly ts.Diagnostic[], pretty?: boolean) { - Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), !errors || (errors.length === 0) ? null : getErrorBaseline(inputFiles, errors, pretty)); // eslint-disable-line no-null/no-null + export function doErrorBaseline( + baselinePath: string, + inputFiles: readonly TestFile[], + errors: readonly ts.Diagnostic[], + pretty?: boolean, + ) { + Baseline.runBaseline( + baselinePath.replace(/\.tsx?$/, ".errors.txt"), + !errors || (errors.length === 0) ? null : getErrorBaseline(inputFiles, errors, pretty), + ); // eslint-disable-line no-null/no-null } - export function doTypeAndSymbolBaseline(baselinePath: string, program: ts.Program, allFiles: { unitName: string; content: string; }[], opts?: Baseline.BaselineOptions, multifile?: boolean, skipTypeBaselines?: boolean, skipSymbolBaselines?: boolean, hasErrorBaseline?: boolean) { + export function doTypeAndSymbolBaseline( + baselinePath: string, + program: ts.Program, + allFiles: { unitName: string; content: string; }[], + opts?: Baseline.BaselineOptions, + multifile?: boolean, + skipTypeBaselines?: boolean, + skipSymbolBaselines?: boolean, + hasErrorBaseline?: boolean, + ) { // The full walker simulates the types that you would get from doing a full // compile. The pull walker simulates the types you get when you just do // a type query for a random node (like how the LS would do it). Most of the @@ -753,16 +871,23 @@ namespace Harness { // When calling this function from rwc-runner, the baselinePath will have no extension. // As rwc test- file is stored in json which ".json" will get stripped off. // When calling this function from compiler-runner, the baselinePath will then has either ".ts" or ".tsx" extension - const outputFileName = ts.endsWith(baselinePath, ts.Extension.Ts) || ts.endsWith(baselinePath, ts.Extension.Tsx) ? - baselinePath.replace(/\.tsx?/, "") : baselinePath; + const outputFileName = + ts.endsWith(baselinePath, ts.Extension.Ts) || ts.endsWith(baselinePath, ts.Extension.Tsx) + ? baselinePath.replace(/\.tsx?/, "") : baselinePath; if (!multifile) { - const fullBaseLine = generateBaseLine(isSymbolBaseLine, isSymbolBaseLine ? skipSymbolBaselines : skipTypeBaselines); + const fullBaseLine = generateBaseLine( + isSymbolBaseLine, + isSymbolBaseLine ? skipSymbolBaselines : skipTypeBaselines, + ); Baseline.runBaseline(outputFileName + fullExtension, fullBaseLine, opts); } else { Baseline.runMultifileBaseline(outputFileName, fullExtension, () => { - return iterateBaseLine(isSymbolBaseLine, isSymbolBaseLine ? skipSymbolBaselines : skipTypeBaselines); + return iterateBaseLine( + isSymbolBaseLine, + isSymbolBaseLine ? skipSymbolBaselines : skipTypeBaselines, + ); }, opts); } } @@ -777,7 +902,10 @@ namespace Harness { return result || null; // eslint-disable-line no-null/no-null } - function* iterateBaseLine(isSymbolBaseline: boolean, skipBaseline?: boolean): IterableIterator<[string, string]> { + function* iterateBaseLine( + isSymbolBaseline: boolean, + skipBaseline?: boolean, + ): IterableIterator<[string, string]> { if (skipBaseline) { return; } @@ -787,7 +915,8 @@ namespace Harness { const { unitName } = file; let typeLines = "=== " + unitName + " ===\r\n"; const codeLines = ts.flatMap(file.content.split(/\r?\n/g), e => e.split(/[\r\u2028\u2029]/g)); - const gen: IterableIterator = isSymbolBaseline ? fullWalker.getSymbols(unitName) : fullWalker.getTypes(unitName); + const gen: IterableIterator = isSymbolBaseline ? fullWalker.getSymbols(unitName) + : fullWalker.getTypes(unitName); let lastIndexWritten: number | undefined; for (let { done, value: result } = gen.next(); !done; { done, value: result } = gen.next()) { if (isSymbolBaseline && !result.symbol) { @@ -797,7 +926,11 @@ namespace Harness { typeLines += codeLines.slice(0, result.line + 1).join("\r\n") + "\r\n"; } else if (result.line !== lastIndexWritten) { - if (!((lastIndexWritten + 1 < codeLines.length) && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) || codeLines[lastIndexWritten + 1].trim() === ""))) { + if ( + !((lastIndexWritten + 1 < codeLines.length) + && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) + || codeLines[lastIndexWritten + 1].trim() === "")) + ) { typeLines += "\r\n"; } typeLines += codeLines.slice(lastIndexWritten + 1, result.line + 1).join("\r\n") + "\r\n"; @@ -816,7 +949,11 @@ namespace Harness { } else { if (lastIndexWritten + 1 < codeLines.length) { - if (!((lastIndexWritten + 1 < codeLines.length) && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) || codeLines[lastIndexWritten + 1].trim() === ""))) { + if ( + !((lastIndexWritten + 1 < codeLines.length) + && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) + || codeLines[lastIndexWritten + 1].trim() === "")) + ) { typeLines += "\r\n"; } typeLines += codeLines.slice(lastIndexWritten + 1).join("\r\n"); @@ -828,7 +965,12 @@ namespace Harness { } } - export function doSourcemapBaseline(baselinePath: string, options: ts.CompilerOptions, result: compiler.CompilationResult, harnessSettings: TestCaseParser.CompilerSettings) { + export function doSourcemapBaseline( + baselinePath: string, + options: ts.CompilerOptions, + result: compiler.CompilationResult, + harnessSettings: TestCaseParser.CompilerSettings, + ) { const declMaps = ts.getAreDeclarationMapsEnabled(options); if (options.inlineSourceMap) { if (result.maps.size > 0 && !declMaps) { @@ -837,7 +979,11 @@ namespace Harness { return; } else if (options.sourceMap || declMaps) { - if (result.maps.size !== ((options.sourceMap ? result.getNumberOfJsFiles(/*includeJson*/ false) : 0) + (declMaps ? result.getNumberOfJsFiles(/*includeJson*/ true) : 0))) { + if ( + result.maps.size + !== ((options.sourceMap ? result.getNumberOfJsFiles(/*includeJson*/ false) : 0) + + (declMaps ? result.getNumberOfJsFiles(/*includeJson*/ true) : 0)) + ) { throw new Error("Number of sourcemap files should be same as js files."); } @@ -866,16 +1012,35 @@ namespace Harness { const outputJSFile = result.outputs.find(td => td.file.endsWith(sourcemapJSON.file)); if (!outputJSFile) return ""; - const sourceTDs = ts.map(sourcemapJSON.sources, (s: string) => result.inputs.find(td => td.file.endsWith(s))); + const sourceTDs = ts.map( + sourcemapJSON.sources, + (s: string) => result.inputs.find(td => td.file.endsWith(s)), + ); const anyUnfoundSources = ts.contains(sourceTDs, /*value*/ undefined); if (anyUnfoundSources) return ""; - const hash = "#base64," + ts.map([outputJSFile.text, sourcemap].concat(sourceTDs.map(td => td!.text)), s => ts.convertToBase64(decodeURIComponent(encodeURIComponent(s)))).join(","); + const hash = "#base64," + + ts.map( + [outputJSFile.text, sourcemap].concat(sourceTDs.map(td => td!.text)), + s => ts.convertToBase64(decodeURIComponent(encodeURIComponent(s))), + ).join(","); return "\n//// https://sokra.github.io/source-map-visualization" + hash + "\n"; } - export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: compiler.CompilationResult, tsConfigFiles: readonly TestFile[], toBeCompiled: readonly TestFile[], otherFiles: readonly TestFile[], harnessSettings: TestCaseParser.CompilerSettings) { - if (!options.noEmit && !options.emitDeclarationOnly && result.js.size === 0 && result.diagnostics.length === 0) { + export function doJsEmitBaseline( + baselinePath: string, + header: string, + options: ts.CompilerOptions, + result: compiler.CompilationResult, + tsConfigFiles: readonly TestFile[], + toBeCompiled: readonly TestFile[], + otherFiles: readonly TestFile[], + harnessSettings: TestCaseParser.CompilerSettings, + ) { + if ( + !options.noEmit && !options.emitDeclarationOnly && result.js.size === 0 + && result.diagnostics.length === 0 + ) { throw new Error("Expected at least one js file to be emitted or at least one error to be created."); } @@ -896,7 +1061,13 @@ namespace Harness { jsCode += "\r\n"; } if (!result.diagnostics.length && !ts.endsWith(file.file, ts.Extension.Json)) { - const fileParseResult = ts.createSourceFile(file.file, file.text, ts.getEmitScriptTarget(options), /*parentNodes*/ false, ts.endsWith(file.file, "x") ? ts.ScriptKind.JSX : ts.ScriptKind.JS); + const fileParseResult = ts.createSourceFile( + file.file, + file.text, + ts.getEmitScriptTarget(options), + /*parentNodes*/ false, + ts.endsWith(file.file, "x") ? ts.ScriptKind.JSX : ts.ScriptKind.JS, + ); if (ts.length(fileParseResult.parseDiagnostics)) { jsCode += getErrorBaseline([file.asTestFile()], fileParseResult.parseDiagnostics); return; @@ -925,15 +1096,25 @@ namespace Harness { if (declFileCompilationResult && declFileCompilationResult.declResult.diagnostics.length) { jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n"; jsCode += "\r\n\r\n"; - jsCode += getErrorBaseline(tsConfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.diagnostics); + jsCode += getErrorBaseline( + tsConfigFiles.concat( + declFileCompilationResult.declInputFiles, + declFileCompilationResult.declOtherFiles, + ), + declFileCompilationResult.declResult.diagnostics, + ); } // eslint-disable-next-line no-null/no-null - Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ts.Extension.Js), jsCode.length > 0 ? tsCode + "\r\n\r\n" + jsCode : null); + Baseline.runBaseline( + baselinePath.replace(/\.tsx?/, ts.Extension.Js), + jsCode.length > 0 ? tsCode + "\r\n\r\n" + jsCode : null, + ); } function fileOutput(file: documents.TextDocument, harnessSettings: TestCaseParser.CompilerSettings): string { - const fileName = harnessSettings.fullEmitPaths ? Utils.removeTestPathPrefixes(file.file) : ts.getBaseFileName(file.file); + const fileName = harnessSettings.fullEmitPaths ? Utils.removeTestPathPrefixes(file.file) + : ts.getBaseFileName(file.file); return "//// [" + fileName + "]\r\n" + Utils.removeTestPathPrefixes(file.text); } @@ -953,14 +1134,19 @@ namespace Harness { return result; } - export function* iterateOutputs(outputFiles: Iterable): IterableIterator<[string, string]> { + export function* iterateOutputs( + outputFiles: Iterable, + ): IterableIterator<[string, string]> { // Collect, test, and sort the fileNames const files = Array.from(outputFiles); files.slice().sort((a, b) => ts.compareStringsCaseSensitive(cleanName(a.file), cleanName(b.file))); const dupeCase = new ts.Map(); // Yield them for (const outputFile of files) { - yield [checkDuplicatedFileName(outputFile.file, dupeCase), "/*====== " + outputFile.file + " ======*/\r\n" + Utils.removeByteOrderMark(outputFile.text)]; + yield [ + checkDuplicatedFileName(outputFile.file, dupeCase), + "/*====== " + outputFile.file + " ======*/\r\n" + Utils.removeByteOrderMark(outputFile.text), + ]; } function cleanName(fn: string) { @@ -984,7 +1170,11 @@ namespace Harness { } export function sanitizeTestFilePath(name: string) { - const path = ts.toPath(ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/"), "", Utils.canonicalizeForHarness); + const path = ts.toPath( + ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/"), + "", + Utils.canonicalizeForHarness, + ); if (ts.startsWith(path, "/")) { return path.substring(1); } @@ -1050,7 +1240,10 @@ namespace Harness { for (const exclude of excludes) { const value = values?.get(exclude); let index: number; - while ((index = ts.findIndex(variations, v => v.key === exclude || value !== undefined && v.value === value)) >= 0) { + while ( + (index = ts.findIndex(variations, v => v.key === exclude || value !== undefined && v.value === value)) + >= 0 + ) { ts.orderedRemoveItemAt(variations, index); } } @@ -1062,7 +1255,12 @@ namespace Harness { return ts.map(variations, v => v.key); } - function computeFileBasedTestConfigurationVariations(configurations: FileBasedTestConfiguration[], variationState: FileBasedTestConfiguration, varyByEntries: [string, string[]][], offset: number) { + function computeFileBasedTestConfigurationVariations( + configurations: FileBasedTestConfiguration[], + variationState: FileBasedTestConfiguration, + varyByEntries: [string, string[]][], + offset: number, + ) { if (offset >= varyByEntries.length) { // make a copy of the current variation state configurations.push({ ...variationState }); @@ -1080,7 +1278,10 @@ namespace Harness { let booleanVaryByStarSettingValues: ts.ESMap | undefined; function getVaryByStarSettingValues(varyBy: string): ts.ReadonlyESMap | undefined { - const option = ts.forEach(ts.optionDeclarations, decl => ts.equateStringsCaseInsensitive(decl.name, varyBy) ? decl : undefined); + const option = ts.forEach( + ts.optionDeclarations, + decl => ts.equateStringsCaseInsensitive(decl.name, varyBy) ? decl : undefined, + ); if (option) { if (typeof option.type === "object") { return option.type; @@ -1097,7 +1298,10 @@ namespace Harness { /** * Compute FileBasedTestConfiguration variations based on a supplied list of variable settings. */ - export function getFileBasedTestConfigurations(settings: TestCaseParser.CompilerSettings, varyBy: readonly string[]): FileBasedTestConfiguration[] | undefined { + export function getFileBasedTestConfigurations( + settings: TestCaseParser.CompilerSettings, + varyBy: readonly string[], + ): FileBasedTestConfiguration[] | undefined { let varyByEntries: [string, string[]][] | undefined; let variationCount = 1; for (const varyByKey of varyBy) { @@ -1107,7 +1311,13 @@ namespace Harness { if (entries) { if (!varyByEntries) varyByEntries = []; variationCount *= entries.length; - if (variationCount > 25) throw new Error(`Provided test options exceeded the maximum number of variations: ${varyBy.map(v => `'@${v}'`).join(", ")}`); + if (variationCount > 25) { + throw new Error( + `Provided test options exceeded the maximum number of variations: ${ + varyBy.map(v => `'@${v}'`).join(", ") + }`, + ); + } varyByEntries.push([varyByKey, entries]); } } @@ -1184,7 +1394,12 @@ namespace Harness { } /** Given a test file containing // @FileName directives, return an array of named units of code to be added to an existing compiler instance */ - export function makeUnitsFromTest(code: string, fileName: string, rootDir?: string, settings = extractCompilerSettings(code)): TestCaseContent { + export function makeUnitsFromTest( + code: string, + fileName: string, + rootDir?: string, + settings = extractCompilerSettings(code), + ): TestCaseContent { // List of all the subfiles we've parsed out const testUnitData: TestUnitData[] = []; @@ -1250,7 +1465,8 @@ namespace Harness { } // normalize the fileName for the single file case - currentFileName = testUnitData.length > 0 || currentFileName ? currentFileName : ts.getBaseFileName(fileName); + currentFileName = testUnitData.length > 0 || currentFileName ? currentFileName + : ts.getBaseFileName(fileName); // EOF, push whatever remains const newTestFile2 = { @@ -1267,7 +1483,11 @@ namespace Harness { useCaseSensitiveFileNames: false, readDirectory: () => [], fileExists: () => true, - readFile: name => ts.forEach(testUnitData, data => data.name.toLowerCase() === name.toLowerCase() ? data.content : undefined), + readFile: name => + ts.forEach( + testUnitData, + data => data.name.toLowerCase() === name.toLowerCase() ? data.content : undefined, + ), }; // check if project has tsconfig.json in the list of files @@ -1358,7 +1578,13 @@ namespace Harness { return { expected, actual }; } - function writeComparison(expected: string, actual: string, relativeFileName: string, actualFileName: string, opts?: BaselineOptions) { + function writeComparison( + expected: string, + actual: string, + relativeFileName: string, + actualFileName: string, + opts?: BaselineOptions, + ) { // For now this is written using TypeScript, because sys is not available when running old test cases. // But we need to move to sys once we have // Creates the directory including its parent if not already present @@ -1395,12 +1621,21 @@ namespace Harness { const errorMessage = getBaselineFileChangedErrorMessage(relativeFileName); if (!!require && opts && opts.PrintDiff) { const Diff = require("diff"); - const patch = Diff.createTwoFilesPatch("Expected", "Actual", expected, actual, "The current baseline", "The new version"); + const patch = Diff.createTwoFilesPatch( + "Expected", + "Actual", + expected, + actual, + "The current baseline", + "The new version", + ); throw new Error(`${errorMessage}${ts.ForegroundColorEscapeSequences.Grey}\n\n${patch}`); } else { if (!IO.fileExists(expected)) { - throw new Error(`New baseline created at ${IO.joinPath("tests", "baselines", "local", relativeFileName)}`); + throw new Error( + `New baseline created at ${IO.joinPath("tests", "baselines", "local", relativeFileName)}`, + ); } else { throw new Error(errorMessage); @@ -1422,7 +1657,16 @@ namespace Harness { writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName, opts); } - export function runMultifileBaseline(relativeFileBase: string, extension: string, generateContent: () => IterableIterator<[string, string, number]> | IterableIterator<[string, string]> | null, opts?: BaselineOptions, referencedExtensions?: string[]): void { + export function runMultifileBaseline( + relativeFileBase: string, + extension: string, + generateContent: () => + | IterableIterator<[string, string, number]> + | IterableIterator<[string, string]> + | null, + opts?: BaselineOptions, + referencedExtensions?: string[], + ): void { const gen = generateContent(); const writtenFiles = new ts.Map(); const errors: Error[] = []; @@ -1433,7 +1677,11 @@ namespace Harness { const [name, content, count] = value as [string, string, number | undefined]; if (count === 0) continue; // Allow error reporter to skip writing files without errors const relativeFileName = relativeFileBase + "/" + name + extension; - const actualFileName = localPath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder); + const actualFileName = localPath( + relativeFileName, + opts && opts.Baselinefolder, + opts && opts.Subfolder, + ); const comparison = compareToBaseline(content, relativeFileName, opts); try { writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName); @@ -1447,7 +1695,11 @@ namespace Harness { const referenceDir = referencePath(relativeFileBase, opts && opts.Baselinefolder, opts && opts.Subfolder); let existing = IO.readDirectory(referenceDir, referencedExtensions || [extension]); - if (extension === ".ts" || referencedExtensions && referencedExtensions.indexOf(".ts") > -1 && referencedExtensions.indexOf(".d.ts") === -1) { + if ( + extension === ".ts" + || referencedExtensions && referencedExtensions.indexOf(".ts") > -1 + && referencedExtensions.indexOf(".d.ts") === -1 + ) { // special-case and filter .d.ts out of .ts results existing = existing.filter(f => !ts.endsWith(f, ".d.ts")); } @@ -1467,14 +1719,23 @@ namespace Harness { if (errors.length || missing.length) { let errorMsg = ""; if (errors.length) { - errorMsg += `The baseline for ${relativeFileBase} in ${errors.length} files has changed:${"\n " + errors.slice(0, 5).map(e => e.message).join("\n ") + (errors.length > 5 ? "\n" + ` and ${errors.length - 5} more` : "")}`; + errorMsg += `The baseline for ${relativeFileBase} in ${errors.length} files has changed:${ + "\n " + errors.slice(0, 5).map(e => e.message).join("\n ") + + (errors.length > 5 ? "\n" + ` and ${errors.length - 5} more` : "") + }`; } if (errors.length && missing.length) { errorMsg += "\n"; } if (missing.length) { const writtenFilesArray = ts.arrayFrom(writtenFiles.keys()); - errorMsg += `Baseline missing ${missing.length} files:${"\n " + missing.slice(0, 5).join("\n ") + (missing.length > 5 ? "\n" + ` and ${missing.length - 5} more` : "") + "\n"}Written ${writtenFiles.size} files:${"\n " + writtenFilesArray.slice(0, 5).join("\n ") + (writtenFilesArray.length > 5 ? "\n" + ` and ${writtenFilesArray.length - 5} more` : "")}`; + errorMsg += `Baseline missing ${missing.length} files:${ + "\n " + missing.slice(0, 5).join("\n ") + + (missing.length > 5 ? "\n" + ` and ${missing.length - 5} more` : "") + "\n" + }Written ${writtenFiles.size} files:${ + "\n " + writtenFilesArray.slice(0, 5).join("\n ") + + (writtenFilesArray.length > 5 ? "\n" + ` and ${writtenFilesArray.length - 5} more` : "") + }`; } throw new Error(errorMsg); } @@ -1488,8 +1749,8 @@ namespace Harness { } export function isBuiltFile(filePath: string): boolean { - return filePath.indexOf(libFolder) === 0 || - filePath.indexOf(vpath.addTrailingSeparator(vfs.builtFolder)) === 0; + return filePath.indexOf(libFolder) === 0 + || filePath.indexOf(vpath.addTrailingSeparator(vfs.builtFolder)) === 0; } export function getDefaultLibraryFile(filePath: string, io: IO): Compiler.TestFile { diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 0cc73febdbe0f..a885d58a77e65 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -130,7 +130,10 @@ namespace Harness.LanguageService { public typesRegistry: ts.ESMap | undefined; private scriptInfos: collections.SortedMap; - constructor(protected cancellationToken = DefaultHostCancellationToken.instance, protected settings = ts.getDefaultCompilerOptions()) { + constructor( + protected cancellationToken = DefaultHostCancellationToken.instance, + protected settings = ts.getDefaultCompilerOptions(), + ) { this.scriptInfos = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); } @@ -192,14 +195,22 @@ namespace Harness.LanguageService { public addScript(fileName: string, content: string, isRootFile: boolean): void { this.vfs.mkdirpSync(vpath.dirname(fileName)); this.vfs.writeFileSync(fileName, content); - this.scriptInfos.set(vpath.resolve(this.vfs.cwd(), fileName), new ScriptInfo(fileName, content, isRootFile)); + this.scriptInfos.set( + vpath.resolve(this.vfs.cwd(), fileName), + new ScriptInfo(fileName, content, isRootFile), + ); } public renameFileOrDirectory(oldPath: string, newPath: string): void { this.vfs.mkdirpSync(ts.getDirectoryPath(newPath)); this.vfs.renameSync(oldPath, newPath); - const updater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(this.useCaseSensitiveFileNames()), /*sourceMapper*/ undefined); + const updater = ts.getPathUpdater( + oldPath, + newPath, + ts.createGetCanonicalFileName(this.useCaseSensitiveFileNames()), + /*sourceMapper*/ undefined, + ); this.scriptInfos.forEach((scriptInfo, key) => { const newFileName = updater(key); if (newFileName !== undefined) { @@ -237,7 +248,11 @@ namespace Harness.LanguageService { public lineAndCharacterToPosition(fileName: string, lineAndCharacter: ts.LineAndCharacter): number { const script: ScriptInfo = this.getScriptInfo(fileName)!; assert.isOk(script); - return ts.computePositionOfLineAndCharacter(script.getLineMap(), lineAndCharacter.line, lineAndCharacter.character); + return ts.computePositionOfLineAndCharacter( + script.getLineMap(), + lineAndCharacter.line, + lineAndCharacter.character, + ); } useCaseSensitiveFileNames() { @@ -246,7 +261,9 @@ namespace Harness.LanguageService { } /// Native adapter - class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost, LanguageServiceAdapterHost { + class NativeLanguageServiceHost extends LanguageServiceAdapterHost + implements ts.LanguageServiceHost, LanguageServiceAdapterHost + { isKnownTypesPackageName(name: string): boolean { return !!this.typesRegistry && this.typesRegistry.has(name); } @@ -303,7 +320,13 @@ namespace Harness.LanguageService { return this.sys.fileExists(fileName); } - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { return this.sys.readDirectory(path, extensions, exclude, include, depth); } @@ -344,13 +367,19 @@ namespace Harness.LanguageService { } /// Shim adapter - class ShimLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceShimHost, ts.CoreServicesShimHost { + class ShimLanguageServiceHost extends LanguageServiceAdapterHost + implements ts.LanguageServiceShimHost, ts.CoreServicesShimHost + { private nativeHost: NativeLanguageServiceHost; public getModuleResolutionsForFile: ((fileName: string) => string) | undefined; public getTypeReferenceDirectiveResolutionsForFile: ((fileName: string) => string) | undefined; - constructor(preprocessToResolve: boolean, cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { + constructor( + preprocessToResolve: boolean, + cancellationToken?: ts.HostCancellationToken, + options?: ts.CompilerOptions, + ) { super(cancellationToken, options); this.nativeHost = new NativeLanguageServiceHost(cancellationToken, options); @@ -369,7 +398,12 @@ namespace Harness.LanguageService { const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ true); const imports: ts.MapLike = {}; for (const module of preprocessInfo.importedFiles) { - const resolutionInfo = ts.resolveModuleName(module.fileName, fileName, compilerOptions, moduleResolutionHost); + const resolutionInfo = ts.resolveModuleName( + module.fileName, + fileName, + compilerOptions, + moduleResolutionHost, + ); if (resolutionInfo.resolvedModule) { imports[module.fileName] = resolutionInfo.resolvedModule.resolvedFileName; } @@ -383,9 +417,15 @@ namespace Harness.LanguageService { const resolutions: ts.MapLike = {}; const settings = this.nativeHost.getCompilationSettings(); for (const typeReferenceDirective of preprocessInfo.typeReferenceDirectives) { - const resolutionInfo = ts.resolveTypeReferenceDirective(typeReferenceDirective.fileName, fileName, settings, moduleResolutionHost); + const resolutionInfo = ts.resolveTypeReferenceDirective( + typeReferenceDirective.fileName, + fileName, + settings, + moduleResolutionHost, + ); if (resolutionInfo.resolvedTypeReferenceDirective!.resolvedFileName) { - resolutions[typeReferenceDirective.fileName] = resolutionInfo.resolvedTypeReferenceDirective!; + resolutions[typeReferenceDirective.fileName] = resolutionInfo + .resolvedTypeReferenceDirective!; } } return JSON.stringify(resolutions); @@ -473,10 +513,18 @@ namespace Harness.LanguageService { class ClassifierShimProxy implements ts.Classifier { constructor(private shim: ts.ClassifierShim) { } - getEncodedLexicalClassifications(_text: string, _lexState: ts.EndOfLineState, _classifyKeywordsInGenerics?: boolean): ts.Classifications { + getEncodedLexicalClassifications( + _text: string, + _lexState: ts.EndOfLineState, + _classifyKeywordsInGenerics?: boolean, + ): ts.Classifications { return ts.notImplemented(); } - getClassificationsForLine(text: string, lexState: ts.EndOfLineState, classifyKeywordsInGenerics?: boolean): ts.ClassificationResult { + getClassificationsForLine( + text: string, + lexState: ts.EndOfLineState, + classifyKeywordsInGenerics?: boolean, + ): ts.ClassificationResult { const result = this.shim.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics).split("\n"); const entries: ts.ClassificationInfo[] = []; let i = 0; @@ -493,7 +541,12 @@ namespace Harness.LanguageService { } const finalLexState = parseInt(result[result.length - 1]); - assert.equal(position, text.length, "Expected cumulative length of all entries to match the length of the source. expected: " + text.length + ", but got: " + position); + assert.equal( + position, + text.length, + "Expected cumulative length of all entries to match the length of the source. expected: " + text.length + + ", but got: " + position, + ); return { finalLexState, @@ -534,21 +587,60 @@ namespace Harness.LanguageService { getSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] { return unwrapJSONCallResult(this.shim.getSyntacticClassifications(fileName, span.start, span.length)); } - getSemanticClassifications(fileName: string, span: ts.TextSpan, format?: ts.SemanticClassificationFormat): ts.ClassifiedSpan[] { - return unwrapJSONCallResult(this.shim.getSemanticClassifications(fileName, span.start, span.length, format)); + getSemanticClassifications( + fileName: string, + span: ts.TextSpan, + format?: ts.SemanticClassificationFormat, + ): ts.ClassifiedSpan[] { + return unwrapJSONCallResult( + this.shim.getSemanticClassifications(fileName, span.start, span.length, format), + ); } getEncodedSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications { - return unwrapJSONCallResult(this.shim.getEncodedSyntacticClassifications(fileName, span.start, span.length)); + return unwrapJSONCallResult( + this.shim.getEncodedSyntacticClassifications(fileName, span.start, span.length), + ); } - getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan, format?: ts.SemanticClassificationFormat): ts.Classifications { + getEncodedSemanticClassifications( + fileName: string, + span: ts.TextSpan, + format?: ts.SemanticClassificationFormat, + ): ts.Classifications { const responseFormat = format || ts.SemanticClassificationFormat.Original; - return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length, responseFormat)); + return unwrapJSONCallResult( + this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length, responseFormat), + ); } - getCompletionsAtPosition(fileName: string, position: number, preferences: ts.UserPreferences | undefined, formattingSettings: ts.FormatCodeSettings | undefined): ts.CompletionInfo { - return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position, preferences, formattingSettings)); + getCompletionsAtPosition( + fileName: string, + position: number, + preferences: ts.UserPreferences | undefined, + formattingSettings: ts.FormatCodeSettings | undefined, + ): ts.CompletionInfo { + return unwrapJSONCallResult( + this.shim.getCompletionsAtPosition(fileName, position, preferences, formattingSettings), + ); } - getCompletionEntryDetails(fileName: string, position: number, entryName: string, formatOptions: ts.FormatCodeOptions | undefined, source: string | undefined, preferences: ts.UserPreferences | undefined, data: ts.CompletionEntryData | undefined): ts.CompletionEntryDetails { - return unwrapJSONCallResult(this.shim.getCompletionEntryDetails(fileName, position, entryName, JSON.stringify(formatOptions), source, preferences, data)); + getCompletionEntryDetails( + fileName: string, + position: number, + entryName: string, + formatOptions: ts.FormatCodeOptions | undefined, + source: string | undefined, + preferences: ts.UserPreferences | undefined, + data: ts.CompletionEntryData | undefined, + ): ts.CompletionEntryDetails { + return unwrapJSONCallResult( + this.shim.getCompletionEntryDetails( + fileName, + position, + entryName, + JSON.stringify(formatOptions), + source, + preferences, + data, + ), + ); } getCompletionEntrySymbol(): ts.Symbol { throw new Error("getCompletionEntrySymbol not implemented across the shim layer."); @@ -562,7 +654,11 @@ namespace Harness.LanguageService { getBreakpointStatementAtPosition(fileName: string, position: number): ts.TextSpan { return unwrapJSONCallResult(this.shim.getBreakpointStatementAtPosition(fileName, position)); } - getSignatureHelpItems(fileName: string, position: number, options: ts.SignatureHelpItemsOptions | undefined): ts.SignatureHelpItems { + getSignatureHelpItems( + fileName: string, + position: number, + options: ts.SignatureHelpItemsOptions | undefined, + ): ts.SignatureHelpItems { return unwrapJSONCallResult(this.shim.getSignatureHelpItems(fileName, position, options)); } getRenameInfo(fileName: string, position: number, preferences: ts.UserPreferences): ts.RenameInfo { @@ -571,8 +667,22 @@ namespace Harness.LanguageService { getSmartSelectionRange(fileName: string, position: number): ts.SelectionRange { return unwrapJSONCallResult(this.shim.getSmartSelectionRange(fileName, position)); } - findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ts.RenameLocation[] { - return unwrapJSONCallResult(this.shim.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename)); + findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + providePrefixAndSuffixTextForRename?: boolean, + ): ts.RenameLocation[] { + return unwrapJSONCallResult( + this.shim.findRenameLocations( + fileName, + position, + findInStrings, + findInComments, + providePrefixAndSuffixTextForRename, + ), + ); } getDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] { return unwrapJSONCallResult(this.shim.getDefinitionAtPosition(fileName, position)); @@ -599,7 +709,9 @@ namespace Harness.LanguageService { return unwrapJSONCallResult(this.shim.getOccurrencesAtPosition(fileName, position)); } getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): ts.DocumentHighlights[] { - return unwrapJSONCallResult(this.shim.getDocumentHighlights(fileName, position, JSON.stringify(filesToSearch))); + return unwrapJSONCallResult( + this.shim.getDocumentHighlights(fileName, position, JSON.stringify(filesToSearch)), + ); } getNavigateToItems(searchValue: string): ts.NavigateToItem[] { return unwrapJSONCallResult(this.shim.getNavigateToItems(searchValue)); @@ -620,18 +732,38 @@ namespace Harness.LanguageService { return unwrapJSONCallResult(this.shim.getBraceMatchingAtPosition(fileName, position)); } getIndentationAtPosition(fileName: string, position: number, options: ts.EditorOptions): number { - return unwrapJSONCallResult(this.shim.getIndentationAtPosition(fileName, position, JSON.stringify(options))); + return unwrapJSONCallResult( + this.shim.getIndentationAtPosition(fileName, position, JSON.stringify(options)), + ); } - getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): ts.TextChange[] { - return unwrapJSONCallResult(this.shim.getFormattingEditsForRange(fileName, start, end, JSON.stringify(options))); + getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: ts.FormatCodeOptions, + ): ts.TextChange[] { + return unwrapJSONCallResult( + this.shim.getFormattingEditsForRange(fileName, start, end, JSON.stringify(options)), + ); } getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): ts.TextChange[] { return unwrapJSONCallResult(this.shim.getFormattingEditsForDocument(fileName, JSON.stringify(options))); } - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: ts.FormatCodeOptions): ts.TextChange[] { - return unwrapJSONCallResult(this.shim.getFormattingEditsAfterKeystroke(fileName, position, key, JSON.stringify(options))); + getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: ts.FormatCodeOptions, + ): ts.TextChange[] { + return unwrapJSONCallResult( + this.shim.getFormattingEditsAfterKeystroke(fileName, position, key, JSON.stringify(options)), + ); } - getDocCommentTemplateAtPosition(fileName: string, position: number, options?: ts.DocCommentTemplateOptions): ts.TextInsertion { + getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: ts.DocCommentTemplateOptions, + ): ts.TextInsertion { return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position, options)); } isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean { @@ -657,7 +789,10 @@ namespace Harness.LanguageService { getApplicableRefactors(): ts.ApplicableRefactorInfo[] { throw new Error("Not supported on the shim."); } - organizeImports(_args: ts.OrganizeImportsArgs, _formatOptions: ts.FormatCodeSettings): readonly ts.FileTextChanges[] { + organizeImports( + _args: ts.OrganizeImportsArgs, + _formatOptions: ts.FormatCodeSettings, + ): readonly ts.FileTextChanges[] { throw new Error("Not supported on the shim."); } getEditsForFileRename(): readonly ts.FileTextChanges[] { @@ -687,7 +822,10 @@ namespace Harness.LanguageService { getAutoImportProvider(): ts.Program | undefined { throw new Error("Program can not be marshaled across the shim layer."); } - updateIsDefinitionOfReferencedSymbols(_referencedSymbols: readonly ts.ReferencedSymbol[], _knownSymbolSpans: ts.Set): boolean { + updateIsDefinitionOfReferencedSymbols( + _referencedSymbols: readonly ts.ReferencedSymbol[], + _knownSymbolSpans: ts.Set, + ): boolean { return ts.notImplemented(); } getNonBoundSourceFile(): ts.SourceFile { @@ -722,7 +860,11 @@ namespace Harness.LanguageService { export class ShimLanguageServiceAdapter implements LanguageServiceAdapter { private host: ShimLanguageServiceHost; private factory: ts.TypeScriptServicesFactory; - constructor(preprocessToResolve: boolean, cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { + constructor( + preprocessToResolve: boolean, + cancellationToken?: ts.HostCancellationToken, + options?: ts.CompilerOptions, + ) { this.host = new ShimLanguageServiceHost(preprocessToResolve, cancellationToken, options); this.factory = new ts.TypeScriptServicesFactory(); } @@ -742,7 +884,9 @@ namespace Harness.LanguageService { typeReferenceDirectives: ts.ShimsFileReference[]; importedFiles: ts.ShimsFileReference[]; isLibFile: boolean; - } = unwrapJSONCallResult(coreServicesShim.getPreProcessedFileInfo(fileName, ts.ScriptSnapshot.fromString(fileContents))); + } = unwrapJSONCallResult( + coreServicesShim.getPreProcessedFileInfo(fileName, ts.ScriptSnapshot.fromString(fileContents)), + ); const convertResult: ts.PreProcessedFileInfo = { referencedFiles: [], @@ -828,7 +972,8 @@ namespace Harness.LanguageService { } // System FS would follow symlinks, even though snapshots are stored by original file name - const snapshot = this.host.getScriptSnapshot(fileName) || this.host.getScriptSnapshot(this.realpath(fileName)); + const snapshot = this.host.getScriptSnapshot(fileName) + || this.host.getScriptSnapshot(this.realpath(fileName)); return snapshot && ts.getSnapshotText(snapshot); } @@ -873,7 +1018,13 @@ namespace Harness.LanguageService { return ts.sys.getEnvironmentVariable(name); } - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { return this.host.readDirectory(path, extensions, exclude, include, depth); } @@ -987,7 +1138,13 @@ namespace Harness.LanguageService { const proxy = makeDefaultProxy(info); proxy.getSemanticDiagnostics = filename => { const prev = info.languageService.getSemanticDiagnostics(filename); - const sourceFile: ts.SourceFile = info.project.getSourceFile(ts.toPath(filename, /*basePath*/ undefined, ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames)))!; + const sourceFile: ts.SourceFile = info.project.getSourceFile( + ts.toPath( + filename, + /*basePath*/ undefined, + ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames), + ), + )!; prev.push({ category: ts.DiagnosticCategory.Warning, file: sourceFile, @@ -1014,7 +1171,13 @@ namespace Harness.LanguageService { const proxy = makeDefaultProxy(info); proxy.getSemanticDiagnostics = filename => { const prev = info.languageService.getSemanticDiagnostics(filename); - const sourceFile: ts.SourceFile = info.project.getSourceFile(ts.toPath(filename, /*basePath*/ undefined, ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames)))!; + const sourceFile: ts.SourceFile = info.project.getSourceFile( + ts.toPath( + filename, + /*basePath*/ undefined, + ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames), + ), + )!; prev.push({ category: ts.DiagnosticCategory.Error, file: sourceFile, @@ -1045,7 +1208,12 @@ namespace Harness.LanguageService { class FourslashSession extends ts.server.Session { getText(fileName: string) { - return ts.getSnapshotText(this.projectService.getDefaultProjectForFile(ts.server.toNormalizedPath(fileName), /*ensureProject*/ true)!.getScriptSnapshot(fileName)!); + return ts.getSnapshotText( + this.projectService.getDefaultProjectForFile( + ts.server.toNormalizedPath(fileName), + /*ensureProject*/ true, + )!.getScriptSnapshot(fileName)!, + ); } } @@ -1066,7 +1234,10 @@ namespace Harness.LanguageService { cancellationToken: ts.server.nullCancellationToken, useSingleInferredProject: false, useInferredProjectPerProjectRoot: false, - typingsInstaller: { ...ts.server.nullTypingsInstaller, globalTypingsCacheLocation: "/Library/Caches/typescript" }, + typingsInstaller: { + ...ts.server.nullTypingsInstaller, + globalTypingsCacheLocation: "/Library/Caches/typescript", + }, byteLength: Utils.byteLength, hrtime: process.hrtime, logger: serverHost, diff --git a/src/harness/harnessUtils.ts b/src/harness/harnessUtils.ts index 13ab6b8a413e6..7c9c5508e5189 100644 --- a/src/harness/harnessUtils.ts +++ b/src/harness/harnessUtils.ts @@ -119,28 +119,32 @@ namespace Utils { for (const childName in node) { if ( - childName === "parent" || - childName === "nextContainer" || - childName === "modifiers" || - childName === "externalModuleIndicator" || + childName === "parent" + || childName === "nextContainer" + || childName === "modifiers" + || childName === "externalModuleIndicator" // for now ignore jsdoc comments - childName === "jsDocComment" || - childName === "checkJsDirective" || - childName === "commonJsModuleIndicator" || + || childName === "jsDocComment" + || childName === "checkJsDirective" + || childName === "commonJsModuleIndicator" // ignore nodes added only to report grammar errors - childName === "illegalInitializer" || - childName === "illegalDecorators" || - childName === "illegalModifiers" || - childName === "illegalQuestionToken" || - childName === "illegalExclamationToken" || - childName === "illegalTypeParameters" || - childName === "illegalType" + || childName === "illegalInitializer" + || childName === "illegalDecorators" + || childName === "illegalModifiers" + || childName === "illegalQuestionToken" + || childName === "illegalExclamationToken" + || childName === "illegalTypeParameters" + || childName === "illegalType" ) { continue; } const child = (node as any)[childName]; if (isNodeOrArray(child)) { - assert.isFalse(childNodesAndArrays.indexOf(child) < 0, "Missing child when forEach'ing over node: " + ts.Debug.formatSyntaxKind(node.kind) + "-" + childName); + assert.isFalse( + childNodesAndArrays.indexOf(child) < 0, + "Missing child when forEach'ing over node: " + ts.Debug.formatSyntaxKind(node.kind) + "-" + + childName, + ); } } } @@ -185,7 +189,11 @@ namespace Utils { o.containsParseError = true; } - for (const propertyName of Object.getOwnPropertyNames(n) as readonly (keyof ts.SourceFile | keyof ts.Identifier)[]) { + for ( + const propertyName of Object.getOwnPropertyNames( + n, + ) as readonly (keyof ts.SourceFile | keyof ts.Identifier)[] + ) { switch (propertyName) { case "parent": case "symbol": @@ -220,7 +228,11 @@ namespace Utils { case "nextContainer": if (n.nextContainer) { - o[propertyName] = { kind: n.nextContainer.kind, pos: n.nextContainer.pos, end: n.nextContainer.end }; + o[propertyName] = { + kind: n.nextContainer.kind, + pos: n.nextContainer.pos, + end: n.nextContainer.end, + }; } break; @@ -280,7 +292,11 @@ namespace Utils { // call this on both nodes to ensure all propagated flags have been set (and thus can be // compared). assert.equal(ts.containsParseError(node1), ts.containsParseError(node2)); - assert.equal(node1.flags & ~ts.NodeFlags.ReachabilityAndEmitFlags, node2.flags & ~ts.NodeFlags.ReachabilityAndEmitFlags, "node1.flags !== node2.flags"); + assert.equal( + node1.flags & ~ts.NodeFlags.ReachabilityAndEmitFlags, + node2.flags & ~ts.NodeFlags.ReachabilityAndEmitFlags, + "node1.flags !== node2.flags", + ); ts.forEachChild(node1, child1 => { const childName = findChildName(node1, child1); diff --git a/src/harness/runnerbase.ts b/src/harness/runnerbase.ts index 160dcbf8d2e35..a439df8d03461 100644 --- a/src/harness/runnerbase.ts +++ b/src/harness/runnerbase.ts @@ -1,5 +1,13 @@ namespace Harness { - export type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project" | "rwc" | "test262" | "user" | "dt" | "docker"; + export type TestRunnerKind = + | CompilerTestKind + | FourslashTestKind + | "project" + | "rwc" + | "test262" + | "user" + | "dt" + | "docker"; export type CompilerTestKind = "conformance" | "compiler"; export type FourslashTestKind = "fourslash" | "fourslash-shims" | "fourslash-shims-pp" | "fourslash-server"; @@ -26,7 +34,10 @@ namespace Harness { } public enumerateFiles(folder: string, regex?: RegExp, options?: { recursive: boolean; }): string[] { - return ts.map(IO.listFiles(userSpecifiedRoot + folder, regex, { recursive: (options ? options.recursive : false) }), ts.normalizeSlashes); + return ts.map( + IO.listFiles(userSpecifiedRoot + folder, regex, { recursive: (options ? options.recursive : false) }), + ts.normalizeSlashes, + ); } abstract kind(): TestRunnerKind; diff --git a/src/harness/sourceMapRecorder.ts b/src/harness/sourceMapRecorder.ts index 2e16d0742c4c3..d9cf992b3c180 100644 --- a/src/harness/sourceMapRecorder.ts +++ b/src/harness/sourceMapRecorder.ts @@ -23,7 +23,9 @@ namespace Harness.SourceMapRecorder { export function decodeNextEncodedSourceMapSpan(): DecodedMapping { if (!mappings) return ts.Debug.fail("not initialized"); const result = mappings.next(); - if (result.done) return { error: mappings.error || "No encoded entry found", sourceMapSpan: mappings.state }; + if (result.done) { + return { error: mappings.error || "No encoded entry found", sourceMapSpan: mappings.state }; + } return { sourceMapSpan: result.value }; } @@ -52,7 +54,11 @@ namespace Harness.SourceMapRecorder { let nextJsLineToWrite: number; let spanMarkerContinues: boolean; - export function initializeSourceMapSpanWriter(sourceMapRecordWriter: Compiler.WriterAggregator, sourceMap: ts.RawSourceMap, currentJsFile: documents.TextDocument) { + export function initializeSourceMapSpanWriter( + sourceMapRecordWriter: Compiler.WriterAggregator, + sourceMap: ts.RawSourceMap, + currentJsFile: documents.TextDocument, + ) { sourceMapRecorder = sourceMapRecordWriter; sourceMapSources = sourceMap.sources; sourceMapNames = sourceMap.names; @@ -80,7 +86,8 @@ namespace Harness.SourceMapRecorder { function getSourceMapSpanString(mapEntry: ts.Mapping, getAbsentNameIndex?: boolean) { let mapString = "Emitted(" + (mapEntry.generatedLine + 1) + ", " + (mapEntry.generatedCharacter + 1) + ")"; if (ts.isSourceMapping(mapEntry)) { - mapString += " Source(" + (mapEntry.sourceLine + 1) + ", " + (mapEntry.sourceCharacter + 1) + ") + SourceIndex(" + mapEntry.sourceIndex + ")"; + mapString += " Source(" + (mapEntry.sourceLine + 1) + ", " + (mapEntry.sourceCharacter + 1) + + ") + SourceIndex(" + mapEntry.sourceIndex + ")"; if (mapEntry.nameIndex! >= 0 && mapEntry.nameIndex! < sourceMapNames!.length) { mapString += " name (" + sourceMapNames![mapEntry.nameIndex!] + ")"; } @@ -100,15 +107,27 @@ namespace Harness.SourceMapRecorder { let decodeErrors: string[] | undefined; if (typeof decodeResult.error === "string" || !ts.sameMapping(decodeResult.sourceMapSpan, sourceMapSpan)) { if (decodeResult.error) { - decodeErrors = ["!!^^ !!^^ There was decoding error in the sourcemap at this location: " + decodeResult.error]; + decodeErrors = [ + "!!^^ !!^^ There was decoding error in the sourcemap at this location: " + decodeResult.error, + ]; } else { - decodeErrors = ["!!^^ !!^^ The decoded span from sourcemap's mapping entry does not match what was encoded for this span:"]; + decodeErrors = [ + "!!^^ !!^^ The decoded span from sourcemap's mapping entry does not match what was encoded for this span:", + ]; } - decodeErrors.push("!!^^ !!^^ Decoded span from sourcemap's mappings entry: " + getSourceMapSpanString(decodeResult.sourceMapSpan, /*getAbsentNameIndex*/ true) + " Span encoded by the emitter:" + getSourceMapSpanString(sourceMapSpan, /*getAbsentNameIndex*/ true)); + decodeErrors.push( + "!!^^ !!^^ Decoded span from sourcemap's mappings entry: " + + getSourceMapSpanString(decodeResult.sourceMapSpan, /*getAbsentNameIndex*/ true) + + " Span encoded by the emitter:" + + getSourceMapSpanString(sourceMapSpan, /*getAbsentNameIndex*/ true), + ); } - if (spansOnSingleLine.length && spansOnSingleLine[0].sourceMapSpan.generatedLine !== sourceMapSpan.generatedLine) { + if ( + spansOnSingleLine.length + && spansOnSingleLine[0].sourceMapSpan.generatedLine !== sourceMapSpan.generatedLine + ) { // On different line from the one that we have been recording till now, writeRecordedSpans(); spansOnSingleLine = []; @@ -118,7 +137,10 @@ namespace Harness.SourceMapRecorder { export function recordNewSourceFileSpan(sourceMapSpan: ts.Mapping, newSourceFileCode: string) { let continuesLine = false; - if (spansOnSingleLine.length > 0 && spansOnSingleLine[0].sourceMapSpan.generatedCharacter === sourceMapSpan.generatedLine) { + if ( + spansOnSingleLine.length > 0 + && spansOnSingleLine[0].sourceMapSpan.generatedCharacter === sourceMapSpan.generatedLine + ) { writeRecordedSpans(); spansOnSingleLine = []; nextJsLineToWrite--; // walk back one line to reprint the line @@ -129,8 +151,14 @@ namespace Harness.SourceMapRecorder { assert.isTrue(spansOnSingleLine.length === 1); sourceMapRecorder.WriteLine("-------------------------------------------------------------------"); - sourceMapRecorder.WriteLine("emittedFile:" + jsFile.file + (continuesLine ? ` (${sourceMapSpan.generatedLine + 1}, ${sourceMapSpan.generatedCharacter + 1})` : "")); - sourceMapRecorder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex!]); + sourceMapRecorder.WriteLine( + "emittedFile:" + jsFile.file + + (continuesLine ? ` (${sourceMapSpan.generatedLine + 1}, ${sourceMapSpan.generatedCharacter + 1})` + : ""), + ); + sourceMapRecorder.WriteLine( + "sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex!], + ); sourceMapRecorder.WriteLine("-------------------------------------------------------------------"); tsLineMap = ts.computeLineStarts(newSourceFileCode); @@ -143,8 +171,12 @@ namespace Harness.SourceMapRecorder { writeRecordedSpans(); if (!SourceMapDecoder.hasCompletedDecoding()) { - sourceMapRecorder.WriteLine("!!!! **** There are more source map entries in the sourceMap's mapping than what was encoded"); - sourceMapRecorder.WriteLine("!!!! **** Remaining decoded string: " + SourceMapDecoder.getRemainingDecodeString()); + sourceMapRecorder.WriteLine( + "!!!! **** There are more source map entries in the sourceMap's mapping than what was encoded", + ); + sourceMapRecorder.WriteLine( + "!!!! **** Remaining decoded string: " + SourceMapDecoder.getRemainingDecodeString(), + ); } // write remaining js lines @@ -199,7 +231,12 @@ namespace Harness.SourceMapRecorder { } } - function writeSourceMapMarker(currentSpan: SourceMapSpanWithDecodeErrors, index: number, endColumn = currentSpan.sourceMapSpan.generatedCharacter, endContinues = false) { + function writeSourceMapMarker( + currentSpan: SourceMapSpanWithDecodeErrors, + index: number, + endColumn = currentSpan.sourceMapSpan.generatedCharacter, + endContinues = false, + ) { const markerId = getMarkerId(index); markerIds.push(markerId); @@ -216,7 +253,8 @@ namespace Harness.SourceMapRecorder { } function writeSourceMapSourceText(currentSpan: SourceMapSpanWithDecodeErrors, index: number) { - const sourcePos = tsLineMap[currentSpan.sourceMapSpan.sourceLine!] + (currentSpan.sourceMapSpan.sourceCharacter!); + const sourcePos = tsLineMap[currentSpan.sourceMapSpan.sourceLine!] + + (currentSpan.sourceMapSpan.sourceCharacter!); let sourceText = ""; if (prevWrittenSourcePos < sourcePos) { // Position that goes forward, get text @@ -259,7 +297,12 @@ namespace Harness.SourceMapRecorder { const jsFileText = getTextOfLine(currentJsLine + 1, jsLineMap, jsFile.text); if (prevEmittedCol < jsFileText.length - 1) { // There is remaining text on this line that will be part of next source span so write marker that continues - writeSourceMapMarker(/*currentSpan*/ undefined!, spansOnSingleLine.length, /*endColumn*/ jsFileText.length - 1, /*endContinues*/ true); // TODO: GH#18217 + writeSourceMapMarker( + /*currentSpan*/ undefined!, + spansOnSingleLine.length, + /*endColumn*/ jsFileText.length - 1, + /*endContinues*/ true, + ); // TODO: GH#18217 } // Emit Source text @@ -273,7 +316,12 @@ namespace Harness.SourceMapRecorder { } } - export function getSourceMapRecord(sourceMapDataList: readonly ts.SourceMapEmitResult[], program: ts.Program, jsFiles: readonly documents.TextDocument[], declarationFiles: readonly documents.TextDocument[]) { + export function getSourceMapRecord( + sourceMapDataList: readonly ts.SourceMapEmitResult[], + program: ts.Program, + jsFiles: readonly documents.TextDocument[], + declarationFiles: readonly documents.TextDocument[], + ) { const sourceMapRecorder = new Compiler.WriterAggregator(); for (let i = 0; i < sourceMapDataList.length; i++) { @@ -327,9 +375,12 @@ namespace Harness.SourceMapRecorder { const sourceMap = ts.tryParseRawSourceMap(sys.readFile(sourceMapFile, "utf8")!); if (sourceMap) { const mapDirectory = ts.getDirectoryPath(sourceMapFile); - const sourceRoot = sourceMap.sourceRoot ? ts.getNormalizedAbsolutePath(sourceMap.sourceRoot, mapDirectory) : mapDirectory; + const sourceRoot = sourceMap.sourceRoot ? ts.getNormalizedAbsolutePath(sourceMap.sourceRoot, mapDirectory) + : mapDirectory; const generatedAbsoluteFilePath = ts.getNormalizedAbsolutePath(sourceMap.file, mapDirectory); - const sourceFileAbsolutePaths = sourceMap.sources.map(source => ts.getNormalizedAbsolutePath(source, sourceRoot)); + const sourceFileAbsolutePaths = sourceMap.sources.map(source => + ts.getNormalizedAbsolutePath(source, sourceRoot) + ); const currentFile = getFile(generatedAbsoluteFilePath); SourceMapSpanWriter.initializeSourceMapSpanWriter(sourceMapRecorder, sourceMap, currentFile); diff --git a/src/harness/typeWriter.ts b/src/harness/typeWriter.ts index fa7b1d63e2b25..3f19f1e4c66e5 100644 --- a/src/harness/typeWriter.ts +++ b/src/harness/typeWriter.ts @@ -80,7 +80,9 @@ namespace Harness { } private isImportStatementName(node: ts.Node) { - if (ts.isImportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) return true; + if (ts.isImportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) { + return true; + } if (ts.isImportClause(node.parent) && node.parent.name === node) return true; if (ts.isImportEqualsDeclaration(node.parent) && node.parent.name === node) return true; return false; @@ -88,13 +90,17 @@ namespace Harness { private isExportStatementName(node: ts.Node) { if (ts.isExportAssignment(node.parent) && node.parent.expression === node) return true; - if (ts.isExportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) return true; + if (ts.isExportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) { + return true; + } return false; } private isIntrinsicJsxTag(node: ts.Node) { const p = node.parent; - if (!(ts.isJsxOpeningElement(p) || ts.isJsxClosingElement(p) || ts.isJsxSelfClosingElement(p))) return false; + if (!(ts.isJsxOpeningElement(p) || ts.isJsxClosingElement(p) || ts.isJsxSelfClosingElement(p))) { + return false; + } if (p.tagName !== node) return false; return ts.isIntrinsicJsxName(node.getText()); } @@ -107,13 +113,18 @@ namespace Harness { if (!isSymbolWalk) { // Don't try to get the type of something that's already a type. // Exception for `T` in `type T = something` because that may evaluate to some interesting type. - if (ts.isPartOfTypeNode(node) || ts.isIdentifier(node) && !(ts.getMeaningFromDeclaration(node.parent) & ts.SemanticMeaning.Value) && !(ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node)) { + if ( + ts.isPartOfTypeNode(node) + || ts.isIdentifier(node) && !(ts.getMeaningFromDeclaration(node.parent) & ts.SemanticMeaning.Value) + && !(ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node) + ) { return undefined; } // Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions // let type = this.checker.getTypeAtLocation(node); - let type = ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) ? this.checker.getTypeAtLocation(node.parent) : undefined; + let type = ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) + ? this.checker.getTypeAtLocation(node.parent) : undefined; if (!type || type.flags & ts.TypeFlags.Any) type = this.checker.getTypeAtLocation(node); // Distinguish `errorType`s from `any`s; but only if the file has no errors. // Additionally, @@ -129,25 +140,37 @@ namespace Harness { // But this is generally expected, so we don't call those out, either let typeString: string; if ( - !this.hadErrorBaseline && - type.flags & ts.TypeFlags.Any && - !ts.isBindingElement(node.parent) && - !ts.isPropertyAccessOrQualifiedName(node.parent) && - !ts.isLabelName(node) && - !(ts.isModuleDeclaration(node.parent) && ts.isGlobalScopeAugmentation(node.parent)) && - !ts.isMetaProperty(node.parent) && - !this.isImportStatementName(node) && - !this.isExportStatementName(node) && - !this.isIntrinsicJsxTag(node) + !this.hadErrorBaseline + && type.flags & ts.TypeFlags.Any + && !ts.isBindingElement(node.parent) + && !ts.isPropertyAccessOrQualifiedName(node.parent) + && !ts.isLabelName(node) + && !(ts.isModuleDeclaration(node.parent) && ts.isGlobalScopeAugmentation(node.parent)) + && !ts.isMetaProperty(node.parent) + && !this.isImportStatementName(node) + && !this.isExportStatementName(node) + && !this.isIntrinsicJsxTag(node) ) { typeString = (type as ts.IntrinsicType).intrinsicName; } else { - typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType); - if (ts.isIdentifier(node) && ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node && typeString === ts.idText(node)) { + typeString = this.checker.typeToString( + type, + node.parent, + ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType, + ); + if ( + ts.isIdentifier(node) && ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node + && typeString === ts.idText(node) + ) { // for a complex type alias `type T = ...`, showing "T : T" isn't very helpful for type tests. When the type produced is the same as // the name of the type alias, recreate the type string without reusing the alias name - typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType | ts.TypeFormatFlags.InTypeAlias); + typeString = this.checker.typeToString( + type, + node.parent, + ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType + | ts.TypeFormatFlags.InTypeAlias, + ); } } return { @@ -179,7 +202,9 @@ namespace Harness { const declLineAndCharacter = declSourceFile.getLineAndCharacterOfPosition(declaration.pos); const fileName = ts.getBaseFileName(declSourceFile.fileName); const isLibFile = /lib(.*)\.d\.ts/i.test(fileName); - const declText = `Decl(${fileName}, ${isLibFile ? "--" : declLineAndCharacter.line}, ${isLibFile ? "--" : declLineAndCharacter.character})`; + const declText = `Decl(${fileName}, ${isLibFile ? "--" : declLineAndCharacter.line}, ${ + isLibFile ? "--" : declLineAndCharacter.character + })`; symbolString += declText; (declaration as any).__symbolTestOutputCache = declText; } diff --git a/src/harness/util.ts b/src/harness/util.ts index 0e7a0155c39fe..6ea395916a200 100644 --- a/src/harness/util.ts +++ b/src/harness/util.ts @@ -4,18 +4,28 @@ namespace Utils { const testPathPrefixRegExp = /(?:(file:\/{3})|\/)\.(ts|lib|src)\//g; export function removeTestPathPrefixes(text: string, retainTrailingDirectorySeparator?: boolean): string { - return text !== undefined ? text.replace(testPathPrefixRegExp, (_, scheme) => scheme || (retainTrailingDirectorySeparator ? "/" : "")) : undefined!; // TODO: GH#18217 + return text !== undefined + ? text.replace(testPathPrefixRegExp, (_, scheme) => scheme || (retainTrailingDirectorySeparator ? "/" : "")) + : undefined!; // TODO: GH#18217 } - function createDiagnosticMessageReplacer string[]>(diagnosticMessage: ts.DiagnosticMessage, replacer: R) { + function createDiagnosticMessageReplacer string[]>( + diagnosticMessage: ts.DiagnosticMessage, + replacer: R, + ) { const messageParts = diagnosticMessage.message.split(/{\d+}/g); const regExp = new RegExp(`^(?:${messageParts.map(ts.regExpEscape).join("(.*?)")})$`); type Args = R extends (messageArgs: string[], ...args: infer A) => string[] ? A : []; - return (text: string, ...args: Args) => text.replace(regExp, (_, ...fixedArgs) => ts.formatStringFromArgs(diagnosticMessage.message, replacer(fixedArgs, ...args))); + return (text: string, ...args: Args) => + text.replace( + regExp, + (_, ...fixedArgs) => ts.formatStringFromArgs(diagnosticMessage.message, replacer(fixedArgs, ...args)), + ); } const replaceTypesVersionsMessage = createDiagnosticMessageReplacer( - ts.Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, + ts.Diagnostics + .package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, ([entry, , moduleName], compilerVersion) => [entry, compilerVersion, moduleName], ); @@ -85,7 +95,9 @@ namespace Utils { if (ch0 === 0xfeff) return 1; if (ch0 === 0xfe) return text.length >= 2 && text.charCodeAt(1) === 0xff ? 2 : 0; if (ch0 === 0xff) return text.length >= 2 && text.charCodeAt(1) === 0xfe ? 2 : 0; - if (ch0 === 0xef) return text.length >= 3 && text.charCodeAt(1) === 0xbb && text.charCodeAt(2) === 0xbf ? 3 : 0; + if (ch0 === 0xef) { + return text.length >= 3 && text.charCodeAt(1) === 0xbb && text.charCodeAt(2) === 0xbf ? 3 : 0; + } } return 0; } @@ -106,9 +118,9 @@ namespace Utils { } function formatTheoryDatum(value: any) { - return typeof value === "function" ? value.name || "" : - value === undefined ? "undefined" : - JSON.stringify(value); + return typeof value === "function" ? value.name || "" + : value === undefined ? "undefined" + : JSON.stringify(value); } export interface Deferred { diff --git a/src/harness/vfsUtil.ts b/src/harness/vfsUtil.ts index ec6c65e09b986..9afb8e1978262 100644 --- a/src/harness/vfsUtil.ts +++ b/src/harness/vfsUtil.ts @@ -155,7 +155,9 @@ namespace vfs { */ public shadow(ignoreCase = this.ignoreCase) { if (!this.isReadonly) throw new Error("Cannot shadow a mutable file system."); - if (ignoreCase && !this.ignoreCase) throw new Error("Cannot create a case-insensitive file system from a case-sensitive one."); + if (ignoreCase && !this.ignoreCase) { + throw new Error("Cannot create a case-insensitive file system from a case-sensitive one."); + } const fs = new FileSystem(ignoreCase, { time: this._time }); fs._shadowRoot = this; fs._cwd = this._cwd; @@ -278,11 +280,25 @@ namespace vfs { public lscanSync(path: string, axis: Axis, traversal: Traversal) { path = this._resolve(path); const results: string[] = []; - this._scan(path, this._stat(this._walk(path, /*noFollow*/ true)), axis, traversal, /*noFollow*/ true, results); + this._scan( + path, + this._stat(this._walk(path, /*noFollow*/ true)), + axis, + traversal, + /*noFollow*/ true, + results, + ); return results; } - private _scan(path: string, stats: Stats, axis: Axis, traversal: Traversal, noFollow: boolean, results: string[]) { + private _scan( + path: string, + stats: Stats, + axis: Axis, + traversal: Traversal, + noFollow: boolean, + results: string[], + ) { if (axis === "ancestors-or-self" || axis === "self" || axis === "descendants-or-self") { if (!traversal.accept || traversal.accept(path, stats)) { results.push(path); @@ -326,7 +342,10 @@ namespace vfs { source = vpath.validate(source, vpath.ValidationFlags.Absolute); - const { parent, links, node: existingNode, basename } = this._walk(this._resolve(target), /*noFollow*/ true); + const { parent, links, node: existingNode, basename } = this._walk( + this._resolve(target), + /*noFollow*/ true, + ); if (existingNode) throw createIOError("EEXIST"); const time = this.time(); @@ -548,7 +567,10 @@ namespace vfs { if (!node) throw createIOError("ENOENT"); if (isDirectory(node)) throw createIOError("EPERM"); - const { parent, links, basename, node: existingNode } = this._walk(this._resolve(newpath), /*noFollow*/ true); + const { parent, links, basename, node: existingNode } = this._walk( + this._resolve(newpath), + /*noFollow*/ true, + ); if (!parent) throw createIOError("EPERM"); if (existingNode) throw createIOError("EEXIST"); @@ -583,11 +605,17 @@ namespace vfs { public renameSync(oldpath: string, newpath: string) { if (this.isReadonly) throw createIOError("EROFS"); - const { parent: oldParent, links: oldParentLinks, node, basename: oldBasename } = this._walk(this._resolve(oldpath), /*noFollow*/ true); + const { parent: oldParent, links: oldParentLinks, node, basename: oldBasename } = this._walk( + this._resolve(oldpath), + /*noFollow*/ true, + ); if (!oldParent) throw createIOError("EPERM"); if (!node) throw createIOError("ENOENT"); - const { parent: newParent, links: newParentLinks, node: existingNode, basename: newBasename } = this._walk(this._resolve(newpath), /*noFollow*/ true); + const { parent: newParent, links: newParentLinks, node: existingNode, basename: newBasename } = this._walk( + this._resolve(newpath), + /*noFollow*/ true, + ); if (!newParent) throw createIOError("EPERM"); const time = this.time(); @@ -596,7 +624,9 @@ namespace vfs { if (!isDirectory(existingNode)) throw createIOError("ENOTDIR"); // if both old and new arguments point to the same directory, just pass. So we could rename /src/a/1 to /src/A/1 in Win. // if not and the directory pointed by the new path is not empty, throw an error. - if (this.stringComparer(oldpath, newpath) !== 0 && this._getLinks(existingNode).size > 0) throw createIOError("ENOTEMPTY"); + if (this.stringComparer(oldpath, newpath) !== 0 && this._getLinks(existingNode).size > 0) { + throw createIOError("ENOTEMPTY"); + } } else { if (isDirectory(existingNode)) throw createIOError("EISDIR"); @@ -604,7 +634,16 @@ namespace vfs { this._removeLink(newParent, newParentLinks, newBasename, existingNode, time); } - this._replaceLink(oldParent, oldParentLinks, oldBasename, newParent, newParentLinks, newBasename, node, time); + this._replaceLink( + oldParent, + oldParentLinks, + oldBasename, + newParent, + newParentLinks, + newBasename, + node, + time, + ); } /** @@ -617,7 +656,10 @@ namespace vfs { public symlinkSync(target: string, linkpath: string) { if (this.isReadonly) throw createIOError("EROFS"); - const { parent, links, node: existingNode, basename } = this._walk(this._resolve(linkpath), /*noFollow*/ true); + const { parent, links, node: existingNode, basename } = this._walk( + this._resolve(linkpath), + /*noFollow*/ true, + ); if (!parent) throw createIOError("EPERM"); if (existingNode) throw createIOError("EEXIST"); @@ -688,7 +730,8 @@ namespace vfs { if (isDirectory(node)) throw createIOError("EISDIR"); if (!isFile(node)) throw createIOError("EBADF"); - node.buffer = Buffer.isBuffer(data) ? data.slice() : ts.sys.bufferFrom!("" + data, encoding || "utf8") as Buffer; + node.buffer = Buffer.isBuffer(data) ? data.slice() + : ts.sys.bufferFrom!("" + data, encoding || "utf8") as Buffer; node.size = node.buffer.byteLength; node.mtimeMs = time; node.ctimeMs = time; @@ -701,9 +744,9 @@ namespace vfs { public diff(base?: FileSystem | undefined, options: DiffOptions = {}) { if (!base && !options.baseIsNotShadowRoot) base = this.shadowRoot; const differences: FileSet = {}; - const hasDifferences = base ? - FileSystem.rootDiff(differences, this, base, options) : - FileSystem.trackCreatedInodes(differences, this, this._getRootLinks()); + const hasDifferences = base + ? FileSystem.rootDiff(differences, this, base, options) + : FileSystem.trackCreatedInodes(differences, this, this._getRootLinks()); return hasDifferences ? differences : undefined; } @@ -712,12 +755,19 @@ namespace vfs { */ public static diff(changed: FileSystem, base: FileSystem, options: DiffOptions = {}) { const differences: FileSet = {}; - return FileSystem.rootDiff(differences, changed, base, options) ? - differences : - undefined; - } - - private static diffWorker(container: FileSet, changed: FileSystem, changedLinks: ReadonlyMap | undefined, base: FileSystem, baseLinks: ReadonlyMap | undefined, options: DiffOptions) { + return FileSystem.rootDiff(differences, changed, base, options) + ? differences + : undefined; + } + + private static diffWorker( + container: FileSet, + changed: FileSystem, + changedLinks: ReadonlyMap | undefined, + base: FileSystem, + baseLinks: ReadonlyMap | undefined, + options: DiffOptions, + ) { if (changedLinks && !baseLinks) return FileSystem.trackCreatedInodes(container, changed, changedLinks); if (baseLinks && !changedLinks) return FileSystem.trackDeletedInodes(container, baseLinks); if (changedLinks && baseLinks) { @@ -734,16 +784,28 @@ namespace vfs { const baseNode = baseLinks.get(basename); if (baseNode) { if (isDirectory(changedNode) && isDirectory(baseNode)) { - return hasChanges = FileSystem.directoryDiff(container, basename, changed, changedNode, base, baseNode, options) || hasChanges; + return hasChanges = FileSystem.directoryDiff( + container, + basename, + changed, + changedNode, + base, + baseNode, + options, + ) || hasChanges; } if (isFile(changedNode) && isFile(baseNode)) { - return hasChanges = FileSystem.fileDiff(container, basename, changed, changedNode, base, baseNode, options) || hasChanges; + return hasChanges = + FileSystem.fileDiff(container, basename, changed, changedNode, base, baseNode, options) + || hasChanges; } if (isSymlink(changedNode) && isSymlink(baseNode)) { - return hasChanges = FileSystem.symlinkDiff(container, basename, changedNode, baseNode) || hasChanges; + return hasChanges = FileSystem.symlinkDiff(container, basename, changedNode, baseNode) + || hasChanges; } } - return hasChanges = FileSystem.trackCreatedInode(container, basename, changed, changedNode) || hasChanges; + return hasChanges = FileSystem.trackCreatedInode(container, basename, changed, changedNode) + || hasChanges; }); return hasChanges; } @@ -760,10 +822,25 @@ namespace vfs { // no difference if the root links are empty and unshadowed if (!changed._lazy.links && !changed._shadowRoot && !base._lazy.links && !base._shadowRoot) return false; - return FileSystem.diffWorker(container, changed, changed._getRootLinks(), base, base._getRootLinks(), options); + return FileSystem.diffWorker( + container, + changed, + changed._getRootLinks(), + base, + base._getRootLinks(), + options, + ); } - private static directoryDiff(container: FileSet, basename: string, changed: FileSystem, changedNode: DirectoryInode, base: FileSystem, baseNode: DirectoryInode, options: DiffOptions) { + private static directoryDiff( + container: FileSet, + basename: string, + changed: FileSystem, + changedNode: DirectoryInode, + base: FileSystem, + baseNode: DirectoryInode, + options: DiffOptions, + ) { while (!changedNode.links && changedNode.shadowRoot) changedNode = changedNode.shadowRoot; while (!baseNode.links && baseNode.shadowRoot) baseNode = baseNode.shadowRoot; @@ -775,14 +852,23 @@ namespace vfs { // no difference if both nodes are unpopulated and point to the same mounted file system if ( - !changedNode.links && !baseNode.links && - changedNode.resolver && changedNode.source !== undefined && - baseNode.resolver === changedNode.resolver && baseNode.source === changedNode.source + !changedNode.links && !baseNode.links + && changedNode.resolver && changedNode.source !== undefined + && baseNode.resolver === changedNode.resolver && baseNode.source === changedNode.source ) return false; // no difference if both nodes have identical children const children: FileSet = {}; - if (!FileSystem.diffWorker(children, changed, changed._getLinks(changedNode), base, base._getLinks(baseNode), options)) { + if ( + !FileSystem.diffWorker( + children, + changed, + changed._getLinks(changedNode), + base, + base._getLinks(baseNode), + options, + ) + ) { return false; } @@ -790,7 +876,15 @@ namespace vfs { return true; } - private static fileDiff(container: FileSet, basename: string, changed: FileSystem, changedNode: FileInode, base: FileSystem, baseNode: FileInode, options: DiffOptions) { + private static fileDiff( + container: FileSet, + basename: string, + changed: FileSystem, + changedNode: FileInode, + base: FileSystem, + baseNode: FileInode, + options: DiffOptions, + ) { while (!changedNode.buffer && changedNode.shadowRoot) changedNode = changedNode.shadowRoot; while (!baseNode.buffer && baseNode.shadowRoot) baseNode = baseNode.shadowRoot; @@ -802,9 +896,9 @@ namespace vfs { // no difference if both nodes are unpopulated and point to the same mounted file system if ( - !changedNode.buffer && !baseNode.buffer && - changedNode.resolver && changedNode.source !== undefined && - baseNode.resolver === changedNode.resolver && baseNode.source === changedNode.source + !changedNode.buffer && !baseNode.buffer + && changedNode.resolver && changedNode.source !== undefined + && baseNode.resolver === changedNode.resolver && baseNode.source === changedNode.source ) return false; const changedBuffer = changed._getBuffer(changedNode); @@ -812,7 +906,9 @@ namespace vfs { // no difference if both buffers are the same reference if (changedBuffer === baseBuffer) { - if (!options.includeChangedFileWithSameContent || changedNode.mtimeMs === baseNode.mtimeMs) return false; + if (!options.includeChangedFileWithSameContent || changedNode.mtimeMs === baseNode.mtimeMs) { + return false; + } container[basename] = new SameFileWithModifiedTime(changedBuffer); return true; } @@ -828,7 +924,12 @@ namespace vfs { return true; } - private static symlinkDiff(container: FileSet, basename: string, changedNode: SymlinkInode, baseNode: SymlinkInode) { + private static symlinkDiff( + container: FileSet, + basename: string, + changedNode: SymlinkInode, + baseNode: SymlinkInode, + ) { // no difference if the nodes are the same reference if (changedNode.symlink === baseNode.symlink) return false; container[basename] = new Symlink(changedNode.symlink); @@ -850,7 +951,11 @@ namespace vfs { return true; } - private static trackCreatedInodes(container: FileSet, changed: FileSystem, changedLinks: ReadonlyMap) { + private static trackCreatedInodes( + container: FileSet, + changed: FileSystem, + changedLinks: ReadonlyMap, + ) { // no difference if links are empty if (!changedLinks.size) return false; @@ -885,7 +990,13 @@ namespace vfs { } as Inode; } - private _addLink(parent: DirectoryInode | undefined, links: collections.SortedMap, name: string, node: Inode, time = this.time()) { + private _addLink( + parent: DirectoryInode | undefined, + links: collections.SortedMap, + name: string, + node: Inode, + time = this.time(), + ) { links.set(name, node); node.nlink++; node.ctimeMs = time; @@ -893,14 +1004,29 @@ namespace vfs { if (!parent && !this._cwd) this._cwd = name; } - private _removeLink(parent: DirectoryInode | undefined, links: collections.SortedMap, name: string, node: Inode, time = this.time()) { + private _removeLink( + parent: DirectoryInode | undefined, + links: collections.SortedMap, + name: string, + node: Inode, + time = this.time(), + ) { links.delete(name); node.nlink--; node.ctimeMs = time; if (parent) parent.mtimeMs = time; } - private _replaceLink(oldParent: DirectoryInode, oldLinks: collections.SortedMap, oldName: string, newParent: DirectoryInode, newLinks: collections.SortedMap, newName: string, node: Inode, time: number) { + private _replaceLink( + oldParent: DirectoryInode, + oldLinks: collections.SortedMap, + oldName: string, + newParent: DirectoryInode, + newLinks: collections.SortedMap, + newName: string, + node: Inode, + time: number, + ) { if (oldParent !== newParent) { this._removeLink(oldParent, oldLinks, oldName, node, time); this._addLink(newParent, newLinks, newName, node, time); @@ -1033,9 +1159,21 @@ namespace vfs { * * @link http://man7.org/linux/man-pages/man7/path_resolution.7.html */ - private _walk(path: string, noFollow?: boolean, onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "retry" | "throw"): WalkResult; - private _walk(path: string, noFollow?: boolean, onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw"): WalkResult | undefined; - private _walk(path: string, noFollow?: boolean, onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw"): WalkResult | undefined { + private _walk( + path: string, + noFollow?: boolean, + onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "retry" | "throw", + ): WalkResult; + private _walk( + path: string, + noFollow?: boolean, + onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw", + ): WalkResult | undefined; + private _walk( + path: string, + noFollow?: boolean, + onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw", + ): WalkResult | undefined { let links = this._getRootLinks(); let parent: DirectoryInode | undefined; let components = vpath.parse(path); @@ -1083,7 +1221,8 @@ namespace vfs { function trapError(error: NodeJS.ErrnoException, node?: Inode) { const realpath = vpath.format(components.slice(0, step + 1)); const basename = components[step]; - const result = !retry && onError ? onError(error, { realpath, basename, parent, links, node }) : "throw"; + const result = !retry && onError ? onError(error, { realpath, basename, parent, links, node }) + : "throw"; if (result === "stop") return false; if (result === "retry") { retry = true; @@ -1098,7 +1237,13 @@ namespace vfs { */ private _resolve(path: string) { return this._cwd - ? vpath.resolve(this._cwd, vpath.validate(path, vpath.ValidationFlags.RelativeOrAbsolute | vpath.ValidationFlags.AllowWildcard)) + ? vpath.resolve( + this._cwd, + vpath.validate( + path, + vpath.ValidationFlags.RelativeOrAbsolute | vpath.ValidationFlags.AllowWildcard, + ), + ) : vpath.validate(path, vpath.ValidationFlags.Absolute | vpath.ValidationFlags.AllowWildcard); } @@ -1248,7 +1393,11 @@ namespace vfs { * * Unless overridden, `/.src` will be the current working directory for the virtual file system. */ - export function createFromFileSystem(host: FileSystemResolverHost, ignoreCase: boolean, { documents, files, cwd, time, meta }: FileSystemCreateOptions = {}) { + export function createFromFileSystem( + host: FileSystemResolverHost, + ignoreCase: boolean, + { documents, files, cwd, time, meta }: FileSystemCreateOptions = {}, + ) { const fs = getBuiltLocal(host, ignoreCase).shadow(); if (meta) { for (const key of Object.keys(meta)) { @@ -1304,8 +1453,34 @@ namespace vfs { public birthtime: Date; constructor(); - constructor(dev: number, ino: number, mode: number, nlink: number, rdev: number, size: number, blksize: number, blocks: number, atimeMs: number, mtimeMs: number, ctimeMs: number, birthtimeMs: number); - constructor(dev = 0, ino = 0, mode = 0, nlink = 0, rdev = 0, size = 0, blksize = 0, blocks = 0, atimeMs = 0, mtimeMs = 0, ctimeMs = 0, birthtimeMs = 0) { + constructor( + dev: number, + ino: number, + mode: number, + nlink: number, + rdev: number, + size: number, + blksize: number, + blocks: number, + atimeMs: number, + mtimeMs: number, + ctimeMs: number, + birthtimeMs: number, + ); + constructor( + dev = 0, + ino = 0, + mode = 0, + nlink = 0, + rdev = 0, + size = 0, + blksize = 0, + blocks = 0, + atimeMs = 0, + mtimeMs = 0, + ctimeMs = 0, + birthtimeMs = 0, + ) { this.dev = dev; this.ino = ino; this.mode = mode; @@ -1396,7 +1571,10 @@ namespace vfs { public readonly data: Buffer | string; public readonly encoding: string | undefined; public readonly meta: Record | undefined; - constructor(data: Buffer | string, { meta, encoding }: { encoding?: string; meta?: Record; } = {}) { + constructor( + data: Buffer | string, + { meta, encoding }: { encoding?: string; meta?: Record; } = {}, + ) { this.data = data; this.encoding = encoding; this.meta = meta; @@ -1568,15 +1746,15 @@ namespace vfs { /* eslint-disable no-null/no-null */ function normalizeFileSetEntry(value: FileSet[string]) { if ( - value === undefined || - value === null || - value instanceof Directory || - value instanceof File || - value instanceof Link || - value instanceof Symlink || - value instanceof Mount || - value instanceof Rmdir || - value instanceof Unlink + value === undefined + || value === null + || value instanceof Directory + || value instanceof File + || value instanceof Link + || value instanceof Symlink + || value instanceof Mount + || value instanceof Rmdir + || value instanceof Unlink ) { return value; } diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 0070496599693..396b525fce7d2 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -30,11 +30,17 @@ interface Array { length: number; [n: number]: T; }`, inodeWatching?: boolean; } - export function createWatchedSystem(fileOrFolderList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], params?: TestServerHostCreationParameters): TestServerHost { + export function createWatchedSystem( + fileOrFolderList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], + params?: TestServerHostCreationParameters, + ): TestServerHost { return new TestServerHost(fileOrFolderList, params); } - export function createServerHost(fileOrFolderList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], params?: TestServerHostCreationParameters): TestServerHost { + export function createServerHost( + fileOrFolderList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], + params?: TestServerHostCreationParameters, + ): TestServerHost { const host = new TestServerHost(fileOrFolderList, params); // Just like sys, patch the host to use writeFile patchWriteFileEnsuringDirectory(host); @@ -154,14 +160,36 @@ interface Array { length: number; [n: number]: T; }`, } export function verifyMapSize(caption: string, map: ESMap, expectedKeys: readonly string[]) { - assert.equal(map.size, expectedKeys.length, `${caption}: incorrect size of map: Actual keys: ${arrayFrom(map.keys())} Expected: ${expectedKeys}${getDiffInKeys(map, expectedKeys)}`); + assert.equal( + map.size, + expectedKeys.length, + `${caption}: incorrect size of map: Actual keys: ${arrayFrom(map.keys())} Expected: ${expectedKeys}${ + getDiffInKeys(map, expectedKeys) + }`, + ); } export type MapValueTester = [ESMap | undefined, (value: T) => U]; - export function checkMap(caption: string, actual: MultiMap, expectedKeys: ReadonlyESMap, valueTester?: MapValueTester): void; - export function checkMap(caption: string, actual: MultiMap, expectedKeys: readonly string[], eachKeyCount: number, valueTester?: MapValueTester): void; - export function checkMap(caption: string, actual: ESMap | MultiMap, expectedKeys: readonly string[], eachKeyCount: undefined): void; + export function checkMap( + caption: string, + actual: MultiMap, + expectedKeys: ReadonlyESMap, + valueTester?: MapValueTester, + ): void; + export function checkMap( + caption: string, + actual: MultiMap, + expectedKeys: readonly string[], + eachKeyCount: number, + valueTester?: MapValueTester, + ): void; + export function checkMap( + caption: string, + actual: ESMap | MultiMap, + expectedKeys: readonly string[], + eachKeyCount: undefined, + ): void; export function checkMap( caption: string, actual: ESMap | MultiMap, @@ -169,17 +197,32 @@ interface Array { length: number; [n: number]: T; }`, eachKeyCountOrValueTester?: number | MapValueTester, valueTester?: MapValueTester, ) { - const expectedKeys = isArray(expectedKeysMapOrArray) ? arrayToMap(expectedKeysMapOrArray, s => s, () => eachKeyCountOrValueTester as number) : expectedKeysMapOrArray; - verifyMapSize(caption, actual, isArray(expectedKeysMapOrArray) ? expectedKeysMapOrArray : arrayFrom(expectedKeys.keys())); + const expectedKeys = isArray(expectedKeysMapOrArray) + ? arrayToMap(expectedKeysMapOrArray, s => s, () => eachKeyCountOrValueTester as number) + : expectedKeysMapOrArray; + verifyMapSize( + caption, + actual, + isArray(expectedKeysMapOrArray) ? expectedKeysMapOrArray : arrayFrom(expectedKeys.keys()), + ); if (!isNumber(eachKeyCountOrValueTester)) { valueTester = eachKeyCountOrValueTester; } const [expectedValues, valueMapper] = valueTester || [undefined, undefined!]; expectedKeys.forEach((count, name) => { - assert.isTrue(actual.has(name), `${caption}: expected to contain ${name}, actual keys: ${arrayFrom(actual.keys())}`); + assert.isTrue( + actual.has(name), + `${caption}: expected to contain ${name}, actual keys: ${arrayFrom(actual.keys())}`, + ); // Check key information only if eachKeyCount is provided if (!isArray(expectedKeysMapOrArray) || eachKeyCountOrValueTester !== undefined) { - assert.equal((actual as MultiMap).get(name)!.length, count, `${caption}: Expected to be have ${count} entries for ${name}. Actual entry: ${JSON.stringify(actual.get(name))}`); + assert.equal( + (actual as MultiMap).get(name)!.length, + count, + `${caption}: Expected to be have ${count} entries for ${name}. Actual entry: ${ + JSON.stringify(actual.get(name)) + }`, + ); if (expectedValues) { assert.deepEqual( (actual as MultiMap).get(name)!.map(valueMapper), @@ -205,7 +248,13 @@ interface Array { length: number; [n: number]: T; }`, mapSeen.add(f); } } - assert.equal(mapExpected.size, 0, `Output has missing ${JSON.stringify(arrayFrom(mapExpected.keys()))} in ${JSON.stringify(host.getOutput())}`); + assert.equal( + mapExpected.size, + 0, + `Output has missing ${JSON.stringify(arrayFrom(mapExpected.keys()))} in ${ + JSON.stringify(host.getOutput()) + }`, + ); } export function checkOutputDoesNotContain(host: TestServerHost, expectedToBeAbsent: string[] | readonly string[]) { @@ -459,9 +508,9 @@ interface Array { length: number; [n: number]: T; }`, if (isArray(fileOrFolderOrSymLinkList)) { fileOrFolderOrSymLinkList.forEach(f => this.ensureFileOrFolder( - !this.windowsStyleRoot ? - f : - { ...f, path: this.getHostSpecificPath(f.path) }, + !this.windowsStyleRoot + ? f + : { ...f, path: this.getHostSpecificPath(f.path) }, ) ); } @@ -490,7 +539,12 @@ interface Array { length: number; [n: number]: T; }`, if (options && options.invokeFileDeleteCreateAsPartInsteadOfChange) { this.removeFileOrFolder(currentEntry, /*isRenaming*/ false, options); - this.ensureFileOrFolder({ path: filePath, content }, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ undefined, /*ignoreParentWatch*/ undefined, options); + this.ensureFileOrFolder( + { path: filePath, content }, + /*ignoreWatchInvokedWithTriggerAsFileCreate*/ undefined, + /*ignoreParentWatch*/ undefined, + options, + ); } else { currentEntry.content = content; @@ -499,11 +553,28 @@ interface Array { length: number; [n: number]: T; }`, if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) { const directoryFullPath = getDirectoryPath(currentEntry.fullPath); this.invokeFileWatcher(directoryFullPath, FileWatcherEventKind.Changed, currentEntry.modifiedTime); - this.invokeFsWatchesCallbacks(directoryFullPath, "rename", currentEntry.modifiedTime, currentEntry.fullPath, options.useTildeAsSuffixInRenameEventFileName); - this.invokeRecursiveFsWatches(directoryFullPath, "rename", currentEntry.modifiedTime, currentEntry.fullPath, options.useTildeAsSuffixInRenameEventFileName); + this.invokeFsWatchesCallbacks( + directoryFullPath, + "rename", + currentEntry.modifiedTime, + currentEntry.fullPath, + options.useTildeAsSuffixInRenameEventFileName, + ); + this.invokeRecursiveFsWatches( + directoryFullPath, + "rename", + currentEntry.modifiedTime, + currentEntry.fullPath, + options.useTildeAsSuffixInRenameEventFileName, + ); } else { - this.invokeFileAndFsWatches(currentEntry.fullPath, FileWatcherEventKind.Changed, currentEntry.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName); + this.invokeFileAndFsWatches( + currentEntry.fullPath, + FileWatcherEventKind.Changed, + currentEntry.modifiedTime, + options?.useTildeAsSuffixInRenameEventFileName, + ); } } } @@ -570,7 +641,12 @@ interface Array { length: number; [n: number]: T; }`, } } - ensureFileOrFolder(fileOrDirectoryOrSymLink: FileOrFolderOrSymLink, ignoreWatchInvokedWithTriggerAsFileCreate?: boolean, ignoreParentWatch?: boolean, options?: Partial) { + ensureFileOrFolder( + fileOrDirectoryOrSymLink: FileOrFolderOrSymLink, + ignoreWatchInvokedWithTriggerAsFileCreate?: boolean, + ignoreParentWatch?: boolean, + options?: Partial, + ) { if (isFile(fileOrDirectoryOrSymLink)) { const file = this.toFsFile(fileOrDirectoryOrSymLink); // file may already exist when updating existing type declaration file @@ -592,7 +668,11 @@ interface Array { length: number; [n: number]: T; }`, } } - private ensureFolder(fullPath: string, ignoreWatch: boolean | undefined, options: Partial | undefined): FsFolder { + private ensureFolder( + fullPath: string, + ignoreWatch: boolean | undefined, + options: Partial | undefined, + ): FsFolder { const path = this.toPath(fullPath); let folder = this.fs.get(path) as FsFolder; if (!folder) { @@ -614,9 +694,18 @@ interface Array { length: number; [n: number]: T; }`, return folder; } - private addFileOrFolderInFolder(folder: FsFolder, fileOrDirectory: FsFile | FsFolder | FsSymLink, ignoreWatch?: boolean, options?: Partial) { + private addFileOrFolderInFolder( + folder: FsFolder, + fileOrDirectory: FsFile | FsFolder | FsSymLink, + ignoreWatch?: boolean, + options?: Partial, + ) { if (!this.fs.has(fileOrDirectory.path)) { - insertSorted(folder.entries, fileOrDirectory, (a, b) => compareStringsCaseSensitive(getBaseFileName(a.path), getBaseFileName(b.path))); + insertSorted( + folder.entries, + fileOrDirectory, + (a, b) => compareStringsCaseSensitive(getBaseFileName(a.path), getBaseFileName(b.path)), + ); } folder.modifiedTime = this.now(); this.fs.set(fileOrDirectory.path, fileOrDirectory); @@ -627,12 +716,26 @@ interface Array { length: number; [n: number]: T; }`, } const inodeWatching = this.inodeWatching; if (options?.skipInodeCheckOnCreate) this.inodeWatching = false; - this.invokeFileAndFsWatches(fileOrDirectory.fullPath, FileWatcherEventKind.Created, fileOrDirectory.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName); - this.invokeFileAndFsWatches(folder.fullPath, FileWatcherEventKind.Changed, fileOrDirectory.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName); + this.invokeFileAndFsWatches( + fileOrDirectory.fullPath, + FileWatcherEventKind.Created, + fileOrDirectory.modifiedTime, + options?.useTildeAsSuffixInRenameEventFileName, + ); + this.invokeFileAndFsWatches( + folder.fullPath, + FileWatcherEventKind.Changed, + fileOrDirectory.modifiedTime, + options?.useTildeAsSuffixInRenameEventFileName, + ); this.inodeWatching = inodeWatching; } - private removeFileOrFolder(fileOrDirectory: FsFile | FsFolder | FsSymLink, isRenaming?: boolean, options?: Partial) { + private removeFileOrFolder( + fileOrDirectory: FsFile | FsFolder | FsSymLink, + isRenaming?: boolean, + options?: Partial, + ) { const basePath = getDirectoryPath(fileOrDirectory.path); const baseFolder = this.fs.get(basePath) as FsFolder; if (basePath !== fileOrDirectory.path) { @@ -645,9 +748,23 @@ interface Array { length: number; [n: number]: T; }`, if (isFsFolder(fileOrDirectory)) { Debug.assert(fileOrDirectory.entries.length === 0 || isRenaming); } - if (!options?.ignoreDelete) this.invokeFileAndFsWatches(fileOrDirectory.fullPath, FileWatcherEventKind.Deleted, /*modifiedTime*/ undefined, options?.useTildeAsSuffixInRenameEventFileName); + if (!options?.ignoreDelete) { + this.invokeFileAndFsWatches( + fileOrDirectory.fullPath, + FileWatcherEventKind.Deleted, + /*modifiedTime*/ undefined, + options?.useTildeAsSuffixInRenameEventFileName, + ); + } this.inodes?.delete(fileOrDirectory.path); - if (!options?.ignoreDelete) this.invokeFileAndFsWatches(baseFolder.fullPath, FileWatcherEventKind.Changed, baseFolder.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName); + if (!options?.ignoreDelete) { + this.invokeFileAndFsWatches( + baseFolder.fullPath, + FileWatcherEventKind.Changed, + baseFolder.modifiedTime, + options?.useTildeAsSuffixInRenameEventFileName, + ); + } } deleteFile(filePath: string) { @@ -688,7 +805,9 @@ interface Array { length: number; [n: number]: T; }`, recursive: boolean, cb: FsWatchCallback, ) { - if (this.runWithFallbackPolling) throw new Error("Need to use fallback polling instead of file system native watching"); + if (this.runWithFallbackPolling) { + throw new Error("Need to use fallback polling instead of file system native watching"); + } const path = this.toFullPath(fileOrDirectory); // Error if the path does not exist if (this.inodeWatching && !this.inodes?.has(path)) throw new Error(); @@ -705,50 +824,126 @@ interface Array { length: number; [n: number]: T; }`, } invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, modifiedTime: Date | undefined) { - invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath)), ({ cb }) => cb(fileFullPath, eventKind, modifiedTime)); + invokeWatcherCallbacks( + this.watchedFiles.get(this.toPath(fileFullPath)), + ({ cb }) => cb(fileFullPath, eventKind, modifiedTime), + ); } - private fsWatchCallback(map: MultiMap, fullPath: string, eventName: "rename" | "change", modifiedTime: Date | undefined, entryFullPath: string | undefined, useTildeSuffix: boolean | undefined) { + private fsWatchCallback( + map: MultiMap, + fullPath: string, + eventName: "rename" | "change", + modifiedTime: Date | undefined, + entryFullPath: string | undefined, + useTildeSuffix: boolean | undefined, + ) { const path = this.toPath(fullPath); const currentInode = this.inodes?.get(path); invokeWatcherCallbacks(map.get(path), ({ cb, inode }) => { // TODO:: if (this.inodeWatching && inode !== undefined && inode !== currentInode) return; let relativeFileName = (entryFullPath ? this.getRelativePathToDirectory(fullPath, entryFullPath) : ""); - if (useTildeSuffix) relativeFileName = (relativeFileName ? relativeFileName : getBaseFileName(fullPath)) + "~"; + if (useTildeSuffix) { + relativeFileName = (relativeFileName ? relativeFileName : getBaseFileName(fullPath)) + "~"; + } cb(eventName, relativeFileName, modifiedTime); }); } - invokeFsWatchesCallbacks(fullPath: string, eventName: "rename" | "change", modifiedTime?: Date, entryFullPath?: string, useTildeSuffix?: boolean) { + invokeFsWatchesCallbacks( + fullPath: string, + eventName: "rename" | "change", + modifiedTime?: Date, + entryFullPath?: string, + useTildeSuffix?: boolean, + ) { this.fsWatchCallback(this.fsWatches, fullPath, eventName, modifiedTime, entryFullPath, useTildeSuffix); } - invokeFsWatchesRecursiveCallbacks(fullPath: string, eventName: "rename" | "change", modifiedTime?: Date, entryFullPath?: string, useTildeSuffix?: boolean) { - this.fsWatchCallback(this.fsWatchesRecursive, fullPath, eventName, modifiedTime, entryFullPath, useTildeSuffix); + invokeFsWatchesRecursiveCallbacks( + fullPath: string, + eventName: "rename" | "change", + modifiedTime?: Date, + entryFullPath?: string, + useTildeSuffix?: boolean, + ) { + this.fsWatchCallback( + this.fsWatchesRecursive, + fullPath, + eventName, + modifiedTime, + entryFullPath, + useTildeSuffix, + ); } private getRelativePathToDirectory(directoryFullPath: string, fileFullPath: string) { - return getRelativePathToDirectoryOrUrl(directoryFullPath, fileFullPath, this.currentDirectory, this.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); + return getRelativePathToDirectoryOrUrl( + directoryFullPath, + fileFullPath, + this.currentDirectory, + this.getCanonicalFileName, + /*isAbsolutePathAnUrl*/ false, + ); } - private invokeRecursiveFsWatches(fullPath: string, eventName: "rename" | "change", modifiedTime?: Date, entryFullPath?: string, useTildeSuffix?: boolean) { + private invokeRecursiveFsWatches( + fullPath: string, + eventName: "rename" | "change", + modifiedTime?: Date, + entryFullPath?: string, + useTildeSuffix?: boolean, + ) { this.invokeFsWatchesRecursiveCallbacks(fullPath, eventName, modifiedTime, entryFullPath, useTildeSuffix); const basePath = getDirectoryPath(fullPath); if (this.getCanonicalFileName(fullPath) !== this.getCanonicalFileName(basePath)) { - this.invokeRecursiveFsWatches(basePath, eventName, modifiedTime, entryFullPath || fullPath, useTildeSuffix); + this.invokeRecursiveFsWatches( + basePath, + eventName, + modifiedTime, + entryFullPath || fullPath, + useTildeSuffix, + ); } } - private invokeFsWatches(fullPath: string, eventName: "rename" | "change", modifiedTime: Date | undefined, useTildeSuffix: boolean | undefined) { + private invokeFsWatches( + fullPath: string, + eventName: "rename" | "change", + modifiedTime: Date | undefined, + useTildeSuffix: boolean | undefined, + ) { this.invokeFsWatchesCallbacks(fullPath, eventName, modifiedTime, fullPath, useTildeSuffix); - this.invokeFsWatchesCallbacks(getDirectoryPath(fullPath), eventName, modifiedTime, fullPath, useTildeSuffix); - this.invokeRecursiveFsWatches(fullPath, eventName, modifiedTime, /*entryFullPath*/ undefined, useTildeSuffix); + this.invokeFsWatchesCallbacks( + getDirectoryPath(fullPath), + eventName, + modifiedTime, + fullPath, + useTildeSuffix, + ); + this.invokeRecursiveFsWatches( + fullPath, + eventName, + modifiedTime, + /*entryFullPath*/ undefined, + useTildeSuffix, + ); } - private invokeFileAndFsWatches(fileOrFolderFullPath: string, eventKind: FileWatcherEventKind, modifiedTime?: Date, useTildeSuffix?: boolean) { + private invokeFileAndFsWatches( + fileOrFolderFullPath: string, + eventKind: FileWatcherEventKind, + modifiedTime?: Date, + useTildeSuffix?: boolean, + ) { this.invokeFileWatcher(fileOrFolderFullPath, eventKind, modifiedTime); - this.invokeFsWatches(fileOrFolderFullPath, eventKind === FileWatcherEventKind.Changed ? "change" : "rename", modifiedTime, useTildeSuffix); + this.invokeFsWatches( + fileOrFolderFullPath, + eventKind === FileWatcherEventKind.Changed ? "change" : "rename", + modifiedTime, + useTildeSuffix, + ); } private toFsEntry(path: string): FSEntryBase { @@ -779,7 +974,11 @@ interface Array { length: number; [n: number]: T; }`, return fsFolder; } - private getRealFsEntry(isFsEntry: (fsEntry: FSEntry) => fsEntry is T, path: Path, fsEntry = this.fs.get(path)!): T | undefined { + private getRealFsEntry( + isFsEntry: (fsEntry: FSEntry) => fsEntry is T, + path: Path, + fsEntry = this.fs.get(path)!, + ): T | undefined { if (isFsEntry(fsEntry)) { return fsEntry; } @@ -864,32 +1063,51 @@ interface Array { length: number; [n: number]: T; }`, const path = this.toFullPath(s); const folder = this.getRealFolder(path); if (folder) { - return mapDefined(folder.entries, entry => this.isFsFolder(entry) ? getBaseFileName(entry.fullPath) : undefined); + return mapDefined( + folder.entries, + entry => this.isFsFolder(entry) ? getBaseFileName(entry.fullPath) : undefined, + ); } Debug.fail(folder ? "getDirectories called on file" : "getDirectories called on missing folder"); return []; } - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { - return matchFiles(path, extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), depth, dir => { - const directories: string[] = []; - const files: string[] = []; - const folder = this.getRealFolder(this.toPath(dir)); - if (folder) { - folder.entries.forEach(entry => { - if (this.isFsFolder(entry)) { - directories.push(getBaseFileName(entry.fullPath)); - } - else if (this.isFsFile(entry)) { - files.push(getBaseFileName(entry.fullPath)); - } - else { - Debug.fail("Unknown entry"); - } - }); - } - return { directories, files }; - }, path => this.realpath(path)); + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { + return matchFiles( + path, + extensions, + exclude, + include, + this.useCaseSensitiveFileNames, + this.getCurrentDirectory(), + depth, + dir => { + const directories: string[] = []; + const files: string[] = []; + const folder = this.getRealFolder(this.toPath(dir)); + if (folder) { + folder.entries.forEach(entry => { + if (this.isFsFolder(entry)) { + directories.push(getBaseFileName(entry.fullPath)); + } + else if (this.isFsFile(entry)) { + files.push(getBaseFileName(entry.fullPath)); + } + else { + Debug.fail("Unknown entry"); + } + }); + } + return { directories, files }; + }, + path => this.realpath(path), + ); } createHash(s: string): string { @@ -924,7 +1142,11 @@ interface Array { length: number; [n: number]: T; }`, checkTimeoutQueueLength(expected: number) { const callbacksCount = this.timeoutCallbacks.count(); - assert.equal(callbacksCount, expected, `expected ${expected} timeout callbacks queued but found ${callbacksCount}.`); + assert.equal( + callbacksCount, + expected, + `expected ${expected} timeout callbacks queued but found ${callbacksCount}.`, + ); } runQueuedTimeoutCallbacks(timeoutId?: number) { @@ -1099,7 +1321,13 @@ interface Array { length: number; [n: number]: T; }`, function inodeString(inode: number | undefined) { return inode !== undefined ? ` Inode:: ${inode}` : ""; } - function diffFsEntry(baseline: string[], oldFsEntry: FSEntry | undefined, newFsEntry: FSEntry | undefined, newInode: number | undefined, writtenFiles: ESMap | undefined): void { + function diffFsEntry( + baseline: string[], + oldFsEntry: FSEntry | undefined, + newFsEntry: FSEntry | undefined, + newInode: number | undefined, + writtenFiles: ESMap | undefined, + ): void { const file = newFsEntry && newFsEntry.fullPath; if (isFsFile(oldFsEntry)) { if (isFsFile(newFsEntry)) { @@ -1108,7 +1336,9 @@ interface Array { length: number; [n: number]: T; }`, } else if (oldFsEntry.modifiedTime !== newFsEntry.modifiedTime) { if (oldFsEntry.fullPath !== newFsEntry.fullPath) { - baseline.push(`//// [${file}] file was renamed from file ${oldFsEntry.fullPath}${inodeString(newInode)}`); + baseline.push( + `//// [${file}] file was renamed from file ${oldFsEntry.fullPath}${inodeString(newInode)}`, + ); } else if (writtenFiles && !writtenFiles.has(newFsEntry.path)) { baseline.push(`//// [${file}] file changed its modified time${inodeString(newInode)}`); @@ -1132,7 +1362,11 @@ interface Array { length: number; [n: number]: T; }`, } else if (oldFsEntry.modifiedTime !== newFsEntry.modifiedTime) { if (oldFsEntry.fullPath !== newFsEntry.fullPath) { - baseline.push(`//// [${file}] symlink was renamed from symlink ${oldFsEntry.fullPath}${inodeString(newInode)}`); + baseline.push( + `//// [${file}] symlink was renamed from symlink ${oldFsEntry.fullPath}${ + inodeString(newInode) + }`, + ); } else if (writtenFiles && !writtenFiles.has(newFsEntry.path)) { baseline.push(`//// [${file}] symlink changed its modified time${inodeString(newInode)}`); diff --git a/src/harness/vpathUtil.ts b/src/harness/vpathUtil.ts index ec573861fbb4d..5533f2f578528 100644 --- a/src/harness/vpathUtil.ts +++ b/src/harness/vpathUtil.ts @@ -52,10 +52,12 @@ namespace vpath { Root = RequireRoot | AllowRoot | AllowTrailingSeparator, /** Path must be a absolute */ - Absolute = RequireRoot | AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator | AllowNavigation, + Absolute = RequireRoot | AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator + | AllowNavigation, /** Path may be relative or absolute */ - RelativeOrAbsolute = AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator | AllowNavigation, + RelativeOrAbsolute = AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator + | AllowNavigation, /** Path may only be a filename */ Basename = RequireBasename | AllowExtname, @@ -67,8 +69,10 @@ namespace vpath { const hasBasename = components.length > 1; const hasExtname = hasBasename && extRegExp.test(components[components.length - 1]); const invalidComponentRegExp = flags & ValidationFlags.AllowNavigation - ? flags & ValidationFlags.AllowWildcard ? invalidNavigableComponentWithWildcardsRegExp : invalidNavigableComponentRegExp - : flags & ValidationFlags.AllowWildcard ? invalidNonNavigableComponentWithWildcardsRegExp : invalidNonNavigableComponentRegExp; + ? flags & ValidationFlags.AllowWildcard ? invalidNavigableComponentWithWildcardsRegExp + : invalidNavigableComponentRegExp + : flags & ValidationFlags.AllowWildcard ? invalidNonNavigableComponentWithWildcardsRegExp + : invalidNonNavigableComponentRegExp; // Validate required components if (flags & ValidationFlags.RequireRoot && !hasRoot) return false; diff --git a/src/jsTyping/jsTyping.ts b/src/jsTyping/jsTyping.ts index 6ae6927d7dd64..1f7683764eceb 100644 --- a/src/jsTyping/jsTyping.ts +++ b/src/jsTyping/jsTyping.ts @@ -4,7 +4,13 @@ namespace ts.JsTyping { directoryExists(path: string): boolean; fileExists(fileName: string): boolean; readFile(path: string, encoding?: string): string | undefined; - readDirectory(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[] | undefined, depth?: number): string[]; + readDirectory( + rootDir: string, + extensions: readonly string[], + excludes: readonly string[] | undefined, + includes: readonly string[] | undefined, + depth?: number, + ): string[]; } interface PackageJson { @@ -23,7 +29,10 @@ namespace ts.JsTyping { } export function isTypingUpToDate(cachedTyping: CachedTyping, availableTypingVersions: MapLike) { - const availableVersion = new Version(getProperty(availableTypingVersions, `ts${versionMajorMinor}`) || getProperty(availableTypingVersions, "latest")!); + const availableVersion = new Version( + getProperty(availableTypingVersions, `ts${versionMajorMinor}`) + || getProperty(availableTypingVersions, "latest")!, + ); return availableVersion.compareTo(cachedTyping.version) <= 0; } @@ -79,7 +88,10 @@ namespace ts.JsTyping { export const prefixedNodeCoreModuleList = unprefixedNodeCoreModuleList.map(name => `node:${name}`); - export const nodeCoreModuleList: readonly string[] = [...unprefixedNodeCoreModuleList, ...prefixedNodeCoreModuleList]; + export const nodeCoreModuleList: readonly string[] = [ + ...unprefixedNodeCoreModuleList, + ...prefixedNodeCoreModuleList, + ]; export const nodeCoreModules = new Set(nodeCoreModuleList); @@ -171,7 +183,10 @@ namespace ts.JsTyping { // Add the cached typing locations for inferred typings that are already installed packageNameToTypingLocation.forEach((typing, name) => { const registryEntry = typesRegistry.get(name); - if (inferredTypings.has(name) && inferredTypings.get(name) === undefined && registryEntry !== undefined && isTypingUpToDate(typing, registryEntry)) { + if ( + inferredTypings.has(name) && inferredTypings.get(name) === undefined && registryEntry !== undefined + && isTypingUpToDate(typing, registryEntry) + ) { inferredTypings.set(name, typing.typingLocation); } }); @@ -214,7 +229,12 @@ namespace ts.JsTyping { * @param modulesDirName is the directory name for modules (node_modules or bower_components). Should be lowercase! * @param filesToWatch are the files to watch for changes. We will push things into this array. */ - function getTypingNames(projectRootPath: string, manifestName: string, modulesDirName: string, filesToWatch: string[]): void { + function getTypingNames( + projectRootPath: string, + manifestName: string, + modulesDirName: string, + filesToWatch: string[], + ): void { // First, we check the manifests themselves. They're not // _required_, but they allow us to do some filtering when dealing // with big flat dep directories. @@ -224,7 +244,12 @@ namespace ts.JsTyping { if (host.fileExists(manifestPath)) { filesToWatch.push(manifestPath); manifest = readConfigFile(manifestPath, path => host.readFile(path)).config; - manifestTypingNames = flatMap([manifest.dependencies, manifest.devDependencies, manifest.optionalDependencies, manifest.peerDependencies], getOwnKeys); + manifestTypingNames = flatMap([ + manifest.dependencies, + manifest.devDependencies, + manifest.optionalDependencies, + manifest.peerDependencies, + ], getOwnKeys); addInferredTypings(manifestTypingNames, `Typing names in '${manifestPath}' dependencies`); } @@ -257,7 +282,13 @@ namespace ts.JsTyping { // This is #1 described above. ? manifestTypingNames.map(typingName => combinePaths(packagesFolderPath, typingName, manifestName)) // And #2. Depth = 3 because scoped packages look like `node_modules/@foo/bar/package.json` - : host.readDirectory(packagesFolderPath, [Extension.Json], /*excludes*/ undefined, /*includes*/ undefined, /*depth*/ 3) + : host.readDirectory( + packagesFolderPath, + [Extension.Json], + /*excludes*/ undefined, + /*includes*/ undefined, + /*depth*/ 3, + ) .filter(manifestPath => { if (getBaseFileName(manifestPath) !== manifestName) { return false; @@ -269,11 +300,15 @@ namespace ts.JsTyping { // packages. So that needs this dance here. const pathComponents = getPathComponents(normalizePath(manifestPath)); const isScoped = pathComponents[pathComponents.length - 3][0] === "@"; - return isScoped && pathComponents[pathComponents.length - 4].toLowerCase() === modulesDirName || // `node_modules/@foo/bar` - !isScoped && pathComponents[pathComponents.length - 3].toLowerCase() === modulesDirName; // `node_modules/foo` + return isScoped && pathComponents[pathComponents.length - 4].toLowerCase() === modulesDirName // `node_modules/@foo/bar` + || !isScoped && pathComponents[pathComponents.length - 3].toLowerCase() === modulesDirName; // `node_modules/foo` }); - if (log) log(`Searching for typing names in ${packagesFolderPath}; all files: ${JSON.stringify(dependencyManifestNames)}`); + if (log) { + log(`Searching for typing names in ${packagesFolderPath}; all files: ${ + JSON.stringify(dependencyManifestNames) + }`); + } // Once we have the names of things to look up, we iterate over // and either collect their included typings, or add them to the @@ -360,7 +395,10 @@ namespace ts.JsTyping { function validatePackageNameWorker(packageName: string, supportScopedPackage: false): NameValidationResult; function validatePackageNameWorker(packageName: string, supportScopedPackage: true): PackageNameValidationResult; - function validatePackageNameWorker(packageName: string, supportScopedPackage: boolean): PackageNameValidationResult { + function validatePackageNameWorker( + packageName: string, + supportScopedPackage: boolean, + ): PackageNameValidationResult { if (!packageName) { return NameValidationResult.EmptyName; } @@ -396,12 +434,17 @@ namespace ts.JsTyping { } export function renderPackageNameValidationFailure(result: PackageNameValidationResult, typing: string): string { - return typeof result === "object" ? - renderPackageNameValidationFailureWorker(typing, result.result, result.name, result.isScopeName) : - renderPackageNameValidationFailureWorker(typing, result, typing, /*isScopeName*/ false); + return typeof result === "object" + ? renderPackageNameValidationFailureWorker(typing, result.result, result.name, result.isScopeName) + : renderPackageNameValidationFailureWorker(typing, result, typing, /*isScopeName*/ false); } - function renderPackageNameValidationFailureWorker(typing: string, result: NameValidationResult, name: string, isScopeName: boolean): string { + function renderPackageNameValidationFailureWorker( + typing: string, + result: NameValidationResult, + name: string, + isScopeName: boolean, + ): string { const kind = isScopeName ? "Scope" : "Package"; switch (result) { case NameValidationResult.EmptyName: diff --git a/src/jsTyping/shared.ts b/src/jsTyping/shared.ts index b41d3d0c455af..b1a92ae3fd26a 100644 --- a/src/jsTyping/shared.ts +++ b/src/jsTyping/shared.ts @@ -57,6 +57,8 @@ namespace ts.server { export function nowString() { // E.g. "12:34:56.789" const d = new Date(); - return `${padLeft(d.getHours().toString(), 2, "0")}:${padLeft(d.getMinutes().toString(), 2, "0")}:${padLeft(d.getSeconds().toString(), 2, "0")}.${padLeft(d.getMilliseconds().toString(), 3, "0")}`; + return `${padLeft(d.getHours().toString(), 2, "0")}:${padLeft(d.getMinutes().toString(), 2, "0")}:${ + padLeft(d.getSeconds().toString(), 2, "0") + }.${padLeft(d.getMilliseconds().toString(), 3, "0")}`; } } diff --git a/src/jsTyping/types.ts b/src/jsTyping/types.ts index 26d2c69795d96..33740bb7a5b63 100644 --- a/src/jsTyping/types.ts +++ b/src/jsTyping/types.ts @@ -1,6 +1,13 @@ declare namespace ts.server { export interface TypingInstallerResponse { - readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed; + readonly kind: + | ActionSet + | ActionInvalidate + | EventTypesRegistry + | ActionPackageInstalled + | EventBeginInstallTypes + | EventEndInstallTypes + | EventInitializationFailed; } export interface TypingInstallerRequestWithProjectName { @@ -8,7 +15,11 @@ declare namespace ts.server { } /* @internal */ - export type TypingInstallerRequestUnion = DiscoverTypings | CloseProject | TypesRegistryRequest | InstallPackageRequest; + export type TypingInstallerRequestUnion = + | DiscoverTypings + | CloseProject + | TypesRegistryRequest + | InstallPackageRequest; export interface DiscoverTypings extends TypingInstallerRequestWithProjectName { readonly fileNames: string[]; @@ -84,8 +95,18 @@ declare namespace ts.server { writeFile(path: string, content: string): void; createDirectory(path: string): void; getCurrentDirectory?(): string; - watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; - watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; + watchFile?( + path: string, + callback: FileWatcherCallback, + pollingInterval?: number, + options?: WatchOptions, + ): FileWatcher; + watchDirectory?( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher; } export interface SetTypings extends ProjectResponse { @@ -97,5 +118,11 @@ declare namespace ts.server { } /* @internal */ - export type TypingInstallerResponseUnion = SetTypings | InvalidateCachedTypings | TypesRegistryResponse | PackageInstalledResponse | InstallTypes | InitializationFailedResponse; + export type TypingInstallerResponseUnion = + | SetTypings + | InvalidateCachedTypings + | TypesRegistryResponse + | PackageInstalledResponse + | InstallTypes + | InitializationFailedResponse; } diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts index 2ec02979095bb..c823f6cad18b9 100644 --- a/src/lib/es2015.core.d.ts +++ b/src/lib/es2015.core.d.ts @@ -8,7 +8,10 @@ interface Array { * @param thisArg If provided, it will be used as the this value for each invocation of * predicate. If it is not provided, undefined is used instead. */ - find(predicate: (this: void, value: T, index: number, obj: T[]) => value is S, thisArg?: any): S | undefined; + find( + predicate: (this: void, value: T, index: number, obj: T[]) => value is S, + thisArg?: any, + ): S | undefined; find(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): T | undefined; /** @@ -329,7 +332,10 @@ interface ReadonlyArray { * @param thisArg If provided, it will be used as the this value for each invocation of * predicate. If it is not provided, undefined is used instead. */ - find(predicate: (this: void, value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined; + find( + predicate: (this: void, value: T, index: number, obj: readonly T[]) => value is S, + thisArg?: any, + ): S | undefined; find(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined; /** diff --git a/src/lib/es2015.promise.d.ts b/src/lib/es2015.promise.d.ts index e4925d8b14962..3636347d1f1f8 100644 --- a/src/lib/es2015.promise.d.ts +++ b/src/lib/es2015.promise.d.ts @@ -10,7 +10,9 @@ interface PromiseConstructor { * a resolve callback used to resolve the promise with a value or the result of another promise, * and a reject callback used to reject the promise with a provided reason or error. */ - new (executor: (resolve: (value: T | PromiseLike) => void, reject: (reason?: any) => void) => void): Promise; + new ( + executor: (resolve: (value: T | PromiseLike) => void, reject: (reason?: any) => void) => void, + ): Promise; /** * Creates a Promise that is resolved with an array of results when all of the provided Promises diff --git a/src/lib/es2015.reflect.d.ts b/src/lib/es2015.reflect.d.ts index 4f4ddc404f02f..a3f74bbfeeb64 100644 --- a/src/lib/es2015.reflect.d.ts +++ b/src/lib/es2015.reflect.d.ts @@ -34,7 +34,11 @@ declare namespace Reflect { * @param propertyKey The property name. * @param attributes Descriptor for the property. It can be for a data property or an accessor property. */ - function defineProperty(target: object, propertyKey: PropertyKey, attributes: PropertyDescriptor & ThisType): boolean; + function defineProperty( + target: object, + propertyKey: PropertyKey, + attributes: PropertyDescriptor & ThisType, + ): boolean; /** * Removes a property from an object, equivalent to `delete target[propertyKey]`, diff --git a/src/lib/es2015.symbol.wellknown.d.ts b/src/lib/es2015.symbol.wellknown.d.ts index f27dc68850016..bf56343884938 100644 --- a/src/lib/es2015.symbol.wellknown.d.ts +++ b/src/lib/es2015.symbol.wellknown.d.ts @@ -223,14 +223,22 @@ interface String { * @param searchValue An object that supports searching for and replacing matches within a string. * @param replaceValue The replacement text. */ - replace(searchValue: { [Symbol.replace](string: string, replaceValue: string): string; }, replaceValue: string): string; + replace( + searchValue: { [Symbol.replace](string: string, replaceValue: string): string; }, + replaceValue: string, + ): string; /** * Replaces text in a string, using an object that supports replacement within a string. * @param searchValue A object can search for and replace matches within a string. * @param replacer A function that returns the replacement text. */ - replace(searchValue: { [Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string; }, replacer: (substring: string, ...args: any[]) => string): string; + replace( + searchValue: { + [Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string; + }, + replacer: (substring: string, ...args: any[]) => string, + ): string; /** * Finds the first substring match in a regular expression search. diff --git a/src/lib/es2017.object.d.ts b/src/lib/es2017.object.d.ts index 139cc5b81ba39..43e234a3c4dd2 100644 --- a/src/lib/es2017.object.d.ts +++ b/src/lib/es2017.object.d.ts @@ -27,5 +27,7 @@ interface ObjectConstructor { * Returns an object containing all own property descriptors of an object * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object. */ - getOwnPropertyDescriptors(o: T): { [P in keyof T]: TypedPropertyDescriptor; } & { [x: string]: PropertyDescriptor; }; + getOwnPropertyDescriptors( + o: T, + ): { [P in keyof T]: TypedPropertyDescriptor; } & { [x: string]: PropertyDescriptor; }; } diff --git a/src/lib/es2017.sharedmemory.d.ts b/src/lib/es2017.sharedmemory.d.ts index 0d93ba914e09e..77b88af98a408 100644 --- a/src/lib/es2017.sharedmemory.d.ts +++ b/src/lib/es2017.sharedmemory.d.ts @@ -31,28 +31,45 @@ interface Atomics { * Until this atomic operation completes, any other read or write operation against the array * will block. */ - add(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + add( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Stores the bitwise AND of a value with the value at the given position in the array, * returning the original value. Until this atomic operation completes, any other read or * write operation against the array will block. */ - and(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + and( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Replaces the value at the given position in the array if the original value equals the given * expected value, returning the original value. Until this atomic operation completes, any * other read or write operation against the array will block. */ - compareExchange(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, expectedValue: number, replacementValue: number): number; + compareExchange( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + expectedValue: number, + replacementValue: number, + ): number; /** * Replaces the value at the given position in the array, returning the original value. Until * this atomic operation completes, any other read or write operation against the array will * block. */ - exchange(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + exchange( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Returns a value indicating whether high-performance algorithms can use atomic operations @@ -65,27 +82,42 @@ interface Atomics { * Returns the value at the given position in the array. Until this atomic operation completes, * any other read or write operation against the array will block. */ - load(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number): number; + load( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + ): number; /** * Stores the bitwise OR of a value with the value at the given position in the array, * returning the original value. Until this atomic operation completes, any other read or write * operation against the array will block. */ - or(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + or( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Stores a value at the given position in the array, returning the new value. Until this * atomic operation completes, any other read or write operation against the array will block. */ - store(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + store( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Subtracts a value from the value at the given position in the array, returning the original * value. Until this atomic operation completes, any other read or write operation against the * array will block. */ - sub(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + sub( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * If the value at the given position in the array is equal to the provided value, the current @@ -109,7 +141,11 @@ interface Atomics { * returning the original value. Until this atomic operation completes, any other read or write * operation against the array will block. */ - xor(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + xor( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; readonly [Symbol.toStringTag]: "Atomics"; } diff --git a/src/lib/es2018.intl.d.ts b/src/lib/es2018.intl.d.ts index 9dfc84ed364de..345fef902dc23 100644 --- a/src/lib/es2018.intl.d.ts +++ b/src/lib/es2018.intl.d.ts @@ -37,8 +37,29 @@ declare namespace Intl { }; // We can only have one definition for 'type' in TypeScript, and so you can learn where the keys come from here: - type ES2018NumberFormatPartType = "literal" | "nan" | "infinity" | "percent" | "integer" | "group" | "decimal" | "fraction" | "plusSign" | "minusSign" | "percentSign" | "currency" | "code" | "symbol" | "name"; - type ES2020NumberFormatPartType = "compact" | "exponentInteger" | "exponentMinusSign" | "exponentSeparator" | "unit" | "unknown"; + type ES2018NumberFormatPartType = + | "literal" + | "nan" + | "infinity" + | "percent" + | "integer" + | "group" + | "decimal" + | "fraction" + | "plusSign" + | "minusSign" + | "percentSign" + | "currency" + | "code" + | "symbol" + | "name"; + type ES2020NumberFormatPartType = + | "compact" + | "exponentInteger" + | "exponentMinusSign" + | "exponentSeparator" + | "unit" + | "unknown"; type NumberFormatPartTypes = ES2018NumberFormatPartType | ES2020NumberFormatPartType; interface NumberFormatPart { diff --git a/src/lib/es2019.array.d.ts b/src/lib/es2019.array.d.ts index bd3c5cec27712..b8479a36bad67 100644 --- a/src/lib/es2019.array.d.ts +++ b/src/lib/es2019.array.d.ts @@ -1,6 +1,7 @@ type FlatArray = { "done": Arr; - "recur": Arr extends ReadonlyArray ? FlatArray + "recur": Arr extends ReadonlyArray + ? FlatArray : Arr; }[Depth extends -1 ? "done" : "recur"]; diff --git a/src/lib/es2020.bigint.d.ts b/src/lib/es2020.bigint.d.ts index 597b3822792eb..2851cb7994329 100644 --- a/src/lib/es2020.bigint.d.ts +++ b/src/lib/es2020.bigint.d.ts @@ -45,27 +45,132 @@ interface BigIntToLocaleStringOptions { /** * The minimum number of integer digits to use. Possible values are from 1 to 21; the default is 1. */ - minimumIntegerDigits?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21; + minimumIntegerDigits?: + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20 + | 21; /** * The minimum number of fraction digits to use. Possible values are from 0 to 20; the default for plain number and percent formatting is 0; the default for currency formatting is the number of minor unit digits provided by the {@link http://www.currency-iso.org/en/home/tables/table-a1.html ISO 4217 currency codes list} (2 if the list doesn't provide that information). */ - minimumFractionDigits?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; + minimumFractionDigits?: + | 0 + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20; /** * The maximum number of fraction digits to use. Possible values are from 0 to 20; the default for plain number formatting is the larger of minimumFractionDigits and 3; the default for currency formatting is the larger of minimumFractionDigits and the number of minor unit digits provided by the {@link http://www.currency-iso.org/en/home/tables/table-a1.html ISO 4217 currency codes list} (2 if the list doesn't provide that information); the default for percent formatting is the larger of minimumFractionDigits and 0. */ - maximumFractionDigits?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; + maximumFractionDigits?: + | 0 + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20; /** * The minimum number of significant digits to use. Possible values are from 1 to 21; the default is 1. */ - minimumSignificantDigits?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21; + minimumSignificantDigits?: + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20 + | 21; /** * The maximum number of significant digits to use. Possible values are from 1 to 21; the default is 21. */ - maximumSignificantDigits?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21; + maximumSignificantDigits?: + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20 + | 21; /** * The formatting that should be displayed for the number, the defaults is "standard" @@ -271,7 +376,9 @@ interface BigInt64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint): bigint; + reduce( + callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint, + ): bigint; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -283,7 +390,10 @@ interface BigInt64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -295,7 +405,9 @@ interface BigInt64Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint): bigint; + reduceRight( + callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint, + ): bigint; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -307,7 +419,10 @@ interface BigInt64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, + initialValue: U, + ): U; /** Reverses the elements in the array. */ reverse(): this; @@ -465,7 +580,10 @@ interface BigUint64Array { * @param thisArg If provided, it will be used as the this value for each invocation of * predicate. If it is not provided, undefined is used instead. */ - find(predicate: (value: bigint, index: number, array: BigUint64Array) => boolean, thisArg?: any): bigint | undefined; + find( + predicate: (value: bigint, index: number, array: BigUint64Array) => boolean, + thisArg?: any, + ): bigint | undefined; /** * Returns the index of the first element in the array where predicate is true, and -1 @@ -543,7 +661,14 @@ interface BigUint64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigUint64Array) => bigint): bigint; + reduce( + callbackfn: ( + previousValue: bigint, + currentValue: bigint, + currentIndex: number, + array: BigUint64Array, + ) => bigint, + ): bigint; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -555,7 +680,10 @@ interface BigUint64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -567,7 +695,14 @@ interface BigUint64Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigUint64Array) => bigint): bigint; + reduceRight( + callbackfn: ( + previousValue: bigint, + currentValue: bigint, + currentIndex: number, + array: BigUint64Array, + ) => bigint, + ): bigint; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -579,7 +714,10 @@ interface BigUint64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, + initialValue: U, + ): U; /** Reverses the elements in the array. */ reverse(): this; diff --git a/src/lib/es2020.intl.d.ts b/src/lib/es2020.intl.d.ts index 550edaaa6c848..a82f062b61781 100644 --- a/src/lib/es2020.intl.d.ts +++ b/src/lib/es2020.intl.d.ts @@ -82,7 +82,11 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument). */ - type LocalesArgument = UnicodeBCP47LocaleIdentifier | Locale | readonly (UnicodeBCP47LocaleIdentifier | Locale)[] | undefined; + type LocalesArgument = + | UnicodeBCP47LocaleIdentifier + | Locale + | readonly (UnicodeBCP47LocaleIdentifier | Locale)[] + | undefined; /** * An object with some or all of properties of `options` parameter @@ -406,6 +410,9 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/supportedLocalesOf). */ - supportedLocalesOf(locales?: LocalesArgument, options?: { localeMatcher?: RelativeTimeFormatLocaleMatcher; }): BCP47LanguageTag[]; + supportedLocalesOf( + locales?: LocalesArgument, + options?: { localeMatcher?: RelativeTimeFormatLocaleMatcher; }, + ): BCP47LanguageTag[]; }; } diff --git a/src/lib/es2020.promise.d.ts b/src/lib/es2020.promise.d.ts index a4ebc79a8df28..47018b45db8e1 100644 --- a/src/lib/es2020.promise.d.ts +++ b/src/lib/es2020.promise.d.ts @@ -17,7 +17,9 @@ interface PromiseConstructor { * @param values An array of Promises. * @returns A new Promise. */ - allSettled(values: T): Promise<{ -readonly [P in keyof T]: PromiseSettledResult>; }>; + allSettled( + values: T, + ): Promise<{ -readonly [P in keyof T]: PromiseSettledResult>; }>; /** * Creates a Promise that is resolved with an array of results when all diff --git a/src/lib/es2020.sharedmemory.d.ts b/src/lib/es2020.sharedmemory.d.ts index e8403c18ba82b..5c0680f41f492 100644 --- a/src/lib/es2020.sharedmemory.d.ts +++ b/src/lib/es2020.sharedmemory.d.ts @@ -18,7 +18,12 @@ interface Atomics { * expected value, returning the original value. Until this atomic operation completes, any * other read or write operation against the array will block. */ - compareExchange(typedArray: BigInt64Array | BigUint64Array, index: number, expectedValue: bigint, replacementValue: bigint): bigint; + compareExchange( + typedArray: BigInt64Array | BigUint64Array, + index: number, + expectedValue: bigint, + replacementValue: bigint, + ): bigint; /** * Replaces the value at the given position in the array, returning the original value. Until diff --git a/src/lib/es2021.intl.d.ts b/src/lib/es2021.intl.d.ts index d0982874eec44..b06650ca15306 100644 --- a/src/lib/es2021.intl.d.ts +++ b/src/lib/es2021.intl.d.ts @@ -17,7 +17,10 @@ declare namespace Intl { interface DateTimeFormat { formatRange(startDate: Date | number | bigint, endDate: Date | number | bigint): string; - formatRangeToParts(startDate: Date | number | bigint, endDate: Date | number | bigint): DateTimeRangeFormatPart[]; + formatRangeToParts( + startDate: Date | number | bigint, + endDate: Date | number | bigint, + ): DateTimeRangeFormatPart[]; } interface ResolvedDateTimeFormatOptions { @@ -128,6 +131,9 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/supportedLocalesOf). */ - supportedLocalesOf(locales: BCP47LanguageTag | BCP47LanguageTag[], options?: Pick): BCP47LanguageTag[]; + supportedLocalesOf( + locales: BCP47LanguageTag | BCP47LanguageTag[], + options?: Pick, + ): BCP47LanguageTag[]; }; } diff --git a/src/lib/es2022.intl.d.ts b/src/lib/es2022.intl.d.ts index a465eb2d83d6a..846b58bae53a7 100644 --- a/src/lib/es2022.intl.d.ts +++ b/src/lib/es2022.intl.d.ts @@ -85,6 +85,9 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/supportedLocalesOf) */ - supportedLocalesOf(locales: BCP47LanguageTag | BCP47LanguageTag[], options?: Pick): BCP47LanguageTag[]; + supportedLocalesOf( + locales: BCP47LanguageTag | BCP47LanguageTag[], + options?: Pick, + ): BCP47LanguageTag[]; }; } diff --git a/src/lib/es2022.sharedmemory.d.ts b/src/lib/es2022.sharedmemory.d.ts index 3bc47dfc4d2b5..cf3f6bf516d47 100644 --- a/src/lib/es2022.sharedmemory.d.ts +++ b/src/lib/es2022.sharedmemory.d.ts @@ -3,5 +3,13 @@ interface Atomics { * A non-blocking, asynchronous version of wait which is usable on the main thread. * Waits asynchronously on a shared memory location and returns a Promise */ - waitAsync(typedArray: BigInt64Array | Int32Array, index: number, value: bigint, timeout?: number): { async: false; value: "ok" | "not-equal" | "timed-out"; } | { async: true; value: Promise<"ok" | "not-equal" | "timed-out">; }; + waitAsync( + typedArray: BigInt64Array | Int32Array, + index: number, + value: bigint, + timeout?: number, + ): { async: false; value: "ok" | "not-equal" | "timed-out"; } | { + async: true; + value: Promise<"ok" | "not-equal" | "timed-out">; + }; } diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index b1bd1e14b477b..bb9d048cf9032 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -204,7 +204,10 @@ interface ObjectConstructor { * Prevents the modification of existing property attributes and values, and prevents the addition of new properties. * @param o Object on which to lock the attributes. */ - freeze(o: T): Readonly; + freeze< + T extends { [idx: string]: U | null | undefined | object; }, + U extends string | bigint | number | boolean | symbol, + >(o: T): Readonly; /** * Prevents the modification of existing property attributes and values, and prevents the addition of new properties. @@ -305,7 +308,9 @@ type ThisParameterType = T extends (this: infer U, ...args: never) => any ? U /** * Removes the 'this' parameter from a function type. */ -type OmitThisParameter = unknown extends ThisParameterType ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T; +type OmitThisParameter = unknown extends ThisParameterType ? T + : T extends (...args: infer A) => infer R ? (...args: A) => R + : T; interface CallableFunction extends Function { /** @@ -330,10 +335,32 @@ interface CallableFunction extends Function { * @param args Arguments to bind to the parameters of the function. */ bind(this: T, thisArg: ThisParameterType): OmitThisParameter; - bind(this: (this: T, arg0: A0, ...args: A) => R, thisArg: T, arg0: A0): (...args: A) => R; - bind(this: (this: T, arg0: A0, arg1: A1, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1): (...args: A) => R; - bind(this: (this: T, arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2): (...args: A) => R; - bind(this: (this: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3): (...args: A) => R; + bind( + this: (this: T, arg0: A0, ...args: A) => R, + thisArg: T, + arg0: A0, + ): (...args: A) => R; + bind( + this: (this: T, arg0: A0, arg1: A1, ...args: A) => R, + thisArg: T, + arg0: A0, + arg1: A1, + ): (...args: A) => R; + bind( + this: (this: T, arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, + thisArg: T, + arg0: A0, + arg1: A1, + arg2: A2, + ): (...args: A) => R; + bind( + this: (this: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, + thisArg: T, + arg0: A0, + arg1: A1, + arg2: A2, + arg3: A3, + ): (...args: A) => R; bind(this: (this: T, ...args: AX[]) => R, thisArg: T, ...args: AX[]): (...args: AX[]) => R; } @@ -361,9 +388,27 @@ interface NewableFunction extends Function { */ bind(this: T, thisArg: any): T; bind(this: new (arg0: A0, ...args: A) => R, thisArg: any, arg0: A0): new (...args: A) => R; - bind(this: new (arg0: A0, arg1: A1, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1): new (...args: A) => R; - bind(this: new (arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1, arg2: A2): new (...args: A) => R; - bind(this: new (arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1, arg2: A2, arg3: A3): new (...args: A) => R; + bind( + this: new (arg0: A0, arg1: A1, ...args: A) => R, + thisArg: any, + arg0: A0, + arg1: A1, + ): new (...args: A) => R; + bind( + this: new (arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, + thisArg: any, + arg0: A0, + arg1: A1, + arg2: A2, + ): new (...args: A) => R; + bind( + this: new (arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, + thisArg: any, + arg0: A0, + arg1: A1, + arg2: A2, + arg3: A3, + ): new (...args: A) => R; bind(this: new (...args: AX[]) => R, thisArg: any, ...args: AX[]): new (...args: AX[]) => R; } @@ -892,7 +937,15 @@ interface DateConstructor { * @param seconds Must be supplied if milliseconds is supplied. A number from 0 to 59 that specifies the seconds. * @param ms A number from 0 to 999 that specifies the milliseconds. */ - new (year: number, monthIndex: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date; + new ( + year: number, + monthIndex: number, + date?: number, + hours?: number, + minutes?: number, + seconds?: number, + ms?: number, + ): Date; (): string; readonly prototype: Date; /** @@ -910,7 +963,15 @@ interface DateConstructor { * @param seconds Must be supplied if milliseconds is supplied. A number from 0 to 59 that specifies the seconds. * @param ms A number from 0 to 999 that specifies the milliseconds. */ - UTC(year: number, monthIndex: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): number; + UTC( + year: number, + monthIndex: number, + date?: number, + hours?: number, + minutes?: number, + seconds?: number, + ms?: number, + ): number; /** Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC). */ now(): number; } @@ -1196,7 +1257,10 @@ interface ReadonlyArray { * @param thisArg An object to which the this keyword can refer in the predicate function. * If thisArg is omitted, undefined is used as the this value. */ - every(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): this is readonly S[]; + every( + predicate: (value: T, index: number, array: readonly T[]) => value is S, + thisArg?: any, + ): this is readonly S[]; /** * Determines whether all the members of an array satisfy the specified test. * @param predicate A function that accepts up to three arguments. The every method calls @@ -1245,26 +1309,38 @@ interface ReadonlyArray { * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T; - reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T; + reduce( + callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, + initialValue: T, + ): T; /** * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T; + reduceRight( + callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, + initialValue: T, + ): T; /** * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, + initialValue: U, + ): U; readonly [n: number]: T; } @@ -1442,20 +1518,29 @@ interface Array { * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; + reduceRight( + callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, + initialValue: T, + ): T; /** * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, + initialValue: U, + ): U; [n: number]: T; } @@ -1484,10 +1569,16 @@ interface TypedPropertyDescriptor { declare type ClassDecorator = (target: TFunction) => TFunction | void; declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void; -declare type MethodDecorator = (target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor | void; +declare type MethodDecorator = ( + target: Object, + propertyKey: string | symbol, + descriptor: TypedPropertyDescriptor, +) => TypedPropertyDescriptor | void; declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void; -declare type PromiseConstructorLike = new (executor: (resolve: (value: T | PromiseLike) => void, reject: (reason?: any) => void) => void) => PromiseLike; +declare type PromiseConstructorLike = new ( + executor: (resolve: (value: T | PromiseLike) => void, reject: (reason?: any) => void) => void, +) => PromiseLike; interface PromiseLike { /** @@ -1496,7 +1587,10 @@ interface PromiseLike { * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of which ever callback is executed. */ - then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): PromiseLike; + then( + onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null, + ): PromiseLike; } /** @@ -1509,25 +1603,30 @@ interface Promise { * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of which ever callback is executed. */ - then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + then( + onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null, + ): Promise; /** * Attaches a callback for only the rejection of the Promise. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of the callback. */ - catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + catch( + onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null, + ): Promise; } /** * Recursively unwraps the "awaited type" of a type. Non-promise "thenables" should resolve to `never`. This emulates the behavior of `await`. */ -type Awaited = T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode - T extends object & { then(onfulfilled: infer F, ...args: infer _): any; } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped - F extends ((value: infer V, ...args: infer _) => any) ? // if the argument to `then` is callable, extracts the first argument - Awaited : // recursively unwrap the value - never : // the argument to `then` was not callable - T; // non-object or non-thenable +type Awaited = T extends null | undefined ? T // special case for `null | undefined` when not in `--strictNullChecks` mode + : T extends object & { then(onfulfilled: infer F, ...args: infer _): any; } // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + ? F extends ((value: infer V, ...args: infer _) => any) // if the argument to `then` is callable, extracts the first argument + ? Awaited // recursively unwrap the value + : never // the argument to `then` was not callable + : T; // non-object or non-thenable interface ArrayLike { readonly length: number; @@ -1597,7 +1696,8 @@ type Parameters any> = T extends (...args: infer P) /** * Obtain the parameters of a constructor function type in a tuple */ -type ConstructorParameters any> = T extends abstract new (...args: infer P) => any ? P : never; +type ConstructorParameters any> = T extends + abstract new (...args: infer P) => any ? P : never; /** * Obtain the return type of a function type @@ -1607,7 +1707,8 @@ type ReturnType any> = T extends (...args: any) => i /** * Obtain the return type of a constructor function type */ -type InstanceType any> = T extends abstract new (...args: any) => infer R ? R : any; +type InstanceType any> = T extends abstract new (...args: any) => infer R ? R + : any; /** * Convert string literal type to uppercase @@ -1962,8 +2063,13 @@ interface Int8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -1975,7 +2081,10 @@ interface Int8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int8Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int8Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -1987,8 +2096,13 @@ interface Int8Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2000,7 +2114,10 @@ interface Int8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int8Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int8Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -2242,8 +2359,13 @@ interface Uint8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -2255,7 +2377,10 @@ interface Uint8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2267,8 +2392,13 @@ interface Uint8Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2280,7 +2410,10 @@ interface Uint8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -2442,7 +2575,10 @@ interface Uint8ClampedArray { * @param thisArg An object to which the this keyword can refer in the predicate function. * If thisArg is omitted, undefined is used as the this value. */ - filter(predicate: (value: number, index: number, array: Uint8ClampedArray) => any, thisArg?: any): Uint8ClampedArray; + filter( + predicate: (value: number, index: number, array: Uint8ClampedArray) => any, + thisArg?: any, + ): Uint8ClampedArray; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -2453,7 +2589,10 @@ interface Uint8ClampedArray { * @param thisArg If provided, it will be used as the this value for each invocation of * predicate. If it is not provided, undefined is used instead. */ - find(predicate: (value: number, index: number, obj: Uint8ClampedArray) => boolean, thisArg?: any): number | undefined; + find( + predicate: (value: number, index: number, obj: Uint8ClampedArray) => boolean, + thisArg?: any, + ): number | undefined; /** * Returns the index of the first element in the array where predicate is true, and -1 @@ -2511,7 +2650,10 @@ interface Uint8ClampedArray { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - map(callbackfn: (value: number, index: number, array: Uint8ClampedArray) => number, thisArg?: any): Uint8ClampedArray; + map( + callbackfn: (value: number, index: number, array: Uint8ClampedArray) => number, + thisArg?: any, + ): Uint8ClampedArray; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -2523,8 +2665,23 @@ interface Uint8ClampedArray { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => number, initialValue: number): number; + reduce( + callbackfn: ( + previousValue: number, + currentValue: number, + currentIndex: number, + array: Uint8ClampedArray, + ) => number, + ): number; + reduce( + callbackfn: ( + previousValue: number, + currentValue: number, + currentIndex: number, + array: Uint8ClampedArray, + ) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -2536,7 +2693,10 @@ interface Uint8ClampedArray { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2548,8 +2708,23 @@ interface Uint8ClampedArray { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => number, initialValue: number): number; + reduceRight( + callbackfn: ( + previousValue: number, + currentValue: number, + currentIndex: number, + array: Uint8ClampedArray, + ) => number, + ): number; + reduceRight( + callbackfn: ( + previousValue: number, + currentValue: number, + currentIndex: number, + array: Uint8ClampedArray, + ) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2561,7 +2736,10 @@ interface Uint8ClampedArray { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -2803,8 +2981,13 @@ interface Int16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -2816,7 +2999,10 @@ interface Int16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int16Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int16Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2828,8 +3014,13 @@ interface Int16Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2841,7 +3032,10 @@ interface Int16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int16Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int16Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -3084,8 +3278,13 @@ interface Uint16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -3097,7 +3296,10 @@ interface Uint16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint16Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint16Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3109,8 +3311,13 @@ interface Uint16Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3122,7 +3329,10 @@ interface Uint16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint16Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint16Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -3364,8 +3574,13 @@ interface Int32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -3377,7 +3592,10 @@ interface Int32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int32Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int32Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3389,8 +3607,13 @@ interface Int32Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3402,7 +3625,10 @@ interface Int32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int32Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int32Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -3644,8 +3870,13 @@ interface Uint32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -3657,7 +3888,10 @@ interface Uint32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint32Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint32Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3669,8 +3903,13 @@ interface Uint32Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3682,7 +3921,10 @@ interface Uint32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint32Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint32Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -3925,8 +4167,13 @@ interface Float32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -3938,7 +4185,10 @@ interface Float32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float32Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float32Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3950,8 +4200,13 @@ interface Float32Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3963,7 +4218,10 @@ interface Float32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float32Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float32Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -4206,8 +4464,13 @@ interface Float64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -4219,7 +4482,10 @@ interface Float64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float64Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float64Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -4231,8 +4497,13 @@ interface Float64Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -4244,7 +4515,10 @@ interface Float64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float64Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float64Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. diff --git a/src/loggedIO/loggedIO.ts b/src/loggedIO/loggedIO.ts index 3306b463fd338..422bc59b9d6ab 100644 --- a/src/loggedIO/loggedIO.ts +++ b/src/loggedIO/loggedIO.ts @@ -155,14 +155,22 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file const canonicalizeForHarness = ts.createGetCanonicalFileName(/*caseSensitive*/ false); // This is done so tests work on windows _and_ linux function sanitizeTestFilePath(name: string) { - const path = ts.toPath(ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/"), "", canonicalizeForHarness); + const path = ts.toPath( + ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/"), + "", + canonicalizeForHarness, + ); if (ts.startsWith(path, "/")) { return path.substring(1); } return path; } - export function oldStyleLogIntoNewStyleLog(log: IoLog, writeFile: typeof Harness.IO.writeFile, baseTestName: string) { + export function oldStyleLogIntoNewStyleLog( + log: IoLog, + writeFile: typeof Harness.IO.writeFile, + baseTestName: string, + ) { if (log.filesAppended) { for (const file of log.filesAppended) { if (file.contents !== undefined) { @@ -205,7 +213,9 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file return log; } - export function initWrapper(...[wrapper, underlying]: [PlaybackSystem, ts.System] | [PlaybackIO, Harness.IO]): void { + export function initWrapper( + ...[wrapper, underlying]: [PlaybackSystem, ts.System] | [PlaybackIO, Harness.IO] + ): void { ts.forEach(Object.keys(underlying), prop => { (wrapper as any)[prop] = (underlying as any)[prop]; }); @@ -231,7 +241,8 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file wrapper.startRecord = fileNameBase => { recordLogFileNameBase = fileNameBase; recordLog = createEmptyLog(); - recordLog.useCaseSensitiveFileNames = typeof underlying.useCaseSensitiveFileNames === "function" ? underlying.useCaseSensitiveFileNames() : underlying.useCaseSensitiveFileNames; + recordLog.useCaseSensitiveFileNames = typeof underlying.useCaseSensitiveFileNames === "function" + ? underlying.useCaseSensitiveFileNames() : underlying.useCaseSensitiveFileNames; if (typeof underlying.args !== "function") { recordLog.arguments = underlying.args; } @@ -245,17 +256,26 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file let i = 0; const getBase = () => recordLogFileNameBase + i; while (underlying.fileExists(ts.combinePaths(getBase(), "test.json"))) i++; - const newLog = oldStyleLogIntoNewStyleLog(recordLog, (path, str) => underlying.writeFile(path, str), getBase()); + const newLog = oldStyleLogIntoNewStyleLog( + recordLog, + (path, str) => underlying.writeFile(path, str), + getBase(), + ); underlying.writeFile(ts.combinePaths(getBase(), "test.json"), JSON.stringify(newLog, null, 4)); // eslint-disable-line no-null/no-null const syntheticTsconfig = generateTsconfig(newLog); if (syntheticTsconfig) { - underlying.writeFile(ts.combinePaths(getBase(), "tsconfig.json"), JSON.stringify(syntheticTsconfig, null, 4)); // eslint-disable-line no-null/no-null + underlying.writeFile( + ts.combinePaths(getBase(), "tsconfig.json"), + JSON.stringify(syntheticTsconfig, null, 4), + ); // eslint-disable-line no-null/no-null } recordLog = undefined; } }; - function generateTsconfig(newLog: IoLog): undefined | { compilerOptions: ts.CompilerOptions; files: string[]; } { + function generateTsconfig( + newLog: IoLog, + ): undefined | { compilerOptions: ts.CompilerOptions; files: string[]; } { if (newLog.filesRead.some(file => /tsconfig.+json$/.test(file.path))) { return; } @@ -263,9 +283,9 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file for (const file of newLog.filesRead) { const result = file.result!; if ( - result.contentsPath && - Harness.isDefaultLibraryFile(result.contentsPath) && - /\.[tj]s$/.test(result.contentsPath) + result.contentsPath + && Harness.isDefaultLibraryFile(result.contentsPath) + && /\.[tj]s$/.test(result.contentsPath) ) { files.push(result.contentsPath); } @@ -312,7 +332,14 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file wrapper.resolvePath = recordReplay(wrapper.resolvePath, underlying)( path => callAndRecord(underlying.resolvePath(path), recordLog!.pathsResolved, { path }), - memoize(path => findResultByFields(replayLog!.pathsResolved, { path }, !ts.isRootedDiskPath(ts.normalizeSlashes(path)) && replayLog!.currentDirectory ? replayLog!.currentDirectory + "/" + path : ts.normalizeSlashes(path))), + memoize(path => + findResultByFields( + replayLog!.pathsResolved, + { path }, + !ts.isRootedDiskPath(ts.normalizeSlashes(path)) && replayLog!.currentDirectory + ? replayLog!.currentDirectory + "/" + path : ts.normalizeSlashes(path), + ) + ), ); wrapper.readFile = recordReplay(wrapper.readFile, underlying)( @@ -346,7 +373,12 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file ); wrapper.writeFile = recordReplay(wrapper.writeFile, underlying)( - (path: string, contents: string) => callAndRecord(underlying.writeFile(path, contents), recordLog!.filesWritten, { path, contents, bom: false }), + (path: string, contents: string) => + callAndRecord(underlying.writeFile(path, contents), recordLog!.filesWritten, { + path, + contents, + bom: false, + }), () => noOpReplay("writeFile"), ); @@ -361,7 +393,8 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file if (replayLog !== undefined) { return !!replayLog.useCaseSensitiveFileNames; } - return typeof underlying.useCaseSensitiveFileNames === "function" ? underlying.useCaseSensitiveFileNames() : underlying.useCaseSensitiveFileNames; + return typeof underlying.useCaseSensitiveFileNames === "function" ? underlying.useCaseSensitiveFileNames() + : underlying.useCaseSensitiveFileNames; }; } @@ -393,7 +426,9 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file function findResultByFields(logArray: { result?: T; }[], expectedFields: {}, defaultValue?: T): T | undefined { const predicate = (entry: { result?: T; }) => { - return Object.getOwnPropertyNames(expectedFields).every(name => (entry as any)[name] === (expectedFields as any)[name]); + return Object.getOwnPropertyNames(expectedFields).every(name => + (entry as any)[name] === (expectedFields as any)[name] + ); }; const results = logArray.filter(entry => predicate(entry)); if (results.length === 0) { diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index d9c8a83467cee..e03bf6df733e9 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -157,7 +157,9 @@ namespace ts.server { [name: string]: { match: RegExp; exclude?: (string | number)[][]; types?: string[]; }; } - function prepareConvertersForEnumLikeCompilerOptions(commandLineOptions: CommandLineOption[]): ESMap> { + function prepareConvertersForEnumLikeCompilerOptions( + commandLineOptions: CommandLineOption[], + ): ESMap> { const map = new Map>(); for (const option of commandLineOptions) { if (typeof option.type === "object") { @@ -241,7 +243,9 @@ namespace ts.server { return protocolOptions as any; } - export function convertCompilerOptions(protocolOptions: protocol.ExternalProjectCompilerOptions): CompilerOptions & protocol.CompileOnSaveMixin { + export function convertCompilerOptions( + protocolOptions: protocol.ExternalProjectCompilerOptions, + ): CompilerOptions & protocol.CompileOnSaveMixin { compilerOptionConverters.forEach((mappedValues, id) => { const propertyValue = protocolOptions[id]; if (isString(propertyValue)) { @@ -251,21 +255,26 @@ namespace ts.server { return protocolOptions as any; } - export function convertWatchOptions(protocolOptions: protocol.ExternalProjectCompilerOptions, currentDirectory?: string): WatchOptionsAndErrors | undefined { + export function convertWatchOptions( + protocolOptions: protocol.ExternalProjectCompilerOptions, + currentDirectory?: string, + ): WatchOptionsAndErrors | undefined { let watchOptions: WatchOptions | undefined; let errors: Diagnostic[] | undefined; optionsForWatch.forEach(option => { const propertyValue = protocolOptions[option.name]; if (propertyValue === undefined) return; const mappedValues = watchOptionsConverters.get(option.name); - (watchOptions || (watchOptions = {}))[option.name] = mappedValues ? - isString(propertyValue) ? mappedValues.get(propertyValue.toLowerCase()) : propertyValue : - convertJsonOption(option, propertyValue, currentDirectory || "", errors || (errors = [])); + (watchOptions || (watchOptions = {}))[option.name] = mappedValues + ? isString(propertyValue) ? mappedValues.get(propertyValue.toLowerCase()) : propertyValue + : convertJsonOption(option, propertyValue, currentDirectory || "", errors || (errors = [])); }); return watchOptions && { watchOptions, errors }; } - export function convertTypeAcquisition(protocolOptions: protocol.InferredProjectCompilerOptions): TypeAcquisition | undefined { + export function convertTypeAcquisition( + protocolOptions: protocol.InferredProjectCompilerOptions, + ): TypeAcquisition | undefined { let result: TypeAcquisition | undefined; typeAcquisitionDeclarations.forEach(option => { const propertyValue = protocolOptions[option.name]; @@ -341,7 +350,8 @@ namespace ts.server { } return result!; // TODO: GH#18217 }, - hasMixedContent: (fileName, extraFileExtensions) => some(extraFileExtensions, ext => ext.isMixedContent && fileExtensionIs(fileName, ext.extension)), + hasMixedContent: (fileName, extraFileExtensions) => + some(extraFileExtensions, ext => ext.isMixedContent && fileExtensionIs(fileName, ext.extension)), }; const externalFilePropertyReader: FilePropertyReader = { @@ -427,11 +437,15 @@ namespace ts.server { type OpenScriptInfoOrClosedFileInfo = ScriptInfo | OriginalFileInfo; type OpenScriptInfoOrClosedOrConfigFileInfo = OpenScriptInfoOrClosedFileInfo | AncestorConfigFileInfo; - function isOpenScriptInfo(infoOrFileNameOrConfig: OpenScriptInfoOrClosedOrConfigFileInfo): infoOrFileNameOrConfig is ScriptInfo { + function isOpenScriptInfo( + infoOrFileNameOrConfig: OpenScriptInfoOrClosedOrConfigFileInfo, + ): infoOrFileNameOrConfig is ScriptInfo { return !!(infoOrFileNameOrConfig as ScriptInfo).containingProjects; } - function isAncestorConfigFileInfo(infoOrFileNameOrConfig: OpenScriptInfoOrClosedOrConfigFileInfo): infoOrFileNameOrConfig is AncestorConfigFileInfo { + function isAncestorConfigFileInfo( + infoOrFileNameOrConfig: OpenScriptInfoOrClosedOrConfigFileInfo, + ): infoOrFileNameOrConfig is AncestorConfigFileInfo { return !!(infoOrFileNameOrConfig as AncestorConfigFileInfo).configFileInfo; } @@ -451,7 +465,9 @@ namespace ts.server { project: ConfiguredProject, fileName: string | undefined, cb: (child: ConfiguredProject) => T | undefined, - projectReferenceProjectLoadKind: ProjectReferenceProjectLoadKind.Find | ProjectReferenceProjectLoadKind.FindCreate, + projectReferenceProjectLoadKind: + | ProjectReferenceProjectLoadKind.Find + | ProjectReferenceProjectLoadKind.FindCreate, ): T | undefined; /*@internal*/ export function forEachResolvedProjectReferenceProject( @@ -509,13 +525,13 @@ namespace ts.server { function callback(ref: ResolvedProjectReference, loadKind: ProjectReferenceProjectLoadKind) { const configFileName = toNormalizedPath(ref.sourceFile.fileName); const child = project.projectService.findConfiguredProjectByProjectName(configFileName) || ( - loadKind === ProjectReferenceProjectLoadKind.Find ? - undefined : - loadKind === ProjectReferenceProjectLoadKind.FindCreate ? - project.projectService.createConfiguredProject(configFileName) : - loadKind === ProjectReferenceProjectLoadKind.FindCreateLoad ? - project.projectService.createAndLoadConfiguredProject(configFileName, reason!) : - Debug.assertNever(loadKind) + loadKind === ProjectReferenceProjectLoadKind.Find + ? undefined + : loadKind === ProjectReferenceProjectLoadKind.FindCreate + ? project.projectService.createConfiguredProject(configFileName) + : loadKind === ProjectReferenceProjectLoadKind.FindCreateLoad + ? project.projectService.createAndLoadConfiguredProject(configFileName, reason!) + : Debug.assertNever(loadKind) ); return child && cb(child); @@ -530,7 +546,8 @@ namespace ts.server { projectService: ProjectService, seenResolvedRefs: ESMap | undefined, ): T | undefined { - const loadKind = parentOptions.disableReferencedProjectLoad ? ProjectReferenceProjectLoadKind.Find : projectReferenceProjectLoadKind; + const loadKind = parentOptions.disableReferencedProjectLoad ? ProjectReferenceProjectLoadKind.Find + : projectReferenceProjectLoadKind; return forEach(resolvedProjectReferences, ref => { if (!ref) return undefined; @@ -546,7 +563,15 @@ namespace ts.server { } (seenResolvedRefs || (seenResolvedRefs = new Map())).set(canonicalPath, loadKind); - return ref.references && forEachResolvedProjectReferenceProjectWorker(ref.references, ref.commandLine.options, cb, loadKind, projectService, seenResolvedRefs); + return ref.references + && forEachResolvedProjectReferenceProjectWorker( + ref.references, + ref.commandLine.options, + cb, + loadKind, + projectService, + seenResolvedRefs, + ); }); } @@ -554,8 +579,8 @@ namespace ts.server { project: ConfiguredProject, cb: (potentialProjectReference: Path) => T | undefined, ): T | undefined { - return project.potentialProjectReferences && - forEachKey(project.potentialProjectReferences, cb); + return project.potentialProjectReferences + && forEachKey(project.potentialProjectReferences, cb); } function forEachAnyProjectReferenceKind( @@ -564,11 +589,11 @@ namespace ts.server { cbProjectRef: (projectReference: ProjectReference) => T | undefined, cbPotentialProjectRef: (potentialProjectReference: Path) => T | undefined, ): T | undefined { - return project.getCurrentProgram() ? - project.forEachResolvedProjectReference(cb) : - project.isInitialLoadPending() ? - forEachPotentialProjectReference(project, cbPotentialProjectRef) : - forEach(project.getProjectReferences(), cbProjectRef); + return project.getCurrentProgram() + ? project.forEachResolvedProjectReference(cb) + : project.isInitialLoadPending() + ? forEachPotentialProjectReference(project, cbPotentialProjectRef) + : forEach(project.getProjectReferences(), cbProjectRef); } function callbackRefProject( @@ -600,7 +625,9 @@ namespace ts.server { } function getDetailWatchInfo(watchType: WatchType, project: Project | NormalizedPath | undefined) { - return `${isString(project) ? `Config: ${project} ` : project ? `Project: ${project.getProjectName()} ` : ""}WatchType: ${watchType}`; + return `${ + isString(project) ? `Config: ${project} ` : project ? `Project: ${project.getProjectName()} ` : "" + }WatchType: ${watchType}`; } function isScriptInfoWatchedFromNodeModules(info: ScriptInfo) { @@ -610,8 +637,8 @@ namespace ts.server { /*@internal*/ /** true if script info is part of project and is not in project because it is referenced from project reference source */ export function projectContainsInfoDirectly(project: Project, info: ScriptInfo) { - return project.containsScriptInfo(info) && - !project.isSourceOfProjectReferenceRedirect(info.path); + return project.containsScriptInfo(info) + && !project.isSourceOfProjectReferenceRedirect(info.path); } /*@internal*/ @@ -716,7 +743,9 @@ namespace ts.server { /*@internal*/ readonly newInferredProjectName = createProjectNameFactoryWithCounter(makeInferredProjectName); /*@internal*/ - readonly newAutoImportProviderProjectName = createProjectNameFactoryWithCounter(makeAutoImportProviderProjectName); + readonly newAutoImportProviderProjectName = createProjectNameFactoryWithCounter( + makeAutoImportProviderProjectName, + ); /*@internal*/ readonly newAuxiliaryProjectName = createProjectNameFactoryWithCounter(makeAuxiliaryProjectName); /** @@ -790,7 +819,10 @@ namespace ts.server { readonly watchFactory: WatchFactory; /*@internal*/ - private readonly sharedExtendedConfigFileWatchers = new Map>(); + private readonly sharedExtendedConfigFileWatchers = new Map< + Path, + SharedExtendedConfigFileWatcher + >(); /*@internal*/ private readonly extendedConfigCache = new Map(); @@ -821,7 +853,8 @@ namespace ts.server { this.globalPlugins = opts.globalPlugins || emptyArray; this.pluginProbeLocations = opts.pluginProbeLocations || emptyArray; this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads; - this.typesMapLocation = (opts.typesMapLocation === undefined) ? combinePaths(getDirectoryPath(this.getExecutingFilePath()), "typesMap.json") : opts.typesMapLocation; + this.typesMapLocation = (opts.typesMapLocation === undefined) + ? combinePaths(getDirectoryPath(this.getExecutingFilePath()), "typesMap.json") : opts.typesMapLocation; this.session = opts.session; if (opts.serverMode !== undefined) { @@ -865,17 +898,21 @@ namespace ts.server { extraFileExtensions: [], }; - this.documentRegistry = createDocumentRegistryInternal(this.host.useCaseSensitiveFileNames, this.currentDirectory, this); - const watchLogLevel = this.logger.hasLevel(LogLevel.verbose) ? WatchLogLevel.Verbose : - this.logger.loggingEnabled() ? WatchLogLevel.TriggerOnly : WatchLogLevel.None; + this.documentRegistry = createDocumentRegistryInternal( + this.host.useCaseSensitiveFileNames, + this.currentDirectory, + this, + ); + const watchLogLevel = this.logger.hasLevel(LogLevel.verbose) ? WatchLogLevel.Verbose + : this.logger.loggingEnabled() ? WatchLogLevel.TriggerOnly : WatchLogLevel.None; const log: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? (s => this.logger.info(s)) : noop; this.packageJsonCache = createPackageJsonCache(this); - this.watchFactory = this.serverMode !== LanguageServiceMode.Semantic ? - { + this.watchFactory = this.serverMode !== LanguageServiceMode.Semantic + ? { watchFile: returnNoopFileWatcher, watchDirectory: returnNoopFileWatcher, - } : - getWatchFactory(this.host, watchLogLevel, log, getDetailWatchInfo); + } + : getWatchFactory(this.host, watchLogLevel, log, getDetailWatchInfo); } toPath(fileName: string) { @@ -901,7 +938,8 @@ namespace ts.server { /*@internal*/ getDocument(key: DocumentRegistryBucketKeyWithMode, path: Path): SourceFile | undefined { const info = this.getScriptInfoForPath(path); - return info && info.cacheSourceFile && info.cacheSourceFile.key === key ? info.cacheSourceFile.sourceFile : undefined; + return info && info.cacheSourceFile && info.cacheSourceFile.key === key ? info.cacheSourceFile.sourceFile + : undefined; } /* @internal */ @@ -955,8 +993,22 @@ namespace ts.server { updateTypingsForProject(response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse): void; /** @internal */ - updateTypingsForProject(response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse | BeginInstallTypes | EndInstallTypes): void; // eslint-disable-line @typescript-eslint/unified-signatures - updateTypingsForProject(response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse | BeginInstallTypes | EndInstallTypes): void { + updateTypingsForProject( + response: + | SetTypings + | InvalidateCachedTypings + | PackageInstalledResponse + | BeginInstallTypes + | EndInstallTypes, + ): void; // eslint-disable-line @typescript-eslint/unified-signatures + updateTypingsForProject( + response: + | SetTypings + | InvalidateCachedTypings + | PackageInstalledResponse + | BeginInstallTypes + | EndInstallTypes, + ): void { const project = this.findProject(response.projectName); if (!project) { return; @@ -964,11 +1016,23 @@ namespace ts.server { switch (response.kind) { case ActionSet: // Update the typing files and update the project - project.updateTypingFiles(this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typeAcquisition, response.unresolvedImports, response.typings)); + project.updateTypingFiles( + this.typingsCache.updateTypingsForProject( + response.projectName, + response.compilerOptions, + response.typeAcquisition, + response.unresolvedImports, + response.typings, + ), + ); return; case ActionInvalidate: // Do not clear resolution cache, there was changes detected in typings, so enque typing request and let it get us correct results - this.typingsCache.enqueueInstallTypingsForProject(project, project.lastCachedUnresolvedImportsList, /*forceRefresh*/ true); + this.typingsCache.enqueueInstallTypingsForProject( + project, + project.lastCachedUnresolvedImportsList, + /*forceRefresh*/ true, + ); return; } } @@ -995,7 +1059,9 @@ namespace ts.server { private delayUpdateProjectGraph(project: Project) { project.markAsDirty(); - if (project.projectKind !== ProjectKind.AutoImportProvider && project.projectKind !== ProjectKind.Auxiliary) { + if ( + project.projectKind !== ProjectKind.AutoImportProvider && project.projectKind !== ProjectKind.Auxiliary + ) { const projectName = project.getProjectName(); this.pendingProjectUpdates.set(projectName, project); this.throttledOperations.schedule(projectName, /*delay*/ 250, () => { @@ -1020,7 +1086,10 @@ namespace ts.server { const event: ProjectsUpdatedInBackgroundEvent = { eventName: ProjectsUpdatedInBackgroundEvent, data: { - openFiles: arrayFrom(this.openFiles.keys(), path => this.getScriptInfoForPath(path as Path)!.fileName), + openFiles: arrayFrom( + this.openFiles.keys(), + path => this.getScriptInfoForPath(path as Path)!.fileName, + ), }, }; this.eventHandler(event); @@ -1090,8 +1159,14 @@ namespace ts.server { } } - setCompilerOptionsForInferredProjects(projectCompilerOptions: protocol.InferredProjectCompilerOptions, projectRootPath?: string): void { - Debug.assert(projectRootPath === undefined || this.useInferredProjectPerProjectRoot, "Setting compiler options per project root path is only supported when useInferredProjectPerProjectRoot is enabled"); + setCompilerOptionsForInferredProjects( + projectCompilerOptions: protocol.InferredProjectCompilerOptions, + projectRootPath?: string, + ): void { + Debug.assert( + projectRootPath === undefined || this.useInferredProjectPerProjectRoot, + "Setting compiler options per project root path is only supported when useInferredProjectPerProjectRoot is enabled", + ); const compilerOptions = convertCompilerOptions(projectCompilerOptions); const watchOptions = convertWatchOptions(projectCompilerOptions, projectRootPath); @@ -1122,9 +1197,10 @@ namespace ts.server { // - Inferred projects with a projectRootPath, if the new options apply to that // project root path. if ( - canonicalProjectRootPath ? - project.projectRootPath === canonicalProjectRootPath : - !project.projectRootPath || !this.compilerOptionsForInferredProjectsPerProjectRoot.has(project.projectRootPath) + canonicalProjectRootPath + ? project.projectRootPath === canonicalProjectRootPath + : !project.projectRootPath + || !this.compilerOptionsForInferredProjectsPerProjectRoot.has(project.projectRootPath) ) { project.setCompilerOptions(compilerOptions); project.setTypeAcquisition(typeAcquisition); @@ -1146,7 +1222,8 @@ namespace ts.server { if (isInferredProjectName(projectName)) { return findProjectByName(projectName, this.inferredProjects); } - return this.findExternalProjectByProjectName(projectName) || this.findConfiguredProjectByProjectName(toNormalizedPath(projectName)); + return this.findExternalProjectByProjectName(projectName) + || this.findConfiguredProjectByProjectName(toNormalizedPath(projectName)); } /* @internal */ @@ -1166,26 +1243,33 @@ namespace ts.server { } getDefaultProjectForFile(fileName: NormalizedPath, ensureProject: boolean): Project | undefined { - return ensureProject ? this.ensureDefaultProjectForFile(fileName) : this.tryGetDefaultProjectForFile(fileName); + return ensureProject ? this.ensureDefaultProjectForFile(fileName) + : this.tryGetDefaultProjectForFile(fileName); } /* @internal */ tryGetDefaultProjectForFile(fileNameOrScriptInfo: NormalizedPath | ScriptInfo): Project | undefined { - const scriptInfo = isString(fileNameOrScriptInfo) ? this.getScriptInfoForNormalizedPath(fileNameOrScriptInfo) : fileNameOrScriptInfo; + const scriptInfo = isString(fileNameOrScriptInfo) + ? this.getScriptInfoForNormalizedPath(fileNameOrScriptInfo) : fileNameOrScriptInfo; return scriptInfo && !scriptInfo.isOrphan() ? scriptInfo.getDefaultProject() : undefined; } /* @internal */ ensureDefaultProjectForFile(fileNameOrScriptInfo: NormalizedPath | ScriptInfo): Project { - return this.tryGetDefaultProjectForFile(fileNameOrScriptInfo) || this.doEnsureDefaultProjectForFile(fileNameOrScriptInfo); + return this.tryGetDefaultProjectForFile(fileNameOrScriptInfo) + || this.doEnsureDefaultProjectForFile(fileNameOrScriptInfo); } private doEnsureDefaultProjectForFile(fileNameOrScriptInfo: NormalizedPath | ScriptInfo): Project { this.ensureProjectStructuresUptoDate(); - const scriptInfo = isString(fileNameOrScriptInfo) ? this.getScriptInfoForNormalizedPath(fileNameOrScriptInfo) : fileNameOrScriptInfo; - return scriptInfo ? - scriptInfo.getDefaultProject() : - (this.logErrorForScriptInfoNotFound(isString(fileNameOrScriptInfo) ? fileNameOrScriptInfo : fileNameOrScriptInfo.fileName), Errors.ThrowNoProject()); + const scriptInfo = isString(fileNameOrScriptInfo) + ? this.getScriptInfoForNormalizedPath(fileNameOrScriptInfo) : fileNameOrScriptInfo; + return scriptInfo + ? scriptInfo.getDefaultProject() + : (this.logErrorForScriptInfoNotFound( + isString(fileNameOrScriptInfo) ? fileNameOrScriptInfo : fileNameOrScriptInfo.fileName, + ), + Errors.ThrowNoProject()); } getScriptInfoEnsuringProjectsUptoDate(uncheckedFileName: string) { @@ -1307,15 +1391,24 @@ namespace ts.server { * This is to watch whenever files are added or removed to the wildcard directories */ /*@internal*/ - private watchWildcardDirectory(directory: Path, flags: WatchDirectoryFlags, configFileName: NormalizedPath, config: ParsedConfig) { + private watchWildcardDirectory( + directory: Path, + flags: WatchDirectoryFlags, + configFileName: NormalizedPath, + config: ParsedConfig, + ) { return this.watchFactory.watchDirectory( directory, fileOrDirectory => { const fileOrDirectoryPath = this.toPath(fileOrDirectory); - const fsResult = config.cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); + const fsResult = config.cachedDirectoryStructureHost.addOrDeleteFileOrDirectory( + fileOrDirectory, + fileOrDirectoryPath, + ); if ( - getBaseFileName(fileOrDirectoryPath) === "package.json" && !isInsideNodeModules(fileOrDirectoryPath) && - (fsResult && fsResult.fileExists || !fsResult && this.host.fileExists(fileOrDirectoryPath)) + getBaseFileName(fileOrDirectoryPath) === "package.json" + && !isInsideNodeModules(fileOrDirectoryPath) + && (fsResult && fsResult.fileExists || !fsResult && this.host.fileExists(fileOrDirectoryPath)) ) { this.logger.info(`Config: ${configFileName} Detected new package.json: ${fileOrDirectory}`); this.onAddPackageJson(fileOrDirectoryPath); @@ -1331,7 +1424,8 @@ namespace ts.server { extraFileExtensions: this.hostConfiguration.extraFileExtensions, currentDirectory: this.currentDirectory, options: config.parsedCommandLine!.options, - program: configuredProjectForConfig?.getCurrentProgram() || config.parsedCommandLine!.fileNames, + program: configuredProjectForConfig?.getCurrentProgram() + || config.parsedCommandLine!.fileNames, useCaseSensitiveFileNames: this.host.useCaseSensitiveFileNames, writeLog: s => this.logger.info(s), toPath: s => this.toPath(s), @@ -1339,7 +1433,9 @@ namespace ts.server { ) return; // Reload is pending, do the reload - if (config.reloadLevel !== ConfigFileProgramReloadLevel.Full) config.reloadLevel = ConfigFileProgramReloadLevel.Partial; + if (config.reloadLevel !== ConfigFileProgramReloadLevel.Full) { + config.reloadLevel = ConfigFileProgramReloadLevel.Partial; + } config.projects.forEach((watchWildcardDirectories, projectCanonicalPath) => { if (!watchWildcardDirectories) return; const project = this.getConfiguredProjectByCanonicalConfigFilePath(projectCanonicalPath); @@ -1347,14 +1443,19 @@ namespace ts.server { // Load root file names for configured project with the config file name // But only schedule update if project references this config file - const reloadLevel = configuredProjectForConfig === project ? ConfigFileProgramReloadLevel.Partial : ConfigFileProgramReloadLevel.None; + const reloadLevel = configuredProjectForConfig === project + ? ConfigFileProgramReloadLevel.Partial : ConfigFileProgramReloadLevel.None; if (project.pendingReload !== undefined && project.pendingReload > reloadLevel) return; // don't trigger callback on open, existing files if (this.openFiles.has(fileOrDirectoryPath)) { const info = Debug.checkDefined(this.getScriptInfoForPath(fileOrDirectoryPath)); if (info.isAttached(project)) { - const loadLevelToSet = Math.max(reloadLevel, project.openFileWatchTriggered.get(fileOrDirectoryPath) || ConfigFileProgramReloadLevel.None) as ConfigFileProgramReloadLevel; + const loadLevelToSet = Math.max( + reloadLevel, + project.openFileWatchTriggered.get(fileOrDirectoryPath) + || ConfigFileProgramReloadLevel.None, + ) as ConfigFileProgramReloadLevel; project.openFileWatchTriggered.set(fileOrDirectoryPath, loadLevelToSet); } else { @@ -1376,7 +1477,10 @@ namespace ts.server { } /*@internal*/ - private delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalConfigFilePath: NormalizedPath, reloadReason: string) { + private delayUpdateProjectsFromParsedConfigOnConfigFileChange( + canonicalConfigFilePath: NormalizedPath, + reloadReason: string, + ) { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); if (!configFileExistenceInfo?.config) return false; let scheduledAnyProjectUpdate = false; @@ -1397,7 +1501,9 @@ namespace ts.server { } else { // Change in referenced project config file - project.resolutionCache.removeResolutionsFromProjectReferenceRedirects(this.toPath(canonicalConfigFilePath)); + project.resolutionCache.removeResolutionsFromProjectReferenceRedirects( + this.toPath(canonicalConfigFilePath), + ); this.delayUpdateProjectGraph(project); } }); @@ -1414,9 +1520,9 @@ namespace ts.server { configFileExistenceInfo.exists = false; // Remove the configured project for this config file - const project = configFileExistenceInfo.config?.projects.has(canonicalConfigFilePath) ? - this.getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath) : - undefined; + const project = configFileExistenceInfo.config?.projects.has(canonicalConfigFilePath) + ? this.getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath) + : undefined; if (project) this.removeProject(project); } else { @@ -1425,7 +1531,10 @@ namespace ts.server { } // Update projects watching config - this.delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalConfigFilePath, "Change in config file detected"); + this.delayUpdateProjectsFromParsedConfigOnConfigFileChange( + canonicalConfigFilePath, + "Change in config file detected", + ); // Reload the configured projects for the open files in the map as they are affected by this config file // If the configured project was deleted, we want to reload projects for all the open files including files @@ -1437,9 +1546,9 @@ namespace ts.server { configFileExistenceInfo.openFilesImpactedByConfigFile, /*clearSemanticCache*/ false, /*delayReload*/ true, - eventKind !== FileWatcherEventKind.Deleted ? - identity : // Reload open files if they are root of inferred project - returnTrue, // Reload all the open files impacted by config file + eventKind !== FileWatcherEventKind.Deleted + ? identity // Reload open files if they are root of inferred project + : returnTrue, // Reload all the open files impacted by config file "Change in config file detected", ); this.delayEnsureProjectForOpenFiles(); @@ -1462,8 +1571,8 @@ namespace ts.server { mapDefinedIterator( this.filenameToScriptInfo.values(), info => - info.isAttached(project) ? - { + info.isAttached(project) + ? { fileName: info.fileName, projects: info.containingProjects.map(p => p.projectName), hasMixedContent: info.hasMixedContent, @@ -1499,19 +1608,19 @@ namespace ts.server { assignOrphanScriptInfoToInferredProject(info: ScriptInfo, projectRootPath: NormalizedPath | undefined) { Debug.assert(info.isOrphan()); - const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(info, projectRootPath) || - this.getOrCreateSingleInferredProjectIfEnabled() || - this.getOrCreateSingleInferredWithoutProjectRoot( - info.isDynamic ? - projectRootPath || this.currentDirectory : - getDirectoryPath( - isRootedDiskPath(info.fileName) ? - info.fileName : - getNormalizedAbsolutePath( + const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(info, projectRootPath) + || this.getOrCreateSingleInferredProjectIfEnabled() + || this.getOrCreateSingleInferredWithoutProjectRoot( + info.isDynamic + ? projectRootPath || this.currentDirectory + : getDirectoryPath( + isRootedDiskPath(info.fileName) + ? info.fileName + : getNormalizedAbsolutePath( info.fileName, - projectRootPath ? - this.getNormalizedAbsolutePath(projectRootPath) : - this.currentDirectory, + projectRootPath + ? this.getNormalizedAbsolutePath(projectRootPath) + : this.currentDirectory, ), ), ); @@ -1541,7 +1650,13 @@ namespace ts.server { // instead of scanning all open files const roots = inferredProject.getRootScriptInfos(); Debug.assert(roots.length === 1 || !!inferredProject.projectRootPath); - if (roots.length === 1 && forEach(roots[0].containingProjects, p => p !== roots[0].containingProjects[0] && !p.isOrphan())) { + if ( + roots.length === 1 + && forEach( + roots[0].containingProjects, + p => p !== roots[0].containingProjects[0] && !p.isOrphan(), + ) + ) { inferredProject.removeFile(roots[0], /*fileExists*/ true, /*detachFromProject*/ true); } } @@ -1650,7 +1765,11 @@ namespace ts.server { } } - private configFileExists(configFileName: NormalizedPath, canonicalConfigFilePath: NormalizedPath, info: OpenScriptInfoOrClosedOrConfigFileInfo) { + private configFileExists( + configFileName: NormalizedPath, + canonicalConfigFilePath: NormalizedPath, + info: OpenScriptInfoOrClosedOrConfigFileInfo, + ) { let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); if (configFileExistenceInfo) { // By default the info would get impacted by presence of config file since its in the detection path @@ -1682,7 +1801,11 @@ namespace ts.server { } /*@internal*/ - private createConfigFileWatcherForParsedConfig(configFileName: NormalizedPath, canonicalConfigFilePath: NormalizedPath, forProject: ConfiguredProject) { + private createConfigFileWatcherForParsedConfig( + configFileName: NormalizedPath, + canonicalConfigFilePath: NormalizedPath, + forProject: ConfiguredProject, + ) { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath)!; // When watching config file for parsed config, remove the noopFileWatcher that can be created for open files impacted by config file and watch for real if (!configFileExistenceInfo.watcher || configFileExistenceInfo.watcher === noopConfigFileWatcher) { @@ -1690,7 +1813,9 @@ namespace ts.server { configFileName, (_fileName, eventKind) => this.onConfigFileChanged(canonicalConfigFilePath, eventKind), PollingInterval.High, - this.getWatchOptionsFromProjectWatchOptions(configFileExistenceInfo?.config?.parsedCommandLine?.watchOptions), + this.getWatchOptionsFromProjectWatchOptions( + configFileExistenceInfo?.config?.parsedCommandLine?.watchOptions, + ), WatchType.ConfigFile, forProject, ); @@ -1704,8 +1829,8 @@ namespace ts.server { * Returns true if the configFileExistenceInfo is needed/impacted by open files that are root of inferred project */ private configFileExistenceImpactsRootOfInferredProject(configFileExistenceInfo: ConfigFileExistenceInfo) { - return configFileExistenceInfo.openFilesImpactedByConfigFile && - forEachEntry(configFileExistenceInfo.openFilesImpactedByConfigFile, identity); + return configFileExistenceInfo.openFilesImpactedByConfigFile + && forEachEntry(configFileExistenceInfo.openFilesImpactedByConfigFile, identity); } /* @internal */ @@ -1751,9 +1876,9 @@ namespace ts.server { // Close the config file watcher if there are no more open files that are root of inferred project // or if there are no projects that need to watch this config file existence info if ( - configFileExistenceInfo.watcher && - !configFileExistenceInfo.config && - !this.configFileExistenceImpactsRootOfInferredProject(configFileExistenceInfo) + configFileExistenceInfo.watcher + && !configFileExistenceInfo.config + && !this.configFileExistenceImpactsRootOfInferredProject(configFileExistenceInfo) ) { configFileExistenceInfo.watcher.close(); configFileExistenceInfo.watcher = undefined; @@ -1768,7 +1893,9 @@ namespace ts.server { this.forEachConfigFileLocation(info, canonicalConfigFilePath => { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); if (configFileExistenceInfo) { - const infoIsRootOfInferredProject = configFileExistenceInfo.openFilesImpactedByConfigFile?.get(info.path); + const infoIsRootOfInferredProject = configFileExistenceInfo.openFilesImpactedByConfigFile?.get( + info.path, + ); // Delete the info from map, since this file is no more open configFileExistenceInfo.openFilesImpactedByConfigFile?.delete(info.path); @@ -1785,8 +1912,8 @@ namespace ts.server { // and there is are no projects that need the config file existence or parsed config, // remove the cached existence info if ( - !configFileExistenceInfo.openFilesImpactedByConfigFile?.size && - !configFileExistenceInfo.config + !configFileExistenceInfo.openFilesImpactedByConfigFile?.size + && !configFileExistenceInfo.config ) { Debug.assert(!configFileExistenceInfo.watcher); this.configFileExistenceInfoCache.delete(canonicalConfigFilePath); @@ -1813,15 +1940,16 @@ namespace ts.server { (configFileExistenceInfo.openFilesImpactedByConfigFile ||= new Map()).set(info.path, true); // If there is no configured project for this config file, add the file watcher - configFileExistenceInfo.watcher ||= canWatchDirectoryOrFile(getDirectoryPath(canonicalConfigFilePath) as Path) ? - this.watchFactory.watchFile( - configFileName, - (_filename, eventKind) => this.onConfigFileChanged(canonicalConfigFilePath, eventKind), - PollingInterval.High, - this.hostConfiguration.watchOptions, - WatchType.ConfigFileForInferredRoot, - ) : - noopConfigFileWatcher; + configFileExistenceInfo.watcher ||= + canWatchDirectoryOrFile(getDirectoryPath(canonicalConfigFilePath) as Path) + ? this.watchFactory.watchFile( + configFileName, + (_filename, eventKind) => this.onConfigFileChanged(canonicalConfigFilePath, eventKind), + PollingInterval.High, + this.hostConfiguration.watchOptions, + WatchType.ConfigFileForInferredRoot, + ) + : noopConfigFileWatcher; }); } @@ -1852,7 +1980,10 @@ namespace ts.server { * The server must start searching from the directory containing * the newly opened file. */ - private forEachConfigFileLocation(info: OpenScriptInfoOrClosedOrConfigFileInfo, action: (canonicalConfigFilePath: NormalizedPath, configFileName: NormalizedPath) => boolean | void) { + private forEachConfigFileLocation( + info: OpenScriptInfoOrClosedOrConfigFileInfo, + action: (canonicalConfigFilePath: NormalizedPath, configFileName: NormalizedPath) => boolean | void, + ) { if (this.serverMode !== LanguageServiceMode.Semantic) { return undefined; } @@ -1863,7 +1994,8 @@ namespace ts.server { if (scriptInfo.isDynamic) return undefined; let searchPath = asNormalizedPath(getDirectoryPath(info.fileName)); - const isSearchPathInProjectRoot = () => containsPath(projectRootPath!, searchPath, this.currentDirectory, !this.host.useCaseSensitiveFileNames); + const isSearchPathInProjectRoot = () => + containsPath(projectRootPath!, searchPath, this.currentDirectory, !this.host.useCaseSensitiveFileNames); // If projectRootPath doesn't contain info.path, then do normal search for config file const anySearchPathOk = !projectRootPath || !isSearchPathInProjectRoot(); @@ -1871,13 +2003,23 @@ namespace ts.server { let searchInDirectory = !isAncestorConfigFileInfo(info); do { if (searchInDirectory) { - const canonicalSearchPath = normalizedPathToPath(searchPath, this.currentDirectory, this.toCanonicalFileName); + const canonicalSearchPath = normalizedPathToPath( + searchPath, + this.currentDirectory, + this.toCanonicalFileName, + ); const tsconfigFileName = asNormalizedPath(combinePaths(searchPath, "tsconfig.json")); - let result = action(combinePaths(canonicalSearchPath, "tsconfig.json") as NormalizedPath, tsconfigFileName); + let result = action( + combinePaths(canonicalSearchPath, "tsconfig.json") as NormalizedPath, + tsconfigFileName, + ); if (result) return tsconfigFileName; const jsconfigFileName = asNormalizedPath(combinePaths(searchPath, "jsconfig.json")); - result = action(combinePaths(canonicalSearchPath, "jsconfig.json") as NormalizedPath, jsconfigFileName); + result = action( + combinePaths(canonicalSearchPath, "jsconfig.json") as NormalizedPath, + jsconfigFileName, + ); if (result) return jsconfigFileName; // If we started within node_modules, don't look outside node_modules. @@ -1902,12 +2044,12 @@ namespace ts.server { findDefaultConfiguredProject(info: ScriptInfo) { if (!info.isScriptOpen()) return undefined; const configFileName = this.getConfigFileNameForFile(info); - const project = configFileName && - this.findConfiguredProjectByProjectName(configFileName); + const project = configFileName + && this.findConfiguredProjectByProjectName(configFileName); - return project && projectContainsInfoDirectly(project, info) ? - project : - project?.getDefaultChildProjectFromProjectWithReferences(info); + return project && projectContainsInfoDirectly(project, info) + ? project + : project?.getDefaultChildProjectFromProjectWithReferences(info); } /** @@ -1927,7 +2069,11 @@ namespace ts.server { if (result !== undefined) return result || undefined; } this.logger.info(`Search path: ${getDirectoryPath(info.fileName)}`); - const configFileName = this.forEachConfigFileLocation(info, (canonicalConfigFilePath, configFileName) => this.configFileExists(configFileName, canonicalConfigFilePath, info)); + const configFileName = this.forEachConfigFileLocation( + info, + (canonicalConfigFilePath, configFileName) => + this.configFileExists(configFileName, canonicalConfigFilePath, info), + ); if (configFileName) { this.logger.info(`For info: ${info.fileName} :: Config file name: ${configFileName}`); } @@ -1968,7 +2114,9 @@ namespace ts.server { return this.getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath); } - private getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath: string): ConfiguredProject | undefined { + private getConfiguredProjectByCanonicalConfigFilePath( + canonicalConfigFilePath: string, + ): ConfiguredProject | undefined { return this.configuredProjects.get(canonicalConfigFilePath); } @@ -1977,7 +2125,12 @@ namespace ts.server { } /** Get a filename if the language service exceeds the maximum allowed program size; otherwise returns undefined. */ - private getFilenameForExceededTotalSizeLimitForNonTsFiles(name: string, options: CompilerOptions | undefined, fileNames: T[], propertyReader: FilePropertyReader): string | undefined { + private getFilenameForExceededTotalSizeLimitForNonTsFiles( + name: string, + options: CompilerOptions | undefined, + fileNames: T[], + propertyReader: FilePropertyReader, + ): string | undefined { if (options && options.disableSizeLimit || !this.host.getFileSize) { return; } @@ -2002,7 +2155,11 @@ namespace ts.server { .map(name => ({ name, size: this.host.getFileSize!(name) })) .sort((a, b) => b.size - a.size) .slice(0, 5); - this.logger.info(`Non TS file size exceeded limit (${totalNonTsFileSize}). Largest files: ${top5LargestFiles.map(file => `${file.name}:${file.size}`).join(", ")}`); + this.logger.info( + `Non TS file size exceeded limit (${totalNonTsFileSize}). Largest files: ${ + top5LargestFiles.map(file => `${file.name}:${file.size}`).join(", ") + }`, + ); // Keep the size as zero since it's disabled return fileName; } @@ -2010,15 +2167,29 @@ namespace ts.server { this.projectToSizeMap.set(name, totalNonTsFileSize); } - private createExternalProject(projectFileName: string, files: protocol.ExternalFile[], options: protocol.ExternalProjectCompilerOptions, typeAcquisition: TypeAcquisition, excludedFiles: NormalizedPath[]) { + private createExternalProject( + projectFileName: string, + files: protocol.ExternalFile[], + options: protocol.ExternalProjectCompilerOptions, + typeAcquisition: TypeAcquisition, + excludedFiles: NormalizedPath[], + ) { const compilerOptions = convertCompilerOptions(options); - const watchOptionsAndErrors = convertWatchOptions(options, getDirectoryPath(normalizeSlashes(projectFileName))); + const watchOptionsAndErrors = convertWatchOptions( + options, + getDirectoryPath(normalizeSlashes(projectFileName)), + ); const project = new ExternalProject( projectFileName, this, this.documentRegistry, compilerOptions, - /*lastFileExceededProgramSize*/ this.getFilenameForExceededTotalSizeLimitForNonTsFiles(projectFileName, compilerOptions, files, externalFilePropertyReader), + /*lastFileExceededProgramSize*/ this.getFilenameForExceededTotalSizeLimitForNonTsFiles( + projectFileName, + compilerOptions, + files, + externalFilePropertyReader, + ), options.compileOnSave === undefined ? true : options.compileOnSave, /*projectFilePath*/ undefined, this.currentPluginConfigOverrides, @@ -2072,7 +2243,9 @@ namespace ts.server { return getBaseConfigFileName(project.getConfigFilePath()) || "other"; } - function convertTypeAcquisition({ enable, include, exclude }: TypeAcquisition): ProjectInfoTypeAcquisitionData { + function convertTypeAcquisition( + { enable, include, exclude }: TypeAcquisition, + ): ProjectInfoTypeAcquisitionData { return { enable, include: include !== undefined && include.length !== 0, @@ -2081,7 +2254,12 @@ namespace ts.server { } } - private addFilesToNonInferredProject(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader, typeAcquisition: TypeAcquisition): void { + private addFilesToNonInferredProject( + project: ConfiguredProject | ExternalProject, + files: T[], + propertyReader: FilePropertyReader, + typeAcquisition: TypeAcquisition, + ): void { this.updateNonInferredProjectFiles(project, files, propertyReader); project.setTypeAcquisition(typeAcquisition); } @@ -2095,14 +2273,21 @@ namespace ts.server { // We could be in this scenario if project is the configured project tracked by external project // Since that route doesnt check if the config file is present or not if (!configFileExistenceInfo) { - this.configFileExistenceInfoCache.set(canonicalConfigFilePath, configFileExistenceInfo = { exists: true }); + this.configFileExistenceInfoCache.set( + canonicalConfigFilePath, + configFileExistenceInfo = { exists: true }, + ); } else { configFileExistenceInfo.exists = true; } if (!configFileExistenceInfo.config) { configFileExistenceInfo.config = { - cachedDirectoryStructureHost: createCachedDirectoryStructureHost(this.host, this.host.getCurrentDirectory(), this.host.useCaseSensitiveFileNames)!, + cachedDirectoryStructureHost: createCachedDirectoryStructureHost( + this.host, + this.host.getCurrentDirectory(), + this.host.useCaseSensitiveFileNames, + )!, projects: new Map(), reloadLevel: ConfigFileProgramReloadLevel.Full, }; @@ -2147,7 +2332,9 @@ namespace ts.server { */ /* @internal */ private loadConfiguredProject(project: ConfiguredProject, reason: string) { - tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { configFilePath: project.canonicalConfigFilePath }); + tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { + configFilePath: project.canonicalConfigFilePath, + }); this.sendProjectLoadingStartEvent(project, reason); // Read updated contents from disk @@ -2174,10 +2361,17 @@ namespace ts.server { project.canConfigFileJsonReportNoInputFiles = canJsonReportNoInputFiles(parsedCommandLine.raw); project.setProjectErrors(parsedCommandLine.options.configFile!.parseDiagnostics); project.updateReferences(parsedCommandLine.projectReferences); - const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, compilerOptions, parsedCommandLine.fileNames, fileNamePropertyReader); + const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles( + project.canonicalConfigFilePath, + compilerOptions, + parsedCommandLine.fileNames, + fileNamePropertyReader, + ); if (lastFileExceededProgramSize) { project.disableLanguageService(lastFileExceededProgramSize); - this.configFileExistenceInfoCache.forEach((_configFileExistenceInfo, canonicalConfigFilePath) => this.stopWatchingWildCards(canonicalConfigFilePath, project)); + this.configFileExistenceInfoCache.forEach((_configFileExistenceInfo, canonicalConfigFilePath) => + this.stopWatchingWildCards(canonicalConfigFilePath, project) + ); } else { project.setCompilerOptions(compilerOptions); @@ -2187,12 +2381,25 @@ namespace ts.server { } project.enablePluginsWithOptions(compilerOptions, this.currentPluginConfigOverrides); const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles()); - this.updateRootAndOptionsOfNonInferredProject(project, filesToAdd, fileNamePropertyReader, compilerOptions, parsedCommandLine.typeAcquisition!, parsedCommandLine.compileOnSave, parsedCommandLine.watchOptions); + this.updateRootAndOptionsOfNonInferredProject( + project, + filesToAdd, + fileNamePropertyReader, + compilerOptions, + parsedCommandLine.typeAcquisition!, + parsedCommandLine.compileOnSave, + parsedCommandLine.watchOptions, + ); tracing?.pop(); } /*@internal*/ - ensureParsedConfigUptoDate(configFilename: NormalizedPath, canonicalConfigFilePath: NormalizedPath, configFileExistenceInfo: ConfigFileExistenceInfo, forProject: ConfiguredProject): ConfigFileExistenceInfo { + ensureParsedConfigUptoDate( + configFilename: NormalizedPath, + canonicalConfigFilePath: NormalizedPath, + configFileExistenceInfo: ConfigFileExistenceInfo, + forProject: ConfiguredProject, + ): ConfigFileExistenceInfo { if (configFileExistenceInfo.config) { if (!configFileExistenceInfo.config.reloadLevel) return configFileExistenceInfo; if (configFileExistenceInfo.config.reloadLevel === ConfigFileProgramReloadLevel.Partial) { @@ -2202,12 +2409,19 @@ namespace ts.server { } // Parse the config file and ensure its cached - const cachedDirectoryStructureHost = configFileExistenceInfo.config?.cachedDirectoryStructureHost || - createCachedDirectoryStructureHost(this.host, this.host.getCurrentDirectory(), this.host.useCaseSensitiveFileNames)!; + const cachedDirectoryStructureHost = configFileExistenceInfo.config?.cachedDirectoryStructureHost + || createCachedDirectoryStructureHost( + this.host, + this.host.getCurrentDirectory(), + this.host.useCaseSensitiveFileNames, + )!; // Read updated contents from disk const configFileContent = tryReadFile(configFilename, fileName => this.host.readFile(fileName)); - const configFile = parseJsonText(configFilename, isString(configFileContent) ? configFileContent : "") as TsConfigSourceFile; + const configFile = parseJsonText( + configFilename, + isString(configFileContent) ? configFileContent : "", + ) as TsConfigSourceFile; const configFileErrors = configFile.parseDiagnostics as Diagnostic[]; if (!isString(configFileContent)) configFileErrors.push(configFileContent); const parsedCommandLine = parseJsonSourceFileConfigFileContent( @@ -2240,7 +2454,11 @@ namespace ts.server { const oldCommandLine = configFileExistenceInfo.config?.parsedCommandLine; if (!configFileExistenceInfo.config) { - configFileExistenceInfo.config = { parsedCommandLine, cachedDirectoryStructureHost, projects: new Map() }; + configFileExistenceInfo.config = { + parsedCommandLine, + cachedDirectoryStructureHost, + projects: new Map(), + }; } else { configFileExistenceInfo.config.parsedCommandLine = parsedCommandLine; @@ -2274,13 +2492,22 @@ namespace ts.server { extendedConfigFileName, () => { // Update extended config cache - cleanExtendedConfigCache(this.extendedConfigCache, extendedConfigFilePath, fileName => this.toPath(fileName)); + cleanExtendedConfigCache(this.extendedConfigCache, extendedConfigFilePath, fileName => + this.toPath(fileName)); // Update projects let ensureProjectsForOpenFiles = false; - this.sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)?.projects.forEach(canonicalPath => { - ensureProjectsForOpenFiles = this.delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalPath, `Change in extended config file ${extendedConfigFileName} detected`) || ensureProjectsForOpenFiles; - }); - if (ensureProjectsForOpenFiles) this.delayEnsureProjectForOpenFiles(); + this.sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)?.projects.forEach( + canonicalPath => { + ensureProjectsForOpenFiles = + this.delayUpdateProjectsFromParsedConfigOnConfigFileChange( + canonicalPath, + `Change in extended config file ${extendedConfigFileName} detected`, + ) || ensureProjectsForOpenFiles; + }, + ); + if (ensureProjectsForOpenFiles) { + this.delayEnsureProjectForOpenFiles(); + } }, PollingInterval.High, this.hostConfiguration.watchOptions, @@ -2293,7 +2520,11 @@ namespace ts.server { } /*@internal*/ - watchWildcards(configFileName: NormalizedPath, { exists, config }: ConfigFileExistenceInfo, forProject: ConfiguredProject) { + watchWildcards( + configFileName: NormalizedPath, + { exists, config }: ConfigFileExistenceInfo, + forProject: ConfiguredProject, + ) { config!.projects.set(forProject.canonicalConfigFilePath, true); if (exists) { if (config!.watchedDirectories && !config!.watchedDirectoriesStale) return; @@ -2302,7 +2533,8 @@ namespace ts.server { config!.watchedDirectories ||= new Map(), new Map(getEntries(config!.parsedCommandLine!.wildcardDirectories!)), // Create new directory watcher - (directory, flags) => this.watchWildcardDirectory(directory as Path, flags, configFileName, config!), + (directory, flags) => + this.watchWildcardDirectory(directory as Path, flags, configFileName, config!), ); } else { @@ -2317,8 +2549,8 @@ namespace ts.server { stopWatchingWildCards(canonicalConfigFilePath: NormalizedPath, forProject: ConfiguredProject) { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath)!; if ( - !configFileExistenceInfo.config || - !configFileExistenceInfo.config.projects.get(forProject.canonicalConfigFilePath) + !configFileExistenceInfo.config + || !configFileExistenceInfo.config.projects.get(forProject.canonicalConfigFilePath) ) { return; } @@ -2360,7 +2592,10 @@ namespace ts.server { } else { const scriptKind = propertyReader.getScriptKind(f, this.hostConfiguration.extraFileExtensions); - const hasMixedContent = propertyReader.hasMixedContent(f, this.hostConfiguration.extraFileExtensions); + const hasMixedContent = propertyReader.hasMixedContent( + f, + this.hostConfiguration.extraFileExtensions, + ); const scriptInfo = Debug.checkDefined(this.getOrCreateScriptInfoNotOpenedByClientForNormalizedPath( fileName, project.currentDirectory, @@ -2407,7 +2642,15 @@ namespace ts.server { project.markAsDirty(); } - private updateRootAndOptionsOfNonInferredProject(project: ExternalProject | ConfiguredProject, newUncheckedFiles: T[], propertyReader: FilePropertyReader, newOptions: CompilerOptions, newTypeAcquisition: TypeAcquisition, compileOnSave: boolean | undefined, watchOptions: WatchOptions | undefined) { + private updateRootAndOptionsOfNonInferredProject( + project: ExternalProject | ConfiguredProject, + newUncheckedFiles: T[], + propertyReader: FilePropertyReader, + newOptions: CompilerOptions, + newTypeAcquisition: TypeAcquisition, + compileOnSave: boolean | undefined, + watchOptions: WatchOptions | undefined, + ) { project.setCompilerOptions(newOptions); project.setWatchOptions(watchOptions); // VS only set the CompileOnSaveEnabled option in the request if the option was changed recently @@ -2423,9 +2666,16 @@ namespace ts.server { */ /*@internal*/ reloadFileNamesOfConfiguredProject(project: ConfiguredProject) { - const fileNames = this.reloadFileNamesOfParsedConfig(project.getConfigFilePath(), this.configFileExistenceInfoCache.get(project.canonicalConfigFilePath)!.config!); + const fileNames = this.reloadFileNamesOfParsedConfig( + project.getConfigFilePath(), + this.configFileExistenceInfoCache.get(project.canonicalConfigFilePath)!.config!, + ); project.updateErrorOnNoInputFiles(fileNames); - this.updateNonInferredProjectFiles(project, fileNames.concat(project.getExternalFiles()), fileNamePropertyReader); + this.updateNonInferredProjectFiles( + project, + fileNames.concat(project.getExternalFiles()), + fileNamePropertyReader, + ); return project.updateGraph(); } @@ -2454,7 +2704,12 @@ namespace ts.server { * Read the config file of the project again by clearing the cache and update the project graph */ /* @internal */ - reloadConfiguredProject(project: ConfiguredProject, reason: string, isInitialLoad: boolean, clearSemanticCache: boolean) { + reloadConfiguredProject( + project: ConfiguredProject, + reason: string, + isInitialLoad: boolean, + clearSemanticCache: boolean, + ) { // At this point, there is no reason to not have configFile in the host const host = project.getCachedDirectoryStructureHost(); if (clearSemanticCache) this.clearSemanticCache(project); @@ -2491,11 +2746,14 @@ namespace ts.server { } as ConfigFileDiagEvent); } - private getOrCreateInferredProjectForProjectRootPathIfEnabled(info: ScriptInfo, projectRootPath: NormalizedPath | undefined): InferredProject | undefined { + private getOrCreateInferredProjectForProjectRootPathIfEnabled( + info: ScriptInfo, + projectRootPath: NormalizedPath | undefined, + ): InferredProject | undefined { if ( - !this.useInferredProjectPerProjectRoot || + !this.useInferredProjectPerProjectRoot // Its a dynamic info opened without project root - (info.isDynamic && projectRootPath === undefined) + || (info.isDynamic && projectRootPath === undefined) ) { return undefined; } @@ -2518,7 +2776,14 @@ namespace ts.server { // ignore single inferred projects (handled elsewhere) if (!project.projectRootPath) continue; // ignore inferred projects that don't contain the root's path - if (!containsPath(project.projectRootPath, info.path, this.host.getCurrentDirectory(), !this.host.useCaseSensitiveFileNames)) continue; + if ( + !containsPath( + project.projectRootPath, + info.path, + this.host.getCurrentDirectory(), + !this.host.useCaseSensitiveFileNames, + ) + ) continue; // ignore inferred projects that are higher up in the project root. // TODO(rbuckton): Should we add the file as a root to these as well? if (bestMatch && bestMatch.projectRootPath!.length > project.projectRootPath.length) continue; @@ -2551,13 +2816,15 @@ namespace ts.server { private getOrCreateSingleInferredWithoutProjectRoot(currentDirectory: string | undefined): InferredProject { Debug.assert(!this.useSingleInferredProject); - const expectedCurrentDirectory = this.toCanonicalFileName(this.getNormalizedAbsolutePath(currentDirectory || "")); + const expectedCurrentDirectory = this.toCanonicalFileName( + this.getNormalizedAbsolutePath(currentDirectory || ""), + ); // Reuse the project with same current directory but no roots for (const inferredProject of this.inferredProjects) { if ( - !inferredProject.projectRootPath && - inferredProject.isOrphan() && - inferredProject.canonicalCurrentDirectory === expectedCurrentDirectory + !inferredProject.projectRootPath + && inferredProject.isOrphan() + && inferredProject.canonicalCurrentDirectory === expectedCurrentDirectory ) { return inferredProject; } @@ -2566,8 +2833,14 @@ namespace ts.server { return this.createInferredProject(currentDirectory); } - private createInferredProject(currentDirectory: string | undefined, isSingleInferredProject?: boolean, projectRootPath?: NormalizedPath): InferredProject { - const compilerOptions = projectRootPath && this.compilerOptionsForInferredProjectsPerProjectRoot.get(projectRootPath) || this.compilerOptionsForInferredProjects!; // TODO: GH#18217 + private createInferredProject( + currentDirectory: string | undefined, + isSingleInferredProject?: boolean, + projectRootPath?: NormalizedPath, + ): InferredProject { + const compilerOptions = + projectRootPath && this.compilerOptionsForInferredProjectsPerProjectRoot.get(projectRootPath) + || this.compilerOptionsForInferredProjects!; // TODO: GH#18217 let watchOptionsAndErrors: WatchOptionsAndErrors | false | undefined; let typeAcquisition: TypeAcquisition | undefined; if (projectRootPath) { @@ -2581,7 +2854,16 @@ namespace ts.server { typeAcquisition = this.typeAcquisitionForInferredProjects; } watchOptionsAndErrors = watchOptionsAndErrors || undefined; - const project = new InferredProject(this, this.documentRegistry, compilerOptions, watchOptionsAndErrors?.watchOptions, projectRootPath, currentDirectory, this.currentPluginConfigOverrides, typeAcquisition); + const project = new InferredProject( + this, + this.documentRegistry, + compilerOptions, + watchOptionsAndErrors?.watchOptions, + projectRootPath, + currentDirectory, + this.currentPluginConfigOverrides, + typeAcquisition, + ); project.setProjectErrors(watchOptionsAndErrors?.errors); if (isSingleInferredProject) { this.inferredProjects.unshift(project); @@ -2593,7 +2875,11 @@ namespace ts.server { } /*@internal*/ - getOrCreateScriptInfoNotOpenedByClient(uncheckedFileName: string, currentDirectory: string, hostToQueryFileExistsOn: DirectoryStructureHost) { + getOrCreateScriptInfoNotOpenedByClient( + uncheckedFileName: string, + currentDirectory: string, + hostToQueryFileExistsOn: DirectoryStructureHost, + ) { return this.getOrCreateScriptInfoNotOpenedByClientForNormalizedPath( toNormalizedPath(uncheckedFileName), currentDirectory, @@ -2618,8 +2904,14 @@ namespace ts.server { /* @internal */ logErrorForScriptInfoNotFound(fileName: string): void { - const names = arrayFrom(this.filenameToScriptInfo.entries()).map(([path, scriptInfo]) => ({ path, fileName: scriptInfo.fileName })); - this.logger.msg(`Could not find file ${JSON.stringify(fileName)}.\nAll files are: ${JSON.stringify(names)}`, Msg.Err); + const names = arrayFrom(this.filenameToScriptInfo.entries()).map(([path, scriptInfo]) => ({ + path, + fileName: scriptInfo.fileName, + })); + this.logger.msg( + `Could not find file ${JSON.stringify(fileName)}.\nAll files are: ${JSON.stringify(names)}`, + Msg.Err, + ); } /** @@ -2644,16 +2936,21 @@ namespace ts.server { for (const project of toAddInfo.containingProjects) { // Add the projects only if they can use symLink targets and not already in the list if ( - project.languageServiceEnabled && - !project.isOrphan() && - !project.getCompilerOptions().preserveSymlinks && - !info.isAttached(project) + project.languageServiceEnabled + && !project.isOrphan() + && !project.getCompilerOptions().preserveSymlinks + && !info.isAttached(project) ) { if (!projects) { projects = createMultiMap(); projects.add(toAddInfo.path, project); } - else if (!forEachEntry(projects, (projs, path) => path === toAddInfo.path ? false : contains(projs, project))) { + else if ( + !forEachEntry( + projects, + (projs, path) => path === toAddInfo.path ? false : contains(projs, project), + ) + ) { projects.add(toAddInfo.path, project); } } @@ -2667,9 +2964,9 @@ namespace ts.server { // do not watch files with mixed content - server doesn't know how to interpret it // do not watch files in the global cache location if ( - !info.isDynamicOrHasMixedContent() && - (!this.globalCacheLocationDirectoryPath || - !startsWith(info.path, this.globalCacheLocationDirectoryPath)) + !info.isDynamicOrHasMixedContent() + && (!this.globalCacheLocationDirectoryPath + || !startsWith(info.path, this.globalCacheLocationDirectoryPath)) ) { const indexOfNodeModules = info.path.indexOf("/node_modules/"); if (!this.host.getModifiedTime || indexOfNodeModules === -1) { @@ -2683,7 +2980,9 @@ namespace ts.server { } else { info.mTime = this.getModifiedTime(info); - info.fileWatcher = this.watchClosedScriptInfoInNodeModules(info.path.substr(0, indexOfNodeModules) as Path); + info.fileWatcher = this.watchClosedScriptInfoInNodeModules( + info.path.substr(0, indexOfNodeModules) as Path, + ); } } } @@ -2800,9 +3099,23 @@ namespace ts.server { } } - private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, hostToQueryFileExistsOn: DirectoryStructureHost | undefined) { + private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath( + fileName: NormalizedPath, + currentDirectory: string, + scriptKind: ScriptKind | undefined, + hasMixedContent: boolean | undefined, + hostToQueryFileExistsOn: DirectoryStructureHost | undefined, + ) { if (isRootedDiskPath(fileName) || isDynamicFileName(fileName)) { - return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn); + return this.getOrCreateScriptInfoWorker( + fileName, + currentDirectory, + /*openedByClient*/ false, + /*fileContent*/ undefined, + scriptKind, + hasMixedContent, + hostToQueryFileExistsOn, + ); } // This is non rooted path with different current directory than project service current directory @@ -2817,28 +3130,111 @@ namespace ts.server { return undefined; } - private getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined) { - return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent); + private getOrCreateScriptInfoOpenedByClientForNormalizedPath( + fileName: NormalizedPath, + currentDirectory: string, + fileContent: string | undefined, + scriptKind: ScriptKind | undefined, + hasMixedContent: boolean | undefined, + ) { + return this.getOrCreateScriptInfoWorker( + fileName, + currentDirectory, + /*openedByClient*/ true, + fileContent, + scriptKind, + hasMixedContent, + ); } - getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }) { - return this.getOrCreateScriptInfoWorker(fileName, this.currentDirectory, openedByClient, fileContent, scriptKind, hasMixedContent, hostToQueryFileExistsOn); + getOrCreateScriptInfoForNormalizedPath( + fileName: NormalizedPath, + openedByClient: boolean, + fileContent?: string, + scriptKind?: ScriptKind, + hasMixedContent?: boolean, + hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }, + ) { + return this.getOrCreateScriptInfoWorker( + fileName, + this.currentDirectory, + openedByClient, + fileContent, + scriptKind, + hasMixedContent, + hostToQueryFileExistsOn, + ); } - private getOrCreateScriptInfoWorker(fileName: NormalizedPath, currentDirectory: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }) { - Debug.assert(fileContent === undefined || openedByClient, "ScriptInfo needs to be opened by client to be able to set its user defined content"); + private getOrCreateScriptInfoWorker( + fileName: NormalizedPath, + currentDirectory: string, + openedByClient: boolean, + fileContent?: string, + scriptKind?: ScriptKind, + hasMixedContent?: boolean, + hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }, + ) { + Debug.assert( + fileContent === undefined || openedByClient, + "ScriptInfo needs to be opened by client to be able to set its user defined content", + ); const path = normalizedPathToPath(fileName, currentDirectory, this.toCanonicalFileName); let info = this.getScriptInfoForPath(path); if (!info) { const isDynamic = isDynamicFileName(fileName); - Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`); - Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`); - Debug.assert(!isDynamic || this.currentDirectory === currentDirectory || this.useInferredProjectPerProjectRoot, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nDynamic files must always be opened with service's current directory or service should support inferred project per projectRootPath.`); + Debug.assert( + isRootedDiskPath(fileName) || isDynamic || openedByClient, + "", + () => + `${ + JSON.stringify({ + fileName, + currentDirectory, + hostCurrentDirectory: this.currentDirectory, + openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()), + }) + }\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`, + ); + Debug.assert( + !isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory + || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), + "", + () => + `${ + JSON.stringify({ + fileName, + currentDirectory, + hostCurrentDirectory: this.currentDirectory, + openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()), + }) + }\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`, + ); + Debug.assert( + !isDynamic || this.currentDirectory === currentDirectory || this.useInferredProjectPerProjectRoot, + "", + () => + `${ + JSON.stringify({ + fileName, + currentDirectory, + hostCurrentDirectory: this.currentDirectory, + openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()), + }) + }\nDynamic files must always be opened with service's current directory or service should support inferred project per projectRootPath.`, + ); // If the file is not opened by client and the file doesnot exist on the disk, return if (!openedByClient && !isDynamic && !(hostToQueryFileExistsOn || this.host).fileExists(fileName)) { return; } - info = new ScriptInfo(this.host, fileName, scriptKind!, !!hasMixedContent, path, this.filenameToScriptInfoVersion.get(path)); // TODO: GH#18217 + info = new ScriptInfo( + this.host, + fileName, + scriptKind!, + !!hasMixedContent, + path, + this.filenameToScriptInfoVersion.get(path), + ); // TODO: GH#18217 this.filenameToScriptInfo.set(info.path, info); this.filenameToScriptInfoVersion.delete(info.path); if (!openedByClient) { @@ -2865,8 +3261,11 @@ namespace ts.server { * This gets the script info for the normalized path. If the path is not rooted disk path then the open script info with project root context is preferred */ getScriptInfoForNormalizedPath(fileName: NormalizedPath) { - return !isRootedDiskPath(fileName) && this.openFilesWithNonRootedDiskPath.get(this.toCanonicalFileName(fileName)) || - this.getScriptInfoForPath(normalizedPathToPath(fileName, this.currentDirectory, this.toCanonicalFileName)); + return !isRootedDiskPath(fileName) + && this.openFilesWithNonRootedDiskPath.get(this.toCanonicalFileName(fileName)) + || this.getScriptInfoForPath( + normalizedPathToPath(fileName, this.currentDirectory, this.toCanonicalFileName), + ); } getScriptInfoForPath(fileName: Path) { @@ -2874,9 +3273,17 @@ namespace ts.server { } /*@internal*/ - getDocumentPositionMapper(project: Project, generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined { + getDocumentPositionMapper( + project: Project, + generatedFileName: string, + sourceFileName?: string, + ): DocumentPositionMapper | undefined { // Since declaration info and map file watches arent updating project's directory structure host (which can cache file structure) use host - const declarationInfo = this.getOrCreateScriptInfoNotOpenedByClient(generatedFileName, project.currentDirectory, this.host); + const declarationInfo = this.getOrCreateScriptInfoNotOpenedByClient( + generatedFileName, + project.currentDirectory, + this.host, + ); if (!declarationInfo) { if (sourceFileName) { // Project contains source file and it generates the generated file name @@ -2893,14 +3300,23 @@ namespace ts.server { if (sourceMapFileInfo) { sourceMapFileInfo.getSnapshot(); if (sourceMapFileInfo.documentPositionMapper !== undefined) { - sourceMapFileInfo.sourceInfos = this.addSourceInfoToSourceMap(sourceFileName, project, sourceMapFileInfo.sourceInfos); - return sourceMapFileInfo.documentPositionMapper ? sourceMapFileInfo.documentPositionMapper : undefined; + sourceMapFileInfo.sourceInfos = this.addSourceInfoToSourceMap( + sourceFileName, + project, + sourceMapFileInfo.sourceInfos, + ); + return sourceMapFileInfo.documentPositionMapper ? sourceMapFileInfo.documentPositionMapper + : undefined; } } declarationInfo.sourceMapFilePath = undefined; } else if (declarationInfo.sourceMapFilePath) { - declarationInfo.sourceMapFilePath.sourceInfos = this.addSourceInfoToSourceMap(sourceFileName, project, declarationInfo.sourceMapFilePath.sourceInfos); + declarationInfo.sourceMapFilePath.sourceInfos = this.addSourceInfoToSourceMap( + sourceFileName, + project, + declarationInfo.sourceMapFilePath.sourceInfos, + ); return undefined; } else if (declarationInfo.sourceMapFilePath !== undefined) { @@ -2913,7 +3329,11 @@ namespace ts.server { let mapFileNameFromDeclarationInfo: string | undefined; let readMapFile: ReadMapFile | undefined = (mapFileName, mapFileNameFromDts) => { - const mapInfo = this.getOrCreateScriptInfoNotOpenedByClient(mapFileName, project.currentDirectory, this.host); + const mapInfo = this.getOrCreateScriptInfoNotOpenedByClient( + mapFileName, + project.currentDirectory, + this.host, + ); if (!mapInfo) { mapFileNameFromDeclarationInfo = mapFileNameFromDts; return undefined; @@ -2925,7 +3345,11 @@ namespace ts.server { }; const projectName = project.projectName; const documentPositionMapper = getDocumentPositionMapper( - { getCanonicalFileName: this.toCanonicalFileName, log: s => this.logger.info(s), getSourceFileLike: f => this.getSourceFileLike(f, projectName, declarationInfo) }, + { + getCanonicalFileName: this.toCanonicalFileName, + log: s => this.logger.info(s), + getSourceFileLike: f => this.getSourceFileLike(f, projectName, declarationInfo), + }, declarationInfo.fileName, declarationInfo.getLineInfo(), readMapFile, @@ -2935,14 +3359,18 @@ namespace ts.server { declarationInfo.sourceMapFilePath = sourceMapFileInfo.path; sourceMapFileInfo.declarationInfoPath = declarationInfo.path; sourceMapFileInfo.documentPositionMapper = documentPositionMapper || false; - sourceMapFileInfo.sourceInfos = this.addSourceInfoToSourceMap(sourceFileName, project, sourceMapFileInfo.sourceInfos); + sourceMapFileInfo.sourceInfos = this.addSourceInfoToSourceMap( + sourceFileName, + project, + sourceMapFileInfo.sourceInfos, + ); } else if (mapFileNameFromDeclarationInfo) { declarationInfo.sourceMapFilePath = { watcher: this.addMissingSourceMapFile( - project.currentDirectory === this.currentDirectory ? - mapFileNameFromDeclarationInfo : - getNormalizedAbsolutePath(mapFileNameFromDeclarationInfo, project.currentDirectory), + project.currentDirectory === this.currentDirectory + ? mapFileNameFromDeclarationInfo + : getNormalizedAbsolutePath(mapFileNameFromDeclarationInfo, project.currentDirectory), declarationInfo.path, ), sourceInfos: this.addSourceInfoToSourceMap(sourceFileName, project), @@ -2954,10 +3382,18 @@ namespace ts.server { return documentPositionMapper; } - private addSourceInfoToSourceMap(sourceFileName: string | undefined, project: Project, sourceInfos?: Set) { + private addSourceInfoToSourceMap( + sourceFileName: string | undefined, + project: Project, + sourceInfos?: Set, + ) { if (sourceFileName) { // Attach as source - const sourceInfo = this.getOrCreateScriptInfoNotOpenedByClient(sourceFileName, project.currentDirectory, project.directoryStructureHost)!; + const sourceInfo = this.getOrCreateScriptInfoNotOpenedByClient( + sourceFileName, + project.currentDirectory, + project.directoryStructureHost, + )!; (sourceInfos || (sourceInfos = new Set())).add(sourceInfo.path); } return sourceInfos; @@ -2968,9 +3404,15 @@ namespace ts.server { mapFileName, () => { const declarationInfo = this.getScriptInfoForPath(declarationInfoPath); - if (declarationInfo && declarationInfo.sourceMapFilePath && !isString(declarationInfo.sourceMapFilePath)) { + if ( + declarationInfo && declarationInfo.sourceMapFilePath + && !isString(declarationInfo.sourceMapFilePath) + ) { // Update declaration and source projects - this.delayUpdateProjectGraphs(declarationInfo.containingProjects, /*clearSourceMapperCache*/ true); + this.delayUpdateProjectGraphs( + declarationInfo.containingProjects, + /*clearSourceMapperCache*/ true, + ); this.delayUpdateSourceInfoProjects(declarationInfo.sourceMapFilePath.sourceInfos); declarationInfo.closeSourceMapFileWatcher(); } @@ -2984,7 +3426,8 @@ namespace ts.server { /*@internal*/ getSourceFileLike(fileName: string, projectNameOrProject: string | Project, declarationInfo?: ScriptInfo) { - const project = (projectNameOrProject as Project).projectName ? projectNameOrProject as Project : this.findProject(projectNameOrProject as string); + const project = (projectNameOrProject as Project).projectName ? projectNameOrProject as Project + : this.findProject(projectNameOrProject as string); if (project) { const path = project.toPath(fileName); const sourceFile = project.getSourceFile(path); @@ -2992,7 +3435,11 @@ namespace ts.server { } // Need to look for other files. - const info = this.getOrCreateScriptInfoNotOpenedByClient(fileName, (project || this).currentDirectory, project ? project.directoryStructureHost : this.host); + const info = this.getOrCreateScriptInfoNotOpenedByClient( + fileName, + (project || this).currentDirectory, + project ? project.directoryStructureHost : this.host, + ); if (!info) return undefined; // Attach as source @@ -3017,7 +3464,8 @@ namespace ts.server { const lineOffset = info.positionToLineOffset(pos); return { line: lineOffset.line - 1, character: lineOffset.offset - 1 }; }, - getPositionOfLineAndCharacter: (line, character, allowEdits) => info.lineOffsetToPosition(line + 1, character + 1, allowEdits), + getPositionOfLineAndCharacter: (line, character, allowEdits) => + info.lineOffsetToPosition(line + 1, character + 1, allowEdits), }; } return info.sourceFileLike; @@ -3042,7 +3490,10 @@ namespace ts.server { this.logger.info(`Host information ${args.hostInfo}`); } if (args.formatOptions) { - this.hostConfiguration.formatCodeOptions = { ...this.hostConfiguration.formatCodeOptions, ...convertFormatOptions(args.formatOptions) }; + this.hostConfiguration.formatCodeOptions = { + ...this.hostConfiguration.formatCodeOptions, + ...convertFormatOptions(args.formatOptions), + }; this.logger.info("Format host information updated"); } if (args.preferences) { @@ -3052,13 +3503,16 @@ namespace ts.server { } = this.hostConfiguration.preferences; this.hostConfiguration.preferences = { ...this.hostConfiguration.preferences, ...args.preferences }; - if (lazyConfiguredProjectsFromExternalProject && !this.hostConfiguration.preferences.lazyConfiguredProjectsFromExternalProject) { + if ( + lazyConfiguredProjectsFromExternalProject + && !this.hostConfiguration.preferences.lazyConfiguredProjectsFromExternalProject + ) { // Load configured projects for external projects that are pending reload this.configuredProjects.forEach(project => { if ( - project.hasExternalProjectRef() && - project.pendingReload === ConfigFileProgramReloadLevel.Full && - !this.pendingProjectUpdates.has(project.getProjectName()) + project.hasExternalProjectRef() + && project.pendingReload === ConfigFileProgramReloadLevel.Full + && !this.pendingProjectUpdates.has(project.getProjectName()) ) { project.updateGraph(); } @@ -3078,7 +3532,11 @@ namespace ts.server { if (args.watchOptions) { this.hostConfiguration.watchOptions = convertWatchOptions(args.watchOptions)?.watchOptions; - this.logger.info(`Host watch options changed to ${JSON.stringify(this.hostConfiguration.watchOptions)}, it will be take effect for next watches.`); + this.logger.info( + `Host watch options changed to ${ + JSON.stringify(this.hostConfiguration.watchOptions) + }, it will be take effect for next watches.`, + ); } } } @@ -3090,9 +3548,9 @@ namespace ts.server { /*@internal*/ private getWatchOptionsFromProjectWatchOptions(projectOptions: WatchOptions | undefined) { - return projectOptions && this.hostConfiguration.watchOptions ? - { ...this.hostConfiguration.watchOptions, ...projectOptions } : - projectOptions || this.hostConfiguration.watchOptions; + return projectOptions && this.hostConfiguration.watchOptions + ? { ...this.hostConfiguration.watchOptions, ...projectOptions } + : projectOptions || this.hostConfiguration.watchOptions; } closeLog() { @@ -3115,7 +3573,10 @@ namespace ts.server { if (this.openFiles.has(info.path)) return; // Skip open files if (!info.fileWatcher) return; // not watched file // Handle as if file is changed or deleted - this.onSourceFileChanged(info, this.host.fileExists(info.fileName) ? FileWatcherEventKind.Changed : FileWatcherEventKind.Deleted); + this.onSourceFileChanged( + info, + this.host.fileExists(info.fileName) ? FileWatcherEventKind.Changed : FileWatcherEventKind.Deleted, + ); }); // Cancel all project updates since we will be updating them now this.pendingProjectUpdates.forEach((_project, projectName) => { @@ -3131,7 +3592,13 @@ namespace ts.server { }); // Reload Projects - this.reloadConfiguredProjectForFiles(this.openFiles as ESMap, /*clearSemanticCache*/ true, /*delayReload*/ false, returnTrue, "User requested reload projects"); + this.reloadConfiguredProjectForFiles( + this.openFiles as ESMap, + /*clearSemanticCache*/ true, + /*delayReload*/ false, + returnTrue, + "User requested reload projects", + ); this.externalProjects.forEach(project => { this.clearSemanticCache(project); project.updateGraph(); @@ -3147,7 +3614,13 @@ namespace ts.server { * If there is no existing project it just opens the configured project for the config file * reloadForInfo provides a way to filter out files to reload configured project for */ - private reloadConfiguredProjectForFiles(openFiles: ESMap | undefined, clearSemanticCache: boolean, delayReload: boolean, shouldReloadProjectFor: (openFileValue: T) => boolean, reason: string) { + private reloadConfiguredProjectForFiles( + openFiles: ESMap | undefined, + clearSemanticCache: boolean, + delayReload: boolean, + shouldReloadProjectFor: (openFileValue: T) => boolean, + reason: string, + ) { const updatedProjects = new Map(); const reloadChildProject = (child: ConfiguredProject) => { if (!updatedProjects.has(child.canonicalConfigFilePath)) { @@ -3172,7 +3645,8 @@ namespace ts.server { // otherwise we create a new one. const configFileName = this.getConfigFileNameForFile(info); if (configFileName) { - const project = this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName); + const project = this.findConfiguredProjectByProjectName(configFileName) + || this.createConfiguredProject(configFileName); if (!updatedProjects.has(project.canonicalConfigFilePath)) { updatedProjects.set(project.canonicalConfigFilePath, true); if (delayReload) { @@ -3233,10 +3707,10 @@ namespace ts.server { const firstProject = info.containingProjects[0]; if ( - !firstProject.isOrphan() && - isInferredProject(firstProject) && - firstProject.isRoot(info) && - forEach(info.containingProjects, p => p !== firstProject && !p.isOrphan()) + !firstProject.isOrphan() + && isInferredProject(firstProject) + && firstProject.isRoot(info) + && forEach(info.containingProjects, p => p !== firstProject && !p.isOrphan()) ) { firstProject.removeFile(info, /*fileExists*/ true, /*detachFromProject*/ true); } @@ -3276,27 +3750,46 @@ namespace ts.server { * @param filename is absolute pathname * @param fileContent is a known version of the file content that is more up to date than the one on disk */ - openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: string): OpenConfiguredProjectResult { - return this.openClientFileWithNormalizedPath(toNormalizedPath(fileName), fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath ? toNormalizedPath(projectRootPath) : undefined); + openClientFile( + fileName: string, + fileContent?: string, + scriptKind?: ScriptKind, + projectRootPath?: string, + ): OpenConfiguredProjectResult { + return this.openClientFileWithNormalizedPath( + toNormalizedPath(fileName), + fileContent, + scriptKind, + /*hasMixedContent*/ false, + projectRootPath ? toNormalizedPath(projectRootPath) : undefined, + ); } /*@internal*/ - getOriginalLocationEnsuringConfiguredProject(project: Project, location: DocumentPosition): DocumentPosition | undefined { + getOriginalLocationEnsuringConfiguredProject( + project: Project, + location: DocumentPosition, + ): DocumentPosition | undefined { const isSourceOfProjectReferenceRedirect = project.isSourceOfProjectReferenceRedirect(location.fileName); - const originalLocation = isSourceOfProjectReferenceRedirect ? - location : - project.getSourceMapper().tryGetSourcePosition(location); + const originalLocation = isSourceOfProjectReferenceRedirect + ? location + : project.getSourceMapper().tryGetSourcePosition(location); if (!originalLocation) return undefined; const { fileName } = originalLocation; const scriptInfo = this.getScriptInfo(fileName); if (!scriptInfo && !this.host.fileExists(fileName)) return undefined; - const originalFileInfo: OriginalFileInfo = { fileName: toNormalizedPath(fileName), path: this.toPath(fileName) }; + const originalFileInfo: OriginalFileInfo = { + fileName: toNormalizedPath(fileName), + path: this.toPath(fileName), + }; const configFileName = this.getConfigFileNameForFile(originalFileInfo); if (!configFileName) return undefined; - let configuredProject: ConfiguredProject | undefined = this.findConfiguredProjectByProjectName(configFileName); + let configuredProject: ConfiguredProject | undefined = this.findConfiguredProjectByProjectName( + configFileName, + ); if (!configuredProject) { if (project.getCompilerOptions().disableReferencedProjectLoad) { // If location was a project reference redirect, then `location` and `originalLocation` are the same. @@ -3313,7 +3806,12 @@ namespace ts.server { : location; } - configuredProject = this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location: " + location.fileName : ""}`); + configuredProject = this.createAndLoadConfiguredProject( + configFileName, + `Creating project for original file: ${originalFileInfo.fileName}${ + location !== originalLocation ? " for location: " + location.fileName : "" + }`, + ); } updateProjectIfDirty(configuredProject); @@ -3332,7 +3830,9 @@ namespace ts.server { return projectContainsOriginalInfo(child) ? child : undefined; }, ProjectReferenceProjectLoadKind.FindCreateLoad, - `Creating project referenced in solution ${configuredProject.projectName} to find possible configured project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location: " + location.fileName : ""}`, + `Creating project referenced in solution ${configuredProject.projectName} to find possible configured project for original file: ${originalFileInfo.fileName}${ + location !== originalLocation ? " for location: " + location.fileName : "" + }`, ); if (!configuredProject) return undefined; if (configuredProject === project) return originalLocation; @@ -3373,8 +3873,20 @@ namespace ts.server { }); } - private getOrCreateOpenScriptInfo(fileName: NormalizedPath, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, projectRootPath: NormalizedPath | undefined) { - const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, fileContent, scriptKind, hasMixedContent)!; // TODO: GH#18217 + private getOrCreateOpenScriptInfo( + fileName: NormalizedPath, + fileContent: string | undefined, + scriptKind: ScriptKind | undefined, + hasMixedContent: boolean | undefined, + projectRootPath: NormalizedPath | undefined, + ) { + const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath( + fileName, + projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, + fileContent, + scriptKind, + hasMixedContent, + )!; // TODO: GH#18217 this.openFiles.set(info.path, projectRootPath); return info; } @@ -3382,7 +3894,8 @@ namespace ts.server { private assignProjectToOpenedScriptInfo(info: ScriptInfo): AssignProjectResult { let configFileName: NormalizedPath | undefined; let configFileErrors: readonly Diagnostic[] | undefined; - let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info); + let project: ConfiguredProject | ExternalProject | undefined = this + .findExternalProjectContainingOpenScriptInfo(info); let retainProjects: ConfiguredProject[] | ConfiguredProject | undefined; let projectForConfigFileDiag: ConfiguredProject | undefined; let defaultConfigProjectIsCreated = false; @@ -3391,7 +3904,10 @@ namespace ts.server { if (configFileName) { project = this.findConfiguredProjectByProjectName(configFileName); if (!project) { - project = this.createLoadAndUpdateConfiguredProject(configFileName, `Creating possible configured project for ${info.fileName} to open`); + project = this.createLoadAndUpdateConfiguredProject( + configFileName, + `Creating possible configured project for ${info.fileName} to open`, + ); defaultConfigProjectIsCreated = true; } else { @@ -3486,10 +4002,10 @@ namespace ts.server { while (true) { // Skip if project is not composite if ( - !project.isInitialLoadPending() && - ( - !project.getCompilerOptions().composite || - project.getCompilerOptions().disableSolutionSearching + !project.isInitialLoadPending() + && ( + !project.getCompilerOptions().composite + || project.getCompilerOptions().disableSolutionSearching ) ) return; @@ -3502,8 +4018,11 @@ namespace ts.server { if (!configFileName) return; // find or delay load the project - const ancestor = this.findConfiguredProjectByProjectName(configFileName) || - this.createConfiguredProjectWithDelayLoad(configFileName, `Creating project possibly referencing default composite project ${project.getProjectName()} of open file ${info.fileName}`); + const ancestor = this.findConfiguredProjectByProjectName(configFileName) + || this.createConfiguredProjectWithDelayLoad( + configFileName, + `Creating project possibly referencing default composite project ${project.getProjectName()} of open file ${info.fileName}`, + ); if (ancestor.isInitialLoadPending()) { // Set a potential project reference ancestor.setPotentialProjectReference(project.canonicalConfigFilePath); @@ -3531,7 +4050,11 @@ namespace ts.server { } } - private ensureProjectChildren(project: ConfiguredProject, forProjects: ReadonlyCollection, seenProjects: Set) { + private ensureProjectChildren( + project: ConfiguredProject, + forProjects: ReadonlyCollection, + seenProjects: Set, + ) { if (!tryAddToSet(seenProjects, project.canonicalConfigFilePath)) return; // If this project disables child load ignore it @@ -3542,13 +4065,19 @@ namespace ts.server { for (const child of children) { if (!child) continue; - const referencedProject = forEachResolvedProjectReference(child.references, ref => forProjects.has(ref.sourceFile.path) ? ref : undefined); + const referencedProject = forEachResolvedProjectReference( + child.references, + ref => forProjects.has(ref.sourceFile.path) ? ref : undefined, + ); if (!referencedProject) continue; // Load this project, const configFileName = toNormalizedPath(child.sourceFile.fileName); - const childProject = project.projectService.findConfiguredProjectByProjectName(configFileName) || - project.projectService.createAndLoadConfiguredProject(configFileName, `Creating project referenced by : ${project.projectName} as it references project ${referencedProject.sourceFile.fileName}`); + const childProject = project.projectService.findConfiguredProjectByProjectName(configFileName) + || project.projectService.createAndLoadConfiguredProject( + configFileName, + `Creating project referenced by : ${project.projectName} as it references project ${referencedProject.sourceFile.fileName}`, + ); updateProjectIfDirty(childProject); // Ensure children for this project @@ -3556,7 +4085,9 @@ namespace ts.server { } } - private cleanupAfterOpeningFile(toRetainConfigProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined) { + private cleanupAfterOpeningFile( + toRetainConfigProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined, + ) { // This was postponed from closeOpenFile to after opening next file, // so that we can reuse the project if we need to right away this.removeOrphanConfiguredProjects(toRetainConfigProjects); @@ -3576,8 +4107,20 @@ namespace ts.server { this.removeOrphanScriptInfos(); } - openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult { - const info = this.getOrCreateOpenScriptInfo(fileName, fileContent, scriptKind, hasMixedContent, projectRootPath); + openClientFileWithNormalizedPath( + fileName: NormalizedPath, + fileContent?: string, + scriptKind?: ScriptKind, + hasMixedContent?: boolean, + projectRootPath?: NormalizedPath, + ): OpenConfiguredProjectResult { + const info = this.getOrCreateOpenScriptInfo( + fileName, + fileContent, + scriptKind, + hasMixedContent, + projectRootPath, + ); const { retainProjects, ...result } = this.assignProjectToOpenedScriptInfo(info); this.cleanupAfterOpeningFile(retainProjects); this.telemetryOnOpenFile(info); @@ -3585,7 +4128,9 @@ namespace ts.server { return result; } - private removeOrphanConfiguredProjects(toRetainConfiguredProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined) { + private removeOrphanConfiguredProjects( + toRetainConfiguredProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined, + ) { const toRemoveConfiguredProjects = new Map(this.configuredProjects); const markOriginalProjectsAsUsed = (project: Project) => { if (!project.isOrphan() && project.originalConfiguredProjects) { @@ -3694,7 +4239,10 @@ namespace ts.server { } private telemetryOnOpenFile(scriptInfo: ScriptInfo): void { - if (this.serverMode !== LanguageServiceMode.Semantic || !this.eventHandler || !scriptInfo.isJavaScript() || !addToSeen(this.allJsFilesForOpenFileTelemetry, scriptInfo.path)) { + if ( + this.serverMode !== LanguageServiceMode.Semantic || !this.eventHandler || !scriptInfo.isJavaScript() + || !addToSeen(this.allJsFilesForOpenFileTelemetry, scriptInfo.path) + ) { return; } @@ -3732,21 +4280,38 @@ namespace ts.server { ): void { for (const proj of currentProjects) { const knownProject = find(lastKnownProjectVersions, p => p.projectName === proj.getProjectName()); - result.push(proj.getChangesSinceVersion(knownProject && knownProject.version, includeProjectReferenceRedirectInfo)); + result.push( + proj.getChangesSinceVersion( + knownProject && knownProject.version, + includeProjectReferenceRedirectInfo, + ), + ); } } /* @internal */ - synchronizeProjectList(knownProjects: protocol.ProjectVersionInfo[], includeProjectReferenceRedirectInfo?: boolean): ProjectFilesWithTSDiagnostics[] { + synchronizeProjectList( + knownProjects: protocol.ProjectVersionInfo[], + includeProjectReferenceRedirectInfo?: boolean, + ): ProjectFilesWithTSDiagnostics[] { const files: ProjectFilesWithTSDiagnostics[] = []; this.collectChanges(knownProjects, this.externalProjects, includeProjectReferenceRedirectInfo, files); - this.collectChanges(knownProjects, arrayFrom(this.configuredProjects.values()), includeProjectReferenceRedirectInfo, files); + this.collectChanges( + knownProjects, + arrayFrom(this.configuredProjects.values()), + includeProjectReferenceRedirectInfo, + files, + ); this.collectChanges(knownProjects, this.inferredProjects, includeProjectReferenceRedirectInfo, files); return files; } /* @internal */ - applyChangesInOpenFiles(openFiles: Iterator | undefined, changedFiles?: Iterator, closedFiles?: string[]): void { + applyChangesInOpenFiles( + openFiles: Iterator | undefined, + changedFiles?: Iterator, + closedFiles?: string[], + ): void { let openScriptInfos: ScriptInfo[] | undefined; let assignOrphanScriptInfosToInferredProject = false; if (openFiles) { @@ -3781,14 +4346,19 @@ namespace ts.server { if (closedFiles) { for (const file of closedFiles) { // Close files, but dont assign projects to orphan open script infos, that part comes later - assignOrphanScriptInfosToInferredProject = this.closeClientFile(file, /*skipAssignOrphanScriptInfosToInferredProject*/ true) || assignOrphanScriptInfosToInferredProject; + assignOrphanScriptInfosToInferredProject = + this.closeClientFile(file, /*skipAssignOrphanScriptInfosToInferredProject*/ true) + || assignOrphanScriptInfosToInferredProject; } } // All the script infos now exist, so ok to go update projects for open files let retainProjects: readonly ConfiguredProject[] | undefined; if (openScriptInfos) { - retainProjects = flatMap(openScriptInfos, info => this.assignProjectToOpenedScriptInfo(info).retainProjects); + retainProjects = flatMap( + openScriptInfos, + info => this.assignProjectToOpenedScriptInfo(info).retainProjects, + ); } // While closing files there could be open files that needed assigning new inferred projects, do it now @@ -3917,7 +4487,9 @@ namespace ts.server { if (typeof groupNumberOrString === "number") { if (!isString(groups[groupNumberOrString])) { // Specification was wrong - exclude nothing! - this.logger.info(`Incorrect RegExp specification in safelist rule ${name} - not enough groups`); + this.logger.info( + `Incorrect RegExp specification in safelist rule ${name} - not enough groups`, + ); // * can't appear in a filename; escape it because it's feeding into a RegExp return "\\*"; } @@ -3958,7 +4530,11 @@ namespace ts.server { const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName); const typeName = this.legacySafelist.get(cleanedTypingName); if (typeName !== undefined) { - this.logger.info(`Excluded '${normalizedNames[i]}' because it matched ${cleanedTypingName} from the legacy safelist`); + this.logger.info( + `Excluded '${ + normalizedNames[i] + }' because it matched ${cleanedTypingName} from the legacy safelist`, + ); excludedFiles.push(normalizedNames[i]); // *exclude* it from the project... exclude = true; @@ -4026,8 +4602,16 @@ namespace ts.server { externalProject.excludedFiles = excludedFiles; if (!tsConfigFiles) { const compilerOptions = convertCompilerOptions(proj.options); - const watchOptionsAndErrors = convertWatchOptions(proj.options, externalProject.getCurrentDirectory()); - const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(proj.projectFileName, compilerOptions, proj.rootFiles, externalFilePropertyReader); + const watchOptionsAndErrors = convertWatchOptions( + proj.options, + externalProject.getCurrentDirectory(), + ); + const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles( + proj.projectFileName, + compilerOptions, + proj.rootFiles, + externalFilePropertyReader, + ); if (lastFileExceededProgramSize) { externalProject.disableLanguageService(lastFileExceededProgramSize); } @@ -4037,7 +4621,15 @@ namespace ts.server { externalProject.setProjectErrors(watchOptionsAndErrors?.errors); // external project already exists and not config files were added - update the project and return; // The graph update here isnt postponed since any file open operation needs all updated external projects - this.updateRootAndOptionsOfNonInferredProject(externalProject, proj.rootFiles, externalFilePropertyReader, compilerOptions, proj.typeAcquisition, proj.options.compileOnSave, watchOptionsAndErrors?.watchOptions); + this.updateRootAndOptionsOfNonInferredProject( + externalProject, + proj.rootFiles, + externalFilePropertyReader, + compilerOptions, + proj.typeAcquisition, + proj.options.compileOnSave, + watchOptionsAndErrors?.watchOptions, + ); externalProject.updateGraph(); return; } @@ -4086,9 +4678,15 @@ namespace ts.server { let project = this.findConfiguredProjectByProjectName(tsconfigFile); if (!project) { // errors are stored in the project, do not need to update the graph - project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject ? - this.createConfiguredProjectWithDelayLoad(tsconfigFile, `Creating configured project in external project: ${proj.projectFileName}`) : - this.createLoadAndUpdateConfiguredProject(tsconfigFile, `Creating configured project in external project: ${proj.projectFileName}`); + project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject + ? this.createConfiguredProjectWithDelayLoad( + tsconfigFile, + `Creating configured project in external project: ${proj.projectFileName}`, + ) + : this.createLoadAndUpdateConfiguredProject( + tsconfigFile, + `Creating configured project in external project: ${proj.projectFileName}`, + ); } if (project && !contains(exisingConfigFiles, tsconfigFile)) { // keep project alive even if no documents are opened - its lifetime is bound to the lifetime of containing external project @@ -4101,7 +4699,13 @@ namespace ts.server { // Create external project and update its graph, do not delay update since // any file open operation needs all updated external projects this.externalProjectToConfiguredProjectMap.delete(proj.projectFileName); - const project = this.createExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition, excludedFiles); + const project = this.createExternalProject( + proj.projectFileName, + rootFiles, + proj.options, + proj.typeAcquisition, + excludedFiles, + ); project.updateGraph(); } } @@ -4117,21 +4721,38 @@ namespace ts.server { } /*@internal*/ - requestEnablePlugin(project: Project, pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map | undefined) { + requestEnablePlugin( + project: Project, + pluginConfigEntry: PluginImport, + searchPaths: string[], + pluginConfigOverrides: Map | undefined, + ) { if (!this.host.importPlugin && !this.host.require) { - this.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded"); + this.logger.info( + "Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded", + ); return; } - this.logger.info(`Enabling plugin ${pluginConfigEntry.name} from candidate paths: ${searchPaths.join(",")}`); + this.logger.info( + `Enabling plugin ${pluginConfigEntry.name} from candidate paths: ${searchPaths.join(",")}`, + ); if (!pluginConfigEntry.name || parsePackageName(pluginConfigEntry.name).rest) { - this.logger.info(`Skipped loading plugin ${pluginConfigEntry.name || JSON.stringify(pluginConfigEntry)} because only package name is allowed plugin name`); + this.logger.info( + `Skipped loading plugin ${ + pluginConfigEntry.name || JSON.stringify(pluginConfigEntry) + } because only package name is allowed plugin name`, + ); return; } // If the host supports dynamic import, begin enabling the plugin asynchronously. if (this.host.importPlugin) { - const importPromise = project.beginEnablePluginAsync(pluginConfigEntry, searchPaths, pluginConfigOverrides); + const importPromise = project.beginEnablePluginAsync( + pluginConfigEntry, + searchPaths, + pluginConfigOverrides, + ); this.pendingPluginEnablements ??= new Map(); let promises = this.pendingPluginEnablements.get(project); if (!promises) this.pendingPluginEnablements.set(project, promises = []); @@ -4140,7 +4761,9 @@ namespace ts.server { } // Otherwise, load the plugin using `require` - project.endEnablePlugin(project.beginEnablePluginSync(pluginConfigEntry, searchPaths, pluginConfigOverrides)); + project.endEnablePlugin( + project.beginEnablePluginSync(pluginConfigEntry, searchPaths, pluginConfigOverrides), + ); } /* @internal */ @@ -4200,14 +4823,22 @@ namespace ts.server { // Process all pending plugins, partitioned by project. This way a project with few plugins doesn't need to wait // on a project with many plugins. - await Promise.all(map(pendingPlugins, ([project, promises]) => this.enableRequestedPluginsForProjectAsync(project, promises))); + await Promise.all( + map( + pendingPlugins, + ([project, promises]) => this.enableRequestedPluginsForProjectAsync(project, promises), + ), + ); // Clear the pending operation and notify the client that projects have been updated. this.currentPluginEnablementPromise = undefined; this.sendProjectsUpdatedInBackgroundEvent(); } - private async enableRequestedPluginsForProjectAsync(project: Project, promises: Promise[]) { + private async enableRequestedPluginsForProjectAsync( + project: Project, + promises: Promise[], + ) { // Await all pending plugin imports. This ensures all requested plugin modules are fully loaded // prior to patching the language service, and that any promise rejections are observed. const results = await Promise.all(promises); @@ -4226,7 +4857,9 @@ namespace ts.server { configurePlugin(args: protocol.ConfigurePluginRequestArguments) { // For any projects that already have the plugin loaded, configure the plugin - this.forEachEnabledProject(project => project.onPluginConfigurationChanged(args.pluginName, args.configuration)); + this.forEachEnabledProject(project => + project.onPluginConfigurationChanged(args.pluginName, args.configuration) + ); // Also save the current configuration to pass on to any projects that are yet to be loaded. // If a plugin is configured twice, only the latest configuration will be remembered. diff --git a/src/server/moduleSpecifierCache.ts b/src/server/moduleSpecifierCache.ts index c463de93cbe7d..f23bf2de7964d 100644 --- a/src/server/moduleSpecifierCache.ts +++ b/src/server/moduleSpecifierCache.ts @@ -14,7 +14,10 @@ namespace ts.server { return cache.get(toFileName); }, set(fromFileName, toFileName, preferences, options, modulePaths, moduleSpecifiers) { - ensureCache(fromFileName, preferences, options).set(toFileName, createInfo(modulePaths, moduleSpecifiers, /*isBlockedByPackageJsonDependencies*/ false)); + ensureCache(fromFileName, preferences, options).set( + toFileName, + createInfo(modulePaths, moduleSpecifiers, /*isBlockedByPackageJsonDependencies*/ false), + ); // If any module specifiers were generated based off paths in node_modules, // a package.json file in that package was read and is an input to the cached. @@ -25,7 +28,10 @@ namespace ts.server { for (const p of modulePaths) { if (p.isInNodeModules) { // No trailing slash - const nodeModulesPath = p.path.substring(0, p.path.indexOf(nodeModulesPathPart) + nodeModulesPathPart.length - 1); + const nodeModulesPath = p.path.substring( + 0, + p.path.indexOf(nodeModulesPathPart) + nodeModulesPathPart.length - 1, + ); if (!containedNodeModulesWatchers?.has(nodeModulesPath)) { (containedNodeModulesWatchers ||= new Map()).set( nodeModulesPath, @@ -43,17 +49,37 @@ namespace ts.server { info.modulePaths = modulePaths; } else { - cache.set(toFileName, createInfo(modulePaths, /*moduleSpecifiers*/ undefined, /*isBlockedByPackageJsonDependencies*/ undefined)); + cache.set( + toFileName, + createInfo( + modulePaths, + /*moduleSpecifiers*/ undefined, + /*isBlockedByPackageJsonDependencies*/ undefined, + ), + ); } }, - setBlockedByPackageJsonDependencies(fromFileName, toFileName, preferences, options, isBlockedByPackageJsonDependencies) { + setBlockedByPackageJsonDependencies( + fromFileName, + toFileName, + preferences, + options, + isBlockedByPackageJsonDependencies, + ) { const cache = ensureCache(fromFileName, preferences, options); const info = cache.get(toFileName); if (info) { info.isBlockedByPackageJsonDependencies = isBlockedByPackageJsonDependencies; } else { - cache.set(toFileName, createInfo(/*modulePaths*/ undefined, /*moduleSpecifiers*/ undefined, isBlockedByPackageJsonDependencies)); + cache.set( + toFileName, + createInfo( + /*modulePaths*/ undefined, + /*moduleSpecifiers*/ undefined, + isBlockedByPackageJsonDependencies, + ), + ); } }, clear() { diff --git a/src/server/packageJsonCache.ts b/src/server/packageJsonCache.ts index 5c88fb9334dd5..9a352835741cc 100644 --- a/src/server/packageJsonCache.ts +++ b/src/server/packageJsonCache.ts @@ -48,9 +48,9 @@ namespace ts.server { } function directoryHasPackageJson(directory: Path) { - return packageJsons.has(combinePaths(directory, "package.json")) ? Ternary.True : - directoriesWithoutPackageJson.has(directory) ? Ternary.False : - Ternary.Maybe; + return packageJsons.has(combinePaths(directory, "package.json")) ? Ternary.True + : directoriesWithoutPackageJson.has(directory) ? Ternary.False + : Ternary.Maybe; } } } diff --git a/src/server/project.ts b/src/server/project.ts index a53e8c0815c99..734680f0a73a7 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -77,7 +77,10 @@ namespace ts.server { /* @internal */ export function hasNoTypeScriptSource(fileNames: string[]): boolean { - return !fileNames.some(fileName => (fileExtensionIs(fileName, Extension.Ts) && !isDeclarationFileName(fileName)) || fileExtensionIs(fileName, Extension.Tsx)); + return !fileNames.some(fileName => + (fileExtensionIs(fileName, Extension.Ts) && !isDeclarationFileName(fileName)) + || fileExtensionIs(fileName, Extension.Tsx) + ); } /* @internal */ @@ -248,7 +251,13 @@ namespace ts.server { return hasOneOrMoreJsAndNoTsFiles(this); } - public static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void, logErrors?: (message: string) => void): {} | undefined { + public static resolveModule( + moduleName: string, + initialDir: string, + host: ServerHost, + log: (message: string) => void, + logErrors?: (message: string) => void, + ): {} | undefined { const resolvedPath = normalizeSlashes(host.resolvePath(combinePaths(initialDir, "node_modules"))); log(`Loading ${moduleName} from ${initialDir} (resolved to ${resolvedPath})`); const result = host.require!(resolvedPath, moduleName); // TODO: GH#18217 @@ -261,7 +270,13 @@ namespace ts.server { } /*@internal*/ - public static async importServicePluginAsync(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void, logErrors?: (message: string) => void): Promise<{} | undefined> { + public static async importServicePluginAsync( + moduleName: string, + initialDir: string, + host: ServerHost, + log: (message: string) => void, + logErrors?: (message: string) => void, + ): Promise<{} | undefined> { Debug.assertIsDefined(host.importPlugin); const resolvedPath = combinePaths(initialDir, "node_modules"); log(`Dynamically importing ${moduleName} from ${initialDir} (resolved to ${resolvedPath})`); @@ -320,13 +335,19 @@ namespace ts.server { this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory || ""); this.getCanonicalFileName = this.projectService.toCanonicalFileName; - this.cancellationToken = new ThrottledCancellationToken(this.projectService.cancellationToken, this.projectService.throttleWaitMilliseconds); + this.cancellationToken = new ThrottledCancellationToken( + this.projectService.cancellationToken, + this.projectService.throttleWaitMilliseconds, + ); if (!this.compilerOptions) { this.compilerOptions = getDefaultCompilerOptions(); this.compilerOptions.allowNonTsExtensions = true; this.compilerOptions.allowJs = true; } - else if (hasExplicitListOfFiles || getAllowJSCompilerOption(this.compilerOptions) || this.projectService.hasDeferredExtension()) { + else if ( + hasExplicitListOfFiles || getAllowJSCompilerOption(this.compilerOptions) + || this.projectService.hasDeferredExtension() + ) { // If files are listed explicitly or allowJs is specified, allow all extensions this.compilerOptions.allowNonTsExtensions = true; } @@ -379,7 +400,11 @@ namespace ts.server { return this.typingsCache.isKnownTypesPackageName(name); } installPackage(options: InstallPackageOptions): Promise { - return this.typingsCache.installPackage({ ...options, projectName: this.projectName, projectRootPath: this.toPath(this.currentDirectory) }); + return this.typingsCache.installPackage({ + ...options, + projectName: this.projectName, + projectRootPath: this.toPath(this.currentDirectory), + }); } /*@internal*/ @@ -444,7 +469,11 @@ namespace ts.server { } private getOrCreateScriptInfoAndAttachToProject(fileName: string) { - const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.currentDirectory, this.directoryStructureHost); + const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient( + fileName, + this.currentDirectory, + this.directoryStructureHost, + ); if (scriptInfo) { const existingValue = this.rootFilesMap.get(scriptInfo.path); if (existingValue && existingValue.info !== scriptInfo) { @@ -465,7 +494,11 @@ namespace ts.server { getScriptVersion(filename: string) { // Don't attach to the project if version is asked - const info = this.projectService.getOrCreateScriptInfoNotOpenedByClient(filename, this.currentDirectory, this.directoryStructureHost); + const info = this.projectService.getOrCreateScriptInfoNotOpenedByClient( + filename, + this.currentDirectory, + this.directoryStructureHost, + ); return (info && info.getLatestVersion())!; // TODO: GH#18217 } @@ -493,7 +526,13 @@ namespace ts.server { return this.projectService.host.useCaseSensitiveFileNames; } - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { return this.directoryStructureHost.readDirectory!(path, extensions, exclude, include, depth); } @@ -512,20 +551,52 @@ namespace ts.server { return !this.isWatchedMissingFile(path) && this.directoryStructureHost.fileExists(file); } - resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference, _options?: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModuleFull | undefined)[] { - return this.resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, containingSourceFile); + resolveModuleNames( + moduleNames: string[], + containingFile: string, + reusedNames?: string[], + redirectedReference?: ResolvedProjectReference, + _options?: CompilerOptions, + containingSourceFile?: SourceFile, + ): (ResolvedModuleFull | undefined)[] { + return this.resolutionCache.resolveModuleNames( + moduleNames, + containingFile, + reusedNames, + redirectedReference, + containingSourceFile, + ); } getModuleResolutionCache(): ModuleResolutionCache | undefined { return this.resolutionCache.getModuleResolutionCache(); } - getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined { - return this.resolutionCache.getResolvedModuleWithFailedLookupLocationsFromCache(moduleName, containingFile, resolutionMode); + getResolvedModuleWithFailedLookupLocationsFromCache( + moduleName: string, + containingFile: string, + resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): ResolvedModuleWithFailedLookupLocations | undefined { + return this.resolutionCache.getResolvedModuleWithFailedLookupLocationsFromCache( + moduleName, + containingFile, + resolutionMode, + ); } - resolveTypeReferenceDirectives(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference?: ResolvedProjectReference, _options?: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[] { - return this.resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference, containingFileMode); + resolveTypeReferenceDirectives( + typeDirectiveNames: string[] | FileReference[], + containingFile: string, + redirectedReference?: ResolvedProjectReference, + _options?: CompilerOptions, + containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, + ): (ResolvedTypeReferenceDirective | undefined)[] { + return this.resolutionCache.resolveTypeReferenceDirectives( + typeDirectiveNames, + containingFile, + redirectedReference, + containingFileMode, + ); } directoryExists(path: string): boolean { @@ -547,7 +618,11 @@ namespace ts.server { } /*@internal*/ - watchDirectoryOfFailedLookupLocation(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags) { + watchDirectoryOfFailedLookupLocation( + directory: string, + cb: DirectoryWatcherCallback, + flags: WatchDirectoryFlags, + ) { return this.projectService.watchFactory.watchDirectory( directory, cb, @@ -577,18 +652,22 @@ namespace ts.server { /*@internal*/ scheduleInvalidateResolutionsOfFailedLookupLocations() { - this.projectService.throttledOperations.schedule(`${this.getProjectName()}FailedLookupInvalidation`, /*delay*/ 1000, () => { - if (this.resolutionCache.invalidateResolutionsOfFailedLookupLocations()) { - this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this); - } - }); + this.projectService.throttledOperations.schedule( + `${this.getProjectName()}FailedLookupInvalidation`, + /*delay*/ 1000, + () => { + if (this.resolutionCache.invalidateResolutionsOfFailedLookupLocations()) { + this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this); + } + }, + ); } /*@internal*/ invalidateResolutionsOfFailedLookupLocations() { if ( - this.clearInvalidateResolutionOfFailedLookupTimer() && - this.resolutionCache.invalidateResolutionsOfFailedLookupLocations() + this.clearInvalidateResolutionOfFailedLookupTimer() + && this.resolutionCache.invalidateResolutionsOfFailedLookupLocations() ) { this.markAsDirty(); this.projectService.delayEnsureProjectForOpenFiles(); @@ -624,7 +703,8 @@ namespace ts.server { /*@internal*/ getGlobalCache() { - return this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation : undefined; + return this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation + : undefined; } /*@internal*/ @@ -690,7 +770,10 @@ namespace ts.server { } /*@internal*/ - getDocumentPositionMapper(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined { + getDocumentPositionMapper( + generatedFileName: string, + sourceFileName?: string, + ): DocumentPositionMapper | undefined { return this.projectService.getDocumentPositionMapper(this, generatedFileName, sourceFileName); } @@ -701,9 +784,9 @@ namespace ts.server { /*@internal*/ shouldEmitFile(scriptInfo: ScriptInfo | undefined) { - return scriptInfo && - !scriptInfo.isDynamicOrHasMixedContent() && - !this.program!.isSourceOfProjectReferenceRedirect(scriptInfo.path); + return scriptInfo + && !scriptInfo.isDynamicOrHasMixedContent() + && !this.program!.isSourceOfProjectReferenceRedirect(scriptInfo.path); } getCompileOnSaveAffectedFileList(scriptInfo: ScriptInfo): string[] { @@ -711,7 +794,12 @@ namespace ts.server { return []; } updateProjectIfDirty(this); - this.builderState = BuilderState.create(this.program!, this.projectService.toCanonicalFileName, this.builderState, /*disableUseFileVersionAsSignature*/ true); + this.builderState = BuilderState.create( + this.program!, + this.projectService.toCanonicalFileName, + this.builderState, + /*disableUseFileVersionAsSignature*/ true, + ); return mapDefined( BuilderState.getFilesAffectedBy( this.builderState, @@ -721,21 +809,31 @@ namespace ts.server { maybeBind(this.projectService.host, this.projectService.host.createHash), this.getCanonicalFileName, ), - sourceFile => this.shouldEmitFile(this.projectService.getScriptInfoForPath(sourceFile.path)) ? sourceFile.fileName : undefined, + sourceFile => + this.shouldEmitFile(this.projectService.getScriptInfoForPath(sourceFile.path)) ? sourceFile.fileName + : undefined, ); } /** * Returns true if emit was conducted */ - emitFile(scriptInfo: ScriptInfo, writeFile: (path: string, data: string, writeByteOrderMark?: boolean) => void): EmitResult { + emitFile( + scriptInfo: ScriptInfo, + writeFile: (path: string, data: string, writeByteOrderMark?: boolean) => void, + ): EmitResult { if (!this.languageServiceEnabled || !this.shouldEmitFile(scriptInfo)) { return { emitSkipped: true, diagnostics: emptyArray }; } - const { emitSkipped, diagnostics, outputFiles } = this.getLanguageService().getEmitOutput(scriptInfo.fileName); + const { emitSkipped, diagnostics, outputFiles } = this.getLanguageService().getEmitOutput( + scriptInfo.fileName, + ); if (!emitSkipped) { for (const outputFile of outputFiles) { - const outputFileAbsoluteFileName = getNormalizedAbsolutePath(outputFile.name, this.currentDirectory); + const outputFileAbsoluteFileName = getNormalizedAbsolutePath( + outputFile.name, + this.currentDirectory, + ); writeFile(outputFileAbsoluteFileName, outputFile.text, outputFile.writeByteOrderMark); } @@ -744,9 +842,9 @@ namespace ts.server { const dtsFiles = outputFiles.filter(f => isDeclarationFileName(f.name)); if (dtsFiles.length === 1) { const sourceFile = this.program!.getSourceFile(scriptInfo.fileName)!; - const signature = this.projectService.host.createHash ? - this.projectService.host.createHash(dtsFiles[0].text) : - generateDjb2Hash(dtsFiles[0].text); + const signature = this.projectService.host.createHash + ? this.projectService.host.createHash(dtsFiles[0].text) + : generateDjb2Hash(dtsFiles[0].text); BuilderState.updateSignatureOfFile(this.builderState, signature, sourceFile.resolvedPath); } } @@ -830,7 +928,9 @@ namespace ts.server { for (const f of this.program.getSourceFiles()) { this.detachScriptInfoIfNotRoot(f.fileName); } - this.program.forEachResolvedProjectReference(ref => this.detachScriptInfoFromProject(ref.sourceFile.fileName)); + this.program.forEachResolvedProjectReference(ref => + this.detachScriptInfoFromProject(ref.sourceFile.fileName) + ); } // Release external files @@ -918,7 +1018,12 @@ namespace ts.server { } return map(this.program!.getSourceFiles(), sourceFile => { const scriptInfo = this.projectService.getScriptInfoForPath(sourceFile.resolvedPath); - Debug.assert(!!scriptInfo, "getScriptInfo", () => `scriptInfo for a file '${sourceFile.fileName}' Path: '${sourceFile.path}' / '${sourceFile.resolvedPath}' is missing.`); + Debug.assert( + !!scriptInfo, + "getScriptInfo", + () => + `scriptInfo for a file '${sourceFile.fileName}' Path: '${sourceFile.path}' / '${sourceFile.resolvedPath}' is missing.`, + ); return scriptInfo; }); } @@ -968,7 +1073,8 @@ namespace ts.server { getFileNamesWithRedirectInfo(includeProjectReferenceRedirectInfo: boolean) { return this.getFileNames().map((fileName): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName, - isSourceOfProjectReferenceRedirect: includeProjectReferenceRedirectInfo && this.isSourceOfProjectReferenceRedirect(fileName), + isSourceOfProjectReferenceRedirect: includeProjectReferenceRedirectInfo + && this.isSourceOfProjectReferenceRedirect(fileName), })); } @@ -1104,7 +1210,10 @@ namespace ts.server { * @returns: true if set of files in the project stays the same and false - otherwise. */ updateGraph(): boolean { - tracing?.push(tracing.Phase.Session, "updateGraph", { name: this.projectName, kind: ProjectKind[this.projectKind] }); + tracing?.push(tracing.Phase.Session, "updateGraph", { + name: this.projectName, + kind: ProjectKind[this.projectKind], + }); perfLogger.logStartUpdateGraph(); this.resolutionCache.startRecordingFilesWithChangedResolutions(); @@ -1113,7 +1222,8 @@ namespace ts.server { this.hasAddedorRemovedFiles = false; this.hasAddedOrRemovedSymlinks = false; - const changedFiles: readonly Path[] = this.resolutionCache.finishRecordingFilesWithChangedResolutions() || emptyArray; + const changedFiles: readonly Path[] = this.resolutionCache.finishRecordingFilesWithChangedResolutions() + || emptyArray; for (const file of changedFiles) { // delete cached information for changed files @@ -1130,10 +1240,17 @@ namespace ts.server { // (can reuse cached imports for files that were not changed) // 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch if (hasNewProgram || changedFiles.length) { - this.lastCachedUnresolvedImportsList = getUnresolvedImports(this.program!, this.cachedUnresolvedImportsPerFile); + this.lastCachedUnresolvedImportsList = getUnresolvedImports( + this.program!, + this.cachedUnresolvedImportsPerFile, + ); } - this.projectService.typingsCache.enqueueInstallTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasAddedorRemovedFiles); + this.projectService.typingsCache.enqueueInstallTypingsForProject( + this, + this.lastCachedUnresolvedImportsList, + hasAddedorRemovedFiles, + ); } else { this.lastCachedUnresolvedImportsList = undefined; @@ -1158,11 +1275,21 @@ namespace ts.server { /*@internal*/ updateTypingFiles(typingFiles: SortedReadonlyArray) { - if (enumerateInsertsAndDeletes(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()), /*inserted*/ noop, removed => this.detachScriptInfoFromProject(removed))) { + if ( + enumerateInsertsAndDeletes( + typingFiles, + this.typingFiles, + getStringComparer(!this.useCaseSensitiveFileNames()), + /*inserted*/ noop, + removed => this.detachScriptInfoFromProject(removed), + ) + ) { // If typing files changed, then only schedule project update this.typingFiles = typingFiles; // Invalidate files with unresolved imports - this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile); + this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports( + this.cachedUnresolvedImportsPerFile, + ); this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this); } } @@ -1196,7 +1323,11 @@ namespace ts.server { // - oldProgram is not set - this is a first time updateGraph is called // - newProgram is different from the old program and structure of the old program was not reused. let hasNewProgram = false; - if (this.program && (!oldProgram || (this.program !== oldProgram && this.program.structureIsReused !== StructureIsReused.Completely))) { + if ( + this.program + && (!oldProgram + || (this.program !== oldProgram && this.program.structureIsReused !== StructureIsReused.Completely)) + ) { hasNewProgram = true; if (oldProgram) { for (const f of oldProgram.getSourceFiles()) { @@ -1209,7 +1340,9 @@ namespace ts.server { } oldProgram.forEachResolvedProjectReference(resolvedProjectReference => { - if (!this.program!.getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) { + if ( + !this.program!.getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path) + ) { this.detachScriptInfoFromProject(resolvedProjectReference.sourceFile.fileName); } }); @@ -1245,10 +1378,16 @@ namespace ts.server { this.generatedFilesMap.forEach((watcher, source) => { const sourceFile = this.program!.getSourceFileByPath(source); if ( - !sourceFile || - sourceFile.resolvedPath !== source || - !this.isValidGeneratedFileWatcher( - getDeclarationEmitOutputFilePathWorker(sourceFile.fileName, this.compilerOptions, this.currentDirectory, this.program!.getCommonSourceDirectory(), this.getCanonicalFileName), + !sourceFile + || sourceFile.resolvedPath !== source + || !this.isValidGeneratedFileWatcher( + getDeclarationEmitOutputFilePathWorker( + sourceFile.fileName, + this.compilerOptions, + this.currentDirectory, + this.program!.getCommonSourceDirectory(), + this.getCanonicalFileName, + ), watcher, ) ) { @@ -1279,7 +1418,11 @@ namespace ts.server { this.exportMapCache!.clear(); return true; } - return this.exportMapCache!.onFileChanged(oldSourceFile, sourceFile, !!this.getTypeAcquisition().enable); + return this.exportMapCache!.onFileChanged( + oldSourceFile, + sourceFile, + !!this.getTypeAcquisition().enable, + ); }); } } @@ -1287,7 +1430,10 @@ namespace ts.server { this.changedFilesForExportMapCache.clear(); } - if (this.hasAddedOrRemovedSymlinks || this.program && !this.program.structureIsReused && this.getCompilerOptions().preserveSymlinks) { + if ( + this.hasAddedOrRemovedSymlinks + || this.program && !this.program.structureIsReused && this.getCompilerOptions().preserveSymlinks + ) { // With --preserveSymlinks, we may not determine that a file is a symlink, so we never set `hasAddedOrRemovedSymlinks` this.symlinks = undefined; this.moduleSpecifierCache.clear(); @@ -1302,14 +1448,23 @@ namespace ts.server { // by the host for files in the program when the program is retrieved above but // the program doesn't contain external files so this must be done explicitly. inserted => { - const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(inserted, this.currentDirectory, this.directoryStructureHost); + const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient( + inserted, + this.currentDirectory, + this.directoryStructureHost, + ); scriptInfo?.attachToProject(this); }, removed => this.detachScriptInfoFromProject(removed), ); const elapsed = timestamp() - start; this.sendPerformanceEvent("UpdateGraph", elapsed); - this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasNewProgram}${this.program ? ` structureIsReused:: ${(ts as any).StructureIsReused[this.program.structureIsReused]}` : ""} Elapsed: ${elapsed}ms`); + this.writeLog( + `Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasNewProgram}${ + this.program + ? ` structureIsReused:: ${(ts as any).StructureIsReused[this.program.structureIsReused]}` : "" + } Elapsed: ${elapsed}ms`, + ); if (this.hasAddedorRemovedFiles) { this.print(/*writeProjectFileNames*/ true); } @@ -1337,7 +1492,9 @@ namespace ts.server { private addMissingFileWatcher(missingFilePath: Path) { if (isConfiguredProject(this)) { // If this file is referenced config file, we are already watching it, no need to watch again - const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(missingFilePath as string as NormalizedPath); + const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get( + missingFilePath as string as NormalizedPath, + ); if (configFileExistenceInfo?.config?.projects.has(this.canonicalConfigFilePath)) return noopFileWatcher; } const fileWatcher = this.projectService.watchFactory.watchFile( @@ -1380,7 +1537,11 @@ namespace ts.server { const path = this.toPath(sourceFile); if (this.generatedFilesMap) { if (isGeneratedFileWatcher(this.generatedFilesMap)) { - Debug.fail(`${this.projectName} Expected to not have --out watcher for generated file with options: ${JSON.stringify(this.compilerOptions)}`); + Debug.fail( + `${this.projectName} Expected to not have --out watcher for generated file with options: ${ + JSON.stringify(this.compilerOptions) + }`, + ); return; } if (this.generatedFilesMap.has(path)) return; @@ -1455,7 +1616,9 @@ namespace ts.server { /*@internal*/ print(writeProjectFileNames: boolean) { this.writeLog(`Project '${this.projectName}' (${ProjectKind[this.projectKind]})`); - this.writeLog(this.filesToString(writeProjectFileNames && this.projectService.logger.hasLevel(LogLevel.verbose))); + this.writeLog( + this.filesToString(writeProjectFileNames && this.projectService.logger.hasLevel(LogLevel.verbose)), + ); this.writeLog("-----------------------------------------------"); if (this.autoImportProviderHost) { this.autoImportProviderHost.print(/*writeProjectFileNames*/ false); @@ -1501,13 +1664,21 @@ namespace ts.server { } /* @internal */ - getChangesSinceVersion(lastKnownVersion?: number, includeProjectReferenceRedirectInfo?: boolean): ProjectFilesWithTSDiagnostics { + getChangesSinceVersion( + lastKnownVersion?: number, + includeProjectReferenceRedirectInfo?: boolean, + ): ProjectFilesWithTSDiagnostics { const includeProjectReferenceRedirectInfoIfRequested = includeProjectReferenceRedirectInfo ? (files: ESMap) => - arrayFrom(files.entries(), ([fileName, isSourceOfProjectReferenceRedirect]): protocol.FileWithProjectReferenceRedirectInfo => ({ - fileName, - isSourceOfProjectReferenceRedirect, - })) + arrayFrom( + files.entries(), + ( + [fileName, isSourceOfProjectReferenceRedirect], + ): protocol.FileWithProjectReferenceRedirectInfo => ({ + fileName, + isSourceOfProjectReferenceRedirect, + }), + ) : (files: ESMap) => arrayFrom(files.keys()); // Update the graph only if initial configured project load is not pending @@ -1533,7 +1704,9 @@ namespace ts.server { } // compute and return the difference const lastReportedFileNames = this.lastReportedFileNames; - const externalFiles = this.getExternalFiles().map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ + const externalFiles = this.getExternalFiles().map(( + f, + ): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName: toNormalizedPath(f), isSourceOfProjectReferenceRedirect: false, })); @@ -1553,7 +1726,10 @@ namespace ts.server { if (!lastReportedFileNames.has(fileName)) { added.set(fileName, isSourceOfProjectReferenceRedirect); } - else if (includeProjectReferenceRedirectInfo && isSourceOfProjectReferenceRedirect !== lastReportedFileNames.get(fileName)) { + else if ( + includeProjectReferenceRedirectInfo + && isSourceOfProjectReferenceRedirect !== lastReportedFileNames.get(fileName) + ) { updatedRedirects.push({ fileName, isSourceOfProjectReferenceRedirect, @@ -1586,7 +1762,9 @@ namespace ts.server { else { // unknown version - return everything const projectFileNames = this.getFileNamesWithRedirectInfo(!!includeProjectReferenceRedirectInfo); - const externalFiles = this.getExternalFiles().map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ + const externalFiles = this.getExternalFiles().map(( + f, + ): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName: toNormalizedPath(f), isSourceOfProjectReferenceRedirect: false, })); @@ -1631,7 +1809,9 @@ namespace ts.server { const host = this.projectService.host; if (!host.require && !host.importPlugin) { - this.projectService.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded"); + this.projectService.logger.info( + "Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded", + ); return; } @@ -1647,7 +1827,11 @@ namespace ts.server { // Provide global: true so plugins can detect why they can't find their config this.projectService.logger.info(`Loading global plugin ${globalPluginName}`); - this.enablePlugin({ name: globalPluginName, global: true } as PluginImport, searchPaths, pluginConfigOverrides); + this.enablePlugin( + { name: globalPluginName, global: true } as PluginImport, + searchPaths, + pluginConfigOverrides, + ); } } @@ -1655,7 +1839,11 @@ namespace ts.server { * Performs the initial steps of enabling a plugin by finding and instantiating the module for a plugin synchronously using 'require'. */ /*@internal*/ - beginEnablePluginSync(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map | undefined): BeginEnablePluginResult { + beginEnablePluginSync( + pluginConfigEntry: PluginImport, + searchPaths: string[], + pluginConfigOverrides: Map | undefined, + ): BeginEnablePluginResult { Debug.assertIsDefined(this.projectService.host.require); let errorLogs: string[] | undefined; @@ -1663,7 +1851,17 @@ namespace ts.server { const logError = (message: string) => { (errorLogs ??= []).push(message); }; - const resolvedModule = firstDefined(searchPaths, searchPath => Project.resolveModule(pluginConfigEntry.name, searchPath, this.projectService.host, log, logError) as PluginModuleFactory | undefined); + const resolvedModule = firstDefined( + searchPaths, + searchPath => + Project.resolveModule( + pluginConfigEntry.name, + searchPath, + this.projectService.host, + log, + logError, + ) as PluginModuleFactory | undefined, + ); return { pluginConfigEntry, pluginConfigOverrides, resolvedModule, errorLogs }; } @@ -1671,7 +1869,11 @@ namespace ts.server { * Performs the initial steps of enabling a plugin by finding and instantiating the module for a plugin asynchronously using dynamic `import`. */ /*@internal*/ - async beginEnablePluginAsync(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map | undefined): Promise { + async beginEnablePluginAsync( + pluginConfigEntry: PluginImport, + searchPaths: string[], + pluginConfigOverrides: Map | undefined, + ): Promise { Debug.assertIsDefined(this.projectService.host.importPlugin); let errorLogs: string[] | undefined; @@ -1682,7 +1884,13 @@ namespace ts.server { let resolvedModule: PluginModuleFactory | undefined; for (const searchPath of searchPaths) { - resolvedModule = await Project.importServicePluginAsync(pluginConfigEntry.name, searchPath, this.projectService.host, log, logError) as PluginModuleFactory | undefined; + resolvedModule = await Project.importServicePluginAsync( + pluginConfigEntry.name, + searchPath, + this.projectService.host, + log, + logError, + ) as PluginModuleFactory | undefined; if (resolvedModule !== undefined) { break; } @@ -1694,9 +1902,12 @@ namespace ts.server { * Performs the remaining steps of enabling a plugin after its module has been instantiated. */ /*@internal*/ - endEnablePlugin({ pluginConfigEntry, pluginConfigOverrides, resolvedModule, errorLogs }: BeginEnablePluginResult) { + endEnablePlugin( + { pluginConfigEntry, pluginConfigOverrides, resolvedModule, errorLogs }: BeginEnablePluginResult, + ) { if (resolvedModule) { - const configurationOverride = pluginConfigOverrides && pluginConfigOverrides.get(pluginConfigEntry.name); + const configurationOverride = pluginConfigOverrides + && pluginConfigOverrides.get(pluginConfigEntry.name); if (configurationOverride) { // Preserve the name property since it's immutable const pluginName = pluginConfigEntry.name; @@ -1712,14 +1923,20 @@ namespace ts.server { } } - protected enablePlugin(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map | undefined): void { + protected enablePlugin( + pluginConfigEntry: PluginImport, + searchPaths: string[], + pluginConfigOverrides: Map | undefined, + ): void { this.projectService.requestEnablePlugin(this, pluginConfigEntry, searchPaths, pluginConfigOverrides); } private enableProxy(pluginModuleFactory: PluginModuleFactory, configEntry: PluginImport) { try { if (typeof pluginModuleFactory !== "function") { - this.projectService.logger.info(`Skipped loading plugin ${configEntry.name} because it did not expose a proper factory function`); + this.projectService.logger.info( + `Skipped loading plugin ${configEntry.name} because it did not expose a proper factory function`, + ); return; } @@ -1737,7 +1954,9 @@ namespace ts.server { for (const k of Object.keys(this.languageService)) { // eslint-disable-next-line local/no-in-operator if (!(k in newLS)) { - this.projectService.logger.info(`Plugin activation warning: Missing proxied method ${k} in created LS. Patching.`); + this.projectService.logger.info( + `Plugin activation warning: Missing proxied method ${k} in created LS. Patching.`, + ); (newLS as any)[k] = (this.languageService as any)[k]; } } @@ -1777,7 +1996,10 @@ namespace ts.server { /*@internal*/ getPackageJsonsForAutoImport(rootDir?: string): readonly ProjectPackageJsonInfo[] { - const packageJsons = this.getPackageJsonsVisibleToFile(combinePaths(this.currentDirectory, inferredTypesContainingFile), rootDir); + const packageJsons = this.getPackageJsonsVisibleToFile( + combinePaths(this.currentDirectory, inferredTypesContainingFile), + rootDir, + ); this.packageJsonsForAutoImport = new Set(packageJsons.map(p => p.fileName)); return packageJsons; } @@ -1805,10 +2027,10 @@ namespace ts.server { /*@internal*/ includePackageJsonAutoImports(): PackageJsonAutoImportPreference { if ( - this.projectService.includePackageJsonAutoImports() === PackageJsonAutoImportPreference.Off || - !this.languageServiceEnabled || - isInsideNodeModules(this.currentDirectory) || - !this.isDefaultProjectForOpenFiles() + this.projectService.includePackageJsonAutoImports() === PackageJsonAutoImportPreference.Off + || !this.languageServiceEnabled + || isInsideNodeModules(this.currentDirectory) + || !this.isDefaultProjectForOpenFiles() ) { return PackageJsonAutoImportPreference.Off; } @@ -1821,7 +2043,8 @@ namespace ts.server { return { fileExists: this.program.fileExists, directoryExists: this.program.directoryExists, - realpath: this.program.realpath || this.projectService.host.realpath?.bind(this.projectService.host), + realpath: this.program.realpath + || this.projectService.host.realpath?.bind(this.projectService.host), getCurrentDirectory: this.getCurrentDirectory.bind(this), readFile: this.projectService.host.readFile.bind(this.projectService.host), getDirectories: this.projectService.host.getDirectories.bind(this.projectService.host), @@ -1855,7 +2078,12 @@ namespace ts.server { if (dependencySelection) { tracing?.push(tracing.Phase.Session, "getPackageJsonAutoImportProvider"); const start = timestamp(); - this.autoImportProviderHost = AutoImportProviderProject.create(dependencySelection, this, this.getModuleResolutionHostForAutoImportProvider(), this.documentRegistry); + this.autoImportProviderHost = AutoImportProviderProject.create( + dependencySelection, + this, + this.getModuleResolutionHostForAutoImportProvider(), + this.documentRegistry, + ); if (this.autoImportProviderHost) { updateProjectIfDirty(this.autoImportProviderHost); this.sendPerformanceEvent("CreatePackageJsonAutoImportProvider", timestamp() - start); @@ -1888,7 +2116,11 @@ namespace ts.server { getNoDtsResolutionProject(rootFileNames: readonly string[]): Project { Debug.assert(this.projectService.serverMode === LanguageServiceMode.Semantic); if (!this.noDtsResolutionProject) { - this.noDtsResolutionProject = new AuxiliaryProject(this.projectService, this.documentRegistry, this.getCompilerOptionsForNoDtsResolutionProject()); + this.noDtsResolutionProject = new AuxiliaryProject( + this.projectService, + this.documentRegistry, + this.getCompilerOptionsForNoDtsResolutionProject(), + ); } enumerateInsertsAndDeletes( @@ -1934,24 +2166,37 @@ namespace ts.server { } } - function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile: ESMap): SortedReadonlyArray { + function getUnresolvedImports( + program: Program, + cachedUnresolvedImportsPerFile: ESMap, + ): SortedReadonlyArray { const sourceFiles = program.getSourceFiles(); tracing?.push(tracing.Phase.Session, "getUnresolvedImports", { count: sourceFiles.length }); const ambientModules = program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName())); - const result = sortAndDeduplicate(flatMap(sourceFiles, sourceFile => extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile))); + const result = sortAndDeduplicate( + flatMap( + sourceFiles, + sourceFile => + extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile), + ), + ); tracing?.pop(); return result; } - function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: readonly string[], cachedUnresolvedImportsPerFile: ESMap): readonly string[] { + function extractUnresolvedImportsFromSourceFile( + file: SourceFile, + ambientModules: readonly string[], + cachedUnresolvedImportsPerFile: ESMap, + ): readonly string[] { return getOrUpdate(cachedUnresolvedImportsPerFile, file.path, () => { if (!file.resolvedModules) return emptyArray; let unresolvedImports: string[] | undefined; file.resolvedModules.forEach((resolvedModule, name) => { // pick unresolved non-relative names if ( - (!resolvedModule || !resolutionExtensionIsTSOrJson(resolvedModule.extension)) && - !isExternalModuleNameRelative(name) && - !ambientModules.some(m => m === name) + (!resolvedModule || !resolutionExtensionIsTSOrJson(resolvedModule.extension)) + && !isExternalModuleNameRelative(name) + && !ambientModules.some(m => m === name) ) { unresolvedImports = append(unresolvedImports, parsePackageName(name).packageName); } @@ -2058,12 +2303,15 @@ namespace ts.server { // - when useSingleInferredProject is not set and projectRootPath is not set, // we can guarantee that this will be the only root // - other wise it has single root if it has single root script info - return (!this.projectRootPath && !this.projectService.useSingleInferredProject) || - this.getRootScriptInfos().length === 1; + return (!this.projectRootPath && !this.projectService.useSingleInferredProject) + || this.getRootScriptInfos().length === 1; } close() { - forEach(this.getRootScriptInfos(), info => this.projectService.stopWatchingConfigFilesForInferredProjectRoot(info)); + forEach( + this.getRootScriptInfos(), + info => this.projectService.stopWatchingConfigFilesForInferredProjectRoot(info), + ); super.close(); } @@ -2077,8 +2325,24 @@ namespace ts.server { } class AuxiliaryProject extends Project { - constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions) { - super(projectService.newAuxiliaryProjectName(), ProjectKind.Auxiliary, projectService, documentRegistry, /*hasExplicitListOfFiles*/ false, /*lastFileExceededProgramSize*/ undefined, compilerOptions, /*compileOnSaveEnabled*/ false, /*watchOptions*/ undefined, projectService.host, /*currentDirectory*/ undefined); + constructor( + projectService: ProjectService, + documentRegistry: DocumentRegistry, + compilerOptions: CompilerOptions, + ) { + super( + projectService.newAuxiliaryProjectName(), + ProjectKind.Auxiliary, + projectService, + documentRegistry, + /*hasExplicitListOfFiles*/ false, + /*lastFileExceededProgramSize*/ undefined, + compilerOptions, + /*compileOnSaveEnabled*/ false, + /*watchOptions*/ undefined, + projectService.host, + /*currentDirectory*/ undefined, + ); } isOrphan(): boolean { @@ -2097,7 +2361,12 @@ namespace ts.server { private static readonly maxDependencies = 10; /*@internal*/ - static getRootFileNames(dependencySelection: PackageJsonAutoImportPreference, hostProject: Project, moduleResolutionHost: ModuleResolutionHost, compilerOptions: CompilerOptions): string[] { + static getRootFileNames( + dependencySelection: PackageJsonAutoImportPreference, + hostProject: Project, + moduleResolutionHost: ModuleResolutionHost, + compilerOptions: CompilerOptions, + ): string[] { if (!dependencySelection) { return ts.emptyArray; } @@ -2111,7 +2380,9 @@ namespace ts.server { let dependencyNames: Set | undefined; let rootNames: string[] | undefined; const rootFileName = combinePaths(hostProject.currentDirectory, inferredTypesContainingFile); - const packageJsons = hostProject.getPackageJsonsForAutoImport(combinePaths(hostProject.currentDirectory, rootFileName)); + const packageJsons = hostProject.getPackageJsonsForAutoImport( + combinePaths(hostProject.currentDirectory, rootFileName), + ); for (const packageJson of packageJsons) { packageJson.dependencies?.forEach((_, dependenyName) => addDependency(dependenyName)); packageJson.peerDependencies?.forEach((_, dependencyName) => addDependency(dependencyName)); @@ -2122,8 +2393,13 @@ namespace ts.server { const symlinkCache = hostProject.getSymlinkCache(); for (const name of arrayFrom(dependencyNames.keys())) { // Avoid creating a large project that would significantly slow down time to editor interactivity - if (dependencySelection === PackageJsonAutoImportPreference.Auto && dependenciesAdded > this.maxDependencies) { - hostProject.log(`AutoImportProviderProject: attempted to add more than ${this.maxDependencies} dependencies. Aborting.`); + if ( + dependencySelection === PackageJsonAutoImportPreference.Auto + && dependenciesAdded > this.maxDependencies + ) { + hostProject.log( + `AutoImportProviderProject: attempted to add more than ${this.maxDependencies} dependencies. Aborting.`, + ); return ts.emptyArray; } @@ -2149,23 +2425,30 @@ namespace ts.server { // 2. Try to load from the @types package in the tree and in the global // typings cache location, if enabled. - const done = forEach([hostProject.currentDirectory, hostProject.getGlobalTypingsCacheLocation()], directory => { - if (directory) { - const typesPackageJson = resolvePackageNameToPackageJson( - `@types/${name}`, - directory, - compilerOptions, - moduleResolutionHost, - program.getModuleResolutionCache(), - ); - if (typesPackageJson) { - const entrypoints = getRootNamesFromPackageJson(typesPackageJson, program, symlinkCache); - rootNames = concatenate(rootNames, entrypoints); - dependenciesAdded += entrypoints?.length ? 1 : 0; - return true; + const done = forEach( + [hostProject.currentDirectory, hostProject.getGlobalTypingsCacheLocation()], + directory => { + if (directory) { + const typesPackageJson = resolvePackageNameToPackageJson( + `@types/${name}`, + directory, + compilerOptions, + moduleResolutionHost, + program.getModuleResolutionCache(), + ); + if (typesPackageJson) { + const entrypoints = getRootNamesFromPackageJson( + typesPackageJson, + program, + symlinkCache, + ); + rootNames = concatenate(rootNames, entrypoints); + dependenciesAdded += entrypoints?.length ? 1 : 0; + return true; + } } - } - }); + }, + ); if (done) continue; @@ -2173,7 +2456,12 @@ namespace ts.server { // allow processing JS from node_modules, go back to the implementation // package and load the JS. if (packageJson && compilerOptions.allowJs && compilerOptions.maxNodeModuleJsDepth) { - const entrypoints = getRootNamesFromPackageJson(packageJson, program, symlinkCache, /*allowJs*/ true); + const entrypoints = getRootNamesFromPackageJson( + packageJson, + program, + symlinkCache, + /*allowJs*/ true, + ); rootNames = concatenate(rootNames, entrypoints); dependenciesAdded += entrypoints?.length ? 1 : 0; } @@ -2181,7 +2469,11 @@ namespace ts.server { } if (rootNames?.length) { - hostProject.log(`AutoImportProviderProject: found ${rootNames.length} root files in ${dependenciesAdded} dependencies in ${timestamp() - start} ms`); + hostProject.log( + `AutoImportProviderProject: found ${rootNames.length} root files in ${dependenciesAdded} dependencies in ${ + timestamp() - start + } ms`, + ); } return rootNames || ts.emptyArray; @@ -2191,7 +2483,12 @@ namespace ts.server { } } - function getRootNamesFromPackageJson(packageJson: PackageJsonInfo, program: Program, symlinkCache: SymlinkCache, resolveJs?: boolean) { + function getRootNamesFromPackageJson( + packageJson: PackageJsonInfo, + program: Program, + symlinkCache: SymlinkCache, + resolveJs?: boolean, + ) { const entrypoints = getEntrypointsFromPackageJsonInfo( packageJson, compilerOptions, @@ -2210,8 +2507,12 @@ namespace ts.server { } return mapDefined(entrypoints, entrypoint => { - const resolvedFileName = isSymlink ? entrypoint.replace(packageJson.packageDirectory, real) : entrypoint; - if (!program.getSourceFile(resolvedFileName) && !(isSymlink && program.getSourceFile(entrypoint))) { + const resolvedFileName = isSymlink ? entrypoint.replace(packageJson.packageDirectory, real) + : entrypoint; + if ( + !program.getSourceFile(resolvedFileName) + && !(isSymlink && program.getSourceFile(entrypoint)) + ) { return resolvedFileName; } }); @@ -2230,7 +2531,12 @@ namespace ts.server { }; /*@internal*/ - static create(dependencySelection: PackageJsonAutoImportPreference, hostProject: Project, moduleResolutionHost: ModuleResolutionHost, documentRegistry: DocumentRegistry): AutoImportProviderProject | undefined { + static create( + dependencySelection: PackageJsonAutoImportPreference, + hostProject: Project, + moduleResolutionHost: ModuleResolutionHost, + documentRegistry: DocumentRegistry, + ): AutoImportProviderProject | undefined { if (dependencySelection === PackageJsonAutoImportPreference.Off) { return undefined; } @@ -2240,7 +2546,12 @@ namespace ts.server { ...this.compilerOptionsOverrides, }; - const rootNames = this.getRootFileNames(dependencySelection, hostProject, moduleResolutionHost, compilerOptions); + const rootNames = this.getRootFileNames( + dependencySelection, + hostProject, + moduleResolutionHost, + compilerOptions, + ); if (!rootNames.length) { return undefined; } @@ -2257,10 +2568,25 @@ namespace ts.server { documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, ) { - super(hostProject.projectService.newAutoImportProviderProjectName(), ProjectKind.AutoImportProvider, hostProject.projectService, documentRegistry, /*hasExplicitListOfFiles*/ false, /*lastFileExceededProgramSize*/ undefined, compilerOptions, /*compileOnSaveEnabled*/ false, hostProject.getWatchOptions(), hostProject.projectService.host, hostProject.currentDirectory); + super( + hostProject.projectService.newAutoImportProviderProjectName(), + ProjectKind.AutoImportProvider, + hostProject.projectService, + documentRegistry, + /*hasExplicitListOfFiles*/ false, + /*lastFileExceededProgramSize*/ undefined, + compilerOptions, + /*compileOnSaveEnabled*/ false, + hostProject.getWatchOptions(), + hostProject.projectService.host, + hostProject.currentDirectory, + ); this.rootFileNames = initialRootNames; - this.useSourceOfProjectReferenceRedirect = maybeBind(this.hostProject, this.hostProject.useSourceOfProjectReferenceRedirect); + this.useSourceOfProjectReferenceRedirect = maybeBind( + this.hostProject, + this.hostProject.useSourceOfProjectReferenceRedirect, + ); this.getParsedCommandLine = maybeBind(this.hostProject, this.hostProject.getParsedCommandLine); } @@ -2314,7 +2640,9 @@ namespace ts.server { } getLanguageService(): never { - throw new Error("AutoImportProviderProject language service should never be used. To get the program, use `project.getCurrentProgram()`."); + throw new Error( + "AutoImportProviderProject language service should never be used. To get the program, use `project.getCurrentProgram()`.", + ); } /*@internal*/ @@ -2328,7 +2656,9 @@ namespace ts.server { } getModuleResolutionHostForAutoImportProvider(): never { - throw new Error("AutoImportProviderProject cannot provide its own host; use `hostProject.getModuleResolutionHostForAutomImportProvider()` instead."); + throw new Error( + "AutoImportProviderProject cannot provide its own host; use `hostProject.getModuleResolutionHostForAutomImportProvider()` instead.", + ); } getProjectReferences() { @@ -2394,8 +2724,26 @@ namespace ts.server { private compilerHost?: CompilerHost; /*@internal*/ - constructor(configFileName: NormalizedPath, readonly canonicalConfigFilePath: NormalizedPath, projectService: ProjectService, documentRegistry: DocumentRegistry, cachedDirectoryStructureHost: CachedDirectoryStructureHost) { - super(configFileName, ProjectKind.Configured, projectService, documentRegistry, /*hasExplicitListOfFiles*/ false, /*lastFileExceededProgramSize*/ undefined, /*compilerOptions*/ {}, /*compileOnSaveEnabled*/ false, /*watchOptions*/ undefined, cachedDirectoryStructureHost, getDirectoryPath(configFileName)); + constructor( + configFileName: NormalizedPath, + readonly canonicalConfigFilePath: NormalizedPath, + projectService: ProjectService, + documentRegistry: DocumentRegistry, + cachedDirectoryStructureHost: CachedDirectoryStructureHost, + ) { + super( + configFileName, + ProjectKind.Configured, + projectService, + documentRegistry, + /*hasExplicitListOfFiles*/ false, + /*lastFileExceededProgramSize*/ undefined, + /*compilerOptions*/ {}, + /*compileOnSaveEnabled*/ false, + /*watchOptions*/ undefined, + cachedDirectoryStructureHost, + getDirectoryPath(configFileName), + ); } /* @internal */ @@ -2420,10 +2768,18 @@ namespace ts.server { // Ensure the config file existience info is cached let configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(canonicalConfigFilePath); if (!configFileExistenceInfo) { - this.projectService.configFileExistenceInfoCache.set(canonicalConfigFilePath, configFileExistenceInfo = { exists: this.projectService.host.fileExists(configFileName) }); + this.projectService.configFileExistenceInfoCache.set( + canonicalConfigFilePath, + configFileExistenceInfo = { exists: this.projectService.host.fileExists(configFileName) }, + ); } // Ensure we have upto date parsed command line - this.projectService.ensureParsedConfigUptoDate(configFileName, canonicalConfigFilePath, configFileExistenceInfo, this); + this.projectService.ensureParsedConfigUptoDate( + configFileName, + canonicalConfigFilePath, + configFileExistenceInfo, + this, + ); // Watch wild cards if LS is enabled if (this.languageServiceEnabled && this.projectService.serverMode === LanguageServiceMode.Semantic) { this.projectService.watchWildcards(configFileName, configFileExistenceInfo, this); @@ -2433,7 +2789,9 @@ namespace ts.server { /* @internal */ onReleaseParsedCommandLine(fileName: string) { - this.releaseParsedConfig(asNormalizedPath(this.projectService.toCanonicalFileName(asNormalizedPath(normalizePath(fileName))))); + this.releaseParsedConfig( + asNormalizedPath(this.projectService.toCanonicalFileName(asNormalizedPath(normalizePath(fileName)))), + ); } /* @internal */ @@ -2461,7 +2819,12 @@ namespace ts.server { this.openFileWatchTriggered.clear(); const reason = Debug.checkDefined(this.pendingReloadReason); this.pendingReloadReason = undefined; - this.projectService.reloadConfiguredProject(this, reason, isInitialLoad, /*clearSemanticCache*/ false); + this.projectService.reloadConfiguredProject( + this, + reason, + isInitialLoad, + /*clearSemanticCache*/ false, + ); result = true; break; default: @@ -2511,12 +2874,17 @@ namespace ts.server { } /*@internal*/ - enablePluginsWithOptions(options: CompilerOptions, pluginConfigOverrides: ESMap | undefined): void { + enablePluginsWithOptions( + options: CompilerOptions, + pluginConfigOverrides: ESMap | undefined, + ): void { this.plugins.length = 0; if (!options.plugins?.length && !this.projectService.globalPlugins.length) return; const host = this.projectService.host; if (!host.require && !host.importPlugin) { - this.projectService.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded"); + this.projectService.logger.info( + "Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded", + ); return; } @@ -2556,7 +2924,10 @@ namespace ts.server { } close() { - this.projectService.configFileExistenceInfoCache.forEach((_configFileExistenceInfo, canonicalConfigFilePath) => this.releaseParsedConfig(canonicalConfigFilePath)); + this.projectService.configFileExistenceInfoCache.forEach(( + _configFileExistenceInfo, + canonicalConfigFilePath, + ) => this.releaseParsedConfig(canonicalConfigFilePath)); this.projectErrors = undefined; this.openFileWatchTriggered.clear(); this.compilerHost = undefined; @@ -2575,8 +2946,8 @@ namespace ts.server { /* @internal */ isSolution() { - return this.getRootFilesMap().size === 0 && - !this.canConfigFileJsonReportNoInputFiles; + return this.getRootFilesMap().size === 0 + && !this.canConfigFileJsonReportNoInputFiles; } /* @internal */ @@ -2586,9 +2957,9 @@ namespace ts.server { this, info.path, child => - projectContainsInfoDirectly(child, info) ? - child : - undefined, + projectContainsInfoDirectly(child, info) + ? child + : undefined, ProjectReferenceProjectLoadKind.Find, ); } @@ -2605,7 +2976,9 @@ namespace ts.server { return false; } - const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(this.canonicalConfigFilePath)!; + const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get( + this.canonicalConfigFilePath, + )!; if (this.projectService.hasPendingProjectUpdate(this)) { // If there is pending update for this project, // we dont know if this project would be needed by any of the open files impacted by this config file @@ -2620,8 +2993,8 @@ namespace ts.server { configFileExistenceInfo.openFilesImpactedByConfigFile, (_value, infoPath) => { const info = this.projectService.getScriptInfoForPath(infoPath)!; - return this.containsScriptInfo(info) || - !!forEachResolvedProjectReferenceProject( + return this.containsScriptInfo(info) + || !!forEachResolvedProjectReferenceProject( this, info.path, child => child.containsScriptInfo(info), @@ -2642,7 +3015,13 @@ namespace ts.server { /*@internal*/ updateErrorOnNoInputFiles(fileNames: string[]) { - updateErrorForNoInputFiles(fileNames, this.getConfigFilePath(), this.getCompilerOptions().configFile!.configFileSpecs!, this.projectErrors!, this.canConfigFileJsonReportNoInputFiles); + updateErrorForNoInputFiles( + fileNames, + this.getConfigFilePath(), + this.getCompilerOptions().configFile!.configFileSpecs!, + this.projectErrors!, + this.canConfigFileJsonReportNoInputFiles, + ); } } @@ -2653,8 +3032,30 @@ namespace ts.server { export class ExternalProject extends Project { excludedFiles: readonly NormalizedPath[] = []; /*@internal*/ - constructor(public externalProjectName: string, projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, lastFileExceededProgramSize: string | undefined, public compileOnSaveEnabled: boolean, projectFilePath?: string, pluginConfigOverrides?: ESMap, watchOptions?: WatchOptions) { - super(externalProjectName, ProjectKind.External, projectService, documentRegistry, /*hasExplicitListOfFiles*/ true, lastFileExceededProgramSize, compilerOptions, compileOnSaveEnabled, watchOptions, projectService.host, getDirectoryPath(projectFilePath || normalizeSlashes(externalProjectName))); + constructor( + public externalProjectName: string, + projectService: ProjectService, + documentRegistry: DocumentRegistry, + compilerOptions: CompilerOptions, + lastFileExceededProgramSize: string | undefined, + public compileOnSaveEnabled: boolean, + projectFilePath?: string, + pluginConfigOverrides?: ESMap, + watchOptions?: WatchOptions, + ) { + super( + externalProjectName, + ProjectKind.External, + projectService, + documentRegistry, + /*hasExplicitListOfFiles*/ true, + lastFileExceededProgramSize, + compilerOptions, + compileOnSaveEnabled, + watchOptions, + projectService.host, + getDirectoryPath(projectFilePath || normalizeSlashes(externalProjectName)), + ); this.enableGlobalPlugins(this.getCompilerOptions(), pluginConfigOverrides); } diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index b45decbc42761..91512cf584bcd 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -46,7 +46,11 @@ namespace ts.server { */ private pendingReloadFromDisk = false; - constructor(private readonly host: ServerHost, private readonly info: ScriptInfo, initialVersion?: ScriptInfoVersion) { + constructor( + private readonly host: ServerHost, + private readonly info: ScriptInfo, + initialVersion?: ScriptInfoVersion, + ) { this.version = initialVersion || { svc: 0, text: 0 }; } @@ -189,7 +193,13 @@ namespace ts.server { */ lineOffsetToPosition(line: number, offset: number, allowEdits?: true): number { if (!this.useScriptVersionCacheIfValidOrOpen()) { - return computePositionOfLineAndCharacter(this.getLineMap(), line - 1, offset - 1, this.text, allowEdits); + return computePositionOfLineAndCharacter( + this.getLineMap(), + line - 1, + offset - 1, + this.text, + allowEdits, + ); } // TODO: assert this offset is actually on the line @@ -214,7 +224,9 @@ namespace ts.server { if (fileSize > maxFileSize) { Debug.assert(!!this.info.containingProjects.length); const service = this.info.containingProjects[0].projectService; - service.logger.info(`Skipped loading contents of large file ${fileName} for info ${this.info.fileName}: fileSize: ${fileSize}`); + service.logger.info( + `Skipped loading contents of large file ${fileName} for info ${this.info.fileName}: fileSize: ${fileSize}`, + ); this.info.containingProjects[0].projectService.sendLargeFileReferencedEvent(fileName, fileSize); return { text: "", fileSize }; } @@ -247,7 +259,10 @@ namespace ts.server { private getOrLoadText() { if (this.text === undefined || this.pendingReloadFromDisk) { - Debug.assert(!this.svc || this.pendingReloadFromDisk, "ScriptVersionCache should not be set when reloading from disk"); + Debug.assert( + !this.svc || this.pendingReloadFromDisk, + "ScriptVersionCache should not be set when reloading from disk", + ); this.reloadWithFileText(); } return this.text!; @@ -271,10 +286,10 @@ namespace ts.server { } export function isDynamicFileName(fileName: NormalizedPath) { - return fileName[0] === "^" || - ((stringContains(fileName, "walkThroughSnippet:/") || stringContains(fileName, "untitled:/")) && - getBaseFileName(fileName)[0] === "^") || - (stringContains(fileName, ":^") && !stringContains(fileName, directorySeparator)); + return fileName[0] === "^" + || ((stringContains(fileName, "walkThroughSnippet:/") || stringContains(fileName, "untitled:/")) + && getBaseFileName(fileName)[0] === "^") + || (stringContains(fileName, ":^") && !stringContains(fileName, directorySeparator)); } /*@internal*/ @@ -370,8 +385,8 @@ namespace ts.server { public open(newText: string) { this.textStorage.isOpen = true; if ( - newText !== undefined && - this.textStorage.reload(newText) + newText !== undefined + && this.textStorage.reload(newText) ) { // reload new contents only if the existing contents changed this.markContainingProjectsAsDirty(); @@ -492,7 +507,11 @@ namespace ts.server { detachAllProjects() { for (const p of this.containingProjects) { if (isConfiguredProject(p)) { - p.getCachedDirectoryStructureHost().addOrDeleteFile(this.fileName, this.path, FileWatcherEventKind.Deleted); + p.getCachedDirectoryStructureHost().addOrDeleteFile( + this.fileName, + this.path, + FileWatcherEventKind.Deleted, + ); } const existingRoot = p.getRootFilesMap().get(this.path); // detach is unnecessary since we'll clean the list of containing projects anyways @@ -532,13 +551,16 @@ namespace ts.server { // If we havent found default configuredProject and // its not the last one, find it and use that one if there if ( - defaultConfiguredProject === undefined && - index !== this.containingProjects.length - 1 + defaultConfiguredProject === undefined + && index !== this.containingProjects.length - 1 ) { - defaultConfiguredProject = project.projectService.findDefaultConfiguredProject(this) || false; + defaultConfiguredProject = project.projectService.findDefaultConfiguredProject(this) + || false; } if (defaultConfiguredProject === project) return project; - if (!firstNonSourceOfProjectReferenceRedirect) firstNonSourceOfProjectReferenceRedirect = project; + if (!firstNonSourceOfProjectReferenceRedirect) { + firstNonSourceOfProjectReferenceRedirect = project; + } } if (!firstConfiguredProject) firstConfiguredProject = project; } @@ -550,11 +572,11 @@ namespace ts.server { } } return ensurePrimaryProjectKind( - defaultConfiguredProject || - firstNonSourceOfProjectReferenceRedirect || - firstConfiguredProject || - firstExternalProject || - firstInferredProject, + defaultConfiguredProject + || firstNonSourceOfProjectReferenceRedirect + || firstConfiguredProject + || firstExternalProject + || firstInferredProject, ); } } @@ -693,7 +715,10 @@ namespace ts.server { * reported as the default project for a ScriptInfo. */ function ensurePrimaryProjectKind(project: Project | undefined) { - if (!project || project.projectKind === ProjectKind.AutoImportProvider || project.projectKind === ProjectKind.Auxiliary) { + if ( + !project || project.projectKind === ProjectKind.AutoImportProvider + || project.projectKind === ProjectKind.Auxiliary + ) { return Errors.ThrowNoProject(); } return project; diff --git a/src/server/scriptVersionCache.ts b/src/server/scriptVersionCache.ts index 62719f7ea1b33..2da0dcae66e4a 100644 --- a/src/server/scriptVersionCache.ts +++ b/src/server/scriptVersionCache.ts @@ -27,8 +27,20 @@ namespace ts.server { goSubtree: boolean; done: boolean; leaf(relativeStart: number, relativeLength: number, lineCollection: LineLeaf): void; - pre?(relativeStart: number, relativeLength: number, lineCollection: LineCollection, parent: LineNode, nodeType: CharRangeSection): void; - post?(relativeStart: number, relativeLength: number, lineCollection: LineCollection, parent: LineNode, nodeType: CharRangeSection): void; + pre?( + relativeStart: number, + relativeLength: number, + lineCollection: LineCollection, + parent: LineNode, + nodeType: CharRangeSection, + ): void; + post?( + relativeStart: number, + relativeLength: number, + lineCollection: LineCollection, + parent: LineNode, + nodeType: CharRangeSection, + ): void; } class EditWalker implements LineIndexWalker { @@ -146,7 +158,13 @@ namespace ts.server { this.stack.pop(); } - pre(_relativeStart: number, _relativeLength: number, lineCollection: LineCollection, _parent: LineCollection, nodeType: CharRangeSection): void { + pre( + _relativeStart: number, + _relativeLength: number, + lineCollection: LineCollection, + _parent: LineCollection, + nodeType: CharRangeSection, + ): void { // currentNode corresponds to parent, but in the new tree const currentNode = this.stack[this.stack.length - 1]; @@ -243,7 +261,10 @@ namespace ts.server { } getTextChangeRange() { - return createTextChangeRange(createTextSpan(this.pos, this.deleteLen), this.insertedText ? this.insertedText.length : 0); + return createTextChangeRange( + createTextSpan(this.pos, this.deleteLen), + this.insertedText ? this.insertedText.length : 0, + ); } } @@ -273,9 +294,9 @@ namespace ts.server { edit(pos: number, deleteLen: number, insertedText?: string) { this.changes.push(new TextChange(pos, deleteLen, insertedText)); if ( - this.changes.length > ScriptVersionCache.changeNumberThreshold || - deleteLen > ScriptVersionCache.changeLengthThreshold || - insertedText && insertedText.length > ScriptVersionCache.changeLengthThreshold + this.changes.length > ScriptVersionCache.changeNumberThreshold + || deleteLen > ScriptVersionCache.changeLengthThreshold + || insertedText && insertedText.length > ScriptVersionCache.changeLengthThreshold ) { this.getSnapshot(); } @@ -324,7 +345,8 @@ namespace ts.server { lineToTextSpan(line: number): TextSpan { const index = this._getSnapshot().index; const { lineText, absolutePosition } = index.lineNumberToInfo(line + 1); - const len = lineText !== undefined ? lineText.length : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition; + const len = lineText !== undefined ? lineText.length + : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition; return createTextSpan(absolutePosition, len); } @@ -364,7 +386,12 @@ namespace ts.server { } class LineIndexSnapshot implements IScriptSnapshot { - constructor(readonly version: number, readonly cache: ScriptVersionCache, readonly index: LineIndex, readonly changesSincePreviousVersion: readonly TextChange[] = emptyArray) { + constructor( + readonly version: number, + readonly cache: ScriptVersionCache, + readonly index: LineIndex, + readonly changesSincePreviousVersion: readonly TextChange[] = emptyArray, + ) { } getText(rangeStart: number, rangeEnd: number) { @@ -401,7 +428,9 @@ namespace ts.server { return { line: oneBasedLine, offset: zeroBasedColumn + 1 }; } - private positionToColumnAndLineText(position: number): { zeroBasedColumn: number; lineText: string | undefined; } { + private positionToColumnAndLineText( + position: number, + ): { zeroBasedColumn: number; lineText: string | undefined; } { return this.root.charOffsetToLineInfo(1, position); } @@ -585,7 +614,13 @@ namespace ts.server { } } - private execWalk(rangeStart: number, rangeLength: number, walkFns: LineIndexWalker, childIndex: number, nodeType: CharRangeSection) { + private execWalk( + rangeStart: number, + rangeLength: number, + walkFns: LineIndexWalker, + childIndex: number, + nodeType: CharRangeSection, + ) { if (walkFns.pre) { walkFns.pre(rangeStart, rangeLength, this.children[childIndex], this, nodeType); } @@ -601,7 +636,13 @@ namespace ts.server { return walkFns.done; } - private skipChild(relativeStart: number, relativeLength: number, childIndex: number, walkFns: LineIndexWalker, nodeType: CharRangeSection) { + private skipChild( + relativeStart: number, + relativeLength: number, + childIndex: number, + walkFns: LineIndexWalker, + nodeType: CharRangeSection, + ) { if (walkFns.pre && (!walkFns.done)) { walkFns.pre(relativeStart, relativeLength, this.children[childIndex], this, nodeType); walkFns.goSubtree = true; @@ -628,7 +669,15 @@ namespace ts.server { } else { // Case II: start and end of range in different subtrees (possibly with subtrees in the middle) - if (this.execWalk(adjustedStart, childCharCount - adjustedStart, walkFns, childIndex, CharRangeSection.Start)) { + if ( + this.execWalk( + adjustedStart, + childCharCount - adjustedStart, + walkFns, + childIndex, + CharRangeSection.Start, + ) + ) { return; } let adjustedLength = rangeLength - (childCharCount - adjustedStart); @@ -662,7 +711,10 @@ namespace ts.server { // Input position is relative to the start of this node. // Output line number is absolute. - charOffsetToLineInfo(lineNumberAccumulator: number, relativePosition: number): { oneBasedLine: number; zeroBasedColumn: number; lineText: string | undefined; } { + charOffsetToLineInfo( + lineNumberAccumulator: number, + relativePosition: number, + ): { oneBasedLine: number; zeroBasedColumn: number; lineText: string | undefined; } { if (this.children.length === 0) { // Root node might have no children if this is an empty document. return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: undefined }; @@ -671,7 +723,11 @@ namespace ts.server { for (const child of this.children) { if (child.charCount() > relativePosition) { if (child.isLeaf()) { - return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: child.text }; + return { + oneBasedLine: lineNumberAccumulator, + zeroBasedColumn: relativePosition, + lineText: child.text, + }; } else { return (child as LineNode).charOffsetToLineInfo(lineNumberAccumulator, relativePosition); @@ -697,11 +753,15 @@ namespace ts.server { * Output line number is relative to the child. * positionAccumulator will be an absolute position once relativeLineNumber reaches 0. */ - lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number; leaf: LineLeaf | undefined; } { + lineNumberToInfo( + relativeOneBasedLine: number, + positionAccumulator: number, + ): { position: number; leaf: LineLeaf | undefined; } { for (const child of this.children) { const childLineCount = child.lineCount(); if (childLineCount >= relativeOneBasedLine) { - return child.isLeaf() ? { position: positionAccumulator, leaf: child } : (child as LineNode).lineNumberToInfo(relativeOneBasedLine, positionAccumulator); + return child.isLeaf() ? { position: positionAccumulator, leaf: child } + : (child as LineNode).lineNumberToInfo(relativeOneBasedLine, positionAccumulator); } else { relativeOneBasedLine -= childLineCount; diff --git a/src/server/session.ts b/src/server/session.ts index 5f1d4412e7017..9af44f1d4a0e4 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -35,8 +35,8 @@ namespace ts.server { // file has '// @ts-check'). if ( - (isInferredProject(project) || isExternalProject(project)) && - project.isJsOnlyProject() + (isInferredProject(project) || isExternalProject(project)) + && project.isJsOnlyProject() ) { const scriptInfo = project.getScriptInfoForNormalizedPath(file); return scriptInfo && !scriptInfo.isJavaScript(); @@ -89,9 +89,13 @@ namespace ts.server { function formatDiagnosticToProtocol(diag: Diagnostic, includeFileName: true): protocol.DiagnosticWithFileName; function formatDiagnosticToProtocol(diag: Diagnostic, includeFileName: false): protocol.Diagnostic; - function formatDiagnosticToProtocol(diag: Diagnostic, includeFileName: boolean): protocol.Diagnostic | protocol.DiagnosticWithFileName { + function formatDiagnosticToProtocol( + diag: Diagnostic, + includeFileName: boolean, + ): protocol.Diagnostic | protocol.DiagnosticWithFileName { const start = (diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start!)))!; // TODO: GH#18217 - const end = (diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start! + diag.length!)))!; // TODO: GH#18217 + const end = + (diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start! + diag.length!)))!; // TODO: GH#18217 const text = flattenDiagnosticMessageText(diag.messageText, "\n"); const { code, source } = diag; const category = diagnosticCategoryName(diag); @@ -128,7 +132,12 @@ namespace ts.server { export type CommandNames = protocol.CommandTypes; export const CommandNames = (protocol as any).CommandTypes; - export function formatMessage(msg: T, logger: Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string { + export function formatMessage( + msg: T, + logger: Logger, + byteLength: (s: string, encoding: string) => number, + newLine: string, + ): string { const verboseLogging = logger.hasLevel(LogLevel.verbose); const json = JSON.stringify(msg); @@ -231,7 +240,10 @@ namespace ts.server { tracing?.instant(tracing.Phase.Session, "stepCanceled", { seq: this.requestId }); } else { - tracing?.instant(tracing.Phase.Session, "stepError", { seq: this.requestId, message: (e as Error).message }); + tracing?.instant(tracing.Phase.Session, "stepError", { + seq: this.requestId, + message: (e as Error).message, + }); this.operationHost.logError(e, `delayed processing of request ${this.requestId}`); } } @@ -289,7 +301,10 @@ namespace ts.server { projects: Projects, action: (project: Project, value: T) => readonly U[] | U | undefined, ): U[] { - const outputs = flatMapToMutable(isArray(projects) ? projects : projects.projects, project => action(project, defaultValue)); + const outputs = flatMapToMutable( + isArray(projects) ? projects : projects.projects, + project => action(project, defaultValue), + ); if (!isArray(projects) && projects.symLinkedProjects) { projects.symLinkedProjects.forEach((projects, path) => { const value = getValue(path); @@ -321,7 +336,14 @@ namespace ts.server { defaultProject, initialLocation, /*isForRename*/ true, - (project, position) => project.getLanguageService().findRenameLocations(position.fileName, position.pos, findInStrings, findInComments, providePrefixAndSuffixTextForRename), + (project, position) => + project.getLanguageService().findRenameLocations( + position.fileName, + position.pos, + findInStrings, + findInComments, + providePrefixAndSuffixTextForRename, + ), (renameLocation, cb) => cb(documentSpanLocation(renameLocation)), ); @@ -346,8 +368,17 @@ namespace ts.server { return results; } - function getDefinitionLocation(defaultProject: Project, initialLocation: DocumentPosition, isForRename: boolean): DocumentPosition | undefined { - const infos = defaultProject.getLanguageService().getDefinitionAtPosition(initialLocation.fileName, initialLocation.pos, /*searchOtherFilesOnly*/ false, /*stopAtAlias*/ isForRename); + function getDefinitionLocation( + defaultProject: Project, + initialLocation: DocumentPosition, + isForRename: boolean, + ): DocumentPosition | undefined { + const infos = defaultProject.getLanguageService().getDefinitionAtPosition( + initialLocation.fileName, + initialLocation.pos, + /*searchOtherFilesOnly*/ false, + /*stopAtAlias*/ isForRename, + ); const info = infos && firstOrUndefined(infos); // Note that the value of `isLocal` may depend on whether or not the checker has run on the containing file // (implying that FAR cascading behavior may depend on request order) @@ -366,7 +397,9 @@ namespace ts.server { initialLocation, /*isForRename*/ false, (project, position) => { - logger.info(`Finding references to ${position.fileName} position ${position.pos} in project ${project.getProjectName()}`); + logger.info( + `Finding references to ${position.fileName} position ${position.pos} in project ${project.getProjectName()}`, + ); return project.getLanguageService().findReferences(position.fileName, position.pos); }, (referencedSymbol, cb) => { @@ -415,7 +448,10 @@ namespace ts.server { let progress = false; perProjectResults.forEach((referencedSymbols, project) => { if (updatedProjects.has(project)) return; - const updated = project.getLanguageService().updateIsDefinitionOfReferencedSymbols(referencedSymbols, knownSymbolSpans); + const updated = project.getLanguageService().updateIsDefinitionOfReferencedSymbols( + referencedSymbols, + knownSymbolSpans, + ); if (updated) { updatedProjects.add(project); progress = true; @@ -445,10 +481,13 @@ namespace ts.server { // dropped later when we check for defs with ref-count 0. perProjectResults.forEach((projectResults, project) => { for (const referencedSymbol of projectResults) { - const mappedDefinitionFile = getMappedLocationForProject(documentSpanLocation(referencedSymbol.definition), project); - const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? - referencedSymbol.definition : - { + const mappedDefinitionFile = getMappedLocationForProject( + documentSpanLocation(referencedSymbol.definition), + project, + ); + const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined + ? referencedSymbol.definition + : { ...referencedSymbol.definition, textSpan: createTextSpan(mappedDefinitionFile.pos, referencedSymbol.definition.textSpan.length), // Why would the length be the same in the original? fileName: mappedDefinitionFile.fileName, @@ -478,7 +517,11 @@ namespace ts.server { readonly location: DocumentPosition; } - function forEachProjectInProjects(projects: Projects, path: string | undefined, cb: (project: Project, path: string | undefined) => void): void { + function forEachProjectInProjects( + projects: Projects, + path: string | undefined, + cb: (project: Project, path: string | undefined) => void, + ): void { for (const project of isArray(projects) ? projects : projects.projects) { cb(project, path); } @@ -532,14 +575,14 @@ namespace ts.server { // Don't call these unless !!defaultDefinition const getGeneratedDefinition = memoize(() => - defaultProject.isSourceOfProjectReferenceRedirect(defaultDefinition!.fileName) ? - defaultDefinition : - defaultProject.getLanguageService().getSourceMapper().tryGetGeneratedPosition(defaultDefinition!) + defaultProject.isSourceOfProjectReferenceRedirect(defaultDefinition!.fileName) + ? defaultDefinition + : defaultProject.getLanguageService().getSourceMapper().tryGetGeneratedPosition(defaultDefinition!) ); const getSourceDefinition = memoize(() => - defaultProject.isSourceOfProjectReferenceRedirect(defaultDefinition!.fileName) ? - defaultDefinition : - defaultProject.getLanguageService().getSourceMapper().tryGetSourcePosition(defaultDefinition!) + defaultProject.isSourceOfProjectReferenceRedirect(defaultDefinition!.fileName) + ? defaultDefinition + : defaultProject.getLanguageService().getSourceMapper().tryGetSourcePosition(defaultDefinition!) ); // The keys of resultsMap allow us to check which projects have already been searched, but we also @@ -571,7 +614,12 @@ namespace ts.server { projectService.forEachEnabledProject(project => { if (cancellationToken.isCancellationRequested()) return; // There's no mechanism for skipping the remaining projects if (resultsMap.has(project)) return; // Can loop forever without this (enqueue here, dequeue above, repeat) - const location = mapDefinitionInProject(defaultDefinition, project, getGeneratedDefinition, getSourceDefinition); + const location = mapDefinitionInProject( + defaultDefinition, + project, + getGeneratedDefinition, + getSourceDefinition, + ); if (location) { queue.enqueue({ project, location }); } @@ -596,7 +644,10 @@ namespace ts.server { for (const result of projectResults) { forPositionInResult(result, position => { // This may trigger a search for a tsconfig, but there are several layers of caching that make it inexpensive - const originalLocation = projectService.getOriginalLocationEnsuringConfiguredProject(project, position); + const originalLocation = projectService.getOriginalLocationEnsuringConfiguredProject( + project, + position, + ); if (!originalLocation) return; const originalScriptInfo = projectService.getScriptInfo(originalLocation.fileName)!; @@ -612,7 +663,10 @@ namespace ts.server { symlinkedProjectsMap.forEach((symlinkedProjects, symlinkedPath) => { for (const symlinkedProject of symlinkedProjects) { if (!symlinkedProject.isOrphan() && !resultsMap.has(symlinkedProject)) { // Optimization: don't enqueue if will be discarded - queue.enqueue({ project: symlinkedProject, location: { fileName: symlinkedPath as string, pos: originalLocation.pos } }); + queue.enqueue({ + project: symlinkedProject, + location: { fileName: symlinkedPath as string, pos: originalLocation.pos }, + }); } } }); @@ -632,15 +686,18 @@ namespace ts.server { ): DocumentPosition | undefined { // If the definition is actually from the project, definition is correct as is if ( - project.containsFile(toNormalizedPath(definition.fileName)) && - !isLocationProjectReferenceRedirect(project, definition) + project.containsFile(toNormalizedPath(definition.fileName)) + && !isLocationProjectReferenceRedirect(project, definition) ) { return definition; } const generatedDefinition = getGeneratedDefinition(); - if (generatedDefinition && project.containsFile(toNormalizedPath(generatedDefinition.fileName))) return generatedDefinition; + if (generatedDefinition && project.containsFile(toNormalizedPath(generatedDefinition.fileName))) { + return generatedDefinition; + } const sourceDefinition = getSourceDefinition(); - return sourceDefinition && project.containsFile(toNormalizedPath(sourceDefinition.fileName)) ? sourceDefinition : undefined; + return sourceDefinition && project.containsFile(toNormalizedPath(sourceDefinition.fileName)) ? sourceDefinition + : undefined; } function isLocationProjectReferenceRedirect(project: Project, location: DocumentPosition | undefined) { @@ -654,9 +711,9 @@ namespace ts.server { // This happens when rootFile in project is one of the file from referenced project // Thus root is attached but program doesnt have the actual .ts file but .d.ts // If this is not the file we were actually looking, return rest of the toDo - return !!sourceFile && - sourceFile.resolvedPath !== sourceFile.path && - sourceFile.resolvedPath !== project.toPath(location.fileName); + return !!sourceFile + && sourceFile.resolvedPath !== sourceFile.path + && sourceFile.resolvedPath !== project.toPath(location.fileName); } function getProjectKey(project: Project) { @@ -668,15 +725,27 @@ namespace ts.server { } function getMappedLocationForProject(location: DocumentPosition, project: Project): DocumentPosition | undefined { - return getMappedLocation(location, project.getSourceMapper(), p => project.projectService.fileExists(p as NormalizedPath)); + return getMappedLocation( + location, + project.getSourceMapper(), + p => project.projectService.fileExists(p as NormalizedPath), + ); } function getMappedDocumentSpanForProject(documentSpan: DocumentSpan, project: Project): DocumentSpan | undefined { - return getMappedDocumentSpan(documentSpan, project.getSourceMapper(), p => project.projectService.fileExists(p as NormalizedPath)); + return getMappedDocumentSpan( + documentSpan, + project.getSourceMapper(), + p => project.projectService.fileExists(p as NormalizedPath), + ); } function getMappedContextSpanForProject(documentSpan: DocumentSpan, project: Project): TextSpan | undefined { - return getMappedContextSpan(documentSpan, project.getSourceMapper(), p => project.projectService.fileExists(p as NormalizedPath)); + return getMappedContextSpan( + documentSpan, + project.getSourceMapper(), + p => project.projectService.fileExists(p as NormalizedPath), + ); } const invalidPartialSemanticModeCommands: readonly CommandNames[] = [ @@ -846,7 +915,9 @@ namespace ts.server { case LanguageServiceMode.PartialSemantic: invalidPartialSemanticModeCommands.forEach(commandName => this.handlers.set(commandName, request => { - throw new Error(`Request: ${request.command} not allowed in LanguageServiceMode.PartialSemantic`); + throw new Error( + `Request: ${request.command} not allowed in LanguageServiceMode.PartialSemantic`, + ); }) ); break; @@ -899,15 +970,24 @@ namespace ts.server { break; case ProjectLoadingFinishEvent: const { project: finishProject } = event.data; - this.event({ projectName: finishProject.getProjectName() }, ProjectLoadingFinishEvent); + this.event( + { projectName: finishProject.getProjectName() }, + ProjectLoadingFinishEvent, + ); break; case LargeFileReferencedEvent: const { file, fileSize, maxFileSize } = event.data; - this.event({ file, fileSize, maxFileSize }, LargeFileReferencedEvent); + this.event( + { file, fileSize, maxFileSize }, + LargeFileReferencedEvent, + ); break; case ConfigFileDiagEvent: const { triggerFile, configFileName: configFile, diagnostics } = event.data; - const bakedDiags = map(diagnostics, diagnostic => formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ true)); + const bakedDiags = map( + diagnostics, + diagnostic => formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ true), + ); this.event({ triggerFile, configFile, @@ -934,7 +1014,9 @@ namespace ts.server { } private projectsUpdatedInBackgroundEvent(openFiles: string[]): void { - this.projectService.logger.info(`got projects updated in background, updating diagnostics for ${openFiles}`); + this.projectService.logger.info( + `got projects updated in background, updating diagnostics for ${openFiles}`, + ); if (openFiles.length) { if (!this.suppressDiagnosticEvents && !this.noGetErrOnBackgroundUpdate) { // For now only queue error checking for open files. We can change this to include non open files as well @@ -952,7 +1034,11 @@ namespace ts.server { this.logErrorWorker(err, cmd); } - private logErrorWorker(err: Error & PossibleProgramFileInfo, cmd: string, fileRequest?: protocol.FileRequestArgs): void { + private logErrorWorker( + err: Error & PossibleProgramFileInfo, + cmd: string, + fileRequest?: protocol.FileRequestArgs, + ): void { let msg = "Exception on executing command " + cmd; if (err.message) { msg += ":\n" + indent(err.message); @@ -1019,7 +1105,13 @@ namespace ts.server { this.doOutput(info, cmdName, reqSeq!, /*success*/ !errorMsg, errorMsg); // TODO: GH#18217 } - private doOutput(info: {} | undefined, cmdName: string, reqSeq: number, success: boolean, message?: string): void { + private doOutput( + info: {} | undefined, + cmdName: string, + reqSeq: number, + success: boolean, + message?: string, + ): void { const res: protocol.Response = { seq: 0, type: "response", @@ -1061,7 +1153,10 @@ namespace ts.server { } private semanticCheck(file: NormalizedPath, project: Project) { - tracing?.push(tracing.Phase.Session, "semanticCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails + tracing?.push(tracing.Phase.Session, "semanticCheck", { + file, + configFilePath: (project as ConfiguredProject).canonicalConfigFilePath, + }); // undefined is fine if the cast fails const diags = isDeclarationFileInJSOnlyNonConfiguredProject(project, file) ? emptyArray : project.getLanguageService().getSemanticDiagnostics(file).filter(d => !!d.file); @@ -1070,20 +1165,44 @@ namespace ts.server { } private syntacticCheck(file: NormalizedPath, project: Project) { - tracing?.push(tracing.Phase.Session, "syntacticCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails - this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSyntacticDiagnostics(file), "syntaxDiag"); + tracing?.push(tracing.Phase.Session, "syntacticCheck", { + file, + configFilePath: (project as ConfiguredProject).canonicalConfigFilePath, + }); // undefined is fine if the cast fails + this.sendDiagnosticsEvent( + file, + project, + project.getLanguageService().getSyntacticDiagnostics(file), + "syntaxDiag", + ); tracing?.pop(); } private suggestionCheck(file: NormalizedPath, project: Project) { - tracing?.push(tracing.Phase.Session, "suggestionCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails - this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSuggestionDiagnostics(file), "suggestionDiag"); + tracing?.push(tracing.Phase.Session, "suggestionCheck", { + file, + configFilePath: (project as ConfiguredProject).canonicalConfigFilePath, + }); // undefined is fine if the cast fails + this.sendDiagnosticsEvent( + file, + project, + project.getLanguageService().getSuggestionDiagnostics(file), + "suggestionDiag", + ); tracing?.pop(); } - private sendDiagnosticsEvent(file: NormalizedPath, project: Project, diagnostics: readonly Diagnostic[], kind: protocol.DiagnosticEventKind): void { + private sendDiagnosticsEvent( + file: NormalizedPath, + project: Project, + diagnostics: readonly Diagnostic[], + kind: protocol.DiagnosticEventKind, + ): void { try { - this.event({ file, diagnostics: diagnostics.map(diag => formatDiag(file, project, diag)) }, kind); + this.event({ + file, + diagnostics: diagnostics.map(diag => formatDiag(file, project, diag)), + }, kind); } catch (err) { this.logError(err, kind); @@ -1091,7 +1210,12 @@ namespace ts.server { } /** It is the caller's responsibility to verify that `!this.suppressDiagnosticEvents`. */ - private updateErrorCheck(next: NextStep, checkList: readonly string[] | readonly PendingErrorCheck[], ms: number, requireOpen = true) { + private updateErrorCheck( + next: NextStep, + checkList: readonly string[] | readonly PendingErrorCheck[], + ms: number, + requireOpen = true, + ) { Debug.assert(!this.suppressDiagnosticEvents); // Caller's responsibility const seq = this.changeSeq; @@ -1187,7 +1311,8 @@ namespace ts.server { private getEncodedSemanticClassifications(args: protocol.EncodedSemanticClassificationsRequestArgs) { const { file, project } = this.getFileAndProject(args); - const format = args.format === "2020" ? SemanticClassificationFormat.TwentyTwenty : SemanticClassificationFormat.Original; + const format = args.format === "2020" ? SemanticClassificationFormat.TwentyTwenty + : SemanticClassificationFormat.Original; return project.getLanguageService().getEncodedSemanticClassifications(file, args, format); } @@ -1195,7 +1320,9 @@ namespace ts.server { return projectFileName === undefined ? undefined : this.projectService.findProject(projectFileName); } - private getConfigFileAndProject(args: protocol.FileRequestArgs): { configFile: NormalizedPath | undefined; project: Project | undefined; } { + private getConfigFileAndProject( + args: protocol.FileRequestArgs, + ): { configFile: NormalizedPath | undefined; project: Project | undefined; } { const project = this.getProject(args.projectFileName); const file = toNormalizedPath(args.file); @@ -1212,15 +1339,17 @@ namespace ts.server { concatenate(projectErrors, optionsErrors), diagnostic => !!diagnostic.file && diagnostic.file.fileName === configFile, ); - return includeLinePosition ? - this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnosticsForConfigFile) : - map( + return includeLinePosition + ? this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnosticsForConfigFile) + : map( diagnosticsForConfigFile, diagnostic => formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ false), ); } - private convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics: readonly Diagnostic[]): protocol.DiagnosticWithLinePosition[] { + private convertToDiagnosticsWithLinePositionFromDiagnosticFile( + diagnostics: readonly Diagnostic[], + ): protocol.DiagnosticWithLinePosition[] { return diagnostics.map(d => ({ message: flattenDiagnosticMessageText(d.messageText, this.host.newLine), start: d.start!, // TODO: GH#18217 @@ -1229,7 +1358,8 @@ namespace ts.server { code: d.code, source: d.source, startLocation: (d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start!)))!, // TODO: GH#18217 - endLocation: (d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start! + d.length!)))!, // TODO: GH#18217 + endLocation: + (d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start! + d.length!)))!, // TODO: GH#18217 reportsUnnecessary: d.reportsUnnecessary, reportsDeprecated: d.reportsDeprecated, relatedInformation: map(d.relatedInformation, formatRelatedInformation), @@ -1250,7 +1380,10 @@ namespace ts.server { ); } - private convertToDiagnosticsWithLinePosition(diagnostics: readonly Diagnostic[], scriptInfo: ScriptInfo | undefined): protocol.DiagnosticWithLinePosition[] { + private convertToDiagnosticsWithLinePosition( + diagnostics: readonly Diagnostic[], + scriptInfo: ScriptInfo | undefined, + ): protocol.DiagnosticWithLinePosition[] { return diagnostics.map(d => ({ message: flattenDiagnosticMessageText(d.messageText, this.host.newLine), @@ -1285,14 +1418,24 @@ namespace ts.server { : diagnostics.map(d => formatDiag(file, project, d)); } - private getDefinition(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): readonly protocol.FileSpanWithContext[] | readonly DefinitionInfo[] { + private getDefinition( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.FileSpanWithContext[] | readonly DefinitionInfo[] { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); - const definitions = this.mapDefinitionInfoLocations(project.getLanguageService().getDefinitionAtPosition(file, position) || emptyArray, project); - return simplifiedResult ? this.mapDefinitionInfo(definitions, project) : definitions.map(Session.mapToOriginalLocation); + const definitions = this.mapDefinitionInfoLocations( + project.getLanguageService().getDefinitionAtPosition(file, position) || emptyArray, + project, + ); + return simplifiedResult ? this.mapDefinitionInfo(definitions, project) + : definitions.map(Session.mapToOriginalLocation); } - private mapDefinitionInfoLocations(definitions: readonly DefinitionInfo[], project: Project): readonly DefinitionInfo[] { + private mapDefinitionInfoLocations( + definitions: readonly DefinitionInfo[], + project: Project, + ): readonly DefinitionInfo[] { return definitions.map((info): DefinitionInfo => { const newDocumentSpan = getMappedDocumentSpanForProject(info, project); return !newDocumentSpan ? info : { @@ -1307,12 +1450,18 @@ namespace ts.server { }); } - private getDefinitionAndBoundSpan(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.DefinitionInfoAndBoundSpan | DefinitionInfoAndBoundSpan { + private getDefinitionAndBoundSpan( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): protocol.DefinitionInfoAndBoundSpan | DefinitionInfoAndBoundSpan { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); const scriptInfo = Debug.checkDefined(project.getScriptInfo(file)); - const unmappedDefinitionAndBoundSpan = project.getLanguageService().getDefinitionAndBoundSpan(file, position); + const unmappedDefinitionAndBoundSpan = project.getLanguageService().getDefinitionAndBoundSpan( + file, + position, + ); if (!unmappedDefinitionAndBoundSpan || !unmappedDefinitionAndBoundSpan.definitions) { return { @@ -1341,10 +1490,13 @@ namespace ts.server { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); const unmappedDefinitions = project.getLanguageService().getDefinitionAtPosition(file, position); - let definitions: readonly DefinitionInfo[] = this.mapDefinitionInfoLocations(unmappedDefinitions || emptyArray, project).slice(); + let definitions: readonly DefinitionInfo[] = this.mapDefinitionInfoLocations( + unmappedDefinitions || emptyArray, + project, + ).slice(); const needsJsResolution = this.projectService.serverMode === LanguageServiceMode.Semantic && ( - !some(definitions, d => toNormalizedPath(d.fileName) !== file && !d.isAmbient) || - some(definitions, d => !!d.failedAliasResolution) + !some(definitions, d => toNormalizedPath(d.fileName) !== file && !d.isAmbient) + || some(definitions, d => !!d.failedAliasResolution) ); if (needsJsResolution) { @@ -1352,12 +1504,21 @@ namespace ts.server { definitions?.forEach(d => definitionSet.add(d)); const noDtsProject = project.getNoDtsResolutionProject([file]); const ls = noDtsProject.getLanguageService(); - const jsDefinitions = ls.getDefinitionAtPosition(file, position, /*searchOtherFilesOnly*/ true, /*stopAtAlias*/ false) + const jsDefinitions = ls.getDefinitionAtPosition( + file, + position, + /*searchOtherFilesOnly*/ true, + /*stopAtAlias*/ false, + ) ?.filter(d => toNormalizedPath(d.fileName) !== file); if (some(jsDefinitions)) { for (const jsDefinition of jsDefinitions) { if (jsDefinition.unverified) { - const refined = tryRefineDefinition(jsDefinition, project.getLanguageService().getProgram()!, ls.getProgram()!); + const refined = tryRefineDefinition( + jsDefinition, + project.getLanguageService().getProgram()!, + ls.getProgram()!, + ); if (some(refined)) { for (const def of refined) { definitionSet.add(def); @@ -1369,9 +1530,18 @@ namespace ts.server { } } else { - const ambientCandidates = definitions.filter(d => toNormalizedPath(d.fileName) !== file && d.isAmbient); - for (const candidate of some(ambientCandidates) ? ambientCandidates : getAmbientCandidatesByClimbingAccessChain()) { - const fileNameToSearch = findImplementationFileFromDtsFileName(candidate.fileName, file, noDtsProject); + const ambientCandidates = definitions.filter(d => + toNormalizedPath(d.fileName) !== file && d.isAmbient + ); + for ( + const candidate of some(ambientCandidates) ? ambientCandidates + : getAmbientCandidatesByClimbingAccessChain() + ) { + const fileNameToSearch = findImplementationFileFromDtsFileName( + candidate.fileName, + file, + noDtsProject, + ); if (!fileNameToSearch || !ensureRoot(noDtsProject, fileNameToSearch)) { continue; } @@ -1388,14 +1558,24 @@ namespace ts.server { definitions = definitions.filter(d => !d.isAmbient && !d.failedAliasResolution); return this.mapDefinitionInfo(definitions, project); - function findImplementationFileFromDtsFileName(fileName: string, resolveFromFile: string, auxiliaryProject: Project) { + function findImplementationFileFromDtsFileName( + fileName: string, + resolveFromFile: string, + auxiliaryProject: Project, + ) { const nodeModulesPathParts = getNodeModulePathParts(fileName); - if (nodeModulesPathParts && fileName.lastIndexOf(nodeModulesPathPart) === nodeModulesPathParts.topLevelNodeModulesIndex) { + if ( + nodeModulesPathParts + && fileName.lastIndexOf(nodeModulesPathPart) === nodeModulesPathParts.topLevelNodeModulesIndex + ) { // Second check ensures the fileName only contains one `/node_modules/`. If there's more than one I give up. const packageDirectory = fileName.substring(0, nodeModulesPathParts.packageRootIndex); const packageJsonCache = project.getModuleResolutionCache()?.getPackageJsonInfoCache(); const compilerOptions = project.getCompilationSettings(); - const packageJson = getPackageScopeForPath(getNormalizedAbsolutePath(packageDirectory + "/package.json", project.getCurrentDirectory()), getTemporaryModuleResolutionState(packageJsonCache, project, compilerOptions)); + const packageJson = getPackageScopeForPath( + getNormalizedAbsolutePath(packageDirectory + "/package.json", project.getCurrentDirectory()), + getTemporaryModuleResolutionState(packageJsonCache, project, compilerOptions), + ); if (!packageJson) return undefined; // Use fake options instead of actual compiler options to avoid following export map if the project uses node16 or nodenext - // Mapping from an export map entry across packages is out of scope for now. Returned entrypoints will only be what can be @@ -1411,19 +1591,27 @@ namespace ts.server { nodeModulesPathParts.topLevelPackageNameIndex + 1, nodeModulesPathParts.packageRootIndex, ); - const packageName = getPackageNameFromTypesPackageName(unmangleScopedPackageName(packageNamePathPart)); + const packageName = getPackageNameFromTypesPackageName( + unmangleScopedPackageName(packageNamePathPart), + ); const path = project.toPath(fileName); if (entrypoints && some(entrypoints, e => project.toPath(e) === path)) { // This file was the main entrypoint of a package. Try to resolve that same package name with // the auxiliary project that only resolves to implementation files. - const [implementationResolution] = auxiliaryProject.resolveModuleNames([packageName], resolveFromFile); + const [implementationResolution] = auxiliaryProject.resolveModuleNames( + [packageName], + resolveFromFile, + ); return implementationResolution?.resolvedFileName; } else { // It wasn't the main entrypoint but we are in node_modules. Try a subpath into the package. const pathToFileInPackage = fileName.substring(nodeModulesPathParts.packageRootIndex + 1); const specifier = `${packageName}/${removeFileExtension(pathToFileInPackage)}`; - const [implementationResolution] = auxiliaryProject.resolveModuleNames([specifier], resolveFromFile); + const [implementationResolution] = auxiliaryProject.resolveModuleNames( + [specifier], + resolveFromFile, + ); return implementationResolution?.resolvedFileName; } } @@ -1438,10 +1626,18 @@ namespace ts.server { const ls = project.getLanguageService(); const program = ls.getProgram()!; const initialNode = getTouchingPropertyName(program.getSourceFile(file)!, position); - if ((isStringLiteralLike(initialNode) || isIdentifier(initialNode)) && isAccessExpression(initialNode.parent)) { + if ( + (isStringLiteralLike(initialNode) || isIdentifier(initialNode)) + && isAccessExpression(initialNode.parent) + ) { return forEachNameInAccessChainWalkingLeft(initialNode, nameInChain => { if (nameInChain === initialNode) return undefined; - const candidates = ls.getDefinitionAtPosition(file, nameInChain.getStart(), /*searchOtherFilesOnly*/ true, /*stopAtAlias*/ false) + const candidates = ls.getDefinitionAtPosition( + file, + nameInChain.getStart(), + /*searchOtherFilesOnly*/ true, + /*stopAtAlias*/ false, + ) ?.filter(d => toNormalizedPath(d.fileName) !== file && d.isAmbient) .map(d => ({ fileName: d.fileName, @@ -1462,7 +1658,8 @@ namespace ts.server { } const initialNode = getTouchingPropertyName(program.getSourceFile(file)!, position); const symbol = program.getTypeChecker().getSymbolAtLocation(initialNode); - const importSpecifier = symbol && getDeclarationOfKind(symbol, SyntaxKind.ImportSpecifier); + const importSpecifier = symbol + && getDeclarationOfKind(symbol, SyntaxKind.ImportSpecifier); if (!importSpecifier) return undefined; const nameToSearch = importSpecifier.propertyName?.text || importSpecifier.name.text; @@ -1477,7 +1674,13 @@ namespace ts.server { if (symbol && decl) { // I think the last argument to this is supposed to be the start node, but it doesn't seem important. // Callers internal to GoToDefinition already get confused about this. - return GoToDefinition.createDefinitionInfo(decl, noDtsProgram.getTypeChecker(), symbol, decl, /*unverified*/ true); + return GoToDefinition.createDefinitionInfo( + decl, + noDtsProgram.getTypeChecker(), + symbol, + decl, + /*unverified*/ true, + ); } }); } @@ -1499,46 +1702,71 @@ namespace ts.server { return { emitSkipped: true, outputFiles: [], diagnostics: [] }; } const result = project.getLanguageService().getEmitOutput(file); - return args.richResponse ? - { + return args.richResponse + ? { ...result, - diagnostics: args.includeLinePosition ? - this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(result.diagnostics) : - result.diagnostics.map(d => formatDiagnosticToProtocol(d, /*includeFileName*/ true)), - } : - result; + diagnostics: args.includeLinePosition + ? this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(result.diagnostics) + : result.diagnostics.map(d => formatDiagnosticToProtocol(d, /*includeFileName*/ true)), + } + : result; } - private mapJSDocTagInfo(tags: JSDocTagInfo[] | undefined, project: Project, richResponse: boolean): protocol.JSDocTagInfo[] { + private mapJSDocTagInfo( + tags: JSDocTagInfo[] | undefined, + project: Project, + richResponse: boolean, + ): protocol.JSDocTagInfo[] { return tags ? tags.map(tag => ({ ...tag, - text: richResponse ? this.mapDisplayParts(tag.text, project) : tag.text?.map(part => part.text).join(""), + text: richResponse ? this.mapDisplayParts(tag.text, project) + : tag.text?.map(part => part.text).join(""), })) : []; } - private mapDisplayParts(parts: SymbolDisplayPart[] | undefined, project: Project): protocol.SymbolDisplayPart[] { + private mapDisplayParts( + parts: SymbolDisplayPart[] | undefined, + project: Project, + ): protocol.SymbolDisplayPart[] { if (!parts) { return []; } return parts.map(part => part.kind !== "linkName" ? part : { ...part, - target: this.toFileSpan((part as JSDocLinkDisplayPart).target.fileName, (part as JSDocLinkDisplayPart).target.textSpan, project), + target: this.toFileSpan( + (part as JSDocLinkDisplayPart).target.fileName, + (part as JSDocLinkDisplayPart).target.textSpan, + project, + ), } ); } - private mapSignatureHelpItems(items: SignatureHelpItem[], project: Project, richResponse: boolean): protocol.SignatureHelpItem[] { + private mapSignatureHelpItems( + items: SignatureHelpItem[], + project: Project, + richResponse: boolean, + ): protocol.SignatureHelpItem[] { return items.map(item => ({ ...item, documentation: this.mapDisplayParts(item.documentation, project), - parameters: item.parameters.map(p => ({ ...p, documentation: this.mapDisplayParts(p.documentation, project) })), + parameters: item.parameters.map(p => ({ + ...p, + documentation: this.mapDisplayParts(p.documentation, project), + })), tags: this.mapJSDocTagInfo(item.tags, project, richResponse), })); } - private mapDefinitionInfo(definitions: readonly DefinitionInfo[], project: Project): readonly protocol.DefinitionInfo[] { - return definitions.map(def => ({ ...this.toFileSpanWithContext(def.fileName, def.textSpan, def.contextSpan, project), ...def.unverified && { unverified: def.unverified } })); + private mapDefinitionInfo( + definitions: readonly DefinitionInfo[], + project: Project, + ): readonly protocol.DefinitionInfo[] { + return definitions.map(def => ({ + ...this.toFileSpanWithContext(def.fileName, def.textSpan, def.contextSpan, project), + ...def.unverified && { unverified: def.unverified }, + })); } /* @@ -1550,7 +1778,10 @@ namespace ts.server { */ private static mapToOriginalLocation(def: T): T { if (def.originalFileName) { - Debug.assert(def.originalTextSpan !== undefined, "originalTextSpan should be present if originalFileName is"); + Debug.assert( + def.originalTextSpan !== undefined, + "originalTextSpan should be present if originalFileName is", + ); return { ...def as any, fileName: def.originalFileName, @@ -1576,23 +1807,34 @@ namespace ts.server { }; } - private toFileSpanWithContext(fileName: string, textSpan: TextSpan, contextSpan: TextSpan | undefined, project: Project): protocol.FileSpanWithContext { + private toFileSpanWithContext( + fileName: string, + textSpan: TextSpan, + contextSpan: TextSpan | undefined, + project: Project, + ): protocol.FileSpanWithContext { const fileSpan = this.toFileSpan(fileName, textSpan, project); const context = contextSpan && this.toFileSpan(fileName, contextSpan, project); - return context ? - { ...fileSpan, contextStart: context.start, contextEnd: context.end } : - fileSpan; + return context + ? { ...fileSpan, contextStart: context.start, contextEnd: context.end } + : fileSpan; } private getTypeDefinition(args: protocol.FileLocationRequestArgs): readonly protocol.FileSpanWithContext[] { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); - const definitions = this.mapDefinitionInfoLocations(project.getLanguageService().getTypeDefinitionAtPosition(file, position) || emptyArray, project); + const definitions = this.mapDefinitionInfoLocations( + project.getLanguageService().getTypeDefinitionAtPosition(file, position) || emptyArray, + project, + ); return this.mapDefinitionInfo(definitions, project); } - private mapImplementationLocations(implementations: readonly ImplementationLocation[], project: Project): readonly ImplementationLocation[] { + private mapImplementationLocations( + implementations: readonly ImplementationLocation[], + project: Project, + ): readonly ImplementationLocation[] { return implementations.map((info): ImplementationLocation => { const newDocumentSpan = getMappedDocumentSpanForProject(info, project); return !newDocumentSpan ? info : { @@ -1603,21 +1845,29 @@ namespace ts.server { }); } - private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): readonly protocol.FileSpanWithContext[] | readonly ImplementationLocation[] { + private getImplementation( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.FileSpanWithContext[] | readonly ImplementationLocation[] { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); - const implementations = this.mapImplementationLocations(project.getLanguageService().getImplementationAtPosition(file, position) || emptyArray, project); - return simplifiedResult ? - implementations.map(({ fileName, textSpan, contextSpan }) => this.toFileSpanWithContext(fileName, textSpan, contextSpan, project)) : - implementations.map(Session.mapToOriginalLocation); + const implementations = this.mapImplementationLocations( + project.getLanguageService().getImplementationAtPosition(file, position) || emptyArray, + project, + ); + return simplifiedResult + ? implementations.map(({ fileName, textSpan, contextSpan }) => + this.toFileSpanWithContext(fileName, textSpan, contextSpan, project) + ) + : implementations.map(Session.mapToOriginalLocation); } private getOccurrences(args: protocol.FileLocationRequestArgs): readonly protocol.OccurrencesResponseItem[] { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); const occurrences = project.getLanguageService().getOccurrencesAtPosition(file, position); - return occurrences ? - occurrences.map(occurrence => { + return occurrences + ? occurrences.map(occurrence => { const { fileName, isWriteAccess, textSpan, isInString, contextSpan } = occurrence; const scriptInfo = project.getScriptInfo(fileName)!; return { @@ -1626,8 +1876,8 @@ namespace ts.server { isWriteAccess, ...(isInString ? { isInString } : undefined), }; - }) : - emptyArray; + }) + : emptyArray; } private getSyntacticDiagnosticsSync(args: protocol.SyntacticDiagnosticsSyncRequestArgs) { @@ -1637,7 +1887,12 @@ namespace ts.server { return emptyArray; } - return this.getDiagnosticsWorker(args, /*isSemantic*/ false, (project, file) => project.getLanguageService().getSyntacticDiagnostics(file), !!args.includeLinePosition); + return this.getDiagnosticsWorker( + args, + /*isSemantic*/ false, + (project, file) => project.getLanguageService().getSyntacticDiagnostics(file), + !!args.includeLinePosition, + ); } private getSemanticDiagnosticsSync(args: protocol.SemanticDiagnosticsSyncRequestArgs) { @@ -1645,7 +1900,12 @@ namespace ts.server { if (configFile) { return this.getConfigFileDiagnostics(configFile, project!, !!args.includeLinePosition); // TODO: GH#18217 } - return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSemanticDiagnostics(file).filter(d => !!d.file), !!args.includeLinePosition); + return this.getDiagnosticsWorker( + args, + /*isSemantic*/ true, + (project, file) => project.getLanguageService().getSemanticDiagnostics(file).filter(d => !!d.file), + !!args.includeLinePosition, + ); } private getSuggestionDiagnosticsSync(args: protocol.SuggestionDiagnosticsSyncRequestArgs) { @@ -1655,7 +1915,12 @@ namespace ts.server { return emptyArray; } // isSemantic because we don't want to info diagnostics in declaration files for JS-only users - return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSuggestionDiagnostics(file), !!args.includeLinePosition); + return this.getDiagnosticsWorker( + args, + /*isSemantic*/ true, + (project, file) => project.getLanguageService().getSuggestionDiagnostics(file), + !!args.includeLinePosition, + ); } private getJsxClosingTag(args: protocol.JsxClosingTagRequestArgs): TextInsertion | undefined { @@ -1665,10 +1930,17 @@ namespace ts.server { return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 }; } - private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] { + private getDocumentHighlights( + args: protocol.DocumentHighlightsRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); - const documentHighlights = project.getLanguageService().getDocumentHighlights(file, position, args.filesToSearch); + const documentHighlights = project.getLanguageService().getDocumentHighlights( + file, + position, + args.filesToSearch, + ); if (!documentHighlights) return emptyArray; if (!simplifiedResult) return documentHighlights; @@ -1701,16 +1973,27 @@ namespace ts.server { } private getProjectInfo(args: protocol.ProjectInfoRequestArgs): protocol.ProjectInfo { - return this.getProjectInfoWorker(args.file, args.projectFileName, args.needFileNameList, /*excludeConfigFiles*/ false); + return this.getProjectInfoWorker( + args.file, + args.projectFileName, + args.needFileNameList, + /*excludeConfigFiles*/ false, + ); } - private getProjectInfoWorker(uncheckedFileName: string, projectFileName: string | undefined, needFileNameList: boolean, excludeConfigFiles: boolean) { + private getProjectInfoWorker( + uncheckedFileName: string, + projectFileName: string | undefined, + needFileNameList: boolean, + excludeConfigFiles: boolean, + ) { const { project } = this.getFileAndProjectWorker(uncheckedFileName, projectFileName); updateProjectIfDirty(project); const projectInfo = { configFileName: project.getProjectName(), languageServiceDisabled: !project.languageServiceEnabled, - fileNames: needFileNameList ? project.getFileNames(/*excludeFilesFromExternalLibraries*/ false, excludeConfigFiles) : undefined, + fileNames: needFileNameList + ? project.getFileNames(/*excludeFilesFromExternalLibraries*/ false, excludeConfigFiles) : undefined, }; return projectInfo; } @@ -1722,7 +2005,11 @@ namespace ts.server { return project.getLanguageService().getRenameInfo(file, position, preferences); } - private getProjects(args: protocol.FileRequestArgs, getScriptInfoEnsuringProjectsUptoDate?: boolean, ignoreNoProjectError?: boolean): Projects { + private getProjects( + args: protocol.FileRequestArgs, + getScriptInfoEnsuringProjectsUptoDate?: boolean, + ignoreNoProjectError?: boolean, + ): Projects { let projects: readonly Project[] | undefined; let symLinkedProjects: MultiMap | undefined; if (args.projectFileName) { @@ -1732,9 +2019,9 @@ namespace ts.server { } } else { - const scriptInfo = getScriptInfoEnsuringProjectsUptoDate ? - this.projectService.getScriptInfoEnsuringProjectsUptoDate(args.file) : - this.projectService.getScriptInfo(args.file); + const scriptInfo = getScriptInfoEnsuringProjectsUptoDate + ? this.projectService.getScriptInfoEnsuringProjectsUptoDate(args.file) + : this.projectService.getScriptInfo(args.file); if (!scriptInfo) { if (ignoreNoProjectError) return emptyArray; this.projectService.logErrorForScriptInfoNotFound(args.file); @@ -1770,7 +2057,10 @@ namespace ts.server { return info.getDefaultProject(); } - private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | readonly RenameLocation[] { + private getRenameLocations( + args: protocol.RenameRequestArgs, + simplifiedResult: boolean, + ): protocol.RenameResponseBody | readonly RenameLocation[] { const file = toNormalizedPath(args.file); const position = this.getPositionInFile(args, file); const projects = this.getProjects(args); @@ -1797,9 +2087,18 @@ namespace ts.server { private mapRenameInfo(info: RenameInfo, scriptInfo: ScriptInfo): protocol.RenameInfo { if (info.canRename) { - const { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan } = info; + const { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan } = + info; return identity( - { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: toProtocolTextSpan(triggerSpan, scriptInfo) }, + { + canRename, + fileToRename, + displayName, + fullDisplayName, + kind, + kindModifiers, + triggerSpan: toProtocolTextSpan(triggerSpan, scriptInfo), + }, ); } else { @@ -1809,16 +2108,32 @@ namespace ts.server { private toSpanGroups(locations: readonly RenameLocation[]): readonly protocol.SpanGroup[] { const map = new Map(); - for (const { fileName, textSpan, contextSpan, originalContextSpan: _2, originalTextSpan: _, originalFileName: _1, ...prefixSuffixText } of locations) { + for ( + const { + fileName, + textSpan, + contextSpan, + originalContextSpan: _2, + originalTextSpan: _, + originalFileName: _1, + ...prefixSuffixText + } of locations + ) { let group = map.get(fileName); if (!group) map.set(fileName, group = { file: fileName, locs: [] }); const scriptInfo = Debug.checkDefined(this.projectService.getScriptInfo(fileName)); - group.locs.push({ ...toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo), ...prefixSuffixText }); + group.locs.push({ + ...toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo), + ...prefixSuffixText, + }); } return arrayFrom(map.values()); } - private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | readonly ReferencedSymbol[] { + private getReferences( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): protocol.ReferencesResponseBody | readonly ReferencedSymbol[] { const file = toNormalizedPath(args.file); const projects = this.getProjects(args); const position = this.getPositionInFile(args, file); @@ -1840,12 +2155,17 @@ namespace ts.server { const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0; const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : ""; const refs: readonly protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol => { - return referencedSymbol.references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry, preferences)); + return referencedSymbol.references.map(entry => + referenceEntryToReferencesResponseItem(this.projectService, entry, preferences) + ); }); return { refs, symbolName, symbolStartOffset, symbolDisplayString }; } - private getFileReferences(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.FileReferencesResponseBody | readonly ReferenceEntry[] { + private getFileReferences( + args: protocol.FileRequestArgs, + simplifiedResult: boolean, + ): protocol.FileReferencesResponseBody | readonly ReferenceEntry[] { const projects = this.getProjects(args); const fileName = args.file; const preferences = this.getPreferences(toNormalizedPath(fileName)); @@ -1868,7 +2188,9 @@ namespace ts.server { }); if (!simplifiedResult) return references; - const refs = references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry, preferences)); + const refs = references.map(entry => + referenceEntryToReferencesResponseItem(this.projectService, entry, preferences) + ); return { refs, symbolName: `"${args.file}"`, @@ -1879,12 +2201,24 @@ namespace ts.server { * @param fileName is the name of the file to be opened * @param fileContent is a version of the file content that is known to be more up to date than the one on disk */ - private openClientFile(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: NormalizedPath) { - this.projectService.openClientFileWithNormalizedPath(fileName, fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath); + private openClientFile( + fileName: NormalizedPath, + fileContent?: string, + scriptKind?: ScriptKind, + projectRootPath?: NormalizedPath, + ) { + this.projectService.openClientFileWithNormalizedPath( + fileName, + fileContent, + scriptKind, + /*hasMixedContent*/ false, + projectRootPath, + ); } private getPosition(args: protocol.Location & { position?: number; }, scriptInfo: ScriptInfo): number { - return args.position !== undefined ? args.position : scriptInfo.lineOffsetToPosition(args.line, args.offset); + return args.position !== undefined ? args.position + : scriptInfo.lineOffsetToPosition(args.line, args.offset); } private getPositionInFile(args: protocol.Location & { position?: number; }, file: NormalizedPath): number { @@ -1904,13 +2238,19 @@ namespace ts.server { }; } - private getFileAndProjectWorker(uncheckedFileName: string, projectFileName: string | undefined): { file: NormalizedPath; project: Project; } { + private getFileAndProjectWorker( + uncheckedFileName: string, + projectFileName: string | undefined, + ): { file: NormalizedPath; project: Project; } { const file = toNormalizedPath(uncheckedFileName); const project = this.getProject(projectFileName) || this.projectService.ensureDefaultProjectForFile(file); return { file, project }; } - private getOutliningSpans(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.OutliningSpan[] | OutliningSpan[] { + private getOutliningSpans( + args: protocol.FileRequestArgs, + simplifiedResult: boolean, + ): protocol.OutliningSpan[] | OutliningSpan[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const spans = languageService.getOutliningSpans(file); if (simplifiedResult) { @@ -1972,10 +2312,16 @@ namespace ts.server { return languageService.isValidBraceCompletionAtPosition(file, position, args.openingBrace.charCodeAt(0)); } - private getQuickInfoWorker(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.QuickInfoResponseBody | QuickInfo | undefined { + private getQuickInfoWorker( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): protocol.QuickInfoResponseBody | QuickInfo | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; - const quickInfo = project.getLanguageService().getQuickInfoAtPosition(file, this.getPosition(args, scriptInfo)); + const quickInfo = project.getLanguageService().getQuickInfoAtPosition( + file, + this.getPosition(args, scriptInfo), + ); if (!quickInfo) { return undefined; } @@ -1989,7 +2335,8 @@ namespace ts.server { start: scriptInfo.positionToLineOffset(quickInfo.textSpan.start), end: scriptInfo.positionToLineOffset(textSpanEnd(quickInfo.textSpan)), displayString, - documentation: useDisplayParts ? this.mapDisplayParts(quickInfo.documentation, project) : displayPartsToString(quickInfo.documentation), + documentation: useDisplayParts ? this.mapDisplayParts(quickInfo.documentation, project) + : displayPartsToString(quickInfo.documentation), tags: this.mapJSDocTagInfo(quickInfo.tags, project, useDisplayParts), }; } @@ -2009,7 +2356,12 @@ namespace ts.server { const endPosition = scriptInfo.lineOffsetToPosition(args.endLine, args.endOffset); // TODO: avoid duplicate code (with formatonkey) - const edits = languageService.getFormattingEditsForRange(file, startPosition, endPosition, this.getFormatOptions(file)); + const edits = languageService.getFormattingEditsForRange( + file, + startPosition, + endPosition, + this.getFormatOptions(file), + ); if (!edits) { return undefined; } @@ -2035,7 +2387,9 @@ namespace ts.server { return languageService.getFormattingEditsAfterKeystroke(file, args.position!, args.key, options); // TODO: GH#18217 } - private getFormattingEditsAfterKeystroke(args: protocol.FormatOnKeyRequestArgs): protocol.CodeEdit[] | undefined { + private getFormattingEditsAfterKeystroke( + args: protocol.FormatOnKeyRequestArgs, + ): protocol.CodeEdit[] | undefined { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = scriptInfo.lineOffsetToPosition(args.line, args.offset); @@ -2088,7 +2442,13 @@ namespace ts.server { }); } - private getCompletions(args: protocol.CompletionsRequestArgs, kind: protocol.CommandTypes.CompletionInfo | protocol.CommandTypes.Completions | protocol.CommandTypes.CompletionsFull): WithMetadata | protocol.CompletionInfo | CompletionInfo | undefined { + private getCompletions( + args: protocol.CompletionsRequestArgs, + kind: + | protocol.CommandTypes.CompletionInfo + | protocol.CommandTypes.Completions + | protocol.CommandTypes.CompletionsFull, + ): WithMetadata | protocol.CompletionInfo | CompletionInfo | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = this.getPosition(args, scriptInfo); @@ -2152,19 +2512,25 @@ namespace ts.server { }); if (kind === protocol.CommandTypes.Completions) { - if (completions.metadata) (entries as WithMetadata).metadata = completions.metadata; + if (completions.metadata) { + (entries as WithMetadata).metadata = completions.metadata; + } return entries; } const res: protocol.CompletionInfo = { ...completions, - optionalReplacementSpan: completions.optionalReplacementSpan && toProtocolTextSpan(completions.optionalReplacementSpan, scriptInfo), + optionalReplacementSpan: completions.optionalReplacementSpan + && toProtocolTextSpan(completions.optionalReplacementSpan, scriptInfo), entries, }; return res; } - private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs, fullResult: boolean): readonly protocol.CompletionEntryDetails[] | readonly CompletionEntryDetails[] { + private getCompletionEntryDetails( + args: protocol.CompletionDetailsRequestArgs, + fullResult: boolean, + ): readonly protocol.CompletionEntryDetails[] | readonly CompletionEntryDetails[] { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = this.getPosition(args, scriptInfo); @@ -2172,11 +2538,24 @@ namespace ts.server { const useDisplayParts = !!this.getPreferences(file).displayPartsForJSDoc; const result = mapDefined(args.entryNames, entryName => { - const { name, source, data } = typeof entryName === "string" ? { name: entryName, source: undefined, data: undefined } : entryName; - return project.getLanguageService().getCompletionEntryDetails(file, position, name, formattingOptions, source, this.getPreferences(file), data ? cast(data, isCompletionEntryData) : undefined); + const { name, source, data } = typeof entryName === "string" + ? { name: entryName, source: undefined, data: undefined } : entryName; + return project.getLanguageService().getCompletionEntryDetails( + file, + position, + name, + formattingOptions, + source, + this.getPreferences(file), + data ? cast(data, isCompletionEntryData) : undefined, + ); }); return fullResult - ? (useDisplayParts ? result : result.map(details => ({ ...details, tags: this.mapJSDocTagInfo(details.tags, project, /*richResponse*/ false) as JSDocTagInfo[] }))) + ? (useDisplayParts ? result + : result.map(details => ({ + ...details, + tags: this.mapJSDocTagInfo(details.tags, project, /*richResponse*/ false) as JSDocTagInfo[], + }))) : result.map(details => ({ ...details, codeActions: map(details.codeActions, action => this.mapCodeAction(action)), @@ -2185,8 +2564,14 @@ namespace ts.server { })); } - private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): readonly protocol.CompileOnSaveAffectedFileListSingleProject[] { - const projects = this.getProjects(args, /*getScriptInfoEnsuringProjectsUptoDate*/ true, /*ignoreNoProjectError*/ true); + private getCompileOnSaveAffectedFileList( + args: protocol.FileRequestArgs, + ): readonly protocol.CompileOnSaveAffectedFileListSingleProject[] { + const projects = this.getProjects( + args, + /*getScriptInfoEnsuringProjectsUptoDate*/ true, + /*ignoreNoProjectError*/ true, + ); const info = this.projectService.getScriptInfo(args.file); if (!info) { return emptyArray; @@ -2203,7 +2588,10 @@ namespace ts.server { const compilationSettings = project.getCompilationSettings(); - if (!!compilationSettings.noEmit || isDeclarationFileName(info.fileName) && !dtsChangeCanAffectEmit(compilationSettings)) { + if ( + !!compilationSettings.noEmit + || isDeclarationFileName(info.fileName) && !dtsChangeCanAffectEmit(compilationSettings) + ) { // avoid triggering emit when a change is made in a .d.ts when declaration emit and decorator metadata emit are disabled return undefined; } @@ -2226,18 +2614,24 @@ namespace ts.server { return args.richResponse ? { emitSkipped: true, diagnostics: [] } : false; } const scriptInfo = project.getScriptInfo(file)!; - const { emitSkipped, diagnostics } = project.emitFile(scriptInfo, (path, data, writeByteOrderMark) => this.host.writeFile(path, data, writeByteOrderMark)); - return args.richResponse ? - { + const { emitSkipped, diagnostics } = project.emitFile( + scriptInfo, + (path, data, writeByteOrderMark) => this.host.writeFile(path, data, writeByteOrderMark), + ); + return args.richResponse + ? { emitSkipped, - diagnostics: args.includeLinePosition ? - this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics) : - diagnostics.map(d => formatDiagnosticToProtocol(d, /*includeFileName*/ true)), - } : - !emitSkipped; + diagnostics: args.includeLinePosition + ? this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics) + : diagnostics.map(d => formatDiagnosticToProtocol(d, /*includeFileName*/ true)), + } + : !emitSkipped; } - private getSignatureHelpItems(args: protocol.SignatureHelpRequestArgs, simplifiedResult: boolean): protocol.SignatureHelpItems | SignatureHelpItems | undefined { + private getSignatureHelpItems( + args: protocol.SignatureHelpRequestArgs, + simplifiedResult: boolean, + ): protocol.SignatureHelpItems | SignatureHelpItems | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = this.getPosition(args, scriptInfo); @@ -2260,7 +2654,10 @@ namespace ts.server { else { return { ...helpItems, - items: helpItems.items.map(item => ({ ...item, tags: this.mapJSDocTagInfo(item.tags, project, /*richResponse*/ false) as JSDocTagInfo[] })), + items: helpItems.items.map(item => ({ + ...item, + tags: this.mapJSDocTagInfo(item.tags, project, /*richResponse*/ false) as JSDocTagInfo[], + })), }; } } @@ -2326,7 +2723,10 @@ namespace ts.server { this.projectService.closeClientFile(file); } - private mapLocationNavigationBarItems(items: NavigationBarItem[], scriptInfo: ScriptInfo): protocol.NavigationBarItem[] { + private mapLocationNavigationBarItems( + items: NavigationBarItem[], + scriptInfo: ScriptInfo, + ): protocol.NavigationBarItem[] { return map(items, item => ({ text: item.text, kind: item.kind, @@ -2337,7 +2737,10 @@ namespace ts.server { })); } - private getNavigationBarItems(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.NavigationBarItem[] | NavigationBarItem[] | undefined { + private getNavigationBarItems( + args: protocol.FileRequestArgs, + simplifiedResult: boolean, + ): protocol.NavigationBarItem[] | NavigationBarItem[] | undefined { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const items = languageService.getNavigationBarItems(file); return !items @@ -2358,7 +2761,10 @@ namespace ts.server { }; } - private getNavigationTree(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.NavigationTree | NavigationTree | undefined { + private getNavigationTree( + args: protocol.FileRequestArgs, + simplifiedResult: boolean, + ): protocol.NavigationTree | NavigationTree | undefined { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const tree = languageService.getNavigationTree(file); return !tree @@ -2368,11 +2774,14 @@ namespace ts.server { : tree; } - private getNavigateToItems(args: protocol.NavtoRequestArgs, simplifiedResult: boolean): readonly protocol.NavtoItem[] | readonly NavigateToItem[] { + private getNavigateToItems( + args: protocol.NavtoRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.NavtoItem[] | readonly NavigateToItem[] { const full = this.getFullNavigateToItems(args); - return !simplifiedResult ? - flatMap(full, ({ navigateToItems }) => navigateToItems) : - flatMap( + return !simplifiedResult + ? flatMap(full, ({ navigateToItems }) => navigateToItems) + : flatMap( full, ({ project, navigateToItems }) => navigateToItems.map(navItem => { @@ -2407,7 +2816,10 @@ namespace ts.server { if (currentFileOnly) { Debug.assertIsDefined(args.file); const { file, project } = this.getFileAndProject(args as protocol.FileRequestArgs); - return [{ project, navigateToItems: project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, file) }]; + return [{ + project, + navigateToItems: project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, file), + }]; } const outputs: ProjectNavigateToItems[] = []; @@ -2442,8 +2854,16 @@ namespace ts.server { // Mutates `outputs` function addItemsForProject(project: Project) { - const projectItems = project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, /*filename*/ undefined, /*excludeDts*/ project.isNonTsProject()); - const unseenItems = filter(projectItems, item => tryAddSeenItem(item) && !getMappedLocationForProject(documentSpanLocation(item), project)); + const projectItems = project.getLanguageService().getNavigateToItems( + searchValue, + maxResultCount, + /*filename*/ undefined, + /*excludeDts*/ project.isNonTsProject(), + ); + const unseenItems = filter( + projectItems, + item => tryAddSeenItem(item) && !getMappedLocationForProject(documentSpanLocation(item), project), + ); if (unseenItems.length) { outputs.push({ project, navigateToItems: unseenItems }); } @@ -2476,16 +2896,16 @@ namespace ts.server { if (!a || !b) { return false; } - return a.containerKind === b.containerKind && - a.containerName === b.containerName && - a.fileName === b.fileName && - a.isCaseSensitive === b.isCaseSensitive && - a.kind === b.kind && - a.kindModifiers === b.kindModifiers && - a.matchKind === b.matchKind && - a.name === b.name && - a.textSpan.start === b.textSpan.start && - a.textSpan.length === b.textSpan.length; + return a.containerKind === b.containerKind + && a.containerName === b.containerName + && a.fileName === b.fileName + && a.isCaseSensitive === b.isCaseSensitive + && a.kind === b.kind + && a.kindModifiers === b.kindModifiers + && a.matchKind === b.matchKind + && a.name === b.name + && a.textSpan.start === b.textSpan.start + && a.textSpan.length === b.textSpan.length; } } @@ -2493,11 +2913,16 @@ namespace ts.server { return getSupportedCodeFixes(); } - private isLocation(locationOrSpan: protocol.FileLocationOrRangeRequestArgs): locationOrSpan is protocol.FileLocationRequestArgs { + private isLocation( + locationOrSpan: protocol.FileLocationOrRangeRequestArgs, + ): locationOrSpan is protocol.FileLocationRequestArgs { return (locationOrSpan as protocol.FileLocationRequestArgs).line !== undefined; } - private extractPositionOrRange(args: protocol.FileLocationOrRangeRequestArgs, scriptInfo: ScriptInfo): number | TextRange { + private extractPositionOrRange( + args: protocol.FileLocationOrRangeRequestArgs, + scriptInfo: ScriptInfo, + ): number | TextRange { let position: number | undefined; let textRange: TextRange | undefined; if (this.isLocation(args)) { @@ -2509,7 +2934,8 @@ namespace ts.server { return Debug.checkDefined(position === undefined ? textRange : position); function getPosition(loc: protocol.FileLocationRequestArgs) { - return loc.position !== undefined ? loc.position : scriptInfo.lineOffsetToPosition(loc.line, loc.offset); + return loc.position !== undefined ? loc.position + : scriptInfo.lineOffsetToPosition(loc.line, loc.offset); } } @@ -2519,13 +2945,24 @@ namespace ts.server { return { pos: startPosition, end: endPosition }; } - private getApplicableRefactors(args: protocol.GetApplicableRefactorsRequestArgs): protocol.ApplicableRefactorInfo[] { + private getApplicableRefactors( + args: protocol.GetApplicableRefactorsRequestArgs, + ): protocol.ApplicableRefactorInfo[] { const { file, project } = this.getFileAndProject(args); const scriptInfo = project.getScriptInfoForNormalizedPath(file)!; - return project.getLanguageService().getApplicableRefactors(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file), args.triggerReason, args.kind); + return project.getLanguageService().getApplicableRefactors( + file, + this.extractPositionOrRange(args, scriptInfo), + this.getPreferences(file), + args.triggerReason, + args.kind, + ); } - private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): RefactorEditInfo | protocol.RefactorEditInfo { + private getEditsForRefactor( + args: protocol.GetEditsForRefactorRequestArgs, + simplifiedResult: boolean, + ): RefactorEditInfo | protocol.RefactorEditInfo { const { file, project } = this.getFileAndProject(args); const scriptInfo = project.getScriptInfoForNormalizedPath(file)!; const result = project.getLanguageService().getEditsForRefactor( @@ -2548,22 +2985,35 @@ namespace ts.server { let mappedRenameLocation: protocol.Location | undefined; if (renameFilename !== undefined && renameLocation !== undefined) { const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(renameFilename))!; - mappedRenameLocation = getLocationInNewDocument(getSnapshotText(renameScriptInfo.getSnapshot()), renameFilename, renameLocation, edits); + mappedRenameLocation = getLocationInNewDocument( + getSnapshotText(renameScriptInfo.getSnapshot()), + renameFilename, + renameLocation, + edits, + ); } - return { renameLocation: mappedRenameLocation, renameFilename, edits: this.mapTextChangesToCodeEdits(edits) }; + return { + renameLocation: mappedRenameLocation, + renameFilename, + edits: this.mapTextChangesToCodeEdits(edits), + }; } else { return result; } } - private organizeImports(args: protocol.OrganizeImportsRequestArgs, simplifiedResult: boolean): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { + private organizeImports( + args: protocol.OrganizeImportsRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { Debug.assert(args.scope.type === "file"); const { file, project } = this.getFileAndProject(args.scope.args); const changes = project.getLanguageService().organizeImports( { fileName: file, - mode: args.mode as OrganizeImportsMode | undefined ?? (args.skipDestructiveCodeActions ? OrganizeImportsMode.SortAndCombine : undefined), + mode: args.mode as OrganizeImportsMode | undefined + ?? (args.skipDestructiveCodeActions ? OrganizeImportsMode.SortAndCombine : undefined), type: "file", }, this.getFormatOptions(file), @@ -2577,7 +3027,10 @@ namespace ts.server { } } - private getEditsForFileRename(args: protocol.GetEditsForFileRenameRequestArgs, simplifiedResult: boolean): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { + private getEditsForFileRename( + args: protocol.GetEditsForFileRenameRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { const oldPath = toNormalizedPath(args.oldFilePath); const newPath = toNormalizedPath(args.newFilePath); const formatOptions = this.getHostFormatOptions(); @@ -2590,7 +3043,12 @@ namespace ts.server { // those that are downstream from already-loaded projects. this.projectService.loadAncestorProjectTree(); this.projectService.forEachEnabledProject(project => { - const projectTextChanges = project.getLanguageService().getEditsForFileRename(oldPath, newPath, formatOptions, preferences); + const projectTextChanges = project.getLanguageService().getEditsForFileRename( + oldPath, + newPath, + formatOptions, + preferences, + ); const projectFiles: string[] = []; for (const textChange of projectTextChanges) { if (!seenFiles.has(textChange.fileName)) { @@ -2606,7 +3064,10 @@ namespace ts.server { return simplifiedResult ? textChanges.map(c => this.mapTextChangeToCodeEdit(c)) : textChanges; } - private getCodeFixes(args: protocol.CodeFixRequestArgs, simplifiedResult: boolean): readonly protocol.CodeFixAction[] | readonly CodeFixAction[] | undefined { + private getCodeFixes( + args: protocol.CodeFixRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.CodeFixAction[] | readonly CodeFixAction[] | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = project.getScriptInfoForNormalizedPath(file)!; @@ -2614,7 +3075,14 @@ namespace ts.server { let codeActions: readonly CodeFixAction[]; try { - codeActions = project.getLanguageService().getCodeFixesAtPosition(file, startPosition, endPosition, args.errorCodes, this.getFormatOptions(file), this.getPreferences(file)); + codeActions = project.getLanguageService().getCodeFixesAtPosition( + file, + startPosition, + endPosition, + args.errorCodes, + this.getFormatOptions(file), + this.getPreferences(file), + ); } catch (e) { const ls = project.getLanguageService(); @@ -2628,17 +3096,28 @@ namespace ts.server { ); const badCode = args.errorCodes.find(c => !existingDiagCodes.includes(c)); if (badCode !== undefined) { - e.message = `BADCLIENT: Bad error code, ${badCode} not found in range ${startPosition}..${endPosition} (found: ${existingDiagCodes.join(", ")}); could have caused this error:\n${e.message}`; + e.message = + `BADCLIENT: Bad error code, ${badCode} not found in range ${startPosition}..${endPosition} (found: ${ + existingDiagCodes.join(", ") + }); could have caused this error:\n${e.message}`; } throw e; } return simplifiedResult ? codeActions.map(codeAction => this.mapCodeFixAction(codeAction)) : codeActions; } - private getCombinedCodeFix({ scope, fixId }: protocol.GetCombinedCodeFixRequestArgs, simplifiedResult: boolean): protocol.CombinedCodeActions | CombinedCodeActions { + private getCombinedCodeFix( + { scope, fixId }: protocol.GetCombinedCodeFixRequestArgs, + simplifiedResult: boolean, + ): protocol.CombinedCodeActions | CombinedCodeActions { Debug.assert(scope.type === "file"); const { file, project } = this.getFileAndProject(scope.args); - const res = project.getLanguageService().getCombinedCodeFix({ type: "file", fileName: file }, fixId, this.getFormatOptions(file), this.getPreferences(file)); + const res = project.getLanguageService().getCombinedCodeFix( + { type: "file", fileName: file }, + fixId, + this.getFormatOptions(file), + this.getPreferences(file), + ); if (simplifiedResult) { return { changes: this.mapTextChangesToCodeEdits(res.changes), commands: res.commands }; } @@ -2685,8 +3164,17 @@ namespace ts.server { return { description, changes: this.mapTextChangesToCodeEdits(changes), commands }; } - private mapCodeFixAction({ fixName, description, changes, commands, fixId, fixAllDescription }: CodeFixAction): protocol.CodeFixAction { - return { fixName, description, changes: this.mapTextChangesToCodeEdits(changes), commands, fixId, fixAllDescription }; + private mapCodeFixAction( + { fixName, description, changes, commands, fixId, fixAllDescription }: CodeFixAction, + ): protocol.CodeFixAction { + return { + fixName, + description, + changes: this.mapTextChangesToCodeEdits(changes), + commands, + fixId, + fixAllDescription, + }; } private mapTextChangesToCodeEdits(textChanges: readonly FileTextChanges[]): protocol.FileCodeEdits[] { @@ -2699,10 +3187,18 @@ namespace ts.server { if (!scriptInfo) { // and !isNewFile this.projectService.logErrorForScriptInfoNotFound(textChanges.fileName); } - Debug.fail("Expected isNewFile for (only) new files. " + JSON.stringify({ isNewFile: !!textChanges.isNewFile, hasScriptInfo: !!scriptInfo })); + Debug.fail( + "Expected isNewFile for (only) new files. " + + JSON.stringify({ isNewFile: !!textChanges.isNewFile, hasScriptInfo: !!scriptInfo }), + ); } return scriptInfo - ? { fileName: textChanges.fileName, textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEdit(textChange, scriptInfo)) } + ? { + fileName: textChanges.fileName, + textChanges: textChanges.textChanges.map(textChange => + convertTextChangeToCodeEdit(textChange, scriptInfo) + ), + } : convertNewFileTextChangeToCodeEdit(textChanges); } @@ -2714,7 +3210,10 @@ namespace ts.server { }; } - private getBraceMatching(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.TextSpan[] | TextSpan[] | undefined { + private getBraceMatching( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): protocol.TextSpan[] | TextSpan[] | undefined { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = this.getPosition(args, scriptInfo); @@ -2732,7 +3231,12 @@ namespace ts.server { return; } - const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker(fileName, /*projectFileName*/ undefined, /*needFileNameList*/ true, /*excludeConfigFiles*/ true); + const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker( + fileName, + /*projectFileName*/ undefined, + /*needFileNameList*/ true, + /*excludeConfigFiles*/ true, + ); if (languageServiceDisabled) { return; } @@ -2770,7 +3274,12 @@ namespace ts.server { } } - const sortedFiles = [...highPriorityFiles, ...mediumPriorityFiles, ...lowPriorityFiles, ...veryLowPriorityFiles]; + const sortedFiles = [ + ...highPriorityFiles, + ...mediumPriorityFiles, + ...lowPriorityFiles, + ...veryLowPriorityFiles, + ]; const checkList = sortedFiles.map(fileName => ({ fileName, project })); // Project level error analysis runs on background files too, therefore // doesn't require the file to be opened @@ -2793,7 +3302,10 @@ namespace ts.server { }); } - private toggleLineComment(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] { + private toggleLineComment( + args: protocol.FileRangeRequestArgs, + simplifiedResult: boolean, + ): TextChange[] | protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfo(file)!; const textRange = this.getRange(args, scriptInfo); @@ -2809,7 +3321,10 @@ namespace ts.server { return textChanges; } - private toggleMultilineComment(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] { + private toggleMultilineComment( + args: protocol.FileRangeRequestArgs, + simplifiedResult: boolean, + ): TextChange[] | protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const textRange = this.getRange(args, scriptInfo); @@ -2825,7 +3340,10 @@ namespace ts.server { return textChanges; } - private commentSelection(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] { + private commentSelection( + args: protocol.FileRangeRequestArgs, + simplifiedResult: boolean, + ): TextChange[] | protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const textRange = this.getRange(args, scriptInfo); @@ -2841,7 +3359,10 @@ namespace ts.server { return textChanges; } - private uncommentSelection(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] { + private uncommentSelection( + args: protocol.FileRangeRequestArgs, + simplifiedResult: boolean, + ): TextChange[] | protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const textRange = this.getRange(args, scriptInfo); @@ -2890,7 +3411,9 @@ namespace ts.server { }; } - private toProtocolCallHierarchyIncomingCall(incomingCall: CallHierarchyIncomingCall): protocol.CallHierarchyIncomingCall { + private toProtocolCallHierarchyIncomingCall( + incomingCall: CallHierarchyIncomingCall, + ): protocol.CallHierarchyIncomingCall { const scriptInfo = this.getScriptInfoFromProjectService(incomingCall.from.file); return { from: this.toProtocolCallHierarchyItem(incomingCall.from), @@ -2898,14 +3421,19 @@ namespace ts.server { }; } - private toProtocolCallHierarchyOutgoingCall(outgoingCall: CallHierarchyOutgoingCall, scriptInfo: ScriptInfo): protocol.CallHierarchyOutgoingCall { + private toProtocolCallHierarchyOutgoingCall( + outgoingCall: CallHierarchyOutgoingCall, + scriptInfo: ScriptInfo, + ): protocol.CallHierarchyOutgoingCall { return { to: this.toProtocolCallHierarchyItem(outgoingCall.to), fromSpans: outgoingCall.fromSpans.map(fromSpan => toProtocolTextSpan(fromSpan, scriptInfo)), }; } - private prepareCallHierarchy(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyItem | protocol.CallHierarchyItem[] | undefined { + private prepareCallHierarchy( + args: protocol.FileLocationRequestArgs, + ): protocol.CallHierarchyItem | protocol.CallHierarchyItem[] | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file); if (scriptInfo) { @@ -2916,17 +3444,27 @@ namespace ts.server { return undefined; } - private provideCallHierarchyIncomingCalls(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyIncomingCall[] { + private provideCallHierarchyIncomingCalls( + args: protocol.FileLocationRequestArgs, + ): protocol.CallHierarchyIncomingCall[] { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.getScriptInfoFromProjectService(file); - const incomingCalls = project.getLanguageService().provideCallHierarchyIncomingCalls(file, this.getPosition(args, scriptInfo)); + const incomingCalls = project.getLanguageService().provideCallHierarchyIncomingCalls( + file, + this.getPosition(args, scriptInfo), + ); return incomingCalls.map(call => this.toProtocolCallHierarchyIncomingCall(call)); } - private provideCallHierarchyOutgoingCalls(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyOutgoingCall[] { + private provideCallHierarchyOutgoingCalls( + args: protocol.FileLocationRequestArgs, + ): protocol.CallHierarchyOutgoingCall[] { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.getScriptInfoFromProjectService(file); - const outgoingCalls = project.getLanguageService().provideCallHierarchyOutgoingCalls(file, this.getPosition(args, scriptInfo)); + const outgoingCalls = project.getLanguageService().provideCallHierarchyOutgoingCalls( + file, + this.getPosition(args, scriptInfo), + ); return outgoingCalls.map(call => this.toProtocolCallHierarchyOutgoingCall(call, scriptInfo)); } @@ -2966,7 +3504,10 @@ namespace ts.server { return this.requiredResponse(/*response*/ true); }, [CommandNames.SynchronizeProjectList]: (request: protocol.SynchronizeProjectListRequest) => { - const result = this.projectService.synchronizeProjectList(request.arguments.knownProjects, request.arguments.includeProjectReferenceRedirectInfo); + const result = this.projectService.synchronizeProjectList( + request.arguments.knownProjects, + request.arguments.includeProjectReferenceRedirectInfo, + ); if (!result.some(p => p.projectErrors && p.projectErrors.length !== 0)) { return this.requiredResponse(result); } @@ -2978,7 +3519,10 @@ namespace ts.server { info: p.info, changes: p.changes, files: p.files, - projectErrors: this.convertToDiagnosticsWithLinePosition(p.projectErrors, /*scriptInfo*/ undefined), + projectErrors: this.convertToDiagnosticsWithLinePosition( + p.projectErrors, + /*scriptInfo*/ undefined, + ), }; }); return this.requiredResponse(converted); @@ -2992,15 +3536,17 @@ namespace ts.server { scriptKind: file.scriptKindName, projectRootPath: file.projectRootPath, })), - request.arguments.changedFiles && mapIterator(arrayIterator(request.arguments.changedFiles), file => ({ - fileName: file.fileName, - changes: mapDefinedIterator(arrayReverseIterator(file.textChanges), change => { - const scriptInfo = Debug.checkDefined(this.projectService.getScriptInfo(file.fileName)); - const start = scriptInfo.lineOffsetToPosition(change.start.line, change.start.offset); - const end = scriptInfo.lineOffsetToPosition(change.end.line, change.end.offset); - return start >= 0 ? { span: { start, length: end - start }, newText: change.newText } : undefined; - }), - })), + request.arguments.changedFiles + && mapIterator(arrayIterator(request.arguments.changedFiles), file => ({ + fileName: file.fileName, + changes: mapDefinedIterator(arrayReverseIterator(file.textChanges), change => { + const scriptInfo = Debug.checkDefined(this.projectService.getScriptInfo(file.fileName)); + const start = scriptInfo.lineOffsetToPosition(change.start.line, change.start.offset); + const end = scriptInfo.lineOffsetToPosition(change.end.line, change.end.offset); + return start >= 0 ? { span: { start, length: end - start }, newText: change.newText } + : undefined; + }), + })), request.arguments.closedFiles, ); return this.requiredResponse(/*response*/ true); @@ -3009,11 +3555,12 @@ namespace ts.server { this.changeSeq++; this.projectService.applyChangesInOpenFiles( request.arguments.openFiles && arrayIterator(request.arguments.openFiles), - request.arguments.changedFiles && mapIterator(arrayIterator(request.arguments.changedFiles), file => ({ - fileName: file.fileName, - // apply changes in reverse order - changes: arrayReverseIterator(file.changes), - })), + request.arguments.changedFiles + && mapIterator(arrayIterator(request.arguments.changedFiles), file => ({ + fileName: file.fileName, + // apply changes in reverse order + changes: arrayReverseIterator(file.changes), + })), request.arguments.closedFiles, ); // TODO: report errors @@ -3030,10 +3577,14 @@ namespace ts.server { return this.requiredResponse(this.getDefinition(request.arguments, /*simplifiedResult*/ false)); }, [CommandNames.DefinitionAndBoundSpan]: (request: protocol.DefinitionAndBoundSpanRequest) => { - return this.requiredResponse(this.getDefinitionAndBoundSpan(request.arguments, /*simplifiedResult*/ true)); + return this.requiredResponse( + this.getDefinitionAndBoundSpan(request.arguments, /*simplifiedResult*/ true), + ); }, [CommandNames.DefinitionAndBoundSpanFull]: (request: protocol.DefinitionAndBoundSpanRequest) => { - return this.requiredResponse(this.getDefinitionAndBoundSpan(request.arguments, /*simplifiedResult*/ false)); + return this.requiredResponse( + this.getDefinitionAndBoundSpan(request.arguments, /*simplifiedResult*/ false), + ); }, [CommandNames.FindSourceDefinition]: (request: protocol.FindSourceDefinitionRequest) => { return this.requiredResponse(this.findSourceDefinition(request.arguments)); @@ -3158,10 +3709,14 @@ namespace ts.server { [CommandNames.CompilerOptionsDiagnosticsFull]: (request: protocol.CompilerOptionsDiagnosticsRequest) => { return this.requiredResponse(this.getCompilerOptionsDiagnostics(request.arguments)); }, - [CommandNames.EncodedSyntacticClassificationsFull]: (request: protocol.EncodedSyntacticClassificationsRequest) => { + [CommandNames.EncodedSyntacticClassificationsFull]: ( + request: protocol.EncodedSyntacticClassificationsRequest, + ) => { return this.requiredResponse(this.getEncodedSyntacticClassifications(request.arguments)); }, - [CommandNames.EncodedSemanticClassificationsFull]: (request: protocol.EncodedSemanticClassificationsRequest) => { + [CommandNames.EncodedSemanticClassificationsFull]: ( + request: protocol.EncodedSemanticClassificationsRequest, + ) => { return this.requiredResponse(this.getEncodedSemanticClassifications(request.arguments)); }, [CommandNames.Cleanup]: () => { @@ -3178,11 +3733,15 @@ namespace ts.server { return this.requiredResponse(this.getSuggestionDiagnosticsSync(request.arguments)); }, [CommandNames.Geterr]: (request: protocol.GeterrRequest) => { - this.errorCheck.startNew(next => this.getDiagnostics(next, request.arguments.delay, request.arguments.files)); + this.errorCheck.startNew(next => + this.getDiagnostics(next, request.arguments.delay, request.arguments.files) + ); return this.notRequired(); }, [CommandNames.GeterrForProject]: (request: protocol.GeterrForProjectRequest) => { - this.errorCheck.startNew(next => this.getDiagnosticsForProject(next, request.arguments.delay, request.arguments.file)); + this.errorCheck.startNew(next => + this.getDiagnosticsForProject(next, request.arguments.delay, request.arguments.file) + ); return this.notRequired(); }, [CommandNames.Change]: (request: protocol.ChangeRequest) => { @@ -3241,7 +3800,9 @@ namespace ts.server { [CommandNames.DocumentHighlightsFull]: (request: protocol.DocumentHighlightsRequest) => { return this.requiredResponse(this.getDocumentHighlights(request.arguments, /*simplifiedResult*/ false)); }, - [CommandNames.CompilerOptionsForInferredProjects]: (request: protocol.SetCompilerOptionsForInferredProjectsRequest) => { + [CommandNames.CompilerOptionsForInferredProjects]: ( + request: protocol.SetCompilerOptionsForInferredProjectsRequest, + ) => { this.setCompilerOptionsForInferredProjects(request.arguments); return this.requiredResponse(/*response*/ true); }, @@ -3303,15 +3864,21 @@ namespace ts.server { return this.requiredResponse(this.getSmartSelectionRange(request.arguments, /*simplifiedResult*/ true)); }, [CommandNames.SelectionRangeFull]: (request: protocol.SelectionRangeRequest) => { - return this.requiredResponse(this.getSmartSelectionRange(request.arguments, /*simplifiedResult*/ false)); + return this.requiredResponse( + this.getSmartSelectionRange(request.arguments, /*simplifiedResult*/ false), + ); }, [CommandNames.PrepareCallHierarchy]: (request: protocol.PrepareCallHierarchyRequest) => { return this.requiredResponse(this.prepareCallHierarchy(request.arguments)); }, - [CommandNames.ProvideCallHierarchyIncomingCalls]: (request: protocol.ProvideCallHierarchyIncomingCallsRequest) => { + [CommandNames.ProvideCallHierarchyIncomingCalls]: ( + request: protocol.ProvideCallHierarchyIncomingCallsRequest, + ) => { return this.requiredResponse(this.provideCallHierarchyIncomingCalls(request.arguments)); }, - [CommandNames.ProvideCallHierarchyOutgoingCalls]: (request: protocol.ProvideCallHierarchyOutgoingCallsRequest) => { + [CommandNames.ProvideCallHierarchyOutgoingCalls]: ( + request: protocol.ProvideCallHierarchyOutgoingCallsRequest, + ) => { return this.requiredResponse(this.provideCallHierarchyOutgoingCalls(request.arguments)); }, [CommandNames.ToggleLineComment]: (request: protocol.ToggleLineCommentRequest) => { @@ -3324,7 +3891,9 @@ namespace ts.server { return this.requiredResponse(this.toggleMultilineComment(request.arguments, /*simplifiedResult*/ true)); }, [CommandNames.ToggleMultilineCommentFull]: (request: protocol.ToggleMultilineCommentRequest) => { - return this.requiredResponse(this.toggleMultilineComment(request.arguments, /*simplifiedResult*/ false)); + return this.requiredResponse( + this.toggleMultilineComment(request.arguments, /*simplifiedResult*/ false), + ); }, [CommandNames.CommentSelection]: (request: protocol.CommentSelectionRequest) => { return this.requiredResponse(this.commentSelection(request.arguments, /*simplifiedResult*/ true)); @@ -3381,7 +3950,13 @@ namespace ts.server { } else { this.logger.msg(`Unrecognized JSON command:${stringifyIndented(request)}`, Msg.Err); - this.doOutput(/*info*/ undefined, CommandNames.Unknown, request.seq, /*success*/ false, `Unrecognized JSON command: ${request.command}`); + this.doOutput( + /*info*/ undefined, + CommandNames.Unknown, + request.seq, + /*success*/ false, + `Unrecognized JSON command: ${request.command}`, + ); return { responseRequired: false }; } } @@ -3403,33 +3978,53 @@ namespace ts.server { let relevantFile: protocol.FileRequestArgs | undefined; try { request = this.parseMessage(message); - relevantFile = request.arguments && (request as protocol.FileRequest).arguments.file ? (request as protocol.FileRequest).arguments : undefined; + relevantFile = request.arguments && (request as protocol.FileRequest).arguments.file + ? (request as protocol.FileRequest).arguments : undefined; tracing?.instant(tracing.Phase.Session, "request", { seq: request.seq, command: request.command }); perfLogger.logStartCommand("" + request.command, this.toStringMessage(message).substring(0, 100)); - tracing?.push(tracing.Phase.Session, "executeCommand", { seq: request.seq, command: request.command }, /*separateBeginAndEnd*/ true); + tracing?.push( + tracing.Phase.Session, + "executeCommand", + { seq: request.seq, command: request.command }, + /*separateBeginAndEnd*/ true, + ); const { response, responseRequired } = this.executeCommand(request); tracing?.pop(); if (this.logger.hasLevel(LogLevel.requestTime)) { const elapsedTime = hrTimeToMilliseconds(this.hrtime(start)).toFixed(4); if (responseRequired) { - this.logger.perftrc(`${request.seq}::${request.command}: elapsed time (in milliseconds) ${elapsedTime}`); + this.logger.perftrc( + `${request.seq}::${request.command}: elapsed time (in milliseconds) ${elapsedTime}`, + ); } else { - this.logger.perftrc(`${request.seq}::${request.command}: async elapsed time (in milliseconds) ${elapsedTime}`); + this.logger.perftrc( + `${request.seq}::${request.command}: async elapsed time (in milliseconds) ${elapsedTime}`, + ); } } // Note: Log before writing the response, else the editor can complete its activity before the server does perfLogger.logStopCommand("" + request.command, "Success"); - tracing?.instant(tracing.Phase.Session, "response", { seq: request.seq, command: request.command, success: !!response }); + tracing?.instant(tracing.Phase.Session, "response", { + seq: request.seq, + command: request.command, + success: !!response, + }); if (response) { this.doOutput(response, request.command, request.seq, /*success*/ true); } else if (responseRequired) { - this.doOutput(/*info*/ undefined, request.command, request.seq, /*success*/ false, "No content available."); + this.doOutput( + /*info*/ undefined, + request.command, + request.seq, + /*success*/ false, + "No content available.", + ); } } catch (err) { @@ -3439,21 +4034,29 @@ namespace ts.server { if (err instanceof OperationCanceledException) { // Handle cancellation exceptions perfLogger.logStopCommand("" + (request && request.command), "Canceled: " + err); - tracing?.instant(tracing.Phase.Session, "commandCanceled", { seq: request?.seq, command: request?.command }); + tracing?.instant(tracing.Phase.Session, "commandCanceled", { + seq: request?.seq, + command: request?.command, + }); this.doOutput({ canceled: true }, request!.command, request!.seq, /*success*/ true); return; } this.logErrorWorker(err, this.toStringMessage(message), relevantFile); perfLogger.logStopCommand("" + (request && request.command), "Error: " + err); - tracing?.instant(tracing.Phase.Session, "commandError", { seq: request?.seq, command: request?.command, message: (err as Error).message }); + tracing?.instant(tracing.Phase.Session, "commandError", { + seq: request?.seq, + command: request?.command, + message: (err as Error).message, + }); this.doOutput( /*info*/ undefined, request ? request.command : CommandNames.Unknown, request ? request.seq : 0, /*success*/ false, - "Error processing request. " + (err as StackTraceError).message + "\n" + (err as StackTraceError).stack, + "Error processing request. " + (err as StackTraceError).message + "\n" + + (err as StackTraceError).stack, ); } } @@ -3495,20 +4098,29 @@ namespace ts.server { }; } - function toProtocolTextSpanWithContext(span: TextSpan, contextSpan: TextSpan | undefined, scriptInfo: ScriptInfo): protocol.TextSpanWithContext { + function toProtocolTextSpanWithContext( + span: TextSpan, + contextSpan: TextSpan | undefined, + scriptInfo: ScriptInfo, + ): protocol.TextSpanWithContext { const textSpan = toProtocolTextSpan(span, scriptInfo); const contextTextSpan = contextSpan && toProtocolTextSpan(contextSpan, scriptInfo); - return contextTextSpan ? - { ...textSpan, contextStart: contextTextSpan.start, contextEnd: contextTextSpan.end } : - textSpan; + return contextTextSpan + ? { ...textSpan, contextStart: contextTextSpan.start, contextEnd: contextTextSpan.end } + : textSpan; } function convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfoOrConfig): protocol.CodeEdit { - return { start: positionToLineOffset(scriptInfo, change.span.start), end: positionToLineOffset(scriptInfo, textSpanEnd(change.span)), newText: change.newText }; + return { + start: positionToLineOffset(scriptInfo, change.span.start), + end: positionToLineOffset(scriptInfo, textSpanEnd(change.span)), + newText: change.newText, + }; } function positionToLineOffset(info: ScriptInfoOrConfig, position: number): protocol.Location { - return isConfigFile(info) ? locationFromLineAndCharacter(info.getLineAndCharacterOfPosition(position)) : info.positionToLineOffset(position); + return isConfigFile(info) ? locationFromLineAndCharacter(info.getLineAndCharacterOfPosition(position)) + : info.positionToLineOffset(position); } function locationFromLineAndCharacter(lc: LineAndCharacter): protocol.Location { @@ -3519,7 +4131,10 @@ namespace ts.server { Debug.assert(textChanges.textChanges.length === 1); const change = first(textChanges.textChanges); Debug.assert(change.span.start === 0 && change.span.length === 0); - return { fileName: textChanges.fileName, textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: change.newText }] }; + return { + fileName: textChanges.fileName, + textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: change.newText }], + }; } export interface HandlerResponse { @@ -3529,7 +4144,12 @@ namespace ts.server { /* @internal */ // Exported only for tests - export function getLocationInNewDocument(oldText: string, renameFilename: string, renameLocation: number, edits: readonly FileTextChanges[]): protocol.Location { + export function getLocationInNewDocument( + oldText: string, + renameFilename: string, + renameLocation: number, + edits: readonly FileTextChanges[], + ): protocol.Location { const newText = applyEdits(oldText, renameFilename, edits); const { line, character } = computeLineAndCharacterOfPosition(computeLineStarts(newText), renameLocation); return { line: line + 1, offset: character + 1 }; @@ -3550,7 +4170,11 @@ namespace ts.server { return text; } - function referenceEntryToReferencesResponseItem(projectService: ProjectService, { fileName, textSpan, contextSpan, isWriteAccess, isDefinition }: ReferencedSymbolEntry, { disableLineTextInReferences }: protocol.UserPreferences): protocol.ReferencesResponseItem { + function referenceEntryToReferencesResponseItem( + projectService: ProjectService, + { fileName, textSpan, contextSpan, isWriteAccess, isDefinition }: ReferencedSymbolEntry, + { disableLineTextInReferences }: protocol.UserPreferences, + ): protocol.ReferencesResponseItem { const scriptInfo = Debug.checkDefined(projectService.getScriptInfo(fileName)); const span = toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo); const lineText = disableLineTextInReferences ? undefined : getLineText(scriptInfo, span); diff --git a/src/server/types.ts b/src/server/types.ts index 55445d6d942de..4866ee480b909 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -5,14 +5,27 @@ declare namespace ts.server { data: any; } - export type ModuleImportResult = { module: {}; error: undefined; } | { module: undefined; error: { stack?: string; message?: string; }; }; + export type ModuleImportResult = { module: {}; error: undefined; } | { + module: undefined; + error: { stack?: string; message?: string; }; + }; /** @deprecated Use {@link ModuleImportResult} instead. */ export type RequireResult = ModuleImportResult; export interface ServerHost extends System { - watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; - watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; + watchFile( + path: string, + callback: FileWatcherCallback, + pollingInterval?: number, + options?: WatchOptions, + ): FileWatcher; + watchDirectory( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher; setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any; clearTimeout(timeoutId: any): void; setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; diff --git a/src/server/typingsCache.ts b/src/server/typingsCache.ts index 6250207d72851..247df3749a9fe 100644 --- a/src/server/typingsCache.ts +++ b/src/server/typingsCache.ts @@ -9,7 +9,11 @@ namespace ts.server { export interface ITypingsInstaller { isKnownTypesPackageName(name: string): boolean; installPackage(options: InstallPackageOptionsWithProject): Promise; - enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray | undefined): void; + enqueueInstallTypingsRequest( + p: Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray | undefined, + ): void; attach(projectService: ProjectService): void; onProjectClosed(p: Project): void; readonly globalTypingsCacheLocation: string | undefined; @@ -64,9 +68,9 @@ namespace ts.server { } function typeAcquisitionChanged(opt1: TypeAcquisition, opt2: TypeAcquisition): boolean { - return opt1.enable !== opt2.enable || - !setIsEqualTo(opt1.include, opt2.include) || - !setIsEqualTo(opt1.exclude, opt2.exclude); + return opt1.enable !== opt2.enable + || !setIsEqualTo(opt1.include, opt2.include) + || !setIsEqualTo(opt1.exclude, opt2.exclude); } function compilerOptionsChanged(opt1: CompilerOptions, opt2: CompilerOptions): boolean { @@ -74,7 +78,10 @@ namespace ts.server { return getAllowJSCompilerOption(opt1) !== getAllowJSCompilerOption(opt2); } - function unresolvedImportsChanged(imports1: SortedReadonlyArray | undefined, imports2: SortedReadonlyArray | undefined): boolean { + function unresolvedImportsChanged( + imports1: SortedReadonlyArray | undefined, + imports2: SortedReadonlyArray | undefined, + ): boolean { if (imports1 === imports2) { return false; } @@ -96,7 +103,11 @@ namespace ts.server { return this.installer.installPackage(options); } - enqueueInstallTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray | undefined, forceRefresh: boolean) { + enqueueInstallTypingsForProject( + project: Project, + unresolvedImports: SortedReadonlyArray | undefined, + forceRefresh: boolean, + ) { const typeAcquisition = project.getTypeAcquisition(); if (!typeAcquisition || !typeAcquisition.enable) { @@ -105,11 +116,11 @@ namespace ts.server { const entry = this.perProjectCache.get(project.getProjectName()); if ( - forceRefresh || - !entry || - typeAcquisitionChanged(typeAcquisition, entry.typeAcquisition) || - compilerOptionsChanged(project.getCompilationSettings(), entry.compilerOptions) || - unresolvedImportsChanged(unresolvedImports, entry.unresolvedImports) + forceRefresh + || !entry + || typeAcquisitionChanged(typeAcquisition, entry.typeAcquisition) + || compilerOptionsChanged(project.getCompilationSettings(), entry.compilerOptions) + || unresolvedImportsChanged(unresolvedImports, entry.unresolvedImports) ) { // Note: entry is now poisoned since it does not really contain typings for a given combination of compiler options\typings options. // instead it acts as a placeholder to prevent issuing multiple requests @@ -125,7 +136,13 @@ namespace ts.server { } } - updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray, newTypings: string[]) { + updateTypingsForProject( + projectName: string, + compilerOptions: CompilerOptions, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + newTypings: string[], + ) { const typings = sort(newTypings); this.perProjectCache.set(projectName, { compilerOptions, diff --git a/src/server/utilities.ts b/src/server/utilities.ts index c5a6489b6671e..a82732b75b632 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -20,7 +20,10 @@ namespace ts.server { this.host.clearTimeout(pendingTimeout); } // schedule new operation, pass arguments - this.pendingTimeouts.set(operationId, this.host.setTimeout(ThrottledOperations.run, delay, this, operationId, cb)); + this.pendingTimeouts.set( + operationId, + this.host.setTimeout(ThrottledOperations.run, delay, this, operationId, cb), + ); if (this.logger) { this.logger.info(`Scheduled: ${operationId}${pendingTimeout ? ", Cancelled earlier one" : ""}`); } @@ -46,7 +49,11 @@ namespace ts.server { export class GcTimer { private timerId: any; - constructor(private readonly host: ServerHost, private readonly delay: number, private readonly logger: Logger) { + constructor( + private readonly host: ServerHost, + private readonly delay: number, + private readonly logger: Logger, + ) { } public scheduleCollect() { @@ -73,7 +80,9 @@ namespace ts.server { } } - export function getBaseConfigFileName(configFilePath: NormalizedPath): "tsconfig.json" | "jsconfig.json" | undefined { + export function getBaseConfigFileName( + configFilePath: NormalizedPath, + ): "tsconfig.json" | "jsconfig.json" | undefined { const base = getBaseFileName(configFilePath); return base === "tsconfig.json" || base === "jsconfig.json" ? base : undefined; } diff --git a/src/server/utilitiesPublic.ts b/src/server/utilitiesPublic.ts index ad310c74d2b98..abe39041be288 100644 --- a/src/server/utilitiesPublic.ts +++ b/src/server/utilitiesPublic.ts @@ -31,10 +31,16 @@ namespace ts.server { export type Types = Msg; } - export function createInstallTypingsRequest(project: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray, cachePath?: string): DiscoverTypings { + export function createInstallTypingsRequest( + project: Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + cachePath?: string, + ): DiscoverTypings { return { projectName: project.getProjectName(), - fileNames: project.getFileNames(/*excludeFilesFromExternalLibraries*/ true, /*excludeConfigFiles*/ true).concat(project.getExcludedFiles() as NormalizedPath[]), + fileNames: project.getFileNames(/*excludeFilesFromExternalLibraries*/ true, /*excludeConfigFiles*/ true) + .concat(project.getExcludedFiles() as NormalizedPath[]), compilerOptions: project.getCompilationSettings(), watchOptions: project.projectService.getWatchOptions(project), typeAcquisition, @@ -63,8 +69,13 @@ namespace ts.server { return normalizePath(fileName) as NormalizedPath; } - export function normalizedPathToPath(normalizedPath: NormalizedPath, currentDirectory: string, getCanonicalFileName: (f: string) => string): Path { - const f = isRootedDiskPath(normalizedPath) ? normalizedPath : getNormalizedAbsolutePath(normalizedPath, currentDirectory); + export function normalizedPathToPath( + normalizedPath: NormalizedPath, + currentDirectory: string, + getCanonicalFileName: (f: string) => string, + ): Path { + const f = isRootedDiskPath(normalizedPath) ? normalizedPath + : getNormalizedAbsolutePath(normalizedPath, currentDirectory); return getCanonicalFileName(f) as Path; } diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index bf61881a51af0..95bec92198fc5 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -36,14 +36,17 @@ namespace ts.BreakpointResolver { function textSpan(startNode: Node, endNode?: Node) { const lastDecorator = canHaveDecorators(startNode) ? findLast(startNode.modifiers, isDecorator) : undefined; - const start = lastDecorator ? - skipTrivia(sourceFile.text, lastDecorator.end) : - startNode.getStart(sourceFile); + const start = lastDecorator + ? skipTrivia(sourceFile.text, lastDecorator.end) + : startNode.getStart(sourceFile); return createTextSpanFromBounds(start, (endNode || startNode).getEnd()); } function textSpanEndingAtNextToken(startNode: Node, previousTokenToFindNextEndToken: Node): TextSpan { - return textSpan(startNode, findNextToken(previousTokenToFindNextEndToken, previousTokenToFindNextEndToken.parent, sourceFile)); + return textSpan( + startNode, + findNextToken(previousTokenToFindNextEndToken, previousTokenToFindNextEndToken.parent, sourceFile), + ); } function spanInNodeIfStartsOnSameLine(node: Node | undefined, otherwiseOnNode?: Node): TextSpan | undefined { @@ -53,7 +56,11 @@ namespace ts.BreakpointResolver { return spanInNode(otherwiseOnNode); } - function spanInNodeArray(nodeArray: NodeArray | undefined, node: T, match: (value: Node) => boolean) { + function spanInNodeArray( + nodeArray: NodeArray | undefined, + node: T, + match: (value: Node) => boolean, + ) { if (nodeArray) { const index = nodeArray.indexOf(node); if (index >= 0) { @@ -61,7 +68,10 @@ namespace ts.BreakpointResolver { let end = index + 1; while (start > 0 && match(nodeArray[start - 1])) start--; while (end < nodeArray.length && match(nodeArray[end])) end++; - return createTextSpanFromBounds(skipTrivia(sourceFile.text, nodeArray[start].pos), nodeArray[end - 1].end); + return createTextSpanFromBounds( + skipTrivia(sourceFile.text, nodeArray[start].pos), + nodeArray[end - 1].end, + ); } } return textSpan(node); @@ -86,7 +96,9 @@ namespace ts.BreakpointResolver { case SyntaxKind.VariableDeclaration: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - return spanInVariableDeclaration(node as VariableDeclaration | PropertyDeclaration | PropertySignature); + return spanInVariableDeclaration( + node as VariableDeclaration | PropertyDeclaration | PropertySignature, + ); case SyntaxKind.Parameter: return spanInParameterDeclaration(node as ParameterDeclaration); @@ -273,11 +285,11 @@ namespace ts.BreakpointResolver { // `a` or `...c` or `d: x` from // `[a, b, ...c]` or `{ a, b }` or `{ d: x }` from destructuring pattern if ( - (node.kind === SyntaxKind.Identifier || - node.kind === SyntaxKind.SpreadElement || - node.kind === SyntaxKind.PropertyAssignment || - node.kind === SyntaxKind.ShorthandPropertyAssignment) && - isArrayLiteralOrObjectLiteralDestructuringPattern(parent) + (node.kind === SyntaxKind.Identifier + || node.kind === SyntaxKind.SpreadElement + || node.kind === SyntaxKind.PropertyAssignment + || node.kind === SyntaxKind.ShorthandPropertyAssignment) + && isArrayLiteralOrObjectLiteralDestructuringPattern(parent) ) { return textSpan(node); } @@ -294,7 +306,10 @@ namespace ts.BreakpointResolver { ); } - if (operatorToken.kind === SyntaxKind.EqualsToken && isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) { + if ( + operatorToken.kind === SyntaxKind.EqualsToken + && isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent) + ) { // Set breakpoint on assignment expression element of destructuring pattern // a = expression of // [a = expression, b, c] = someExpression or @@ -322,7 +337,9 @@ namespace ts.BreakpointResolver { return textSpan(node); case SyntaxKind.BinaryExpression: - if ((node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken) { + if ( + (node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken + ) { // If this is a comma expression, the breakpoint is possible in this expression return textSpan(node); } @@ -341,8 +358,8 @@ namespace ts.BreakpointResolver { case SyntaxKind.PropertyAssignment: // If this is name of property assignment, set breakpoint in the initializer if ( - (node.parent as PropertyAssignment).name === node && - !isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.parent) + (node.parent as PropertyAssignment).name === node + && !isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.parent) ) { return spanInNode((node.parent as PropertyAssignment).initializer); } @@ -382,10 +399,18 @@ namespace ts.BreakpointResolver { } } - function textSpanFromVariableDeclaration(variableDeclaration: VariableDeclaration | PropertyDeclaration | PropertySignature): TextSpan { - if (isVariableDeclarationList(variableDeclaration.parent) && variableDeclaration.parent.declarations[0] === variableDeclaration) { + function textSpanFromVariableDeclaration( + variableDeclaration: VariableDeclaration | PropertyDeclaration | PropertySignature, + ): TextSpan { + if ( + isVariableDeclarationList(variableDeclaration.parent) + && variableDeclaration.parent.declarations[0] === variableDeclaration + ) { // First declaration - include let keyword - return textSpan(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent)!, variableDeclaration); + return textSpan( + findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent)!, + variableDeclaration, + ); } else { // Span only on this declaration @@ -393,7 +418,9 @@ namespace ts.BreakpointResolver { } } - function spanInVariableDeclaration(variableDeclaration: VariableDeclaration | PropertyDeclaration | PropertySignature): TextSpan | undefined { + function spanInVariableDeclaration( + variableDeclaration: VariableDeclaration | PropertyDeclaration | PropertySignature, + ): TextSpan | undefined { // If declaration of for in statement, just set the span in parent if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) { return spanInNode(variableDeclaration.parent.parent); @@ -408,29 +435,31 @@ namespace ts.BreakpointResolver { // Breakpoint is possible in variableDeclaration only if there is initialization // or its declaration from 'for of' if ( - (hasOnlyExpressionInitializer(variableDeclaration) && variableDeclaration.initializer) || - hasSyntacticModifier(variableDeclaration, ModifierFlags.Export) || - parent.parent.kind === SyntaxKind.ForOfStatement + (hasOnlyExpressionInitializer(variableDeclaration) && variableDeclaration.initializer) + || hasSyntacticModifier(variableDeclaration, ModifierFlags.Export) + || parent.parent.kind === SyntaxKind.ForOfStatement ) { return textSpanFromVariableDeclaration(variableDeclaration); } if ( - isVariableDeclarationList(variableDeclaration.parent) && - variableDeclaration.parent.declarations[0] !== variableDeclaration + isVariableDeclarationList(variableDeclaration.parent) + && variableDeclaration.parent.declarations[0] !== variableDeclaration ) { // If we cannot set breakpoint on this declaration, set it on previous one // Because the variable declaration may be binding pattern and // we would like to set breakpoint in last binding element if that's the case, // use preceding token instead - return spanInNode(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent)); + return spanInNode( + findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent), + ); } } function canHaveSpanInParameterDeclaration(parameter: ParameterDeclaration): boolean { // Breakpoint is possible on parameter only if it has initializer, is a rest parameter, or has public or private modifier - return !!parameter.initializer || parameter.dotDotDotToken !== undefined || - hasSyntacticModifier(parameter, ModifierFlags.Public | ModifierFlags.Private); + return !!parameter.initializer || parameter.dotDotDotToken !== undefined + || hasSyntacticModifier(parameter, ModifierFlags.Public | ModifierFlags.Private); } function spanInParameterDeclaration(parameter: ParameterDeclaration): TextSpan | undefined { @@ -457,8 +486,9 @@ namespace ts.BreakpointResolver { } function canFunctionHaveSpanInWholeDeclaration(functionDeclaration: FunctionLikeDeclaration) { - return hasSyntacticModifier(functionDeclaration, ModifierFlags.Export) || - (functionDeclaration.parent.kind === SyntaxKind.ClassDeclaration && functionDeclaration.kind !== SyntaxKind.Constructor); + return hasSyntacticModifier(functionDeclaration, ModifierFlags.Export) + || (functionDeclaration.parent.kind === SyntaxKind.ClassDeclaration + && functionDeclaration.kind !== SyntaxKind.Constructor); } function spanInFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration): TextSpan | undefined { @@ -488,7 +518,10 @@ namespace ts.BreakpointResolver { function spanInBlock(block: Block): TextSpan | undefined { switch (block.parent.kind) { case SyntaxKind.ModuleDeclaration: - if (getModuleInstanceState(block.parent as ModuleDeclaration) !== ModuleInstanceState.Instantiated) { + if ( + getModuleInstanceState(block.parent as ModuleDeclaration) + !== ModuleInstanceState.Instantiated + ) { return undefined; } @@ -502,14 +535,19 @@ namespace ts.BreakpointResolver { // Set span on previous token if it starts on same line otherwise on the first statement of the block case SyntaxKind.ForStatement: case SyntaxKind.ForOfStatement: - return spanInNodeIfStartsOnSameLine(findPrecedingToken(block.pos, sourceFile, block.parent), block.statements[0]); + return spanInNodeIfStartsOnSameLine( + findPrecedingToken(block.pos, sourceFile, block.parent), + block.statements[0], + ); } // Default action is to set on first statement return spanInNode(block.statements[0]); } - function spanInInitializerOfForLike(forLikeStatement: ForStatement | ForOfStatement | ForInStatement): TextSpan | undefined { + function spanInInitializerOfForLike( + forLikeStatement: ForStatement | ForOfStatement | ForInStatement, + ): TextSpan | undefined { if (forLikeStatement.initializer!.kind === SyntaxKind.VariableDeclarationList) { // Declaration list - set breakpoint in first declaration const variableDeclarationList = forLikeStatement.initializer as VariableDeclarationList; @@ -538,7 +576,10 @@ namespace ts.BreakpointResolver { function spanInBindingPattern(bindingPattern: BindingPattern): TextSpan | undefined { // Set breakpoint in first binding element - const firstBindingElement = forEach(bindingPattern.elements, element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined); + const firstBindingElement = forEach( + bindingPattern.elements, + element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined, + ); if (firstBindingElement) { return spanInNode(firstBindingElement); @@ -553,11 +594,19 @@ namespace ts.BreakpointResolver { return textSpanFromVariableDeclaration(bindingPattern.parent as VariableDeclaration); } - function spanInArrayLiteralOrObjectLiteralDestructuringPattern(node: DestructuringPattern): TextSpan | undefined { - Debug.assert(node.kind !== SyntaxKind.ArrayBindingPattern && node.kind !== SyntaxKind.ObjectBindingPattern); - const elements: NodeArray = node.kind === SyntaxKind.ArrayLiteralExpression ? node.elements : node.properties; + function spanInArrayLiteralOrObjectLiteralDestructuringPattern( + node: DestructuringPattern, + ): TextSpan | undefined { + Debug.assert( + node.kind !== SyntaxKind.ArrayBindingPattern && node.kind !== SyntaxKind.ObjectBindingPattern, + ); + const elements: NodeArray = + node.kind === SyntaxKind.ArrayLiteralExpression ? node.elements : node.properties; - const firstBindingElement = forEach(elements, element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined); + const firstBindingElement = forEach( + elements, + element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined, + ); if (firstBindingElement) { return spanInNode(firstBindingElement); @@ -575,11 +624,19 @@ namespace ts.BreakpointResolver { switch (node.parent.kind) { case SyntaxKind.EnumDeclaration: const enumDeclaration = node.parent as EnumDeclaration; - return spanInNodeIfStartsOnSameLine(findPrecedingToken(node.pos, sourceFile, node.parent), enumDeclaration.members.length ? enumDeclaration.members[0] : enumDeclaration.getLastToken(sourceFile)); + return spanInNodeIfStartsOnSameLine( + findPrecedingToken(node.pos, sourceFile, node.parent), + enumDeclaration.members.length ? enumDeclaration.members[0] + : enumDeclaration.getLastToken(sourceFile), + ); case SyntaxKind.ClassDeclaration: const classDeclaration = node.parent as ClassDeclaration; - return spanInNodeIfStartsOnSameLine(findPrecedingToken(node.pos, sourceFile, node.parent), classDeclaration.members.length ? classDeclaration.members[0] : classDeclaration.getLastToken(sourceFile)); + return spanInNodeIfStartsOnSameLine( + findPrecedingToken(node.pos, sourceFile, node.parent), + classDeclaration.members.length ? classDeclaration.members[0] + : classDeclaration.getLastToken(sourceFile), + ); case SyntaxKind.CaseBlock: return spanInNodeIfStartsOnSameLine(node.parent.parent, (node.parent as CaseBlock).clauses[0]); @@ -593,7 +650,10 @@ namespace ts.BreakpointResolver { switch (node.parent.kind) { case SyntaxKind.ModuleBlock: // If this is not an instantiated module block, no bp span - if (getModuleInstanceState(node.parent.parent as ModuleDeclaration) !== ModuleInstanceState.Instantiated) { + if ( + getModuleInstanceState(node.parent.parent as ModuleDeclaration) + !== ModuleInstanceState.Instantiated + ) { return undefined; } // falls through @@ -659,9 +719,9 @@ namespace ts.BreakpointResolver { function spanInOpenParenToken(node: Node): TextSpan | undefined { if ( - node.parent.kind === SyntaxKind.DoStatement || // Go to while keyword and do action instead - node.parent.kind === SyntaxKind.CallExpression || - node.parent.kind === SyntaxKind.NewExpression + node.parent.kind === SyntaxKind.DoStatement // Go to while keyword and do action instead + || node.parent.kind === SyntaxKind.CallExpression + || node.parent.kind === SyntaxKind.NewExpression ) { return spanInPreviousNode(node); } @@ -703,9 +763,9 @@ namespace ts.BreakpointResolver { function spanInColonToken(node: Node): TextSpan | undefined { // Is this : specifying return annotation of the function declaration if ( - isFunctionLike(node.parent) || - node.parent.kind === SyntaxKind.PropertyAssignment || - node.parent.kind === SyntaxKind.Parameter + isFunctionLike(node.parent) + || node.parent.kind === SyntaxKind.PropertyAssignment + || node.parent.kind === SyntaxKind.Parameter ) { return spanInPreviousNode(node); } diff --git a/src/services/callHierarchy.ts b/src/services/callHierarchy.ts index 1337a2bb0388f..98f24436e2fa7 100644 --- a/src/services/callHierarchy.ts +++ b/src/services/callHierarchy.ts @@ -74,7 +74,9 @@ namespace ts.CallHierarchy { } /** Gets the node that can be used as a reference to a call hierarchy declaration. */ - function getCallHierarchyDeclarationReferenceNode(node: Exclude) { + function getCallHierarchyDeclarationReferenceNode( + node: Exclude, + ) { if (isSourceFile(node)) return node; if (isNamedDeclaration(node)) return node.name; if (isConstNamedExpression(node)) return node.parent.name; @@ -86,13 +88,19 @@ namespace ts.CallHierarchy { } /** Gets the symbol for a call hierarchy declaration. */ - function getSymbolOfCallHierarchyDeclaration(typeChecker: TypeChecker, node: Exclude) { + function getSymbolOfCallHierarchyDeclaration( + typeChecker: TypeChecker, + node: Exclude, + ) { const location = getCallHierarchyDeclarationReferenceNode(node); return location && typeChecker.getSymbolAtLocation(location); } /** Gets the text and range for the name of a call hierarchy declaration. */ - function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclaration): { text: string; pos: number; end: number; } { + function getCallHierarchyItemName( + program: Program, + node: CallHierarchyDeclaration, + ): { text: string; pos: number; end: number; } { if (isSourceFile(node)) { return { text: node.fileName, pos: 0, end: 0 }; } @@ -114,15 +122,15 @@ namespace ts.CallHierarchy { return { text: `${prefix}static {}`, pos, end }; } - const declName = isConstNamedExpression(node) ? node.parent.name : - Debug.checkDefined(getNameOfDeclaration(node), "Expected call hierarchy item to have a name"); + const declName = isConstNamedExpression(node) ? node.parent.name + : Debug.checkDefined(getNameOfDeclaration(node), "Expected call hierarchy item to have a name"); - let text = isIdentifier(declName) ? idText(declName) : - isStringOrNumericLiteralLike(declName) ? declName.text : - isComputedPropertyName(declName) ? - isStringOrNumericLiteralLike(declName.expression) ? declName.expression.text : - undefined : - undefined; + let text = isIdentifier(declName) ? idText(declName) + : isStringOrNumericLiteralLike(declName) ? declName.text + : isComputedPropertyName(declName) + ? isStringOrNumericLiteralLike(declName.expression) ? declName.expression.text + : undefined + : undefined; if (text === undefined) { const typeChecker = program.getTypeChecker(); const symbol = typeChecker.getSymbolAtLocation(declName); @@ -133,14 +141,19 @@ namespace ts.CallHierarchy { if (text === undefined) { // get the text from printing the node on a single line without comments... const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); - text = usingSingleLineStringWriter(writer => printer.writeNode(EmitHint.Unspecified, node, node.getSourceFile(), writer)); + text = usingSingleLineStringWriter(writer => + printer.writeNode(EmitHint.Unspecified, node, node.getSourceFile(), writer) + ); } return { text, pos: declName.getStart(), end: declName.getEnd() }; } function getCallHierarchItemContainerName(node: CallHierarchyDeclaration): string | undefined { if (isConstNamedExpression(node)) { - if (isModuleBlock(node.parent.parent.parent.parent) && isIdentifier(node.parent.parent.parent.parent.parent.name)) { + if ( + isModuleBlock(node.parent.parent.parent.parent) + && isIdentifier(node.parent.parent.parent.parent.parent.name) + ) { return node.parent.parent.parent.parent.parent.name.getText(); } return; @@ -164,9 +177,18 @@ namespace ts.CallHierarchy { } /** Finds the implementation of a function-like declaration, if one exists. */ - function findImplementation(typeChecker: TypeChecker, node: Extract): Extract | undefined; - function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclaration): FunctionLikeDeclaration | undefined; - function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclaration): FunctionLikeDeclaration | undefined { + function findImplementation( + typeChecker: TypeChecker, + node: Extract, + ): Extract | undefined; + function findImplementation( + typeChecker: TypeChecker, + node: FunctionLikeDeclaration, + ): FunctionLikeDeclaration | undefined; + function findImplementation( + typeChecker: TypeChecker, + node: FunctionLikeDeclaration, + ): FunctionLikeDeclaration | undefined { if (node.body) { return node; } @@ -175,7 +197,10 @@ namespace ts.CallHierarchy { } if (isFunctionDeclaration(node) || isMethodDeclaration(node)) { const symbol = getSymbolOfCallHierarchyDeclaration(typeChecker, node); - if (symbol && symbol.valueDeclaration && isFunctionLikeDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.body) { + if ( + symbol && symbol.valueDeclaration && isFunctionLikeDeclaration(symbol.valueDeclaration) + && symbol.valueDeclaration.body + ) { return symbol.valueDeclaration; } return undefined; @@ -183,13 +208,18 @@ namespace ts.CallHierarchy { return node; } - function findAllInitialDeclarations(typeChecker: TypeChecker, node: Exclude) { + function findAllInitialDeclarations( + typeChecker: TypeChecker, + node: Exclude, + ) { const symbol = getSymbolOfCallHierarchyDeclaration(typeChecker, node); let declarations: CallHierarchyDeclaration[] | undefined; if (symbol && symbol.declarations) { const indices = indicesOf(symbol.declarations); const keys = map(symbol.declarations, decl => ({ file: decl.getSourceFile().fileName, pos: decl.pos })); - indices.sort((a, b) => compareStringsCaseSensitive(keys[a].file, keys[b].file) || keys[a].pos - keys[b].pos); + indices.sort((a, b) => + compareStringsCaseSensitive(keys[a].file, keys[b].file) || keys[a].pos - keys[b].pos + ); const sortedDeclarations = map(indices, i => symbol.declarations![i]); let lastDecl: CallHierarchyDeclaration | undefined; for (const decl of sortedDeclarations) { @@ -205,20 +235,26 @@ namespace ts.CallHierarchy { } /** Find the implementation or the first declaration for a call hierarchy declaration. */ - function findImplementationOrAllInitialDeclarations(typeChecker: TypeChecker, node: CallHierarchyDeclaration): CallHierarchyDeclaration | CallHierarchyDeclaration[] { + function findImplementationOrAllInitialDeclarations( + typeChecker: TypeChecker, + node: CallHierarchyDeclaration, + ): CallHierarchyDeclaration | CallHierarchyDeclaration[] { if (isClassStaticBlockDeclaration(node)) { return node; } if (isFunctionLikeDeclaration(node)) { - return findImplementation(typeChecker, node) ?? - findAllInitialDeclarations(typeChecker, node) ?? - node; + return findImplementation(typeChecker, node) + ?? findAllInitialDeclarations(typeChecker, node) + ?? node; } return findAllInitialDeclarations(typeChecker, node) ?? node; } /** Resolves the call hierarchy declaration for a node. */ - export function resolveCallHierarchyDeclaration(program: Program, location: Node): CallHierarchyDeclaration | CallHierarchyDeclaration[] | undefined { + export function resolveCallHierarchyDeclaration( + program: Program, + location: Node, + ): CallHierarchyDeclaration | CallHierarchyDeclaration[] | undefined { // A call hierarchy item must refer to either a SourceFile, Module Declaration, Class Static Block, or something intrinsically callable that has a name: // - Class Declarations // - Class Expressions (with a name) @@ -251,7 +287,10 @@ namespace ts.CallHierarchy { const ancestor = findAncestor(location.parent, isValidCallHierarchyDeclaration); return ancestor && findImplementationOrAllInitialDeclarations(typeChecker, ancestor); } - if (isVariableDeclaration(location.parent) && location.parent.initializer && isConstNamedExpression(location.parent.initializer)) { + if ( + isVariableDeclaration(location.parent) && location.parent.initializer + && isConstNamedExpression(location.parent.initializer) + ) { return location.parent.initializer; } return undefined; @@ -267,7 +306,9 @@ namespace ts.CallHierarchy { continue; } // #39453 - if (isVariableDeclaration(location) && location.initializer && isConstNamedExpression(location.initializer)) { + if ( + isVariableDeclaration(location) && location.initializer && isConstNamedExpression(location.initializer) + ) { return location.initializer; } if (!followingSymbol) { @@ -294,7 +335,10 @@ namespace ts.CallHierarchy { const containerName = getCallHierarchItemContainerName(node); const kind = getNodeKind(node); const kindModifiers = getNodeModifiers(node); - const span = createTextSpanFromBounds(skipTrivia(sourceFile.text, node.getFullStart(), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true), node.getEnd()); + const span = createTextSpanFromBounds( + skipTrivia(sourceFile.text, node.getFullStart(), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true), + node.getEnd(), + ); const selectionSpan = createTextSpanFromBounds(name.pos, name.end); return { file: sourceFile.fileName, kind, kindModifiers, name: name.text, containerName, span, selectionSpan }; } @@ -315,7 +359,11 @@ namespace ts.CallHierarchy { isCallOrNewExpressionTarget(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true) || isTaggedTemplateTag(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true) || isDecoratorTarget(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true) - || isJsxOpeningLikeElementTagName(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true) + || isJsxOpeningLikeElementTagName( + node, + /*includeElementAccess*/ true, + /*skipPastOuterExpressions*/ true, + ) || isRightSideOfPropertyAccess(node) || isArgumentExpressionOfElementAccess(node) ) { @@ -330,32 +378,66 @@ namespace ts.CallHierarchy { return getNodeId(entry.declaration); } - function createCallHierarchyIncomingCall(from: CallHierarchyItem, fromSpans: TextSpan[]): CallHierarchyIncomingCall { + function createCallHierarchyIncomingCall( + from: CallHierarchyItem, + fromSpans: TextSpan[], + ): CallHierarchyIncomingCall { return { from, fromSpans }; } function convertCallSiteGroupToIncomingCall(program: Program, entries: readonly CallSite[]) { - return createCallHierarchyIncomingCall(createCallHierarchyItem(program, entries[0].declaration), map(entries, entry => createTextSpanFromRange(entry.range))); + return createCallHierarchyIncomingCall( + createCallHierarchyItem(program, entries[0].declaration), + map(entries, entry => createTextSpanFromRange(entry.range)), + ); } /** Gets the call sites that call into the provided call hierarchy declaration. */ - export function getIncomingCalls(program: Program, declaration: CallHierarchyDeclaration, cancellationToken: CancellationToken): CallHierarchyIncomingCall[] { + export function getIncomingCalls( + program: Program, + declaration: CallHierarchyDeclaration, + cancellationToken: CancellationToken, + ): CallHierarchyIncomingCall[] { // Source files and modules have no incoming calls. - if (isSourceFile(declaration) || isModuleDeclaration(declaration) || isClassStaticBlockDeclaration(declaration)) { + if ( + isSourceFile(declaration) || isModuleDeclaration(declaration) || isClassStaticBlockDeclaration(declaration) + ) { return []; } const location = getCallHierarchyDeclarationReferenceNode(declaration); - const calls = filter(FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, program.getSourceFiles(), location, /*position*/ 0, { use: FindAllReferences.FindReferencesUse.References }, convertEntryToCallSite), isDefined); - return calls ? group(calls, getCallSiteGroupKey, entries => convertCallSiteGroupToIncomingCall(program, entries)) : []; + const calls = filter( + FindAllReferences.findReferenceOrRenameEntries( + program, + cancellationToken, + program.getSourceFiles(), + location, + /*position*/ 0, + { use: FindAllReferences.FindReferencesUse.References }, + convertEntryToCallSite, + ), + isDefined, + ); + return calls + ? group(calls, getCallSiteGroupKey, entries => convertCallSiteGroupToIncomingCall(program, entries)) : []; } function createCallSiteCollector(program: Program, callSites: CallSite[]): (node: Node | undefined) => void { - function recordCallSite(node: CallExpression | NewExpression | TaggedTemplateExpression | PropertyAccessExpression | ElementAccessExpression | Decorator | JsxOpeningLikeElement | ClassStaticBlockDeclaration) { - const target = isTaggedTemplateExpression(node) ? node.tag : - isJsxOpeningLikeElement(node) ? node.tagName : - isAccessExpression(node) ? node : - isClassStaticBlockDeclaration(node) ? node : - node.expression; + function recordCallSite( + node: + | CallExpression + | NewExpression + | TaggedTemplateExpression + | PropertyAccessExpression + | ElementAccessExpression + | Decorator + | JsxOpeningLikeElement + | ClassStaticBlockDeclaration, + ) { + const target = isTaggedTemplateExpression(node) ? node.tag + : isJsxOpeningLikeElement(node) ? node.tagName + : isAccessExpression(node) ? node + : isClassStaticBlockDeclaration(node) ? node + : node.expression; const declaration = resolveCallHierarchyDeclaration(program, target); if (declaration) { const range = createTextRangeFromNode(target, node.getSourceFile()); @@ -472,7 +554,11 @@ namespace ts.CallHierarchy { } } - function collectCallSitesOfFunctionLikeDeclaration(typeChecker: TypeChecker, node: FunctionLikeDeclaration, collect: (node: Node | undefined) => void) { + function collectCallSitesOfFunctionLikeDeclaration( + typeChecker: TypeChecker, + node: FunctionLikeDeclaration, + collect: (node: Node | undefined) => void, + ) { const implementation = findImplementation(typeChecker, node); if (implementation) { forEach(implementation.parameters, collect); @@ -480,11 +566,17 @@ namespace ts.CallHierarchy { } } - function collectCallSitesOfClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, collect: (node: Node | undefined) => void) { + function collectCallSitesOfClassStaticBlockDeclaration( + node: ClassStaticBlockDeclaration, + collect: (node: Node | undefined) => void, + ) { collect(node.body); } - function collectCallSitesOfClassLikeDeclaration(node: ClassLikeDeclaration, collect: (node: Node | undefined) => void) { + function collectCallSitesOfClassLikeDeclaration( + node: ClassLikeDeclaration, + collect: (node: Node | undefined) => void, + ) { forEach(node.modifiers, collect); const heritage = getClassExtendsHeritageElement(node); if (heritage) { @@ -543,14 +635,24 @@ namespace ts.CallHierarchy { } function convertCallSiteGroupToOutgoingCall(program: Program, entries: readonly CallSite[]) { - return createCallHierarchyOutgoingCall(createCallHierarchyItem(program, entries[0].declaration), map(entries, entry => createTextSpanFromRange(entry.range))); + return createCallHierarchyOutgoingCall( + createCallHierarchyItem(program, entries[0].declaration), + map(entries, entry => createTextSpanFromRange(entry.range)), + ); } /** Gets the call sites that call out of the provided call hierarchy declaration. */ - export function getOutgoingCalls(program: Program, declaration: CallHierarchyDeclaration): CallHierarchyOutgoingCall[] { + export function getOutgoingCalls( + program: Program, + declaration: CallHierarchyDeclaration, + ): CallHierarchyOutgoingCall[] { if (declaration.flags & NodeFlags.Ambient || isMethodSignature(declaration)) { return []; } - return group(collectCallSites(program, declaration), getCallSiteGroupKey, entries => convertCallSiteGroupToOutgoingCall(program, entries)); + return group( + collectCallSites(program, declaration), + getCallSiteGroupKey, + entries => convertCallSiteGroupToOutgoingCall(program, entries), + ); } } diff --git a/src/services/classifier.ts b/src/services/classifier.ts index 3ba0b7b78e714..e6ece0924c675 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -3,13 +3,24 @@ namespace ts { export function createClassifier(): Classifier { const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false); - function getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult { - return convertClassificationsToResult(getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent), text); + function getClassificationsForLine( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent: boolean, + ): ClassificationResult { + return convertClassificationsToResult( + getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent), + text, + ); } // If there is a syntactic classifier ('syntacticClassifierAbsent' is false), // we will be more conservative in order to avoid conflicting with the syntactic classifier. - function getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): Classifications { + function getEncodedLexicalClassifications( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent: boolean, + ): Classifications { let token = SyntaxKind.Unknown; let lastNonTriviaToken = SyntaxKind.Unknown; @@ -89,7 +100,10 @@ namespace ts { switch (token) { case SyntaxKind.SlashToken: case SyntaxKind.SlashEqualsToken: - if (!noRegexTable[lastNonTriviaToken] && scanner.reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { + if ( + !noRegexTable[lastNonTriviaToken] + && scanner.reScanSlashToken() === SyntaxKind.RegularExpressionLiteral + ) { token = SyntaxKind.RegularExpressionLiteral; } break; @@ -143,11 +157,19 @@ namespace ts { templateStack.pop(); } else { - Debug.assertEqual(token, SyntaxKind.TemplateMiddle, "Should have been a template middle."); + Debug.assertEqual( + token, + SyntaxKind.TemplateMiddle, + "Should have been a template middle.", + ); } } else { - Debug.assertEqual(lastTemplateStackToken, SyntaxKind.OpenBraceToken, "Should have been an open brace"); + Debug.assertEqual( + lastTemplateStackToken, + SyntaxKind.OpenBraceToken, + "Should have been an open brace", + ); templateStack.pop(); } } @@ -160,7 +182,9 @@ namespace ts { if (lastNonTriviaToken === SyntaxKind.DotToken) { token = SyntaxKind.Identifier; } - else if (isKeyword(lastNonTriviaToken) && isKeyword(token) && !canFollow(lastNonTriviaToken, token)) { + else if ( + isKeyword(lastNonTriviaToken) && isKeyword(token) && !canFollow(lastNonTriviaToken, token) + ) { // We have two keywords in a row. Only treat the second as a keyword if // it's a sequence that could legally occur in the language. Otherwise // treat it as an identifier. This way, if someone writes "private var" @@ -200,7 +224,11 @@ namespace ts { () => true, ); - function getNewEndOfLineState(scanner: Scanner, token: SyntaxKind, lastOnTemplateStack: SyntaxKind | undefined): EndOfLineState | undefined { + function getNewEndOfLineState( + scanner: Scanner, + token: SyntaxKind, + lastOnTemplateStack: SyntaxKind | undefined, + ): EndOfLineState | undefined { switch (token) { case SyntaxKind.StringLiteral: { // Check to see if we finished up on a multiline string literal. @@ -215,7 +243,8 @@ namespace ts { // If we have an odd number of backslashes, then the multiline string is unclosed if ((numBackslashes & 1) === 0) return undefined; - return tokenText.charCodeAt(0) === CharacterCodes.doubleQuote ? EndOfLineState.InDoubleQuoteStringLiteral : EndOfLineState.InSingleQuoteStringLiteral; + return tokenText.charCodeAt(0) === CharacterCodes.doubleQuote + ? EndOfLineState.InDoubleQuoteStringLiteral : EndOfLineState.InSingleQuoteStringLiteral; } case SyntaxKind.MultiLineCommentTrivia: // Check to see if the multiline comment was unclosed. @@ -231,14 +260,24 @@ namespace ts { case SyntaxKind.NoSubstitutionTemplateLiteral: return EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate; default: - return Debug.fail("Only 'NoSubstitutionTemplateLiteral's and 'TemplateTail's can be unterminated; got SyntaxKind #" + token); + return Debug.fail( + "Only 'NoSubstitutionTemplateLiteral's and 'TemplateTail's can be unterminated; got SyntaxKind #" + + token, + ); } } - return lastOnTemplateStack === SyntaxKind.TemplateHead ? EndOfLineState.InTemplateSubstitutionPosition : undefined; + return lastOnTemplateStack === SyntaxKind.TemplateHead ? EndOfLineState.InTemplateSubstitutionPosition + : undefined; } } - function pushEncodedClassification(start: number, end: number, offset: number, classification: ClassificationType, result: Push): void { + function pushEncodedClassification( + start: number, + end: number, + offset: number, + classification: ClassificationType, + result: Push, + ): void { if (classification === ClassificationType.whiteSpace) { // Don't bother with whitespace classifications. They're not needed. return; @@ -340,7 +379,9 @@ namespace ts { } } - function getPrefixFromLexState(lexState: EndOfLineState): { readonly prefix: string; readonly pushTemplate?: true; } { + function getPrefixFromLexState( + lexState: EndOfLineState, + ): { readonly prefix: string; readonly pushTemplate?: true; } { // If we're in a string literal, then prepend: "\ // (and a newline). That way when we lex we'll think we're still in a string literal. // @@ -467,8 +508,16 @@ namespace ts { } /* @internal */ - export function getSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: ReadonlySet<__String>, span: TextSpan): ClassifiedSpan[] { - return convertClassificationsToSpans(getEncodedSemanticClassifications(typeChecker, cancellationToken, sourceFile, classifiableNames, span)); + export function getSemanticClassifications( + typeChecker: TypeChecker, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + classifiableNames: ReadonlySet<__String>, + span: TextSpan, + ): ClassifiedSpan[] { + return convertClassificationsToSpans( + getEncodedSemanticClassifications(typeChecker, cancellationToken, sourceFile, classifiableNames, span), + ); } function checkForClassificationCancellation(cancellationToken: CancellationToken, kind: SyntaxKind) { @@ -495,7 +544,13 @@ namespace ts { } /* @internal */ - export function getEncodedSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: ReadonlySet<__String>, span: TextSpan): Classifications { + export function getEncodedSemanticClassifications( + typeChecker: TypeChecker, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + classifiableNames: ReadonlySet<__String>, + span: TextSpan, + ): Classifications { const spans: number[] = []; sourceFile.forEachChild(function cb(node: Node): void { // Only walk into nodes that intersect the requested span. @@ -528,7 +583,11 @@ namespace ts { } } - function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning, checker: TypeChecker): ClassificationType | undefined { + function classifySymbol( + symbol: Symbol, + meaningAtPosition: SemanticMeaning, + checker: TypeChecker, + ): ClassificationType | undefined { const flags = symbol.getFlags(); if ((flags & SymbolFlags.Classifiable) === SymbolFlags.None) { return undefined; @@ -546,13 +605,16 @@ namespace ts { // Only classify a module as such if // - It appears in a namespace context. // - There exists a module declaration which actually impacts the value side. - return meaningAtPosition & SemanticMeaning.Namespace || meaningAtPosition & SemanticMeaning.Value && hasValueSideModule(symbol) ? ClassificationType.moduleName : undefined; + return meaningAtPosition & SemanticMeaning.Namespace + || meaningAtPosition & SemanticMeaning.Value && hasValueSideModule(symbol) + ? ClassificationType.moduleName : undefined; } else if (flags & SymbolFlags.Alias) { return classifySymbol(checker.getAliasedSymbol(symbol), meaningAtPosition, checker); } else if (meaningAtPosition & SemanticMeaning.Type) { - return flags & SymbolFlags.Interface ? ClassificationType.interfaceName : flags & SymbolFlags.TypeParameter ? ClassificationType.typeParameterName : undefined; + return flags & SymbolFlags.Interface ? ClassificationType.interfaceName + : flags & SymbolFlags.TypeParameter ? ClassificationType.typeParameterName : undefined; } else { return undefined; @@ -561,7 +623,12 @@ namespace ts { /** Returns true if there exists a module that introduces entities on the value side. */ function hasValueSideModule(symbol: Symbol): boolean { - return some(symbol.declarations, declaration => isModuleDeclaration(declaration) && getModuleInstanceState(declaration) === ModuleInstanceState.Instantiated); + return some( + symbol.declarations, + declaration => + isModuleDeclaration(declaration) + && getModuleInstanceState(declaration) === ModuleInstanceState.Instantiated, + ); } function getClassificationTypeName(type: ClassificationType): ClassificationTypeNames { @@ -634,18 +701,36 @@ namespace ts { } /* @internal */ - export function getSyntacticClassifications(cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { + export function getSyntacticClassifications( + cancellationToken: CancellationToken, + sourceFile: SourceFile, + span: TextSpan, + ): ClassifiedSpan[] { return convertClassificationsToSpans(getEncodedSyntacticClassifications(cancellationToken, sourceFile, span)); } /* @internal */ - export function getEncodedSyntacticClassifications(cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { + export function getEncodedSyntacticClassifications( + cancellationToken: CancellationToken, + sourceFile: SourceFile, + span: TextSpan, + ): Classifications { const spanStart = span.start; const spanLength = span.length; // Make a scanner we can get trivia from. - const triviaScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, sourceFile.languageVariant, sourceFile.text); - const mergeConflictScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, sourceFile.languageVariant, sourceFile.text); + const triviaScanner = createScanner( + ScriptTarget.Latest, + /*skipTrivia*/ false, + sourceFile.languageVariant, + sourceFile.text, + ); + const mergeConflictScanner = createScanner( + ScriptTarget.Latest, + /*skipTrivia*/ false, + sourceFile.languageVariant, + sourceFile.text, + ); const result: number[] = []; processElement(sourceFile); @@ -758,7 +843,11 @@ namespace ts { } pushClassification(tag.pos, 1, ClassificationType.punctuation); // "@" - pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName); // e.g. "param" + pushClassification( + tag.tagName.pos, + tag.tagName.end - tag.tagName.pos, + ClassificationType.docCommentTagName, + ); // e.g. "param" pos = tag.tagName.end; let commentStart = tag.tagName.end; @@ -780,7 +869,9 @@ namespace ts { break; case SyntaxKind.JSDocTypedefTag: const type = tag as JSDocTypedefTag; - commentStart = type.typeExpression?.kind === SyntaxKind.JSDocTypeExpression && type.fullName?.end || type.typeExpression?.end || commentStart; + commentStart = + type.typeExpression?.kind === SyntaxKind.JSDocTypeExpression && type.fullName?.end + || type.typeExpression?.end || commentStart; break; case SyntaxKind.JSDocCallbackTag: commentStart = (tag as JSDocCallbackTag).typeExpression.end; @@ -979,7 +1070,8 @@ namespace ts { return false; } - const tokenStart = node.kind === SyntaxKind.JsxText ? node.pos : classifyLeadingTriviaAndGetTokenStart(node); + const tokenStart = node.kind === SyntaxKind.JsxText ? node.pos + : classifyLeadingTriviaAndGetTokenStart(node); const tokenWidth = node.end - tokenStart; Debug.assert(tokenWidth >= 0); @@ -1043,20 +1135,20 @@ namespace ts { if (tokenKind === SyntaxKind.EqualsToken) { // the '=' in a variable declaration is special cased here. if ( - parent.kind === SyntaxKind.VariableDeclaration || - parent.kind === SyntaxKind.PropertyDeclaration || - parent.kind === SyntaxKind.Parameter || - parent.kind === SyntaxKind.JsxAttribute + parent.kind === SyntaxKind.VariableDeclaration + || parent.kind === SyntaxKind.PropertyDeclaration + || parent.kind === SyntaxKind.Parameter + || parent.kind === SyntaxKind.JsxAttribute ) { return ClassificationType.operator; } } if ( - parent.kind === SyntaxKind.BinaryExpression || - parent.kind === SyntaxKind.PrefixUnaryExpression || - parent.kind === SyntaxKind.PostfixUnaryExpression || - parent.kind === SyntaxKind.ConditionalExpression + parent.kind === SyntaxKind.BinaryExpression + || parent.kind === SyntaxKind.PrefixUnaryExpression + || parent.kind === SyntaxKind.PostfixUnaryExpression + || parent.kind === SyntaxKind.ConditionalExpression ) { return ClassificationType.operator; } @@ -1071,7 +1163,8 @@ namespace ts { return ClassificationType.bigintLiteral; } else if (tokenKind === SyntaxKind.StringLiteral) { - return token && token.parent.kind === SyntaxKind.JsxAttribute ? ClassificationType.jsxAttributeStringLiteralValue : ClassificationType.stringLiteral; + return token && token.parent.kind === SyntaxKind.JsxAttribute + ? ClassificationType.jsxAttributeStringLiteralValue : ClassificationType.stringLiteral; } else if (tokenKind === SyntaxKind.RegularExpressionLiteral) { // TODO: we should get another classification type for these literals. @@ -1114,7 +1207,8 @@ namespace ts { return; case SyntaxKind.Parameter: if ((token.parent as ParameterDeclaration).name === token) { - return isThisIdentifier(token) ? ClassificationType.keyword : ClassificationType.parameterName; + return isThisIdentifier(token) ? ClassificationType.keyword + : ClassificationType.parameterName; } return; } diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index b27fb6a00276c..554f76452c88a 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -30,7 +30,12 @@ namespace ts.classifier.v2020 { } /** This is mainly used internally for testing */ - export function getSemanticClassifications(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan2020[] { + export function getSemanticClassifications( + program: Program, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + span: TextSpan, + ): ClassifiedSpan2020[] { const classifications = getEncodedSemanticClassifications(program, cancellationToken, sourceFile, span); Debug.assert(classifications.spans.length % 3 === 0); @@ -46,18 +51,32 @@ namespace ts.classifier.v2020 { return result; } - export function getEncodedSemanticClassifications(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { + export function getEncodedSemanticClassifications( + program: Program, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + span: TextSpan, + ): Classifications { return { spans: getSemanticTokens(program, sourceFile, span, cancellationToken), endOfLineState: EndOfLineState.None, }; } - function getSemanticTokens(program: Program, sourceFile: SourceFile, span: TextSpan, cancellationToken: CancellationToken): number[] { + function getSemanticTokens( + program: Program, + sourceFile: SourceFile, + span: TextSpan, + cancellationToken: CancellationToken, + ): number[] { const resultTokens: number[] = []; const collector = (node: Node, typeIdx: number, modifierSet: number) => { - resultTokens.push(node.getStart(sourceFile), node.getWidth(sourceFile), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); + resultTokens.push( + node.getStart(sourceFile), + node.getWidth(sourceFile), + ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet, + ); }; if (program && sourceFile) { @@ -66,7 +85,13 @@ namespace ts.classifier.v2020 { return resultTokens; } - function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, collector: (node: Node, tokenType: number, tokenModifier: number) => void, cancellationToken: CancellationToken) { + function collectTokens( + program: Program, + sourceFile: SourceFile, + span: TextSpan, + collector: (node: Node, tokenType: number, tokenModifier: number) => void, + cancellationToken: CancellationToken, + ) { const typeChecker = program.getTypeChecker(); let inJSXElement = false; @@ -94,7 +119,9 @@ namespace ts.classifier.v2020 { inJSXElement = false; } - if (isIdentifier(node) && !inJSXElement && !inImportClause(node) && !isInfinityOrNaNString(node.escapedText)) { + if ( + isIdentifier(node) && !inJSXElement && !inImportClause(node) && !isInfinityOrNaNString(node.escapedText) + ) { let symbol = typeChecker.getSymbolAtLocation(node); if (symbol) { if (symbol.flags & SymbolFlags.Alias) { @@ -104,7 +131,8 @@ namespace ts.classifier.v2020 { if (typeIdx !== undefined) { let modifierSet = 0; if (node.parent) { - const parentIsDeclaration = (isBindingElement(node.parent) || tokenFromDeclarationMapping.get(node.parent.kind) === typeIdx); + const parentIsDeclaration = (isBindingElement(node.parent) + || tokenFromDeclarationMapping.get(node.parent.kind) === typeIdx); if (parentIsDeclaration && (node.parent as NamedDeclaration).name === node) { modifierSet = 1 << TokenModifier.declaration; } @@ -128,18 +156,27 @@ namespace ts.classifier.v2020 { modifierSet |= 1 << TokenModifier.async; } if (typeIdx !== TokenType.class && typeIdx !== TokenType.interface) { - if ((modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) || (symbol.getFlags() & SymbolFlags.EnumMember)) { + if ( + (modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) + || (symbol.getFlags() & SymbolFlags.EnumMember) + ) { modifierSet |= 1 << TokenModifier.readonly; } } - if ((typeIdx === TokenType.variable || typeIdx === TokenType.function) && isLocalDeclaration(decl, sourceFile)) { + if ( + (typeIdx === TokenType.variable || typeIdx === TokenType.function) + && isLocalDeclaration(decl, sourceFile) + ) { modifierSet |= 1 << TokenModifier.local; } if (program.isSourceFileDefaultLibrary(decl.getSourceFile())) { modifierSet |= 1 << TokenModifier.defaultLibrary; } } - else if (symbol.declarations && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile()))) { + else if ( + symbol.declarations + && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile())) + ) { modifierSet |= 1 << TokenModifier.defaultLibrary; } @@ -191,7 +228,10 @@ namespace ts.classifier.v2020 { if (typeIdx !== TokenType.parameter && test(t => t.getConstructSignatures().length > 0)) { return TokenType.class; } - if (test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) || isExpressionInCallExpression(node)) { + if ( + test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) + || isExpressionInCallExpression(node) + ) { return typeIdx === TokenType.property ? TokenType.member : TokenType.function; } } @@ -204,7 +244,8 @@ namespace ts.classifier.v2020 { decl = getDeclarationForBindingElement(decl); } if (isVariableDeclaration(decl)) { - return (!isSourceFile(decl.parent.parent.parent) || isCatchClause(decl.parent)) && decl.getSourceFile() === sourceFile; + return (!isSourceFile(decl.parent.parent.parent) || isCatchClause(decl.parent)) + && decl.getSourceFile() === sourceFile; } else if (isFunctionDeclaration(decl)) { return !isSourceFile(decl.parent) && decl.getSourceFile() === sourceFile; @@ -236,7 +277,8 @@ namespace ts.classifier.v2020 { } function isRightSideOfQualifiedNameOrPropertyAccess(node: Node): boolean { - return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); + return (isQualifiedName(node.parent) && node.parent.right === node) + || (isPropertyAccessExpression(node.parent) && node.parent.name === node); } const tokenFromDeclarationMapping = new Map([ diff --git a/src/services/codeFixProvider.ts b/src/services/codeFixProvider.ts index 8968609b48376..253dd9e0738ca 100644 --- a/src/services/codeFixProvider.ts +++ b/src/services/codeFixProvider.ts @@ -3,19 +3,64 @@ namespace ts.codefix { const errorCodeToFixes = createMultiMap(); const fixIdToRegistration = new Map(); - export function createCodeFixActionWithoutFixAll(fixName: string, changes: FileTextChanges[], description: DiagnosticAndArguments) { - return createCodeFixActionWorker(fixName, diagnosticToString(description), changes, /*fixId*/ undefined, /*fixAllDescription*/ undefined); + export function createCodeFixActionWithoutFixAll( + fixName: string, + changes: FileTextChanges[], + description: DiagnosticAndArguments, + ) { + return createCodeFixActionWorker( + fixName, + diagnosticToString(description), + changes, + /*fixId*/ undefined, + /*fixAllDescription*/ undefined, + ); } - export function createCodeFixAction(fixName: string, changes: FileTextChanges[], description: DiagnosticAndArguments, fixId: {}, fixAllDescription: DiagnosticAndArguments, command?: CodeActionCommand): CodeFixAction { - return createCodeFixActionWorker(fixName, diagnosticToString(description), changes, fixId, diagnosticToString(fixAllDescription), command); + export function createCodeFixAction( + fixName: string, + changes: FileTextChanges[], + description: DiagnosticAndArguments, + fixId: {}, + fixAllDescription: DiagnosticAndArguments, + command?: CodeActionCommand, + ): CodeFixAction { + return createCodeFixActionWorker( + fixName, + diagnosticToString(description), + changes, + fixId, + diagnosticToString(fixAllDescription), + command, + ); } - export function createCodeFixActionMaybeFixAll(fixName: string, changes: FileTextChanges[], description: DiagnosticAndArguments, fixId?: {}, fixAllDescription?: DiagnosticAndArguments, command?: CodeActionCommand) { - return createCodeFixActionWorker(fixName, diagnosticToString(description), changes, fixId, fixAllDescription && diagnosticToString(fixAllDescription), command); + export function createCodeFixActionMaybeFixAll( + fixName: string, + changes: FileTextChanges[], + description: DiagnosticAndArguments, + fixId?: {}, + fixAllDescription?: DiagnosticAndArguments, + command?: CodeActionCommand, + ) { + return createCodeFixActionWorker( + fixName, + diagnosticToString(description), + changes, + fixId, + fixAllDescription && diagnosticToString(fixAllDescription), + command, + ); } - function createCodeFixActionWorker(fixName: string, description: string, changes: FileTextChanges[], fixId?: {}, fixAllDescription?: string, command?: CodeActionCommand): CodeFixAction { + function createCodeFixActionWorker( + fixName: string, + description: string, + changes: FileTextChanges[], + fixId?: {}, + fixAllDescription?: string, + command?: CodeActionCommand, + ): CodeFixAction { return { fixName, description, changes, fixId, fixAllDescription, commands: command ? [command] : undefined }; } @@ -52,7 +97,10 @@ namespace ts.codefix { export function getFixes(context: CodeFixContext): readonly CodeFixAction[] { const diagnostics = getDiagnostics(context); const registrations = errorCodeToFixes.get(String(context.errorCode)); - return flatMap(registrations, f => map(f.getCodeActions(context), removeFixIdIfFixAllUnavailable(f, diagnostics))); + return flatMap( + registrations, + f => map(f.getCodeActions(context), removeFixIdIfFixAllUnavailable(f, diagnostics)), + ); } export function getAllFixes(context: CodeFixAllContext): CombinedCodeActions { @@ -60,7 +108,10 @@ namespace ts.codefix { return fixIdToRegistration.get(cast(context.fixId, isString))!.getAllCodeActions!(context); } - export function createCombinedCodeActions(changes: FileTextChanges[], commands?: CodeActionCommand[]): CombinedCodeActions { + export function createCombinedCodeActions( + changes: FileTextChanges[], + commands?: CodeActionCommand[], + ): CombinedCodeActions { return { changes, commands }; } @@ -71,14 +122,25 @@ namespace ts.codefix { export function codeFixAll( context: CodeFixAllContext, errorCodes: number[], - use: (changes: textChanges.ChangeTracker, error: DiagnosticWithLocation, commands: Push) => void, + use: ( + changes: textChanges.ChangeTracker, + error: DiagnosticWithLocation, + commands: Push, + ) => void, ): CombinedCodeActions { const commands: CodeActionCommand[] = []; - const changes = textChanges.ChangeTracker.with(context, t => eachDiagnostic(context, errorCodes, diag => use(t, diag, commands))); + const changes = textChanges.ChangeTracker.with( + context, + t => eachDiagnostic(context, errorCodes, diag => use(t, diag, commands)), + ); return createCombinedCodeActions(changes, commands.length === 0 ? undefined : commands); } - export function eachDiagnostic(context: CodeFixAllContext, errorCodes: readonly number[], cb: (diag: DiagnosticWithLocation) => void): void { + export function eachDiagnostic( + context: CodeFixAllContext, + errorCodes: readonly number[], + cb: (diag: DiagnosticWithLocation) => void, + ): void { for (const diag of getDiagnostics(context)) { if (contains(errorCodes, diag.code)) { cb(diag as DiagnosticWithLocation); diff --git a/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts b/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts index fed72acdd5dca..d68f10aaa151b 100644 --- a/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts +++ b/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts @@ -1,14 +1,26 @@ /* @internal */ namespace ts.codefix { const fixId = "addConvertToUnknownForNonOverlappingTypes"; - const errorCodes = [Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first.code]; + const errorCodes = [ + Diagnostics + .Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first + .code, + ]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddConvertToUnknownForNonOverlappingTypes(context) { const assertion = getAssertion(context.sourceFile, context.span.start); if (assertion === undefined) return undefined; const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, assertion)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_unknown_conversion_for_non_overlapping_types, fixId, Diagnostics.Add_unknown_to_all_conversions_of_non_overlapping_types)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_unknown_conversion_for_non_overlapping_types, + fixId, + Diagnostics.Add_unknown_to_all_conversions_of_non_overlapping_types, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -20,15 +32,25 @@ namespace ts.codefix { }), }); - function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, assertion: AsExpression | TypeAssertion) { + function makeChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + assertion: AsExpression | TypeAssertion, + ) { const replacement = isAsExpression(assertion) ? factory.createAsExpression(assertion.expression, factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword)) - : factory.createTypeAssertion(factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword), assertion.expression); + : factory.createTypeAssertion( + factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword), + assertion.expression, + ); changeTracker.replaceNode(sourceFile, assertion.expression, replacement); } function getAssertion(sourceFile: SourceFile, pos: number): AsExpression | TypeAssertion | undefined { if (isInJSFile(sourceFile)) return undefined; - return findAncestor(getTokenAtPosition(sourceFile, pos), (n): n is AsExpression | TypeAssertion => isAsExpression(n) || isTypeAssertionExpression(n)); + return findAncestor( + getTokenAtPosition(sourceFile, pos), + (n): n is AsExpression | TypeAssertion => isAsExpression(n) || isTypeAssertionExpression(n), + ); } } diff --git a/src/services/codefixes/addEmptyExportDeclaration.ts b/src/services/codefixes/addEmptyExportDeclaration.ts index f86b143027889..d1b17b6405843 100644 --- a/src/services/codefixes/addEmptyExportDeclaration.ts +++ b/src/services/codefixes/addEmptyExportDeclaration.ts @@ -2,8 +2,12 @@ namespace ts.codefix { registerCodeFix({ errorCodes: [ - Diagnostics.await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module.code, - Diagnostics.for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module.code, + Diagnostics + .await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module + .code, + Diagnostics + .for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module + .code, ], getCodeActions: function getCodeActionsToAddEmptyExportDeclaration(context) { const { sourceFile } = context; @@ -16,7 +20,13 @@ namespace ts.codefix { ); changes.insertNodeAtEndOfScope(sourceFile, sourceFile, exportDeclaration); }); - return [createCodeFixActionWithoutFixAll("addEmptyExportDeclaration", changes, Diagnostics.Add_export_to_make_this_file_into_a_module)]; + return [ + createCodeFixActionWithoutFixAll( + "addEmptyExportDeclaration", + changes, + Diagnostics.Add_export_to_make_this_file_into_a_module, + ), + ]; }, }); } diff --git a/src/services/codefixes/addMissingAsync.ts b/src/services/codefixes/addMissingAsync.ts index 5f630942abbe1..f174eb05b8ef2 100644 --- a/src/services/codefixes/addMissingAsync.ts +++ b/src/services/codefixes/addMissingAsync.ts @@ -13,8 +13,15 @@ namespace ts.codefix { errorCodes, getCodeActions: function getCodeActionsToAddMissingAsync(context) { const { sourceFile, errorCode, cancellationToken, program, span } = context; - const diagnostic = find(program.getTypeChecker().getDiagnostics(sourceFile, cancellationToken), getIsMatchingAsyncError(span, errorCode)); - const directSpan = diagnostic && diagnostic.relatedInformation && find(diagnostic.relatedInformation, r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code) as TextSpan | undefined; + const diagnostic = find( + program.getTypeChecker().getDiagnostics(sourceFile, cancellationToken), + getIsMatchingAsyncError(span, errorCode), + ); + const directSpan = diagnostic && diagnostic.relatedInformation + && find( + diagnostic.relatedInformation, + r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code, + ) as TextSpan | undefined; const decl = getFixableErrorSpanDeclaration(sourceFile, directSpan); if (!decl) { @@ -28,7 +35,11 @@ namespace ts.codefix { const { sourceFile } = context; const fixedDeclarations = new Set(); return codeFixAll(context, errorCodes, (t, diagnostic) => { - const span = diagnostic.relatedInformation && find(diagnostic.relatedInformation, r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code) as TextSpan | undefined; + const span = diagnostic.relatedInformation + && find( + diagnostic.relatedInformation, + r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code, + ) as TextSpan | undefined; const decl = getFixableErrorSpanDeclaration(sourceFile, span); if (!decl) { return; @@ -40,12 +51,28 @@ namespace ts.codefix { }); type FixableDeclaration = ArrowFunction | FunctionDeclaration | FunctionExpression | MethodDeclaration; - function getFix(context: CodeFixContext | CodeFixAllContext, decl: FixableDeclaration, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Set) { + function getFix( + context: CodeFixContext | CodeFixAllContext, + decl: FixableDeclaration, + trackChanges: ContextualTrackChangesFunction, + fixedDeclarations?: Set, + ) { const changes = trackChanges(t => makeChange(t, context.sourceFile, decl, fixedDeclarations)); - return createCodeFixAction(fixId, changes, Diagnostics.Add_async_modifier_to_containing_function, fixId, Diagnostics.Add_all_missing_async_modifiers); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Add_async_modifier_to_containing_function, + fixId, + Diagnostics.Add_all_missing_async_modifiers, + ); } - function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, insertionSite: FixableDeclaration, fixedDeclarations?: Set) { + function makeChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + insertionSite: FixableDeclaration, + fixedDeclarations?: Set, + ) { if (fixedDeclarations) { if (fixedDeclarations.has(getNodeId(insertionSite))) { return; @@ -54,7 +81,11 @@ namespace ts.codefix { fixedDeclarations?.add(getNodeId(insertionSite)); const cloneWithModifier = factory.updateModifiers( getSynthesizedDeepClone(insertionSite, /*includeTrivia*/ true), - factory.createNodeArray(factory.createModifiersFromModifierFlags(getSyntacticModifierFlags(insertionSite) | ModifierFlags.Async)), + factory.createNodeArray( + factory.createModifiersFromModifierFlags( + getSyntacticModifierFlags(insertionSite) | ModifierFlags.Async, + ), + ), ); changeTracker.replaceNode( sourceFile, @@ -63,7 +94,10 @@ namespace ts.codefix { ); } - function getFixableErrorSpanDeclaration(sourceFile: SourceFile, span: TextSpan | undefined): FixableDeclaration | undefined { + function getFixableErrorSpanDeclaration( + sourceFile: SourceFile, + span: TextSpan | undefined, + ): FixableDeclaration | undefined { if (!span) return undefined; const token = getTokenAtPosition(sourceFile, span.start); // Checker has already done work to determine that async might be possible, and has attached @@ -73,7 +107,8 @@ namespace ts.codefix { if (node.getStart(sourceFile) < span.start || node.getEnd() > textSpanEnd(span)) { return "quit"; } - return (isArrowFunction(node) || isMethodDeclaration(node) || isFunctionExpression(node) || isFunctionDeclaration(node)) && textSpansEqual(span, createTextSpanFromNode(node, sourceFile)); + return (isArrowFunction(node) || isMethodDeclaration(node) || isFunctionExpression(node) + || isFunctionDeclaration(node)) && textSpansEqual(span, createTextSpanFromNode(node, sourceFile)); }) as FixableDeclaration | undefined; return decl; @@ -81,9 +116,12 @@ namespace ts.codefix { function getIsMatchingAsyncError(span: TextSpan, errorCode: number) { return ({ start, length, relatedInformation, code }: Diagnostic) => - isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) && - code === errorCode && - !!relatedInformation && - some(relatedInformation, related => related.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code); + isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) + && code === errorCode + && !!relatedInformation + && some( + relatedInformation, + related => related.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code, + ); } } diff --git a/src/services/codefixes/addMissingAwait.ts b/src/services/codefixes/addMissingAwait.ts index 7bcda9f9aa675..d0aba7e45086f 100644 --- a/src/services/codefixes/addMissingAwait.ts +++ b/src/services/codefixes/addMissingAwait.ts @@ -9,16 +9,22 @@ namespace ts.codefix { ]; const errorCodes = [ Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type.code, - Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type.code, - Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type.code, + Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type + .code, + Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type + .code, Diagnostics.Operator_0_cannot_be_applied_to_type_1.code, Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2.code, Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap.code, Diagnostics.This_condition_will_always_return_true_since_this_0_is_always_defined.code, Diagnostics.Type_0_is_not_an_array_type.code, Diagnostics.Type_0_is_not_an_array_type_or_a_string_type.code, - Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher.code, - Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator.code, + Diagnostics + .Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher + .code, + Diagnostics + .Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator + .code, Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator.code, Diagnostics.Type_0_must_have_a_Symbol_iterator_method_that_returns_an_iterator.code, Diagnostics.Type_0_must_have_a_Symbol_asyncIterator_method_that_returns_an_async_iterator.code, @@ -49,30 +55,65 @@ namespace ts.codefix { const checker = context.program.getTypeChecker(); const fixedDeclarations = new Set(); return codeFixAll(context, errorCodes, (t, diagnostic) => { - const expression = getAwaitErrorSpanExpression(sourceFile, diagnostic.code, diagnostic, cancellationToken, program); + const expression = getAwaitErrorSpanExpression( + sourceFile, + diagnostic.code, + diagnostic, + cancellationToken, + program, + ); if (!expression) { return; } const trackChanges: ContextualTrackChangesFunction = cb => (cb(t), []); - return getDeclarationSiteFix(context, expression, diagnostic.code, checker, trackChanges, fixedDeclarations) + return getDeclarationSiteFix( + context, + expression, + diagnostic.code, + checker, + trackChanges, + fixedDeclarations, + ) || getUseSiteFix(context, expression, diagnostic.code, checker, trackChanges, fixedDeclarations); }); }, }); - function getAwaitErrorSpanExpression(sourceFile: SourceFile, errorCode: number, span: TextSpan, cancellationToken: CancellationToken, program: Program) { + function getAwaitErrorSpanExpression( + sourceFile: SourceFile, + errorCode: number, + span: TextSpan, + cancellationToken: CancellationToken, + program: Program, + ) { const expression = getFixableErrorSpanExpression(sourceFile, span); return expression && isMissingAwaitError(sourceFile, errorCode, span, cancellationToken, program) && isInsideAwaitableBody(expression) ? expression : undefined; } - function getDeclarationSiteFix(context: CodeFixContext | CodeFixAllContext, expression: Expression, errorCode: number, checker: TypeChecker, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Set) { + function getDeclarationSiteFix( + context: CodeFixContext | CodeFixAllContext, + expression: Expression, + errorCode: number, + checker: TypeChecker, + trackChanges: ContextualTrackChangesFunction, + fixedDeclarations?: Set, + ) { const { sourceFile, program, cancellationToken } = context; - const awaitableInitializers = findAwaitableInitializers(expression, sourceFile, cancellationToken, program, checker); + const awaitableInitializers = findAwaitableInitializers( + expression, + sourceFile, + cancellationToken, + program, + checker, + ); if (awaitableInitializers) { const initializerChanges = trackChanges(t => { - forEach(awaitableInitializers.initializers, ({ expression }) => makeChange(t, errorCode, sourceFile, checker, expression, fixedDeclarations)); + forEach( + awaitableInitializers.initializers, + ({ expression }) => makeChange(t, errorCode, sourceFile, checker, expression, fixedDeclarations), + ); if (fixedDeclarations && awaitableInitializers.needsSecondPassForFixAll) { makeChange(t, errorCode, sourceFile, checker, expression, fixedDeclarations); } @@ -83,25 +124,52 @@ namespace ts.codefix { "addMissingAwaitToInitializer", initializerChanges, awaitableInitializers.initializers.length === 1 - ? [Diagnostics.Add_await_to_initializer_for_0, awaitableInitializers.initializers[0].declarationSymbol.name] + ? [ + Diagnostics.Add_await_to_initializer_for_0, + awaitableInitializers.initializers[0].declarationSymbol.name, + ] : Diagnostics.Add_await_to_initializers, ); } } - function getUseSiteFix(context: CodeFixContext | CodeFixAllContext, expression: Expression, errorCode: number, checker: TypeChecker, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Set) { - const changes = trackChanges(t => makeChange(t, errorCode, context.sourceFile, checker, expression, fixedDeclarations)); - return createCodeFixAction(fixId, changes, Diagnostics.Add_await, fixId, Diagnostics.Fix_all_expressions_possibly_missing_await); + function getUseSiteFix( + context: CodeFixContext | CodeFixAllContext, + expression: Expression, + errorCode: number, + checker: TypeChecker, + trackChanges: ContextualTrackChangesFunction, + fixedDeclarations?: Set, + ) { + const changes = trackChanges(t => + makeChange(t, errorCode, context.sourceFile, checker, expression, fixedDeclarations) + ); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Add_await, + fixId, + Diagnostics.Fix_all_expressions_possibly_missing_await, + ); } - function isMissingAwaitError(sourceFile: SourceFile, errorCode: number, span: TextSpan, cancellationToken: CancellationToken, program: Program) { + function isMissingAwaitError( + sourceFile: SourceFile, + errorCode: number, + span: TextSpan, + cancellationToken: CancellationToken, + program: Program, + ) { const checker = program.getTypeChecker(); const diagnostics = checker.getDiagnostics(sourceFile, cancellationToken); - return some(diagnostics, ({ start, length, relatedInformation, code }) => - isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) && - code === errorCode && - !!relatedInformation && - some(relatedInformation, related => related.code === Diagnostics.Did_you_forget_to_use_await.code)); + return some( + diagnostics, + ({ start, length, relatedInformation, code }) => + isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) + && code === errorCode + && !!relatedInformation + && some(relatedInformation, related => related.code === Diagnostics.Did_you_forget_to_use_await.code), + ); } interface AwaitableInitializer { @@ -138,22 +206,28 @@ namespace ts.codefix { const variableName = declaration && tryCast(declaration.name, isIdentifier); const variableStatement = getAncestor(declaration, SyntaxKind.VariableStatement); if ( - !declaration || !variableStatement || - declaration.type || - !declaration.initializer || - variableStatement.getSourceFile() !== sourceFile || - hasSyntacticModifier(variableStatement, ModifierFlags.Export) || - !variableName || - !isInsideAwaitableBody(declaration.initializer) + !declaration || !variableStatement + || declaration.type + || !declaration.initializer + || variableStatement.getSourceFile() !== sourceFile + || hasSyntacticModifier(variableStatement, ModifierFlags.Export) + || !variableName + || !isInsideAwaitableBody(declaration.initializer) ) { isCompleteFix = false; continue; } const diagnostics = program.getSemanticDiagnostics(sourceFile, cancellationToken); - const isUsedElsewhere = FindAllReferences.Core.eachSymbolReferenceInFile(variableName, checker, sourceFile, reference => { - return identifier !== reference && !symbolReferenceIsAlsoMissingAwait(reference, diagnostics, sourceFile, checker); - }); + const isUsedElsewhere = FindAllReferences.Core.eachSymbolReferenceInFile( + variableName, + checker, + sourceFile, + reference => { + return identifier !== reference + && !symbolReferenceIsAlsoMissingAwait(reference, diagnostics, sourceFile, checker); + }, + ); if (isUsedElsewhere) { isCompleteFix = false; @@ -200,15 +274,20 @@ namespace ts.codefix { } } - function symbolReferenceIsAlsoMissingAwait(reference: Identifier, diagnostics: readonly Diagnostic[], sourceFile: SourceFile, checker: TypeChecker) { - const errorNode = isPropertyAccessExpression(reference.parent) ? reference.parent.name : - isBinaryExpression(reference.parent) ? reference.parent : - reference; + function symbolReferenceIsAlsoMissingAwait( + reference: Identifier, + diagnostics: readonly Diagnostic[], + sourceFile: SourceFile, + checker: TypeChecker, + ) { + const errorNode = isPropertyAccessExpression(reference.parent) ? reference.parent.name + : isBinaryExpression(reference.parent) ? reference.parent + : reference; const diagnostic = find(diagnostics, diagnostic => - diagnostic.start === errorNode.getStart(sourceFile) && - (diagnostic.start + diagnostic.length!) === errorNode.getEnd()); + diagnostic.start === errorNode.getStart(sourceFile) + && (diagnostic.start + diagnostic.length!) === errorNode.getEnd()); - return diagnostic && contains(errorCodes, diagnostic.code) || + return diagnostic && contains(errorCodes, diagnostic.code) // A Promise is usually not correct in a binary expression (it’s not valid // in an arithmetic expression and an equality comparison seems unusual), // but if the other side of the binary expression has an error, the side @@ -216,27 +295,48 @@ namespace ts.codefix { // Promise as an invalid operand. So if the whole binary expression is // typed `any` as a result, there is a strong likelihood that this Promise // is accidentally missing `await`. - checker.getTypeAtLocation(errorNode).flags & TypeFlags.Any; + || checker.getTypeAtLocation(errorNode).flags & TypeFlags.Any; } function isInsideAwaitableBody(node: Node) { - return node.kind & NodeFlags.AwaitContext || !!findAncestor(node, ancestor => - ancestor.parent && isArrowFunction(ancestor.parent) && ancestor.parent.body === ancestor || - isBlock(ancestor) && ( - ancestor.parent.kind === SyntaxKind.FunctionDeclaration || - ancestor.parent.kind === SyntaxKind.FunctionExpression || - ancestor.parent.kind === SyntaxKind.ArrowFunction || - ancestor.parent.kind === SyntaxKind.MethodDeclaration - )); + return node.kind & NodeFlags.AwaitContext + || !!findAncestor( + node, + ancestor => + ancestor.parent && isArrowFunction(ancestor.parent) && ancestor.parent.body === ancestor + || isBlock(ancestor) && ( + ancestor.parent.kind === SyntaxKind.FunctionDeclaration + || ancestor.parent.kind === SyntaxKind.FunctionExpression + || ancestor.parent.kind === SyntaxKind.ArrowFunction + || ancestor.parent.kind === SyntaxKind.MethodDeclaration + ), + ); } - function makeChange(changeTracker: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, checker: TypeChecker, insertionSite: Expression, fixedDeclarations?: Set) { + function makeChange( + changeTracker: textChanges.ChangeTracker, + errorCode: number, + sourceFile: SourceFile, + checker: TypeChecker, + insertionSite: Expression, + fixedDeclarations?: Set, + ) { if (isForOfStatement(insertionSite.parent) && !insertionSite.parent.awaitModifier) { const exprType = checker.getTypeAtLocation(insertionSite); const asyncIter = checker.getAsyncIterableType(); if (asyncIter && checker.isTypeAssignableTo(exprType, asyncIter)) { const forOf = insertionSite.parent; - changeTracker.replaceNode(sourceFile, forOf, factory.updateForOfStatement(forOf, factory.createToken(SyntaxKind.AwaitKeyword), forOf.initializer, forOf.expression, forOf.statement)); + changeTracker.replaceNode( + sourceFile, + forOf, + factory.updateForOfStatement( + forOf, + factory.createToken(SyntaxKind.AwaitKeyword), + forOf.initializer, + forOf.expression, + forOf.statement, + ), + ); return; } } @@ -274,11 +374,18 @@ namespace ts.codefix { return; } } - changeTracker.replaceNode(sourceFile, insertionSite, factory.createParenthesizedExpression(factory.createAwaitExpression(insertionSite))); + changeTracker.replaceNode( + sourceFile, + insertionSite, + factory.createParenthesizedExpression(factory.createAwaitExpression(insertionSite)), + ); insertLeadingSemicolonIfNeeded(changeTracker, insertionSite, sourceFile); } else { - if (fixedDeclarations && isVariableDeclaration(insertionSite.parent) && isIdentifier(insertionSite.parent.name)) { + if ( + fixedDeclarations && isVariableDeclaration(insertionSite.parent) + && isIdentifier(insertionSite.parent.name) + ) { const symbol = checker.getSymbolAtLocation(insertionSite.parent.name); if (symbol && !tryAddToSet(fixedDeclarations, getSymbolId(symbol))) { return; @@ -288,7 +395,11 @@ namespace ts.codefix { } } - function insertLeadingSemicolonIfNeeded(changeTracker: textChanges.ChangeTracker, beforeNode: Node, sourceFile: SourceFile) { + function insertLeadingSemicolonIfNeeded( + changeTracker: textChanges.ChangeTracker, + beforeNode: Node, + sourceFile: SourceFile, + ) { const precedingToken = findPrecedingToken(beforeNode.pos, sourceFile); if (precedingToken && positionIsASICandidate(precedingToken.end, precedingToken.parent, sourceFile)) { changeTracker.insertText(sourceFile, beforeNode.getStart(sourceFile), ";"); diff --git a/src/services/codefixes/addMissingConst.ts b/src/services/codefixes/addMissingConst.ts index 937e0d6545890..a4ecf00ad17a2 100644 --- a/src/services/codefixes/addMissingConst.ts +++ b/src/services/codefixes/addMissingConst.ts @@ -3,33 +3,61 @@ namespace ts.codefix { const fixId = "addMissingConst"; const errorCodes = [ Diagnostics.Cannot_find_name_0.code, - Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer.code, + Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer + .code, ]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddMissingConst(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start, context.program)); + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span.start, context.program), + ); if (changes.length > 0) { - return [createCodeFixAction(fixId, changes, Diagnostics.Add_const_to_unresolved_variable, fixId, Diagnostics.Add_const_to_all_unresolved_variables)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_const_to_unresolved_variable, + fixId, + Diagnostics.Add_const_to_all_unresolved_variables, + ), + ]; } }, fixIds: [fixId], getAllCodeActions: context => { const fixedNodes = new Set(); - return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start, context.program, fixedNodes)); + return codeFixAll( + context, + errorCodes, + (changes, diag) => makeChange(changes, diag.file, diag.start, context.program, fixedNodes), + ); }, }); - function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, program: Program, fixedNodes?: Set) { + function makeChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + pos: number, + program: Program, + fixedNodes?: Set, + ) { const token = getTokenAtPosition(sourceFile, pos); - const forInitializer = findAncestor(token, node => - isForInOrOfStatement(node.parent) ? node.parent.initializer === node : - isPossiblyPartOfDestructuring(node) ? false : "quit"); + const forInitializer = findAncestor( + token, + node => + isForInOrOfStatement(node.parent) ? node.parent.initializer === node + : isPossiblyPartOfDestructuring(node) ? false : "quit", + ); if (forInitializer) return applyChange(changeTracker, forInitializer, sourceFile, fixedNodes); const parent = token.parent; - if (isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken && isExpressionStatement(parent.parent)) { + if ( + isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken + && isExpressionStatement(parent.parent) + ) { return applyChange(changeTracker, token, sourceFile, fixedNodes); } @@ -43,8 +71,8 @@ namespace ts.codefix { } const commaExpression = findAncestor(token, node => - isExpressionStatement(node.parent) ? true : - isPossiblyPartOfCommaSeperatedInitializer(node) ? false : "quit"); + isExpressionStatement(node.parent) ? true + : isPossiblyPartOfCommaSeperatedInitializer(node) ? false : "quit"); if (commaExpression) { const checker = program.getTypeChecker(); if (!expressionCouldBeVariableDeclaration(commaExpression, checker)) { @@ -55,7 +83,12 @@ namespace ts.codefix { } } - function applyChange(changeTracker: textChanges.ChangeTracker, initializer: Node, sourceFile: SourceFile, fixedNodes?: Set) { + function applyChange( + changeTracker: textChanges.ChangeTracker, + initializer: Node, + sourceFile: SourceFile, + fixedNodes?: Set, + ) { if (!fixedNodes || tryAddToSet(fixedNodes, initializer)) { changeTracker.insertModifierBefore(sourceFile, SyntaxKind.ConstKeyword, initializer); } @@ -75,9 +108,10 @@ namespace ts.codefix { } function arrayElementCouldBeVariableDeclaration(expression: Expression, checker: TypeChecker): boolean { - const identifier = isIdentifier(expression) ? expression : - isAssignmentExpression(expression, /*excludeCompoundAssignment*/ true) && isIdentifier(expression.left) ? expression.left : - undefined; + const identifier = isIdentifier(expression) ? expression + : isAssignmentExpression(expression, /*excludeCompoundAssignment*/ true) && isIdentifier(expression.left) + ? expression.left + : undefined; return !!identifier && !checker.getSymbolAtLocation(identifier); } @@ -98,7 +132,10 @@ namespace ts.codefix { } if (expression.operatorToken.kind === SyntaxKind.CommaToken) { - return every([expression.left, expression.right], expression => expressionCouldBeVariableDeclaration(expression, checker)); + return every( + [expression.left, expression.right], + expression => expressionCouldBeVariableDeclaration(expression, checker), + ); } return expression.operatorToken.kind === SyntaxKind.EqualsToken diff --git a/src/services/codefixes/addMissingDeclareProperty.ts b/src/services/codefixes/addMissingDeclareProperty.ts index c0d4e96917a9d..4256d02e4fff1 100644 --- a/src/services/codefixes/addMissingDeclareProperty.ts +++ b/src/services/codefixes/addMissingDeclareProperty.ts @@ -2,33 +2,55 @@ namespace ts.codefix { const fixId = "addMissingDeclareProperty"; const errorCodes = [ - Diagnostics.Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration.code, + Diagnostics + .Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration + .code, ]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddMissingDeclareOnProperty(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start)); + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span.start), + ); if (changes.length > 0) { - return [createCodeFixAction(fixId, changes, Diagnostics.Prefix_with_declare, fixId, Diagnostics.Prefix_all_incorrect_property_declarations_with_declare)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Prefix_with_declare, + fixId, + Diagnostics.Prefix_all_incorrect_property_declarations_with_declare, + ), + ]; } }, fixIds: [fixId], getAllCodeActions: context => { const fixedNodes = new Set(); - return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start, fixedNodes)); + return codeFixAll( + context, + errorCodes, + (changes, diag) => makeChange(changes, diag.file, diag.start, fixedNodes), + ); }, }); - function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, fixedNodes?: Set) { + function makeChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + pos: number, + fixedNodes?: Set, + ) { const token = getTokenAtPosition(sourceFile, pos); if (!isIdentifier(token)) { return; } const declaration = token.parent; if ( - declaration.kind === SyntaxKind.PropertyDeclaration && - (!fixedNodes || tryAddToSet(fixedNodes, declaration)) + declaration.kind === SyntaxKind.PropertyDeclaration + && (!fixedNodes || tryAddToSet(fixedNodes, declaration)) ) { changeTracker.insertModifierBefore(sourceFile, SyntaxKind.DeclareKeyword, declaration); } diff --git a/src/services/codefixes/addMissingInvocationForDecorator.ts b/src/services/codefixes/addMissingInvocationForDecorator.ts index 22ce4eef384e1..a73942ca9b37f 100644 --- a/src/services/codefixes/addMissingInvocationForDecorator.ts +++ b/src/services/codefixes/addMissingInvocationForDecorator.ts @@ -1,22 +1,41 @@ /* @internal */ namespace ts.codefix { const fixId = "addMissingInvocationForDecorator"; - const errorCodes = [Diagnostics._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0.code]; + const errorCodes = [ + Diagnostics + ._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0.code, + ]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddMissingInvocationForDecorator(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start)); - return [createCodeFixAction(fixId, changes, Diagnostics.Call_decorator_expression, fixId, Diagnostics.Add_to_all_uncalled_decorators)]; + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span.start), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Call_decorator_expression, + fixId, + Diagnostics.Add_to_all_uncalled_decorators, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)), }); function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { const token = getTokenAtPosition(sourceFile, pos); const decorator = findAncestor(token, isDecorator)!; Debug.assert(!!decorator, "Expected position to be owned by a decorator."); - const replacement = factory.createCallExpression(decorator.expression, /*typeArguments*/ undefined, /*argumentsArray*/ undefined); + const replacement = factory.createCallExpression( + decorator.expression, + /*typeArguments*/ undefined, + /*argumentsArray*/ undefined, + ); changeTracker.replaceNode(sourceFile, decorator.expression, replacement); } } diff --git a/src/services/codefixes/addNameToNamelessParameter.ts b/src/services/codefixes/addNameToNamelessParameter.ts index 951c12c8c34c6..735543aaf2f39 100644 --- a/src/services/codefixes/addNameToNamelessParameter.ts +++ b/src/services/codefixes/addNameToNamelessParameter.ts @@ -5,18 +5,32 @@ namespace ts.codefix { registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddNameToNamelessParameter(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_parameter_name, fixId, Diagnostics.Add_names_to_all_parameters_without_names)]; + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span.start), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_parameter_name, + fixId, + Diagnostics.Add_names_to_all_parameters_without_names, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)), }); function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { const token = getTokenAtPosition(sourceFile, pos); const param = token.parent; if (!isParameter(param)) { - return Debug.fail("Tried to add a parameter name to a non-parameter: " + Debug.formatSyntaxKind(token.kind)); + return Debug.fail( + "Tried to add a parameter name to a non-parameter: " + Debug.formatSyntaxKind(token.kind), + ); } const i = param.parent.parameters.indexOf(param); diff --git a/src/services/codefixes/addOptionalPropertyUndefined.ts b/src/services/codefixes/addOptionalPropertyUndefined.ts index a7d173a9985ce..4ded8e46f71e8 100644 --- a/src/services/codefixes/addOptionalPropertyUndefined.ts +++ b/src/services/codefixes/addOptionalPropertyUndefined.ts @@ -3,9 +3,15 @@ namespace ts.codefix { const addOptionalPropertyUndefined = "addOptionalPropertyUndefined"; const errorCodes = [ - Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target.code, - Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code, - Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code, + Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target + .code, + Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties + .code, + Diagnostics + .Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties + .code, ]; registerCodeFix({ @@ -17,7 +23,13 @@ namespace ts.codefix { return undefined; } const changes = textChanges.ChangeTracker.with(context, t => addUndefinedToOptionalProperty(t, toAdd)); - return [createCodeFixActionWithoutFixAll(addOptionalPropertyUndefined, changes, Diagnostics.Add_undefined_to_optional_property_type)]; + return [ + createCodeFixActionWithoutFixAll( + addOptionalPropertyUndefined, + changes, + Diagnostics.Add_undefined_to_optional_property_type, + ), + ]; }, fixIds: [addOptionalPropertyUndefined], }); @@ -37,7 +49,11 @@ namespace ts.codefix { return checker.getExactOptionalProperties(target); } - function shouldUseParentTypeOfProperty(sourceNode: Node, targetNode: Node, checker: TypeChecker): targetNode is PropertyAccessExpression { + function shouldUseParentTypeOfProperty( + sourceNode: Node, + targetNode: Node, + checker: TypeChecker, + ): targetNode is PropertyAccessExpression { return isPropertyAccessExpression(targetNode) && !!checker.getExactOptionalProperties(checker.getTypeAtLocation(targetNode.expression)).length && checker.getTypeAtLocation(sourceNode) === checker.getUndefinedType(); @@ -47,11 +63,16 @@ namespace ts.codefix { * Find the source and target of the incorrect assignment. * The call is recursive for property assignments. */ - function getSourceTarget(errorNode: Node | undefined, checker: TypeChecker): { source: Node; target: Node; } | undefined { + function getSourceTarget( + errorNode: Node | undefined, + checker: TypeChecker, + ): { source: Node; target: Node; } | undefined { if (!errorNode) { return undefined; } - else if (isBinaryExpression(errorNode.parent) && errorNode.parent.operatorToken.kind === SyntaxKind.EqualsToken) { + else if ( + isBinaryExpression(errorNode.parent) && errorNode.parent.operatorToken.kind === SyntaxKind.EqualsToken + ) { return { source: errorNode.parent.right, target: errorNode.parent.left }; } else if (isVariableDeclaration(errorNode.parent) && errorNode.parent.initializer) { @@ -67,12 +88,15 @@ namespace ts.codefix { if (isIdentifier(name)) return { source: errorNode, target: name }; } else if ( - isPropertyAssignment(errorNode.parent) && isIdentifier(errorNode.parent.name) || - isShorthandPropertyAssignment(errorNode.parent) + isPropertyAssignment(errorNode.parent) && isIdentifier(errorNode.parent.name) + || isShorthandPropertyAssignment(errorNode.parent) ) { const parentTarget = getSourceTarget(errorNode.parent.parent, checker); if (!parentTarget) return undefined; - const prop = checker.getPropertyOfType(checker.getTypeAtLocation(parentTarget.target), (errorNode.parent.name as Identifier).text); + const prop = checker.getPropertyOfType( + checker.getTypeAtLocation(parentTarget.target), + (errorNode.parent.name as Identifier).text, + ); const declaration = prop?.declarations?.[0]; if (!declaration) return undefined; return { diff --git a/src/services/codefixes/annotateWithTypeFromJSDoc.ts b/src/services/codefixes/annotateWithTypeFromJSDoc.ts index 2c1ff64da6ef9..a64a4bce27e87 100644 --- a/src/services/codefixes/annotateWithTypeFromJSDoc.ts +++ b/src/services/codefixes/annotateWithTypeFromJSDoc.ts @@ -8,7 +8,15 @@ namespace ts.codefix { const decl = getDeclaration(context.sourceFile, context.span.start); if (!decl) return; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, decl)); - return [createCodeFixAction(fixId, changes, Diagnostics.Annotate_with_type_from_JSDoc, fixId, Diagnostics.Annotate_everything_with_types_from_JSDoc)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Annotate_with_type_from_JSDoc, + fixId, + Diagnostics.Annotate_everything_with_types_from_JSDoc, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -41,20 +49,35 @@ namespace ts.codefix { } function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, decl: DeclarationWithType): void { - if (isFunctionLikeDeclaration(decl) && (getJSDocReturnType(decl) || decl.parameters.some(p => !!getJSDocType(p)))) { + if ( + isFunctionLikeDeclaration(decl) + && (getJSDocReturnType(decl) || decl.parameters.some(p => !!getJSDocType(p))) + ) { if (!decl.typeParameters) { const typeParameters = getJSDocTypeParameterDeclarations(decl); if (typeParameters.length) changes.insertTypeParameters(sourceFile, decl, typeParameters); } const needParens = isArrowFunction(decl) && !findChildOfKind(decl, SyntaxKind.OpenParenToken, sourceFile); - if (needParens) changes.insertNodeBefore(sourceFile, first(decl.parameters), factory.createToken(SyntaxKind.OpenParenToken)); + if (needParens) { + changes.insertNodeBefore( + sourceFile, + first(decl.parameters), + factory.createToken(SyntaxKind.OpenParenToken), + ); + } for (const param of decl.parameters) { if (!param.type) { const paramType = getJSDocType(param); if (paramType) changes.tryInsertTypeAnnotation(sourceFile, param, transformJSDocType(paramType)); } } - if (needParens) changes.insertNodeAfter(sourceFile, last(decl.parameters), factory.createToken(SyntaxKind.CloseParenToken)); + if (needParens) { + changes.insertNodeAfter( + sourceFile, + last(decl.parameters), + factory.createToken(SyntaxKind.CloseParenToken), + ); + } if (!decl.type) { const returnType = getJSDocReturnType(decl); if (returnType) changes.tryInsertTypeAnnotation(sourceFile, decl, transformJSDocType(returnType)); @@ -68,10 +91,10 @@ namespace ts.codefix { } function isDeclarationWithType(node: Node): node is DeclarationWithType { - return isFunctionLikeDeclaration(node) || - node.kind === SyntaxKind.VariableDeclaration || - node.kind === SyntaxKind.PropertySignature || - node.kind === SyntaxKind.PropertyDeclaration; + return isFunctionLikeDeclaration(node) + || node.kind === SyntaxKind.VariableDeclaration + || node.kind === SyntaxKind.PropertySignature + || node.kind === SyntaxKind.PropertyDeclaration; } function transformJSDocType(node: TypeNode): TypeNode { @@ -99,11 +122,17 @@ namespace ts.codefix { } function transformJSDocOptionalType(node: JSDocOptionalType) { - return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType), factory.createTypeReferenceNode("undefined", emptyArray)]); + return factory.createUnionTypeNode([ + visitNode(node.type, transformJSDocType), + factory.createTypeReferenceNode("undefined", emptyArray), + ]); } function transformJSDocNullableType(node: JSDocNullableType) { - return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType), factory.createTypeReferenceNode("null", emptyArray)]); + return factory.createUnionTypeNode([ + visitNode(node.type, transformJSDocType), + factory.createTypeReferenceNode("null", emptyArray), + ]); } function transformJSDocVariadicType(node: JSDocVariadicType) { @@ -113,7 +142,11 @@ namespace ts.codefix { function transformJSDocFunctionType(node: JSDocFunctionType) { // TODO: This does not properly handle `function(new:C, string)` per https://github.com/google/closure-compiler/wiki/Types-in-the-Closure-Type-System#the-javascript-type-language // however we do handle it correctly in `serializeTypeForDeclaration` in checker.ts - return factory.createFunctionTypeNode(emptyArray, node.parameters.map(transformJSDocParameter), node.type ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)); + return factory.createFunctionTypeNode( + emptyArray, + node.parameters.map(transformJSDocParameter), + node.type ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + ); } function transformJSDocParameter(node: ParameterDeclaration) { @@ -121,7 +154,14 @@ namespace ts.codefix { const isRest = node.type!.kind === SyntaxKind.JSDocVariadicType && index === node.parent.parameters.length - 1; // TODO: GH#18217 const name = node.name || (isRest ? "rest" : "arg" + index); const dotdotdot = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : node.dotDotDotToken; - return factory.createParameterDeclaration(node.modifiers, dotdotdot, name, node.questionToken, visitNode(node.type, transformJSDocType), node.initializer); + return factory.createParameterDeclaration( + node.modifiers, + dotdotdot, + name, + node.questionToken, + visitNode(node.type, transformJSDocType), + node.initializer, + ); } function transformJSDocTypeReference(node: TypeReferenceNode) { @@ -162,10 +202,15 @@ namespace ts.codefix { /*dotDotDotToken*/ undefined, node.typeArguments![0].kind === SyntaxKind.NumberKeyword ? "n" : "s", /*questionToken*/ undefined, - factory.createTypeReferenceNode(node.typeArguments![0].kind === SyntaxKind.NumberKeyword ? "number" : "string", []), + factory.createTypeReferenceNode( + node.typeArguments![0].kind === SyntaxKind.NumberKeyword ? "number" : "string", + [], + ), /*initializer*/ undefined, ); - const indexSignature = factory.createTypeLiteralNode([factory.createIndexSignature(/*modifiers*/ undefined, [index], node.typeArguments![1])]); + const indexSignature = factory.createTypeLiteralNode([ + factory.createIndexSignature(/*modifiers*/ undefined, [index], node.typeArguments![1]), + ]); setEmitFlags(indexSignature, EmitFlags.SingleLine); return indexSignature; } diff --git a/src/services/codefixes/convertConstToLet.ts b/src/services/codefixes/convertConstToLet.ts index 366916b265960..dc5d7894807e7 100644 --- a/src/services/codefixes/convertConstToLet.ts +++ b/src/services/codefixes/convertConstToLet.ts @@ -11,7 +11,15 @@ namespace ts.codefix { if (info === undefined) return; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info.token)); - return [createCodeFixActionMaybeFixAll(fixId, changes, Diagnostics.Convert_const_to_let, fixId, Diagnostics.Convert_all_const_to_let)]; + return [ + createCodeFixActionMaybeFixAll( + fixId, + changes, + Diagnostics.Convert_const_to_let, + fixId, + Diagnostics.Convert_all_const_to_let, + ), + ]; }, getAllCodeActions: context => { const { program } = context; @@ -45,13 +53,21 @@ namespace ts.codefix { const declaration = tryCast(symbol?.valueDeclaration?.parent, isVariableDeclarationList); if (declaration === undefined) return; - const constToken = findChildOfKind>(declaration, SyntaxKind.ConstKeyword, sourceFile); + const constToken = findChildOfKind>( + declaration, + SyntaxKind.ConstKeyword, + sourceFile, + ); if (constToken === undefined) return; return { symbol, token: constToken }; } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Token) { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + token: Token, + ) { changes.replaceNode(sourceFile, token, factory.createToken(SyntaxKind.LetKeyword)); } } diff --git a/src/services/codefixes/convertFunctionToEs6Class.ts b/src/services/codefixes/convertFunctionToEs6Class.ts index 1f8caf878c594..10dab9544bec7 100644 --- a/src/services/codefixes/convertFunctionToEs6Class.ts +++ b/src/services/codefixes/convertFunctionToEs6Class.ts @@ -5,16 +5,57 @@ namespace ts.codefix { registerCodeFix({ errorCodes, getCodeActions(context: CodeFixContext) { - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start, context.program.getTypeChecker(), context.preferences, context.program.getCompilerOptions())); - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_function_to_an_ES2015_class, fixId, Diagnostics.Convert_all_constructor_functions_to_classes)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange( + t, + context.sourceFile, + context.span.start, + context.program.getTypeChecker(), + context.preferences, + context.program.getCompilerOptions(), + ), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_function_to_an_ES2015_class, + fixId, + Diagnostics.Convert_all_constructor_functions_to_classes, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => doChange(changes, err.file, err.start, context.program.getTypeChecker(), context.preferences, context.program.getCompilerOptions())), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, err) => + doChange( + changes, + err.file, + err.start, + context.program.getTypeChecker(), + context.preferences, + context.program.getCompilerOptions(), + ), + ), }); - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker, preferences: UserPreferences, compilerOptions: CompilerOptions): void { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + position: number, + checker: TypeChecker, + preferences: UserPreferences, + compilerOptions: CompilerOptions, + ): void { const ctorSymbol = checker.getSymbolAtLocation(getTokenAtPosition(sourceFile, position))!; - if (!ctorSymbol || !ctorSymbol.valueDeclaration || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) { + if ( + !ctorSymbol || !ctorSymbol.valueDeclaration + || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable)) + ) { // Bad input return undefined; } @@ -48,11 +89,11 @@ namespace ts.codefix { const firstDeclaration = member.declarations[0]; // only one "x.prototype = { ... }" will pass if ( - member.declarations.length === 1 && - isPropertyAccessExpression(firstDeclaration) && - isBinaryExpression(firstDeclaration.parent) && - firstDeclaration.parent.operatorToken.kind === SyntaxKind.EqualsToken && - isObjectLiteralExpression(firstDeclaration.parent.right) + member.declarations.length === 1 + && isPropertyAccessExpression(firstDeclaration) + && isBinaryExpression(firstDeclaration.parent) + && firstDeclaration.parent.operatorToken.kind === SyntaxKind.EqualsToken + && isObjectLiteralExpression(firstDeclaration.parent.right) ) { const prototypes = firstDeclaration.parent.right; createClassElement(prototypes.symbol, /** modifiers */ undefined, memberElements); @@ -68,8 +109,13 @@ namespace ts.codefix { if (symbol.members) { symbol.members.forEach((member, key) => { if (key === "constructor" && member.valueDeclaration) { - const prototypeAssignment = symbol.exports?.get("prototype" as __String)?.declarations?.[0]?.parent; - if (prototypeAssignment && isBinaryExpression(prototypeAssignment) && isObjectLiteralExpression(prototypeAssignment.right) && some(prototypeAssignment.right.properties, isConstructorAssignment)) { + const prototypeAssignment = symbol.exports?.get("prototype" as __String)?.declarations?.[0] + ?.parent; + if ( + prototypeAssignment && isBinaryExpression(prototypeAssignment) + && isObjectLiteralExpression(prototypeAssignment.right) + && some(prototypeAssignment.right.properties, isConstructorAssignment) + ) { // fn.prototype = { constructor: fn } // Already deleted in `createClassElement` in first pass } @@ -98,7 +144,10 @@ namespace ts.codefix { // a() {} if (isMethodDeclaration(property) || isGetOrSetAccessorDeclaration(property)) return true; // a: function() {} - if (isPropertyAssignment(property) && isFunctionExpression(property.initializer) && !!property.name) return true; + if ( + isPropertyAssignment(property) && isFunctionExpression(property.initializer) + && !!property.name + ) return true; // x.prototype.constructor = fn if (isConstructorAssignment(property)) return true; return false; @@ -106,7 +155,11 @@ namespace ts.codefix { } } - function createClassElement(symbol: Symbol, modifiers: Modifier[] | undefined, members: ClassElement[]): void { + function createClassElement( + symbol: Symbol, + modifiers: Modifier[] | undefined, + members: ClassElement[], + ): void { // Right now the only thing we can convert are function expressions, which are marked as methods // or { x: y } type prototype assignments, which are marked as ObjectLiteral if (!(symbol.flags & SymbolFlags.Method) && !(symbol.flags & SymbolFlags.ObjectLiteral)) { @@ -133,17 +186,29 @@ namespace ts.codefix { } // delete the entire statement if this expression is the sole expression to take care of the semicolon at the end - const nodeToDelete = assignmentBinaryExpression.parent && assignmentBinaryExpression.parent.kind === SyntaxKind.ExpressionStatement + const nodeToDelete = assignmentBinaryExpression.parent + && assignmentBinaryExpression.parent.kind === SyntaxKind.ExpressionStatement ? assignmentBinaryExpression.parent : assignmentBinaryExpression; changes.delete(sourceFile, nodeToDelete); if (!assignmentExpr) { - members.push(factory.createPropertyDeclaration(modifiers, symbol.name, /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined)); + members.push( + factory.createPropertyDeclaration( + modifiers, + symbol.name, + /*questionToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined, + ), + ); return; } // f.x = expr - if (isAccessExpression(memberDeclaration) && (isFunctionExpression(assignmentExpr) || isArrowFunction(assignmentExpr))) { + if ( + isAccessExpression(memberDeclaration) + && (isFunctionExpression(assignmentExpr) || isArrowFunction(assignmentExpr)) + ) { const quotePreference = getQuotePreference(sourceFile, preferences); const name = tryGetPropertyName(memberDeclaration, compilerOptions, quotePreference); if (name) { @@ -174,26 +239,58 @@ namespace ts.codefix { // Don't try to declare members in JavaScript files if (isSourceFileJS(sourceFile)) return; if (!isPropertyAccessExpression(memberDeclaration)) return; - const prop = factory.createPropertyDeclaration(modifiers, memberDeclaration.name, /*questionToken*/ undefined, /*type*/ undefined, assignmentExpr); + const prop = factory.createPropertyDeclaration( + modifiers, + memberDeclaration.name, + /*questionToken*/ undefined, + /*type*/ undefined, + assignmentExpr, + ); copyLeadingComments(assignmentBinaryExpression.parent, prop, sourceFile); members.push(prop); return; } - function createFunctionLikeExpressionMember(members: ClassElement[], expression: FunctionExpression | ArrowFunction, name: PropertyName) { - if (isFunctionExpression(expression)) return createFunctionExpressionMember(members, expression, name); + function createFunctionLikeExpressionMember( + members: ClassElement[], + expression: FunctionExpression | ArrowFunction, + name: PropertyName, + ) { + if (isFunctionExpression(expression)) { + return createFunctionExpressionMember(members, expression, name); + } else return createArrowFunctionExpressionMember(members, expression, name); } - function createFunctionExpressionMember(members: ClassElement[], functionExpression: FunctionExpression, name: PropertyName) { - const fullModifiers = concatenate(modifiers, getModifierKindFromSource(functionExpression, SyntaxKind.AsyncKeyword)); - const method = factory.createMethodDeclaration(fullModifiers, /*asteriskToken*/ undefined, name, /*questionToken*/ undefined, /*typeParameters*/ undefined, functionExpression.parameters, /*type*/ undefined, functionExpression.body); + function createFunctionExpressionMember( + members: ClassElement[], + functionExpression: FunctionExpression, + name: PropertyName, + ) { + const fullModifiers = concatenate( + modifiers, + getModifierKindFromSource(functionExpression, SyntaxKind.AsyncKeyword), + ); + const method = factory.createMethodDeclaration( + fullModifiers, + /*asteriskToken*/ undefined, + name, + /*questionToken*/ undefined, + /*typeParameters*/ undefined, + functionExpression.parameters, + /*type*/ undefined, + functionExpression.body, + ); copyLeadingComments(assignmentBinaryExpression, method, sourceFile); members.push(method); return; } - function createArrowFunctionExpressionMember(members: ClassElement[], arrowFunction: ArrowFunction, name: PropertyName) { + function createArrowFunctionExpressionMember( + members: ClassElement[], + arrowFunction: ArrowFunction, + name: PropertyName, + ) { const arrowFunctionBody = arrowFunction.body; let bodyBlock: Block; @@ -205,8 +302,20 @@ namespace ts.codefix { else { bodyBlock = factory.createBlock([factory.createReturnStatement(arrowFunctionBody)]); } - const fullModifiers = concatenate(modifiers, getModifierKindFromSource(arrowFunction, SyntaxKind.AsyncKeyword)); - const method = factory.createMethodDeclaration(fullModifiers, /*asteriskToken*/ undefined, name, /*questionToken*/ undefined, /*typeParameters*/ undefined, arrowFunction.parameters, /*type*/ undefined, bodyBlock); + const fullModifiers = concatenate( + modifiers, + getModifierKindFromSource(arrowFunction, SyntaxKind.AsyncKeyword), + ); + const method = factory.createMethodDeclaration( + fullModifiers, + /*asteriskToken*/ undefined, + name, + /*questionToken*/ undefined, + /*typeParameters*/ undefined, + arrowFunction.parameters, + /*type*/ undefined, + bodyBlock, + ); copyLeadingComments(assignmentBinaryExpression, method, sourceFile); members.push(method); } @@ -221,11 +330,23 @@ namespace ts.codefix { const memberElements = createClassElementsFromSymbol(node.symbol); if (initializer.body) { - memberElements.unshift(factory.createConstructorDeclaration(/*modifiers*/ undefined, initializer.parameters, initializer.body)); + memberElements.unshift( + factory.createConstructorDeclaration( + /*modifiers*/ undefined, + initializer.parameters, + initializer.body, + ), + ); } const modifiers = getModifierKindFromSource(node.parent.parent, SyntaxKind.ExportKeyword); - const cls = factory.createClassDeclaration(modifiers, node.name, /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements); + const cls = factory.createClassDeclaration( + modifiers, + node.name, + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + memberElements, + ); // Don't call copyComments here because we'll already leave them in place return cls; } @@ -233,18 +354,27 @@ namespace ts.codefix { function createClassFromFunction(node: FunctionDeclaration | FunctionExpression): ClassDeclaration { const memberElements = createClassElementsFromSymbol(ctorSymbol); if (node.body) { - memberElements.unshift(factory.createConstructorDeclaration(/*modifiers*/ undefined, node.parameters, node.body)); + memberElements.unshift( + factory.createConstructorDeclaration(/*modifiers*/ undefined, node.parameters, node.body), + ); } const modifiers = getModifierKindFromSource(node, SyntaxKind.ExportKeyword); - const cls = factory.createClassDeclaration(modifiers, node.name, /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements); + const cls = factory.createClassDeclaration( + modifiers, + node.name, + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + memberElements, + ); // Don't call copyComments here because we'll already leave them in place return cls; } } function getModifierKindFromSource(source: Node, kind: Modifier["kind"]): readonly Modifier[] | undefined { - return canHaveModifiers(source) ? filter(source.modifiers, (modifier): modifier is Modifier => modifier.kind === kind) : undefined; + return canHaveModifiers(source) + ? filter(source.modifiers, (modifier): modifier is Modifier => modifier.kind === kind) : undefined; } function isConstructorAssignment(x: ObjectLiteralElementLike | PropertyAccessExpression) { @@ -253,7 +383,11 @@ namespace ts.codefix { return false; } - function tryGetPropertyName(node: AccessExpression, compilerOptions: CompilerOptions, quotePreference: QuotePreference): PropertyName | undefined { + function tryGetPropertyName( + node: AccessExpression, + compilerOptions: CompilerOptions, + quotePreference: QuotePreference, + ): PropertyName | undefined { if (isPropertyAccessExpression(node)) { return node.name; } @@ -264,8 +398,10 @@ namespace ts.codefix { } if (isStringLiteralLike(propName)) { - return isIdentifierText(propName.text, getEmitScriptTarget(compilerOptions)) ? factory.createIdentifier(propName.text) - : isNoSubstitutionTemplateLiteral(propName) ? factory.createStringLiteral(propName.text, quotePreference === QuotePreference.Single) + return isIdentifierText(propName.text, getEmitScriptTarget(compilerOptions)) + ? factory.createIdentifier(propName.text) + : isNoSubstitutionTemplateLiteral(propName) + ? factory.createStringLiteral(propName.text, quotePreference === QuotePreference.Single) : propName; } diff --git a/src/services/codefixes/convertLiteralTypeToMappedType.ts b/src/services/codefixes/convertLiteralTypeToMappedType.ts index b42b839bc0a75..4548bd925f8c6 100644 --- a/src/services/codefixes/convertLiteralTypeToMappedType.ts +++ b/src/services/codefixes/convertLiteralTypeToMappedType.ts @@ -1,7 +1,9 @@ /* @internal */ namespace ts.codefix { const fixId = "convertLiteralTypeToMappedType"; - const errorCodes = [Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0.code]; + const errorCodes = [ + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0.code, + ]; registerCodeFix({ errorCodes, @@ -13,7 +15,15 @@ namespace ts.codefix { } const { name, constraint } = info; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_1_in_0, constraint, name], fixId, Diagnostics.Convert_all_type_literals_to_mapped_type)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Convert_0_to_1_in_0, constraint, name], + fixId, + Diagnostics.Convert_all_type_literals_to_mapped_type, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -47,13 +57,21 @@ namespace ts.codefix { return undefined; } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { container, typeNode, constraint, name }: Info): void { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { container, typeNode, constraint, name }: Info, + ): void { changes.replaceNode( sourceFile, container, factory.createMappedTypeNode( /*readonlyToken*/ undefined, - factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, factory.createTypeReferenceNode(constraint)), + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + name, + factory.createTypeReferenceNode(constraint), + ), /*nameType*/ undefined, /*questionToken*/ undefined, typeNode, diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index 61b8b189bea99..b701391b4d843 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -7,11 +7,32 @@ namespace ts.codefix { errorCodes, getCodeActions(context: CodeFixContext) { codeActionSucceeded = true; - const changes = textChanges.ChangeTracker.with(context, t => convertToAsyncFunction(t, context.sourceFile, context.span.start, context.program.getTypeChecker())); - return codeActionSucceeded ? [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_async_function, fixId, Diagnostics.Convert_all_to_async_functions)] : []; + const changes = textChanges.ChangeTracker.with( + context, + t => convertToAsyncFunction( + t, + context.sourceFile, + context.span.start, + context.program.getTypeChecker(), + ), + ); + return codeActionSucceeded + ? [createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_to_async_function, + fixId, + Diagnostics.Convert_all_to_async_functions, + )] : []; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker())), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, err) => + convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker()), + ), }); const enum SynthBindingNameKind { @@ -50,20 +71,28 @@ namespace ts.codefix { }; } - function convertToAsyncFunction(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker): void { + function convertToAsyncFunction( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + position: number, + checker: TypeChecker, + ): void { // get the function declaration - returns a promise const tokenAtPosition = getTokenAtPosition(sourceFile, position); let functionToConvert: FunctionLikeDeclaration | undefined; // if the parent of a FunctionLikeDeclaration is a variable declaration, the convertToAsync diagnostic will be reported on the variable name if ( - isIdentifier(tokenAtPosition) && isVariableDeclaration(tokenAtPosition.parent) && - tokenAtPosition.parent.initializer && isFunctionLikeDeclaration(tokenAtPosition.parent.initializer) + isIdentifier(tokenAtPosition) && isVariableDeclaration(tokenAtPosition.parent) + && tokenAtPosition.parent.initializer && isFunctionLikeDeclaration(tokenAtPosition.parent.initializer) ) { functionToConvert = tokenAtPosition.parent.initializer; } else { - functionToConvert = tryCast(getContainingFunction(getTokenAtPosition(sourceFile, position)), canBeConvertedToAsync); + functionToConvert = tryCast( + getContainingFunction(getTokenAtPosition(sourceFile, position)), + canBeConvertedToAsync, + ); } if (!functionToConvert) { @@ -78,8 +107,14 @@ namespace ts.codefix { return; } - const returnStatements = functionToConvertRenamed.body && isBlock(functionToConvertRenamed.body) ? getReturnStatementsWithPromiseHandlers(functionToConvertRenamed.body, checker) : emptyArray; - const transformer: Transformer = { checker, synthNamesMap, setOfExpressionsToReturn, isInJSFile: isInJavascript }; + const returnStatements = functionToConvertRenamed.body && isBlock(functionToConvertRenamed.body) + ? getReturnStatementsWithPromiseHandlers(functionToConvertRenamed.body, checker) : emptyArray; + const transformer: Transformer = { + checker, + synthNamesMap, + setOfExpressionsToReturn, + isInJSFile: isInJavascript, + }; if (!returnStatements.length) { return; } @@ -132,8 +167,8 @@ namespace ts.codefix { forEach(node.arguments, visit); } else if ( - isPromiseReturningCallExpression(node, checker, "catch") || - isPromiseReturningCallExpression(node, checker, "finally") + isPromiseReturningCallExpression(node, checker, "catch") + || isPromiseReturningCallExpression(node, checker, "finally") ) { setOfExpressionsToReturn.add(getNodeId(node)); // if .catch() or .finally() is the last call in the chain, move leftward in the chain until we hit something else that should be returned @@ -151,7 +186,11 @@ namespace ts.codefix { return setOfExpressionsToReturn; } - function isPromiseReturningCallExpression(node: Node, checker: TypeChecker, name: Name): node is PromiseReturningCallExpression { + function isPromiseReturningCallExpression( + node: Node, + checker: TypeChecker, + name: Name, + ): node is PromiseReturningCallExpression { if (!isCallExpression(node)) return false; const isExpressionOfName = hasPropertyAccessExpressionWithName(node, name); const nodeType = isExpressionOfName && checker.getTypeAtLocation(node); @@ -165,7 +204,11 @@ namespace ts.codefix { && (type as TypeReference).target === target; } - function getExplicitPromisedTypeOfPromiseReturningCallExpression(node: PromiseReturningCallExpression<"then" | "catch" | "finally">, callback: Expression, checker: TypeChecker) { + function getExplicitPromisedTypeOfPromiseReturningCallExpression( + node: PromiseReturningCallExpression<"then" | "catch" | "finally">, + callback: Expression, + checker: TypeChecker, + ) { if (node.expression.name.escapedText === "finally") { // for a `finally`, there's no type argument return undefined; @@ -176,8 +219,8 @@ namespace ts.codefix { // which type argument is safe to use as an annotation. const promiseType = checker.getTypeAtLocation(node.expression.expression); if ( - isReferenceToType(promiseType, checker.getPromiseType()) || - isReferenceToType(promiseType, checker.getPromiseLikeType()) + isReferenceToType(promiseType, checker.getPromiseType()) + || isReferenceToType(promiseType, checker.getPromiseLikeType()) ) { if (node.expression.name.escapedText === "then") { if (callback === elementAt(node.arguments, 0)) { @@ -205,7 +248,11 @@ namespace ts.codefix { This function collects all existing identifier names and names of identifiers that will be created in the refactor. It then checks for any collisions and renames them through getSynthesizedDeepClone */ - function renameCollidingVarNames(nodeToRename: FunctionLikeDeclaration, checker: TypeChecker, synthNamesMap: ESMap): FunctionLikeDeclaration { + function renameCollidingVarNames( + nodeToRename: FunctionLikeDeclaration, + checker: TypeChecker, + synthNamesMap: ESMap, + ): FunctionLikeDeclaration { const identsToRenameMap = new Map(); // key is the symbol id const collidingSymbolMap = createMultiMap(); forEachChild(nodeToRename, function visit(node: Node) { @@ -225,7 +272,10 @@ namespace ts.codefix { // will eventually become // const response = await fetch('...') // so we push an entry for 'response'. - if (lastCallSignature && !isParameter(node.parent) && !isFunctionLikeDeclaration(node.parent) && !synthNamesMap.has(symbolIdString)) { + if ( + lastCallSignature && !isParameter(node.parent) && !isFunctionLikeDeclaration(node.parent) + && !synthNamesMap.has(symbolIdString) + ) { const firstParameter = firstOrUndefined(lastCallSignature.parameters); const ident = firstParameter?.valueDeclaration && isParameter(firstParameter.valueDeclaration) @@ -236,7 +286,10 @@ namespace ts.codefix { collidingSymbolMap.add(ident.text, symbol); } // We only care about identifiers that are parameters, variable declarations, or binding elements - else if (node.parent && (isParameter(node.parent) || isVariableDeclaration(node.parent) || isBindingElement(node.parent))) { + else if ( + node.parent + && (isParameter(node.parent) || isVariableDeclaration(node.parent) || isBindingElement(node.parent)) + ) { const originalName = node.text; const collidingSymbols = collidingSymbolMap.get(originalName); @@ -300,24 +353,61 @@ namespace ts.codefix { * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows the continuation to which this expression belongs. * @param continuationArgName The argument name for the continuation that follows this call. */ - function transformExpression(returnContextNode: Expression, node: Expression, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { + function transformExpression( + returnContextNode: Expression, + node: Expression, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, + ): readonly Statement[] { if (isPromiseReturningCallExpression(node, transformer.checker, "then")) { - return transformThen(node, elementAt(node.arguments, 0), elementAt(node.arguments, 1), transformer, hasContinuation, continuationArgName); + return transformThen( + node, + elementAt(node.arguments, 0), + elementAt(node.arguments, 1), + transformer, + hasContinuation, + continuationArgName, + ); } if (isPromiseReturningCallExpression(node, transformer.checker, "catch")) { - return transformCatch(node, elementAt(node.arguments, 0), transformer, hasContinuation, continuationArgName); + return transformCatch( + node, + elementAt(node.arguments, 0), + transformer, + hasContinuation, + continuationArgName, + ); } if (isPromiseReturningCallExpression(node, transformer.checker, "finally")) { - return transformFinally(node, elementAt(node.arguments, 0), transformer, hasContinuation, continuationArgName); + return transformFinally( + node, + elementAt(node.arguments, 0), + transformer, + hasContinuation, + continuationArgName, + ); } if (isPropertyAccessExpression(node)) { - return transformExpression(returnContextNode, node.expression, transformer, hasContinuation, continuationArgName); + return transformExpression( + returnContextNode, + node.expression, + transformer, + hasContinuation, + continuationArgName, + ); } const nodeType = transformer.checker.getTypeAtLocation(node); if (nodeType && transformer.checker.getPromisedTypeOfPromise(nodeType)) { Debug.assertNode(getOriginalNode(node).parent, isPropertyAccessExpression); - return transformPromiseExpressionOfPropertyAccess(returnContextNode, node, transformer, hasContinuation, continuationArgName); + return transformPromiseExpressionOfPropertyAccess( + returnContextNode, + node, + transformer, + hasContinuation, + continuationArgName, + ); } return silentFail(); @@ -333,11 +423,18 @@ namespace ts.codefix { } function createUniqueSynthName(prevArgName: SynthIdentifier): SynthIdentifier { - const renamedPrevArg = factory.createUniqueName(prevArgName.identifier.text, GeneratedIdentifierFlags.Optimistic); + const renamedPrevArg = factory.createUniqueName( + prevArgName.identifier.text, + GeneratedIdentifierFlags.Optimistic, + ); return createSynthIdentifier(renamedPrevArg); } - function getPossibleNameForVarDecl(node: PromiseReturningCallExpression<"then" | "catch" | "finally">, transformer: Transformer, continuationArgName?: SynthBindingName) { + function getPossibleNameForVarDecl( + node: PromiseReturningCallExpression<"then" | "catch" | "finally">, + transformer: Transformer, + continuationArgName?: SynthBindingName, + ) { let possibleNameForVarDecl: SynthIdentifier | undefined; // If there is another call in the chain after the .catch() or .finally() we are transforming, we will need to save the result of both paths @@ -356,7 +453,10 @@ namespace ts.codefix { }); } else { - possibleNameForVarDecl = createSynthIdentifier(factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic), continuationArgName.types); + possibleNameForVarDecl = createSynthIdentifier( + factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic), + continuationArgName.types, + ); } // We are about to write a 'let' variable declaration, but `transformExpression` for both @@ -368,7 +468,13 @@ namespace ts.codefix { return possibleNameForVarDecl; } - function finishCatchOrFinallyTransform(node: PromiseReturningCallExpression<"then" | "catch" | "finally">, transformer: Transformer, tryStatement: TryStatement, possibleNameForVarDecl: SynthIdentifier | undefined, continuationArgName?: SynthBindingName) { + function finishCatchOrFinallyTransform( + node: PromiseReturningCallExpression<"then" | "catch" | "finally">, + transformer: Transformer, + tryStatement: TryStatement, + possibleNameForVarDecl: SynthIdentifier | undefined, + continuationArgName?: SynthBindingName, + ) { const statements: Statement[] = []; // In order to avoid an implicit any, we will synthesize a type for the declaration using the unions of the types of both paths (try block and catch block) @@ -378,9 +484,19 @@ namespace ts.codefix { varDeclIdentifier = getSynthesizedDeepClone(declareSynthIdentifier(possibleNameForVarDecl)); const typeArray: Type[] = possibleNameForVarDecl.types; const unionType = transformer.checker.getUnionType(typeArray, UnionReduction.Subtype); - const unionTypeNode = transformer.isInJSFile ? undefined : transformer.checker.typeToTypeNode(unionType, /*enclosingDeclaration*/ undefined, /*flags*/ undefined); - const varDecl = [factory.createVariableDeclaration(varDeclIdentifier, /*exclamationToken*/ undefined, unionTypeNode)]; - const varDeclList = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList(varDecl, NodeFlags.Let)); + const unionTypeNode = transformer.isInJSFile ? undefined + : transformer.checker.typeToTypeNode( + unionType, + /*enclosingDeclaration*/ undefined, + /*flags*/ undefined, + ); + const varDecl = [ + factory.createVariableDeclaration(varDeclIdentifier, /*exclamationToken*/ undefined, unionTypeNode), + ]; + const varDeclList = factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList(varDecl, NodeFlags.Let), + ); statements.push(varDeclList); } @@ -407,62 +523,134 @@ namespace ts.codefix { * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows this continuation. * @param continuationArgName The argument name for the continuation that follows this call. */ - function transformFinally(node: PromiseReturningCallExpression<"finally">, onFinally: Expression | undefined, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { + function transformFinally( + node: PromiseReturningCallExpression<"finally">, + onFinally: Expression | undefined, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, + ): readonly Statement[] { if (!onFinally || isNullOrUndefined(transformer, onFinally)) { // Ignore this call as it has no effect on the result - return transformExpression(/* returnContextNode */ node, node.expression.expression, transformer, hasContinuation, continuationArgName); + return transformExpression( + /* returnContextNode */ node, + node.expression.expression, + transformer, + hasContinuation, + continuationArgName, + ); } const possibleNameForVarDecl = getPossibleNameForVarDecl(node, transformer, continuationArgName); // Transform the left-hand-side of `.finally` into an array of inlined statements. We pass `true` for hasContinuation as `node` is the outer continuation. - const inlinedLeftHandSide = transformExpression(/*returnContextNode*/ node, node.expression.expression, transformer, /*hasContinuation*/ true, possibleNameForVarDecl); + const inlinedLeftHandSide = transformExpression( + /*returnContextNode*/ node, + node.expression.expression, + transformer, + /*hasContinuation*/ true, + possibleNameForVarDecl, + ); if (hasFailed()) return silentFail(); // shortcut out of more work // Transform the callback argument into an array of inlined statements. We pass whether we have an outer continuation here // as that indicates whether `return` is valid. - const inlinedCallback = transformCallbackArgument(onFinally, hasContinuation, /*continuationArgName*/ undefined, /*argName*/ undefined, node, transformer); + const inlinedCallback = transformCallbackArgument( + onFinally, + hasContinuation, + /*continuationArgName*/ undefined, + /*argName*/ undefined, + node, + transformer, + ); if (hasFailed()) return silentFail(); // shortcut out of more work const tryBlock = factory.createBlock(inlinedLeftHandSide); const finallyBlock = factory.createBlock(inlinedCallback); const tryStatement = factory.createTryStatement(tryBlock, /*catchClause*/ undefined, finallyBlock); - return finishCatchOrFinallyTransform(node, transformer, tryStatement, possibleNameForVarDecl, continuationArgName); + return finishCatchOrFinallyTransform( + node, + transformer, + tryStatement, + possibleNameForVarDecl, + continuationArgName, + ); } /** * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows this continuation. * @param continuationArgName The argument name for the continuation that follows this call. */ - function transformCatch(node: PromiseReturningCallExpression<"then" | "catch">, onRejected: Expression | undefined, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { + function transformCatch( + node: PromiseReturningCallExpression<"then" | "catch">, + onRejected: Expression | undefined, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, + ): readonly Statement[] { if (!onRejected || isNullOrUndefined(transformer, onRejected)) { // Ignore this call as it has no effect on the result - return transformExpression(/* returnContextNode */ node, node.expression.expression, transformer, hasContinuation, continuationArgName); + return transformExpression( + /* returnContextNode */ node, + node.expression.expression, + transformer, + hasContinuation, + continuationArgName, + ); } const inputArgName = getArgBindingName(onRejected, transformer); const possibleNameForVarDecl = getPossibleNameForVarDecl(node, transformer, continuationArgName); // Transform the left-hand-side of `.then`/`.catch` into an array of inlined statements. We pass `true` for hasContinuation as `node` is the outer continuation. - const inlinedLeftHandSide = transformExpression(/*returnContextNode*/ node, node.expression.expression, transformer, /*hasContinuation*/ true, possibleNameForVarDecl); + const inlinedLeftHandSide = transformExpression( + /*returnContextNode*/ node, + node.expression.expression, + transformer, + /*hasContinuation*/ true, + possibleNameForVarDecl, + ); if (hasFailed()) return silentFail(); // shortcut out of more work // Transform the callback argument into an array of inlined statements. We pass whether we have an outer continuation here // as that indicates whether `return` is valid. - const inlinedCallback = transformCallbackArgument(onRejected, hasContinuation, possibleNameForVarDecl, inputArgName, node, transformer); + const inlinedCallback = transformCallbackArgument( + onRejected, + hasContinuation, + possibleNameForVarDecl, + inputArgName, + node, + transformer, + ); if (hasFailed()) return silentFail(); // shortcut out of more work const tryBlock = factory.createBlock(inlinedLeftHandSide); - const catchClause = factory.createCatchClause(inputArgName && getSynthesizedDeepClone(declareSynthBindingName(inputArgName)), factory.createBlock(inlinedCallback)); + const catchClause = factory.createCatchClause( + inputArgName && getSynthesizedDeepClone(declareSynthBindingName(inputArgName)), + factory.createBlock(inlinedCallback), + ); const tryStatement = factory.createTryStatement(tryBlock, catchClause, /*finallyBlock*/ undefined); - return finishCatchOrFinallyTransform(node, transformer, tryStatement, possibleNameForVarDecl, continuationArgName); + return finishCatchOrFinallyTransform( + node, + transformer, + tryStatement, + possibleNameForVarDecl, + continuationArgName, + ); } /** * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows this continuation. * @param continuationArgName The argument name for the continuation that follows this call. */ - function transformThen(node: PromiseReturningCallExpression<"then">, onFulfilled: Expression | undefined, onRejected: Expression | undefined, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { + function transformThen( + node: PromiseReturningCallExpression<"then">, + onFulfilled: Expression | undefined, + onRejected: Expression | undefined, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, + ): readonly Statement[] { if (!onFulfilled || isNullOrUndefined(transformer, onFulfilled)) { // If we don't have an `onfulfilled` callback, try treating this as a `.catch`. return transformCatch(node, onRejected, transformer, hasContinuation, continuationArgName); @@ -476,12 +664,25 @@ namespace ts.codefix { const inputArgName = getArgBindingName(onFulfilled, transformer); // Transform the left-hand-side of `.then` into an array of inlined statements. We pass `true` for hasContinuation as `node` is the outer continuation. - const inlinedLeftHandSide = transformExpression(node.expression.expression, node.expression.expression, transformer, /*hasContinuation*/ true, inputArgName); + const inlinedLeftHandSide = transformExpression( + node.expression.expression, + node.expression.expression, + transformer, + /*hasContinuation*/ true, + inputArgName, + ); if (hasFailed()) return silentFail(); // shortcut out of more work // Transform the callback argument into an array of inlined statements. We pass whether we have an outer continuation here // as that indicates whether `return` is valid. - const inlinedCallback = transformCallbackArgument(onFulfilled, hasContinuation, continuationArgName, inputArgName, node, transformer); + const inlinedCallback = transformCallbackArgument( + onFulfilled, + hasContinuation, + continuationArgName, + inputArgName, + node, + transformer, + ); if (hasFailed()) return silentFail(); // shortcut out of more work return concatenate(inlinedLeftHandSide, inlinedCallback); @@ -490,7 +691,13 @@ namespace ts.codefix { /** * Transforms the 'x' part of `x.then(...)`, or the 'y()' part of `y().catch(...)`, where 'x' and 'y()' are Promises. */ - function transformPromiseExpressionOfPropertyAccess(returnContextNode: Expression, node: Expression, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { + function transformPromiseExpressionOfPropertyAccess( + returnContextNode: Expression, + node: Expression, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, + ): readonly Statement[] { if (shouldReturn(returnContextNode, transformer)) { let returnValue = getSynthesizedDeepClone(node); if (hasContinuation) { @@ -499,10 +706,18 @@ namespace ts.codefix { return [factory.createReturnStatement(returnValue)]; } - return createVariableOrAssignmentOrExpressionStatement(continuationArgName, factory.createAwaitExpression(node), /*typeAnnotation*/ undefined); + return createVariableOrAssignmentOrExpressionStatement( + continuationArgName, + factory.createAwaitExpression(node), + /*typeAnnotation*/ undefined, + ); } - function createVariableOrAssignmentOrExpressionStatement(variableName: SynthBindingName | undefined, rightHandSide: Expression, typeAnnotation: TypeNode | undefined): readonly Statement[] { + function createVariableOrAssignmentOrExpressionStatement( + variableName: SynthBindingName | undefined, + rightHandSide: Expression, + typeAnnotation: TypeNode | undefined, + ): readonly Statement[] { if (!variableName || isEmptyBindingName(variableName)) { // if there's no argName to assign to, there still might be side effects return [factory.createExpressionStatement(rightHandSide)]; @@ -510,7 +725,14 @@ namespace ts.codefix { if (isSynthIdentifier(variableName) && variableName.hasBeenDeclared) { // if the variable has already been declared, we don't need "let" or "const" - return [factory.createExpressionStatement(factory.createAssignment(getSynthesizedDeepClone(referenceSynthIdentifier(variableName)), rightHandSide))]; + return [ + factory.createExpressionStatement( + factory.createAssignment( + getSynthesizedDeepClone(referenceSynthIdentifier(variableName)), + rightHandSide, + ), + ), + ]; } return [ @@ -528,11 +750,18 @@ namespace ts.codefix { ]; } - function maybeAnnotateAndReturn(expressionToReturn: Expression | undefined, typeAnnotation: TypeNode | undefined): Statement[] { + function maybeAnnotateAndReturn( + expressionToReturn: Expression | undefined, + typeAnnotation: TypeNode | undefined, + ): Statement[] { if (typeAnnotation && expressionToReturn) { const name = factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic); return [ - ...createVariableOrAssignmentOrExpressionStatement(createSynthIdentifier(name), expressionToReturn, typeAnnotation), + ...createVariableOrAssignmentOrExpressionStatement( + createSynthIdentifier(name), + expressionToReturn, + typeAnnotation, + ), factory.createReturnStatement(name), ]; } @@ -545,7 +774,14 @@ namespace ts.codefix { * @param continuationArgName The argument name for the continuation that follows this call. * @param inputArgName The argument name provided to this call */ - function transformCallbackArgument(func: Expression, hasContinuation: boolean, continuationArgName: SynthBindingName | undefined, inputArgName: SynthBindingName | undefined, parent: PromiseReturningCallExpression<"then" | "catch" | "finally">, transformer: Transformer): readonly Statement[] { + function transformCallbackArgument( + func: Expression, + hasContinuation: boolean, + continuationArgName: SynthBindingName | undefined, + inputArgName: SynthBindingName | undefined, + parent: PromiseReturningCallExpression<"then" | "catch" | "finally">, + transformer: Transformer, + ): readonly Statement[] { switch (func.kind) { case SyntaxKind.NullKeyword: // do not produce a transformed statement for a null argument @@ -557,10 +793,17 @@ namespace ts.codefix { break; } - const synthCall = factory.createCallExpression(getSynthesizedDeepClone(func as Identifier | PropertyAccessExpression), /*typeArguments*/ undefined, isSynthIdentifier(inputArgName) ? [referenceSynthIdentifier(inputArgName)] : []); + const synthCall = factory.createCallExpression( + getSynthesizedDeepClone(func as Identifier | PropertyAccessExpression), + /*typeArguments*/ undefined, + isSynthIdentifier(inputArgName) ? [referenceSynthIdentifier(inputArgName)] : [], + ); if (shouldReturn(parent, transformer)) { - return maybeAnnotateAndReturn(synthCall, getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker)); + return maybeAnnotateAndReturn( + synthCall, + getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker), + ); } const type = transformer.checker.getTypeAtLocation(func); @@ -570,7 +813,11 @@ namespace ts.codefix { return silentFail(); } const returnType = callSignatures[0].getReturnType(); - const varDeclOrAssignment = createVariableOrAssignmentOrExpressionStatement(continuationArgName, factory.createAwaitExpression(synthCall), getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker)); + const varDeclOrAssignment = createVariableOrAssignmentOrExpressionStatement( + continuationArgName, + factory.createAwaitExpression(synthCall), + getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker), + ); if (continuationArgName) { continuationArgName.types.push(transformer.checker.getAwaitedType(returnType) || returnType); } @@ -579,7 +826,10 @@ namespace ts.codefix { case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: { const funcBody = (func as FunctionExpression | ArrowFunction).body; - const returnType = getLastCallSignature(transformer.checker.getTypeAtLocation(func), transformer.checker)?.getReturnType(); + const returnType = getLastCallSignature( + transformer.checker.getTypeAtLocation(func), + transformer.checker, + )?.getReturnType(); // Arrow functions with block bodies { } will enter this control flow if (isBlock(funcBody)) { @@ -589,11 +839,32 @@ namespace ts.codefix { if (isReturnStatement(statement)) { seenReturnStatement = true; if (isReturnStatementWithFixablePromiseHandler(statement, transformer.checker)) { - refactoredStmts = refactoredStmts.concat(transformReturnStatementWithFixablePromiseHandler(transformer, statement, hasContinuation, continuationArgName)); + refactoredStmts = refactoredStmts.concat( + transformReturnStatementWithFixablePromiseHandler( + transformer, + statement, + hasContinuation, + continuationArgName, + ), + ); } else { - const possiblyAwaitedRightHandSide = returnType && statement.expression ? getPossiblyAwaitedRightHandSide(transformer.checker, returnType, statement.expression) : statement.expression; - refactoredStmts.push(...maybeAnnotateAndReturn(possiblyAwaitedRightHandSide, getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker))); + const possiblyAwaitedRightHandSide = returnType && statement.expression + ? getPossiblyAwaitedRightHandSide( + transformer.checker, + returnType, + statement.expression, + ) : statement.expression; + refactoredStmts.push( + ...maybeAnnotateAndReturn( + possiblyAwaitedRightHandSide, + getExplicitPromisedTypeOfPromiseReturningCallExpression( + parent, + func, + transformer.checker, + ), + ), + ); } } else if (hasContinuation && forEachReturnStatement(statement, returnTrue)) { @@ -651,26 +922,48 @@ namespace ts.codefix { ); } else { - const inlinedStatements = isFixablePromiseHandler(funcBody, transformer.checker) ? - transformReturnStatementWithFixablePromiseHandler(transformer, factory.createReturnStatement(funcBody), hasContinuation, continuationArgName) : - emptyArray; + const inlinedStatements = isFixablePromiseHandler(funcBody, transformer.checker) + ? transformReturnStatementWithFixablePromiseHandler( + transformer, + factory.createReturnStatement(funcBody), + hasContinuation, + continuationArgName, + ) + : emptyArray; if (inlinedStatements.length > 0) { return inlinedStatements; } if (returnType) { - const possiblyAwaitedRightHandSide = getPossiblyAwaitedRightHandSide(transformer.checker, returnType, funcBody); + const possiblyAwaitedRightHandSide = getPossiblyAwaitedRightHandSide( + transformer.checker, + returnType, + funcBody, + ); if (!shouldReturn(parent, transformer)) { - const transformedStatement = createVariableOrAssignmentOrExpressionStatement(continuationArgName, possiblyAwaitedRightHandSide, /*typeAnnotation*/ undefined); + const transformedStatement = createVariableOrAssignmentOrExpressionStatement( + continuationArgName, + possiblyAwaitedRightHandSide, + /*typeAnnotation*/ undefined, + ); if (continuationArgName) { - continuationArgName.types.push(transformer.checker.getAwaitedType(returnType) || returnType); + continuationArgName.types.push( + transformer.checker.getAwaitedType(returnType) || returnType, + ); } return transformedStatement; } else { - return maybeAnnotateAndReturn(possiblyAwaitedRightHandSide, getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker)); + return maybeAnnotateAndReturn( + possiblyAwaitedRightHandSide, + getExplicitPromisedTypeOfPromiseReturningCallExpression( + parent, + func, + transformer.checker, + ), + ); } } else { @@ -685,7 +978,11 @@ namespace ts.codefix { return emptyArray; } - function getPossiblyAwaitedRightHandSide(checker: TypeChecker, type: Type, expr: Expression): AwaitExpression | Expression { + function getPossiblyAwaitedRightHandSide( + checker: TypeChecker, + type: Type, + expr: Expression, + ): AwaitExpression | Expression { const rightHandSide = getSynthesizedDeepClone(expr); return !!checker.getPromisedTypeOfPromise(type) ? factory.createAwaitExpression(rightHandSide) : rightHandSide; } @@ -695,20 +992,45 @@ namespace ts.codefix { return lastOrUndefined(callSignatures); } - function removeReturns(stmts: readonly Statement[], prevArgName: SynthBindingName | undefined, transformer: Transformer, seenReturnStatement: boolean): readonly Statement[] { + function removeReturns( + stmts: readonly Statement[], + prevArgName: SynthBindingName | undefined, + transformer: Transformer, + seenReturnStatement: boolean, + ): readonly Statement[] { const ret: Statement[] = []; for (const stmt of stmts) { if (isReturnStatement(stmt)) { if (stmt.expression) { - const possiblyAwaitedExpression = isPromiseTypedExpression(stmt.expression, transformer.checker) ? factory.createAwaitExpression(stmt.expression) : stmt.expression; + const possiblyAwaitedExpression = isPromiseTypedExpression(stmt.expression, transformer.checker) + ? factory.createAwaitExpression(stmt.expression) : stmt.expression; if (prevArgName === undefined) { ret.push(factory.createExpressionStatement(possiblyAwaitedExpression)); } else if (isSynthIdentifier(prevArgName) && prevArgName.hasBeenDeclared) { - ret.push(factory.createExpressionStatement(factory.createAssignment(referenceSynthIdentifier(prevArgName), possiblyAwaitedExpression))); + ret.push( + factory.createExpressionStatement( + factory.createAssignment( + referenceSynthIdentifier(prevArgName), + possiblyAwaitedExpression, + ), + ), + ); } else { - ret.push(factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(declareSynthBindingName(prevArgName), /*exclamationToken*/ undefined, /*type*/ undefined, possiblyAwaitedExpression)], NodeFlags.Const))); + ret.push( + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([ + factory.createVariableDeclaration( + declareSynthBindingName(prevArgName), + /*exclamationToken*/ undefined, + /*type*/ undefined, + possiblyAwaitedExpression, + ), + ], NodeFlags.Const), + ), + ); } } } @@ -719,7 +1041,19 @@ namespace ts.codefix { // if block has no return statement, need to define prevArgName as undefined to prevent undeclared variables if (!seenReturnStatement && prevArgName !== undefined) { - ret.push(factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(declareSynthBindingName(prevArgName), /*exclamationToken*/ undefined, /*type*/ undefined, factory.createIdentifier("undefined"))], NodeFlags.Const))); + ret.push( + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([ + factory.createVariableDeclaration( + declareSynthBindingName(prevArgName), + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createIdentifier("undefined"), + ), + ], NodeFlags.Const), + ), + ); } return ret; @@ -729,7 +1063,12 @@ namespace ts.codefix { * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows the continuation to which this statement belongs. * @param continuationArgName The argument name for the continuation that follows this call. */ - function transformReturnStatementWithFixablePromiseHandler(transformer: Transformer, innerRetStmt: ReturnStatement, hasContinuation: boolean, continuationArgName?: SynthBindingName) { + function transformReturnStatementWithFixablePromiseHandler( + transformer: Transformer, + innerRetStmt: ReturnStatement, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, + ) { let innerCbBody: Statement[] = []; forEachChild(innerRetStmt, function visit(node) { if (isCallExpression(node)) { @@ -813,10 +1152,20 @@ namespace ts.codefix { } function createSynthIdentifier(identifier: Identifier, types: Type[] = []): SynthIdentifier { - return { kind: SynthBindingNameKind.Identifier, identifier, types, hasBeenDeclared: false, hasBeenReferenced: false }; + return { + kind: SynthBindingNameKind.Identifier, + identifier, + types, + hasBeenDeclared: false, + hasBeenReferenced: false, + }; } - function createSynthBindingPattern(bindingPattern: BindingPattern, elements: readonly SynthBindingName[] = emptyArray, types: Type[] = []): SynthBindingPattern { + function createSynthBindingPattern( + bindingPattern: BindingPattern, + elements: readonly SynthBindingName[] = emptyArray, + types: Type[] = [], + ): SynthBindingPattern { return { kind: SynthBindingNameKind.BindingPattern, bindingPattern, elements, types }; } diff --git a/src/services/codefixes/convertToEsModule.ts b/src/services/codefixes/convertToEsModule.ts index 55758e4a85b1e..4f3c479a30491 100644 --- a/src/services/codefixes/convertToEsModule.ts +++ b/src/services/codefixes/convertToEsModule.ts @@ -5,10 +5,21 @@ namespace ts.codefix { getCodeActions(context) { const { sourceFile, program, preferences } = context; const changes = textChanges.ChangeTracker.with(context, changes => { - const moduleExportsChangedToDefault = convertFileToEsModule(sourceFile, program.getTypeChecker(), changes, getEmitScriptTarget(program.getCompilerOptions()), getQuotePreference(sourceFile, preferences)); + const moduleExportsChangedToDefault = convertFileToEsModule( + sourceFile, + program.getTypeChecker(), + changes, + getEmitScriptTarget(program.getCompilerOptions()), + getQuotePreference(sourceFile, preferences), + ); if (moduleExportsChangedToDefault) { for (const importingFile of program.getSourceFiles()) { - fixImportOfModuleExports(importingFile, sourceFile, changes, getQuotePreference(importingFile, preferences)); + fixImportOfModuleExports( + importingFile, + sourceFile, + changes, + getQuotePreference(importingFile, preferences), + ); } } }); @@ -17,9 +28,18 @@ namespace ts.codefix { }, }); - function fixImportOfModuleExports(importingFile: SourceFile, exportingFile: SourceFile, changes: textChanges.ChangeTracker, quotePreference: QuotePreference) { + function fixImportOfModuleExports( + importingFile: SourceFile, + exportingFile: SourceFile, + changes: textChanges.ChangeTracker, + quotePreference: QuotePreference, + ) { for (const moduleSpecifier of importingFile.imports) { - const imported = getResolvedModule(importingFile, moduleSpecifier.text, getModeForUsageLocation(importingFile, moduleSpecifier)); + const imported = getResolvedModule( + importingFile, + moduleSpecifier.text, + getModeForUsageLocation(importingFile, moduleSpecifier), + ); if (!imported || imported.resolvedFileName !== exportingFile.fileName) { continue; } @@ -27,11 +47,19 @@ namespace ts.codefix { const importNode = importFromModuleSpecifier(moduleSpecifier); switch (importNode.kind) { case SyntaxKind.ImportEqualsDeclaration: - changes.replaceNode(importingFile, importNode, makeImport(importNode.name, /*namedImports*/ undefined, moduleSpecifier, quotePreference)); + changes.replaceNode( + importingFile, + importNode, + makeImport(importNode.name, /*namedImports*/ undefined, moduleSpecifier, quotePreference), + ); break; case SyntaxKind.CallExpression: if (isRequireCall(importNode, /*checkArgumentIsStringLiteralLike*/ false)) { - changes.replaceNode(importingFile, importNode, factory.createPropertyAccessExpression(getSynthesizedDeepClone(importNode), "default")); + changes.replaceNode( + importingFile, + importNode, + factory.createPropertyAccessExpression(getSynthesizedDeepClone(importNode), "default"), + ); } break; } @@ -39,7 +67,13 @@ namespace ts.codefix { } /** @returns Whether we converted a `module.exports =` to a default export. */ - function convertFileToEsModule(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, target: ScriptTarget, quotePreference: QuotePreference): ModuleExportsChanged { + function convertFileToEsModule( + sourceFile: SourceFile, + checker: TypeChecker, + changes: textChanges.ChangeTracker, + target: ScriptTarget, + quotePreference: QuotePreference, + ): ModuleExportsChanged { const identifiers: Identifiers = { original: collectFreeIdentifiers(sourceFile), additional: new Set() }; const exports = collectExportRenames(sourceFile, checker, identifiers); convertExportsAccesses(sourceFile, exports, changes); @@ -47,14 +81,32 @@ namespace ts.codefix { let useSitesToUnqualify: ESMap | undefined; // Process variable statements first to collect use sites that need to be updated inside other transformations for (const statement of filter(sourceFile.statements, isVariableStatement)) { - const newUseSites = convertVariableStatement(sourceFile, statement, changes, checker, identifiers, target, quotePreference); + const newUseSites = convertVariableStatement( + sourceFile, + statement, + changes, + checker, + identifiers, + target, + quotePreference, + ); if (newUseSites) { copyEntries(newUseSites, useSitesToUnqualify ??= new Map()); } } // `convertStatement` will delete entries from `useSitesToUnqualify` when containing statements are replaced for (const statement of filter(sourceFile.statements, s => !isVariableStatement(s))) { - const moduleExportsChanged = convertStatement(sourceFile, statement, checker, changes, identifiers, target, exports, useSitesToUnqualify, quotePreference); + const moduleExportsChanged = convertStatement( + sourceFile, + statement, + checker, + changes, + identifiers, + target, + exports, + useSitesToUnqualify, + quotePreference, + ); moduleExportsChangedToDefault = moduleExportsChangedToDefault || moduleExportsChanged; } // Remaining use sites can be changed directly @@ -76,7 +128,11 @@ namespace ts.codefix { */ type ExportRenames = ReadonlyESMap; - function collectExportRenames(sourceFile: SourceFile, checker: TypeChecker, identifiers: Identifiers): ExportRenames { + function collectExportRenames( + sourceFile: SourceFile, + checker: TypeChecker, + identifiers: Identifiers, + ): ExportRenames { const res = new Map(); forEachExportReference(sourceFile, node => { const { text, originalKeywordKind } = node.name; @@ -91,7 +147,11 @@ namespace ts.codefix { return res; } - function convertExportsAccesses(sourceFile: SourceFile, exports: ExportRenames, changes: textChanges.ChangeTracker): void { + function convertExportsAccesses( + sourceFile: SourceFile, + exports: ExportRenames, + changes: textChanges.ChangeTracker, + ): void { forEachExportReference(sourceFile, (node, isAssignmentLhs) => { if (isAssignmentLhs) { return; @@ -101,11 +161,21 @@ namespace ts.codefix { }); } - function forEachExportReference(sourceFile: SourceFile, cb: (node: PropertyAccessExpression & { name: Identifier; }, isAssignmentLhs: boolean) => void): void { + function forEachExportReference( + sourceFile: SourceFile, + cb: (node: PropertyAccessExpression & { name: Identifier; }, isAssignmentLhs: boolean) => void, + ): void { sourceFile.forEachChild(function recur(node) { - if (isPropertyAccessExpression(node) && isExportsOrModuleExportsOrAlias(sourceFile, node.expression) && isIdentifier(node.name)) { + if ( + isPropertyAccessExpression(node) && isExportsOrModuleExportsOrAlias(sourceFile, node.expression) + && isIdentifier(node.name) + ) { const { parent } = node; - cb(node as typeof node & { name: Identifier; }, isBinaryExpression(parent) && parent.left === node && parent.operatorToken.kind === SyntaxKind.EqualsToken); + cb( + node as typeof node & { name: Identifier; }, + isBinaryExpression(parent) && parent.left === node + && parent.operatorToken.kind === SyntaxKind.EqualsToken, + ); } node.forEachChild(recur); }); @@ -127,7 +197,15 @@ namespace ts.codefix { ): ModuleExportsChanged { switch (statement.kind) { case SyntaxKind.VariableStatement: - convertVariableStatement(sourceFile, statement as VariableStatement, changes, checker, identifiers, target, quotePreference); + convertVariableStatement( + sourceFile, + statement as VariableStatement, + changes, + checker, + identifiers, + target, + quotePreference, + ); return false; case SyntaxKind.ExpressionStatement: { const { expression } = statement as ExpressionStatement; @@ -135,13 +213,30 @@ namespace ts.codefix { case SyntaxKind.CallExpression: { if (isRequireCall(expression, /*checkArgumentIsStringLiteralLike*/ true)) { // For side-effecting require() call, just make a side-effecting import. - changes.replaceNode(sourceFile, statement, makeImport(/*name*/ undefined, /*namedImports*/ undefined, expression.arguments[0], quotePreference)); + changes.replaceNode( + sourceFile, + statement, + makeImport( + /*name*/ undefined, + /*namedImports*/ undefined, + expression.arguments[0], + quotePreference, + ), + ); } return false; } case SyntaxKind.BinaryExpression: { const { operatorToken } = expression as BinaryExpression; - return operatorToken.kind === SyntaxKind.EqualsToken && convertAssignment(sourceFile, checker, expression as BinaryExpression, changes, exports, useSitesToUnqualify); + return operatorToken.kind === SyntaxKind.EqualsToken + && convertAssignment( + sourceFile, + checker, + expression as BinaryExpression, + changes, + exports, + useSitesToUnqualify, + ); } } } @@ -172,15 +267,36 @@ namespace ts.codefix { } else if (isRequireCall(initializer, /*checkArgumentIsStringLiteralLike*/ true)) { foundImport = true; - return convertSingleImport(name, initializer.arguments[0], checker, identifiers, target, quotePreference); + return convertSingleImport( + name, + initializer.arguments[0], + checker, + identifiers, + target, + quotePreference, + ); } - else if (isPropertyAccessExpression(initializer) && isRequireCall(initializer.expression, /*checkArgumentIsStringLiteralLike*/ true)) { + else if ( + isPropertyAccessExpression(initializer) + && isRequireCall(initializer.expression, /*checkArgumentIsStringLiteralLike*/ true) + ) { foundImport = true; - return convertPropertyAccessImport(name, initializer.name.text, initializer.expression.arguments[0], identifiers, quotePreference); + return convertPropertyAccessImport( + name, + initializer.name.text, + initializer.expression.arguments[0], + identifiers, + quotePreference, + ); } } // Move it out to its own variable statement. (This will not be used if `!foundImport`) - return convertedImports([factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([decl], declarationList.flags))]); + return convertedImports([ + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([decl], declarationList.flags), + ), + ]); }); if (foundImport) { // useNonAdjustedEndPosition to ensure we don't eat the newline after the statement. @@ -197,7 +313,13 @@ namespace ts.codefix { } /** Converts `const name = require("moduleSpecifier").propertyName` */ - function convertPropertyAccessImport(name: BindingName, propertyName: string, moduleSpecifier: StringLiteralLike, identifiers: Identifiers, quotePreference: QuotePreference): ConvertedImports { + function convertPropertyAccessImport( + name: BindingName, + propertyName: string, + moduleSpecifier: StringLiteralLike, + identifiers: Identifiers, + quotePreference: QuotePreference, + ): ConvertedImports { switch (name.kind) { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: { @@ -212,7 +334,10 @@ namespace ts.codefix { // `const a = require("b").c` --> `import { c as a } from "./b"; return convertedImports([makeSingleImport(name.text, propertyName, moduleSpecifier, quotePreference)]); default: - return Debug.assertNever(name, `Convert to ES module got invalid syntax form ${(name as BindingName).kind}`); + return Debug.assertNever( + name, + `Convert to ES module got invalid syntax form ${(name as BindingName).kind}`, + ); } } @@ -235,21 +360,32 @@ namespace ts.codefix { changes.delete(sourceFile, assignment.parent); } else { - const replacement = isObjectLiteralExpression(right) ? tryChangeModuleExportsObject(right, useSitesToUnqualify) - : isRequireCall(right, /*checkArgumentIsStringLiteralLike*/ true) ? convertReExportAll(right.arguments[0], checker) + const replacement = isObjectLiteralExpression(right) + ? tryChangeModuleExportsObject(right, useSitesToUnqualify) + : isRequireCall(right, /*checkArgumentIsStringLiteralLike*/ true) + ? convertReExportAll(right.arguments[0], checker) : undefined; if (replacement) { changes.replaceNodeWithNodes(sourceFile, assignment.parent, replacement[0]); return replacement[1]; } else { - changes.replaceRangeWithText(sourceFile, createRange(left.getStart(sourceFile), right.pos), "export default"); + changes.replaceRangeWithText( + sourceFile, + createRange(left.getStart(sourceFile), right.pos), + "export default", + ); return true; } } } else if (isExportsOrModuleExportsOrAlias(sourceFile, left.expression)) { - convertNamedExport(sourceFile, assignment as BinaryExpression & { left: PropertyAccessExpression; }, changes, exports); + convertNamedExport( + sourceFile, + assignment as BinaryExpression & { left: PropertyAccessExpression; }, + changes, + exports, + ); } return false; @@ -259,7 +395,10 @@ namespace ts.codefix { * Convert `module.exports = { ... }` to individual exports.. * We can't always do this if the module has interesting members -- then it will be a default export instead. */ - function tryChangeModuleExportsObject(object: ObjectLiteralExpression, useSitesToUnqualify: ESMap | undefined): [readonly Statement[], ModuleExportsChanged] | undefined { + function tryChangeModuleExportsObject( + object: ObjectLiteralExpression, + useSitesToUnqualify: ESMap | undefined, + ): [readonly Statement[], ModuleExportsChanged] | undefined { const statements = mapAllOrFail(object.properties, prop => { switch (prop.kind) { case SyntaxKind.GetAccessor: @@ -270,11 +409,21 @@ namespace ts.codefix { case SyntaxKind.SpreadAssignment: return undefined; case SyntaxKind.PropertyAssignment: - return !isIdentifier(prop.name) ? undefined : convertExportsDotXEquals_replaceNode(prop.name.text, prop.initializer, useSitesToUnqualify); + return !isIdentifier(prop.name) ? undefined + : convertExportsDotXEquals_replaceNode(prop.name.text, prop.initializer, useSitesToUnqualify); case SyntaxKind.MethodDeclaration: - return !isIdentifier(prop.name) ? undefined : functionExpressionToDeclaration(prop.name.text, [factory.createToken(SyntaxKind.ExportKeyword)], prop, useSitesToUnqualify); + return !isIdentifier(prop.name) ? undefined + : functionExpressionToDeclaration( + prop.name.text, + [factory.createToken(SyntaxKind.ExportKeyword)], + prop, + useSitesToUnqualify, + ); default: - Debug.assertNever(prop, `Convert to ES6 got invalid prop kind ${(prop as ObjectLiteralElementLike).kind}`); + Debug.assertNever( + prop, + `Convert to ES6 got invalid prop kind ${(prop as ObjectLiteralElementLike).kind}`, + ); } }); return statements && [statements, false]; @@ -305,28 +454,46 @@ namespace ts.codefix { } } - function convertReExportAll(reExported: StringLiteralLike, checker: TypeChecker): [readonly Statement[], ModuleExportsChanged] { + function convertReExportAll( + reExported: StringLiteralLike, + checker: TypeChecker, + ): [readonly Statement[], ModuleExportsChanged] { // `module.exports = require("x");` ==> `export * from "x"; export { default } from "x";` const moduleSpecifier = reExported.text; const moduleSymbol = checker.getSymbolAtLocation(reExported); const exports = moduleSymbol ? moduleSymbol.exports! : emptyMap as ReadonlyCollection<__String>; - return exports.has(InternalSymbolName.ExportEquals) ? [[reExportDefault(moduleSpecifier)], true] : - !exports.has(InternalSymbolName.Default) ? [[reExportStar(moduleSpecifier)], false] : + return exports.has(InternalSymbolName.ExportEquals) ? [[reExportDefault(moduleSpecifier)], true] + : !exports.has(InternalSymbolName.Default) ? [[reExportStar(moduleSpecifier)], false] // If there's some non-default export, must include both `export *` and `export default`. - exports.size > 1 ? [[reExportStar(moduleSpecifier), reExportDefault(moduleSpecifier)], true] : [[reExportDefault(moduleSpecifier)], true]; + : exports.size > 1 ? [[reExportStar(moduleSpecifier), reExportDefault(moduleSpecifier)], true] + : [[reExportDefault(moduleSpecifier)], true]; } function reExportStar(moduleSpecifier: string): ExportDeclaration { return makeExportDeclaration(/*exportClause*/ undefined, moduleSpecifier); } function reExportDefault(moduleSpecifier: string): ExportDeclaration { - return makeExportDeclaration([factory.createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, "default")], moduleSpecifier); + return makeExportDeclaration([ + factory.createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, "default"), + ], moduleSpecifier); } - function convertExportsPropertyAssignment({ left, right, parent }: BinaryExpression & { left: PropertyAccessExpression; }, sourceFile: SourceFile, changes: textChanges.ChangeTracker): void { + function convertExportsPropertyAssignment( + { left, right, parent }: BinaryExpression & { left: PropertyAccessExpression; }, + sourceFile: SourceFile, + changes: textChanges.ChangeTracker, + ): void { const name = left.name.text; - if ((isFunctionExpression(right) || isArrowFunction(right) || isClassExpression(right)) && (!right.name || right.name.text === name)) { + if ( + (isFunctionExpression(right) || isArrowFunction(right) || isClassExpression(right)) + && (!right.name || right.name.text === name) + ) { // `exports.f = function() {}` -> `export function f() {}` -- Replace `exports.f = ` with `export `, and insert the name after `function`. - changes.replaceRange(sourceFile, { pos: left.getStart(sourceFile), end: right.getStart(sourceFile) }, factory.createToken(SyntaxKind.ExportKeyword), { suffix: " " }); + changes.replaceRange( + sourceFile, + { pos: left.getStart(sourceFile), end: right.getStart(sourceFile) }, + factory.createToken(SyntaxKind.ExportKeyword), + { suffix: " " }, + ); if (!right.name) changes.insertName(sourceFile, right, name); @@ -335,12 +502,22 @@ namespace ts.codefix { } else { // `exports.f = function g() {}` -> `export const f = function g() {}` -- just replace `exports.` with `export const ` - changes.replaceNodeRangeWithNodes(sourceFile, left.expression, findChildOfKind(left, SyntaxKind.DotToken, sourceFile)!, [factory.createToken(SyntaxKind.ExportKeyword), factory.createToken(SyntaxKind.ConstKeyword)], { joiner: " ", suffix: " " }); + changes.replaceNodeRangeWithNodes( + sourceFile, + left.expression, + findChildOfKind(left, SyntaxKind.DotToken, sourceFile)!, + [factory.createToken(SyntaxKind.ExportKeyword), factory.createToken(SyntaxKind.ConstKeyword)], + { joiner: " ", suffix: " " }, + ); } } // TODO: GH#22492 this will cause an error if a change has been made inside the body of the node. - function convertExportsDotXEquals_replaceNode(name: string | undefined, exported: Expression, useSitesToUnqualify: ESMap | undefined): Statement { + function convertExportsDotXEquals_replaceNode( + name: string | undefined, + exported: Expression, + useSitesToUnqualify: ESMap | undefined, + ): Statement { const modifiers = [factory.createToken(SyntaxKind.ExportKeyword)]; switch (exported.kind) { case SyntaxKind.FunctionExpression: { @@ -354,7 +531,12 @@ namespace ts.codefix { // falls through case SyntaxKind.ArrowFunction: // `exports.f = function() {}` --> `export function f() {}` - return functionExpressionToDeclaration(name, modifiers, exported as FunctionExpression | ArrowFunction, useSitesToUnqualify); + return functionExpressionToDeclaration( + name, + modifiers, + exported as FunctionExpression | ArrowFunction, + useSitesToUnqualify, + ); case SyntaxKind.ClassExpression: // `exports.C = class {}` --> `export class C {}` return classExpressionToDeclaration(name, modifiers, exported as ClassExpression, useSitesToUnqualify); @@ -364,14 +546,27 @@ namespace ts.codefix { function exportConst() { // `exports.x = 0;` --> `export const x = 0;` - return makeConst(modifiers, factory.createIdentifier(name!), replaceImportUseSites(exported, useSitesToUnqualify)); // TODO: GH#18217 + return makeConst( + modifiers, + factory.createIdentifier(name!), + replaceImportUseSites(exported, useSitesToUnqualify), + ); // TODO: GH#18217 } } function replaceImportUseSites(node: T, useSitesToUnqualify: ESMap | undefined): T; - function replaceImportUseSites(nodes: NodeArray, useSitesToUnqualify: ESMap | undefined): NodeArray; - function replaceImportUseSites(nodeOrNodes: T | NodeArray, useSitesToUnqualify: ESMap | undefined) { - if (!useSitesToUnqualify || !some(arrayFrom(useSitesToUnqualify.keys()), original => rangeContainsRange(nodeOrNodes, original))) { + function replaceImportUseSites( + nodes: NodeArray, + useSitesToUnqualify: ESMap | undefined, + ): NodeArray; + function replaceImportUseSites( + nodeOrNodes: T | NodeArray, + useSitesToUnqualify: ESMap | undefined, + ) { + if ( + !useSitesToUnqualify + || !some(arrayFrom(useSitesToUnqualify.keys()), original => rangeContainsRange(nodeOrNodes, original)) + ) { return nodeOrNodes; } @@ -405,12 +600,17 @@ namespace ts.codefix { ): ConvertedImports { switch (name.kind) { case SyntaxKind.ObjectBindingPattern: { - const importSpecifiers = mapAllOrFail(name.elements, e => - e.dotDotDotToken || e.initializer || e.propertyName && !isIdentifier(e.propertyName) || !isIdentifier(e.name) + const importSpecifiers = mapAllOrFail( + name.elements, + e => e.dotDotDotToken || e.initializer || e.propertyName && !isIdentifier(e.propertyName) + || !isIdentifier(e.name) ? undefined - : makeImportSpecifier(e.propertyName && e.propertyName.text, e.name.text)); + : makeImportSpecifier(e.propertyName && e.propertyName.text, e.name.text), + ); if (importSpecifiers) { - return convertedImports([makeImport(/*name*/ undefined, importSpecifiers, moduleSpecifier, quotePreference)]); + return convertedImports([ + makeImport(/*name*/ undefined, importSpecifiers, moduleSpecifier, quotePreference), + ]); } } // falls through -- object destructuring has an interesting pattern and must be a variable declaration @@ -421,14 +621,22 @@ namespace ts.codefix { */ const tmp = makeUniqueName(moduleSpecifierToValidIdentifier(moduleSpecifier.text, target), identifiers); return convertedImports([ - makeImport(factory.createIdentifier(tmp), /*namedImports*/ undefined, moduleSpecifier, quotePreference), + makeImport( + factory.createIdentifier(tmp), + /*namedImports*/ undefined, + moduleSpecifier, + quotePreference, + ), makeConst(/*modifiers*/ undefined, getSynthesizedDeepClone(name), factory.createIdentifier(tmp)), ]); } case SyntaxKind.Identifier: return convertSingleIdentifierImport(name, moduleSpecifier, checker, identifiers, quotePreference); default: - return Debug.assertNever(name, `Convert to ES module got invalid name kind ${(name as BindingName).kind}`); + return Debug.assertNever( + name, + `Convert to ES module got invalid name kind ${(name as BindingName).kind}`, + ); } } @@ -438,7 +646,13 @@ namespace ts.codefix { * - Convert `x.default()` to `x()` to handle ES6 default export * - Converts uses like `x.y()` to `y()` and uses a named import. */ - function convertSingleIdentifierImport(name: Identifier, moduleSpecifier: StringLiteralLike, checker: TypeChecker, identifiers: Identifiers, quotePreference: QuotePreference): ConvertedImports { + function convertSingleIdentifierImport( + name: Identifier, + moduleSpecifier: StringLiteralLike, + checker: TypeChecker, + identifiers: Identifiers, + quotePreference: QuotePreference, + ): ConvertedImports { const nameSymbol = checker.getSymbolAtLocation(name); // Maps from module property name to name actually used. (The same if there isn't shadowing.) const namedBindingsNames = new Map(); @@ -477,13 +691,26 @@ namespace ts.codefix { } } - const namedBindings = namedBindingsNames.size === 0 ? undefined : arrayFrom(mapIterator(namedBindingsNames.entries(), ([propertyName, idName]) => factory.createImportSpecifier(/*isTypeOnly*/ false, propertyName === idName ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(idName)))); + const namedBindings = namedBindingsNames.size === 0 ? undefined + : arrayFrom( + mapIterator(namedBindingsNames.entries(), ([propertyName, idName]) => + factory.createImportSpecifier( + /*isTypeOnly*/ false, + propertyName === idName ? undefined : factory.createIdentifier(propertyName), + factory.createIdentifier(idName), + )), + ); if (!namedBindings) { // If it was unused, ensure that we at least import *something*. needDefaultImport = true; } return convertedImports( - [makeImport(needDefaultImport ? getSynthesizedDeepClone(name) : undefined, namedBindings, moduleSpecifier, quotePreference)], + [makeImport( + needDefaultImport ? getSynthesizedDeepClone(name) : undefined, + namedBindings, + moduleSpecifier, + quotePreference, + )], useSitesToUnqualify, ); } @@ -541,7 +768,12 @@ namespace ts.codefix { // Node helpers - function functionExpressionToDeclaration(name: string | undefined, additionalModifiers: readonly Modifier[], fn: FunctionExpression | ArrowFunction | MethodDeclaration, useSitesToUnqualify: ESMap | undefined): FunctionDeclaration { + function functionExpressionToDeclaration( + name: string | undefined, + additionalModifiers: readonly Modifier[], + fn: FunctionExpression | ArrowFunction | MethodDeclaration, + useSitesToUnqualify: ESMap | undefined, + ): FunctionDeclaration { return factory.createFunctionDeclaration( concatenate(additionalModifiers, getSynthesizedDeepClones(fn.modifiers)), getSynthesizedDeepClone(fn.asteriskToken), @@ -553,7 +785,12 @@ namespace ts.codefix { ); } - function classExpressionToDeclaration(name: string | undefined, additionalModifiers: readonly Modifier[], cls: ClassExpression, useSitesToUnqualify: ESMap | undefined): ClassDeclaration { + function classExpressionToDeclaration( + name: string | undefined, + additionalModifiers: readonly Modifier[], + cls: ClassExpression, + useSitesToUnqualify: ESMap | undefined, + ): ClassDeclaration { return factory.createClassDeclaration( concatenate(additionalModifiers, getSynthesizedDeepClones(cls.modifiers)), name, @@ -563,17 +800,40 @@ namespace ts.codefix { ); } - function makeSingleImport(localName: string, propertyName: string, moduleSpecifier: StringLiteralLike, quotePreference: QuotePreference): ImportDeclaration { + function makeSingleImport( + localName: string, + propertyName: string, + moduleSpecifier: StringLiteralLike, + quotePreference: QuotePreference, + ): ImportDeclaration { return propertyName === "default" - ? makeImport(factory.createIdentifier(localName), /*namedImports*/ undefined, moduleSpecifier, quotePreference) - : makeImport(/*name*/ undefined, [makeImportSpecifier(propertyName, localName)], moduleSpecifier, quotePreference); + ? makeImport( + factory.createIdentifier(localName), + /*namedImports*/ undefined, + moduleSpecifier, + quotePreference, + ) + : makeImport( + /*name*/ undefined, + [makeImportSpecifier(propertyName, localName)], + moduleSpecifier, + quotePreference, + ); } function makeImportSpecifier(propertyName: string | undefined, name: string): ImportSpecifier { - return factory.createImportSpecifier(/*isTypeOnly*/ false, propertyName !== undefined && propertyName !== name ? factory.createIdentifier(propertyName) : undefined, factory.createIdentifier(name)); + return factory.createImportSpecifier( + /*isTypeOnly*/ false, + propertyName !== undefined && propertyName !== name ? factory.createIdentifier(propertyName) : undefined, + factory.createIdentifier(name), + ); } - function makeConst(modifiers: readonly Modifier[] | undefined, name: string | BindingName, init: Expression): VariableStatement { + function makeConst( + modifiers: readonly Modifier[] | undefined, + name: string | BindingName, + init: Expression, + ): VariableStatement { return factory.createVariableStatement( modifiers, factory.createVariableDeclarationList( @@ -583,7 +843,10 @@ namespace ts.codefix { ); } - function makeExportDeclaration(exportSpecifiers: ExportSpecifier[] | undefined, moduleSpecifier?: string): ExportDeclaration { + function makeExportDeclaration( + exportSpecifiers: ExportSpecifier[] | undefined, + moduleSpecifier?: string, + ): ExportDeclaration { return factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, diff --git a/src/services/codefixes/convertToMappedObjectType.ts b/src/services/codefixes/convertToMappedObjectType.ts index b81e94bd25c35..73eecd91f3937 100644 --- a/src/services/codefixes/convertToMappedObjectType.ts +++ b/src/services/codefixes/convertToMappedObjectType.ts @@ -1,7 +1,11 @@ /* @internal */ namespace ts.codefix { const fixId = "fixConvertToMappedObjectType"; - const errorCodes = [Diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead.code]; + const errorCodes = [ + Diagnostics + .An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead + .code, + ]; type FixableDeclaration = InterfaceDeclaration | TypeAliasDeclaration; @@ -13,7 +17,12 @@ namespace ts.codefix { if (!info) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info)); const name = idText(info.container.name); - return [createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_mapped_object_type, name], fixId, [Diagnostics.Convert_0_to_mapped_object_type, name])]; + return [ + createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_mapped_object_type, name], fixId, [ + Diagnostics.Convert_0_to_mapped_object_type, + name, + ]), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -32,23 +41,39 @@ namespace ts.codefix { const indexSignature = tryCast(token.parent.parent, isIndexSignatureDeclaration); if (!indexSignature) return undefined; - const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : tryCast(indexSignature.parent.parent, isTypeAliasDeclaration); + const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent + : tryCast(indexSignature.parent.parent, isTypeAliasDeclaration); if (!container) return undefined; return { indexSignature, container }; } function createTypeAliasFromInterface(declaration: FixableDeclaration, type: TypeNode): TypeAliasDeclaration { - return factory.createTypeAliasDeclaration(declaration.modifiers, declaration.name, declaration.typeParameters, type); + return factory.createTypeAliasDeclaration( + declaration.modifiers, + declaration.name, + declaration.typeParameters, + type, + ); } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { indexSignature, container }: Info): void { - const members = isInterfaceDeclaration(container) ? container.members : (container.type as TypeLiteralNode).members; + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { indexSignature, container }: Info, + ): void { + const members = isInterfaceDeclaration(container) ? container.members + : (container.type as TypeLiteralNode).members; const otherMembers = members.filter(member => !isIndexSignatureDeclaration(member)); const parameter = first(indexSignature.parameters); - const mappedTypeParameter = factory.createTypeParameterDeclaration(/*modifiers*/ undefined, cast(parameter.name, isIdentifier), parameter.type); + const mappedTypeParameter = factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + cast(parameter.name, isIdentifier), + parameter.type, + ); const mappedIntersectionType = factory.createMappedTypeNode( - hasEffectiveReadonlyModifier(indexSignature) ? factory.createModifier(SyntaxKind.ReadonlyKeyword) : undefined, + hasEffectiveReadonlyModifier(indexSignature) ? factory.createModifier(SyntaxKind.ReadonlyKeyword) + : undefined, mappedTypeParameter, /*nameType*/ undefined, indexSignature.questionToken, diff --git a/src/services/codefixes/convertToTypeOnlyExport.ts b/src/services/codefixes/convertToTypeOnlyExport.ts index 1e2b72f61660a..9416d7b897ec1 100644 --- a/src/services/codefixes/convertToTypeOnlyExport.ts +++ b/src/services/codefixes/convertToTypeOnlyExport.ts @@ -1,13 +1,30 @@ /* @internal */ namespace ts.codefix { - const errorCodes = [Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type.code]; + const errorCodes = [ + Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type.code, + ]; const fixId = "convertToTypeOnlyExport"; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToConvertToTypeOnlyExport(context) { - const changes = textChanges.ChangeTracker.with(context, t => fixSingleExportDeclaration(t, getExportSpecifierForDiagnosticSpan(context.span, context.sourceFile), context)); + const changes = textChanges.ChangeTracker.with( + context, + t => fixSingleExportDeclaration( + t, + getExportSpecifierForDiagnosticSpan(context.span, context.sourceFile), + context, + ), + ); if (changes.length) { - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_type_only_export, fixId, Diagnostics.Convert_all_re_exported_types_to_type_only_exports)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_to_type_only_export, + fixId, + Diagnostics.Convert_all_re_exported_types_to_type_only_exports, + ), + ]; } }, fixIds: [fixId], @@ -26,7 +43,11 @@ namespace ts.codefix { return tryCast(getTokenAtPosition(sourceFile, span.start).parent, isExportSpecifier); } - function fixSingleExportDeclaration(changes: textChanges.ChangeTracker, exportSpecifier: ExportSpecifier | undefined, context: CodeFixContextBase) { + function fixSingleExportDeclaration( + changes: textChanges.ChangeTracker, + exportSpecifier: ExportSpecifier | undefined, + context: CodeFixContextBase, + ) { if (!exportSpecifier) { return; } @@ -42,7 +63,10 @@ namespace ts.codefix { exportDeclaration, exportDeclaration.modifiers, /*isTypeOnly*/ false, - factory.updateNamedExports(exportClause, filter(exportClause.elements, e => !contains(typeExportSpecifiers, e))), + factory.updateNamedExports( + exportClause, + filter(exportClause.elements, e => !contains(typeExportSpecifiers, e)), + ), exportDeclaration.moduleSpecifier, /*assertClause*/ undefined, ); @@ -62,7 +86,10 @@ namespace ts.codefix { } } - function getTypeExportSpecifiers(originExportSpecifier: ExportSpecifier, context: CodeFixContextBase): readonly ExportSpecifier[] { + function getTypeExportSpecifiers( + originExportSpecifier: ExportSpecifier, + context: CodeFixContextBase, + ): readonly ExportSpecifier[] { const exportClause = originExportSpecifier.parent; if (exportClause.elements.length === 1) { return exportClause.elements; @@ -74,7 +101,8 @@ namespace ts.codefix { ); return filter(exportClause.elements, element => { - return element === originExportSpecifier || findDiagnosticForNode(element, diagnostics)?.code === errorCodes[0]; + return element === originExportSpecifier + || findDiagnosticForNode(element, diagnostics)?.code === errorCodes[0]; }); } } diff --git a/src/services/codefixes/convertToTypeOnlyImport.ts b/src/services/codefixes/convertToTypeOnlyImport.ts index 450025fe8c85c..e375cfec8a321 100644 --- a/src/services/codefixes/convertToTypeOnlyImport.ts +++ b/src/services/codefixes/convertToTypeOnlyImport.ts @@ -1,6 +1,10 @@ /* @internal */ namespace ts.codefix { - const errorCodes = [Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error.code]; + const errorCodes = [ + Diagnostics + .This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error + .code, + ]; const fixId = "convertToTypeOnlyImport"; registerCodeFix({ errorCodes, @@ -10,7 +14,15 @@ namespace ts.codefix { fixSingleImportDeclaration(t, importDeclaration, context); }); if (changes.length) { - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_type_only_import, fixId, Diagnostics.Convert_all_imports_not_used_as_a_value_to_type_only_imports)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_to_type_only_import, + fixId, + Diagnostics.Convert_all_imports_not_used_as_a_value_to_type_only_imports, + ), + ]; } }, fixIds: [fixId], @@ -26,7 +38,11 @@ namespace ts.codefix { return tryCast(getTokenAtPosition(sourceFile, span.start).parent, isImportDeclaration); } - function fixSingleImportDeclaration(changes: textChanges.ChangeTracker, importDeclaration: ImportDeclaration | undefined, context: CodeFixContextBase) { + function fixSingleImportDeclaration( + changes: textChanges.ChangeTracker, + importDeclaration: ImportDeclaration | undefined, + context: CodeFixContextBase, + ) { if (!importDeclaration?.importClause) { return; } @@ -37,7 +53,11 @@ namespace ts.codefix { // `import type foo, { Bar }` is not allowed, so move `foo` to new declaration if (importClause.name && importClause.namedBindings) { - changes.deleteNodeRangeExcludingEnd(context.sourceFile, importClause.name, importDeclaration.importClause.namedBindings); + changes.deleteNodeRangeExcludingEnd( + context.sourceFile, + importClause.name, + importDeclaration.importClause.namedBindings, + ); changes.insertNodeBefore( context.sourceFile, importDeclaration, diff --git a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts index 29b7e36130853..5108367e242cc 100644 --- a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts +++ b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts @@ -1,15 +1,30 @@ /* @internal */ namespace ts.codefix { const fixId = "correctQualifiedNameToIndexedAccessType"; - const errorCodes = [Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1.code]; + const errorCodes = [ + Diagnostics + .Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1 + .code, + ]; registerCodeFix({ errorCodes, getCodeActions(context) { const qualifiedName = getQualifiedName(context.sourceFile, context.span.start); if (!qualifiedName) return undefined; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, qualifiedName)); + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, context.sourceFile, qualifiedName), + ); const newText = `${qualifiedName.left.text}["${qualifiedName.right.text}"]`; - return [createCodeFixAction(fixId, changes, [Diagnostics.Rewrite_as_the_indexed_access_type_0, newText], fixId, Diagnostics.Rewrite_all_as_indexed_access_types)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Rewrite_as_the_indexed_access_type_0, newText], + fixId, + Diagnostics.Rewrite_all_as_indexed_access_types, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -27,7 +42,11 @@ namespace ts.codefix { return isIdentifier(qualifiedName.left) ? qualifiedName as QualifiedName & { left: Identifier; } : undefined; } - function doChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, qualifiedName: QualifiedName): void { + function doChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + qualifiedName: QualifiedName, + ): void { const rightText = qualifiedName.right.text; const replacement = factory.createIndexedAccessTypeNode( factory.createTypeReferenceNode(qualifiedName.left, /*typeArguments*/ undefined), diff --git a/src/services/codefixes/disableJsDiagnostics.ts b/src/services/codefixes/disableJsDiagnostics.ts index 47a947030a66d..38282e858fc13 100644 --- a/src/services/codefixes/disableJsDiagnostics.ts +++ b/src/services/codefixes/disableJsDiagnostics.ts @@ -16,7 +16,8 @@ namespace ts.codefix { return undefined; } - const newLineCharacter = sourceFile.checkJsDirective ? "" : getNewLineOrDefaultFromHost(host, formatContext.options); + const newLineCharacter = sourceFile.checkJsDirective ? "" + : getNewLineOrDefaultFromHost(host, formatContext.options); const fixes: CodeFixAction[] = [ // fixId unnecessary because adding `// @ts-nocheck` even once will ignore every error in the file. createCodeFixActionWithoutFixAll( @@ -24,7 +25,10 @@ namespace ts.codefix { [createFileTextChanges(sourceFile.fileName, [ createTextChange( sourceFile.checkJsDirective - ? createTextSpanFromBounds(sourceFile.checkJsDirective.pos, sourceFile.checkJsDirective.end) + ? createTextSpanFromBounds( + sourceFile.checkJsDirective.pos, + sourceFile.checkJsDirective.end, + ) : createTextSpan(0, 0), `// @ts-nocheck${newLineCharacter}`, ), @@ -34,7 +38,15 @@ namespace ts.codefix { ]; if (textChanges.isValidLocationToAddComment(sourceFile, span.start)) { - fixes.unshift(createCodeFixAction(fixName, textChanges.ChangeTracker.with(context, t => makeChange(t, sourceFile, span.start)), Diagnostics.Ignore_this_error_message, fixId, Diagnostics.Add_ts_ignore_to_all_error_messages)); + fixes.unshift( + createCodeFixAction( + fixName, + textChanges.ChangeTracker.with(context, t => makeChange(t, sourceFile, span.start)), + Diagnostics.Ignore_this_error_message, + fixId, + Diagnostics.Add_ts_ignore_to_all_error_messages, + ), + ); } return fixes; @@ -50,7 +62,12 @@ namespace ts.codefix { }, }); - function makeChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, seenLines?: Set) { + function makeChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + position: number, + seenLines?: Set, + ) { const { line: lineNumber } = getLineAndCharacterOfPosition(sourceFile, position); // Only need to add `// @ts-ignore` for a line once. if (!seenLines || tryAddToSet(seenLines, lineNumber)) { diff --git a/src/services/codefixes/fixAddMissingConstraint.ts b/src/services/codefixes/fixAddMissingConstraint.ts index 10e526cc95584..ee8ede3ca90b0 100644 --- a/src/services/codefixes/fixAddMissingConstraint.ts +++ b/src/services/codefixes/fixAddMissingConstraint.ts @@ -5,10 +5,15 @@ namespace ts.codefix { // We want errors this could be attached to: // Diagnostics.This_type_parameter_probably_needs_an_extends_0_constraint Diagnostics.Type_0_is_not_comparable_to_type_1.code, - Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated.code, - Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code, + Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated + .code, + Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties + .code, Diagnostics.Type_0_is_not_assignable_to_type_1.code, - Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code, + Diagnostics + .Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties + .code, Diagnostics.Property_0_is_incompatible_with_index_signature.code, Diagnostics.Property_0_in_type_1_is_not_assignable_to_type_2.code, Diagnostics.Type_0_does_not_satisfy_the_constraint_1.code, @@ -20,8 +25,19 @@ namespace ts.codefix { const info = getInfo(program, sourceFile, span); if (info === undefined) return; - const changes = textChanges.ChangeTracker.with(context, t => addMissingConstraint(t, program, preferences, host, sourceFile, info)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_extends_constraint, fixId, Diagnostics.Add_extends_constraint_to_all_type_parameters)]; + const changes = textChanges.ChangeTracker.with( + context, + t => addMissingConstraint(t, program, preferences, host, sourceFile, info), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_extends_constraint, + fixId, + Diagnostics.Add_extends_constraint_to_all_type_parameters, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => { @@ -49,11 +65,20 @@ namespace ts.codefix { } function getInfo(program: Program, sourceFile: SourceFile, span: TextSpan): Info | undefined { - const diag = find(program.getSemanticDiagnostics(sourceFile), diag => diag.start === span.start && diag.length === span.length); + const diag = find( + program.getSemanticDiagnostics(sourceFile), + diag => diag.start === span.start && diag.length === span.length, + ); if (diag === undefined || diag.relatedInformation === undefined) return; - const related = find(diag.relatedInformation, related => related.code === Diagnostics.This_type_parameter_might_need_an_extends_0_constraint.code); - if (related === undefined || related.file === undefined || related.start === undefined || related.length === undefined) return; + const related = find( + diag.relatedInformation, + related => related.code === Diagnostics.This_type_parameter_might_need_an_extends_0_constraint.code, + ); + if ( + related === undefined || related.file === undefined || related.start === undefined + || related.length === undefined + ) return; let declaration = findAncestorMatchingSpan(related.file, createTextSpan(related.start, related.length)); if (declaration === undefined) return; @@ -68,14 +93,22 @@ namespace ts.codefix { const token = getTokenAtPosition(sourceFile, span.start); const checker = program.getTypeChecker(); - const constraint = tryGetConstraintType(checker, token) || tryGetConstraintFromDiagnosticMessage(related.messageText); + const constraint = tryGetConstraintType(checker, token) + || tryGetConstraintFromDiagnosticMessage(related.messageText); return { constraint, declaration, token }; } return undefined; } - function addMissingConstraint(changes: textChanges.ChangeTracker, program: Program, preferences: UserPreferences, host: LanguageServiceHost, sourceFile: SourceFile, info: Info): void { + function addMissingConstraint( + changes: textChanges.ChangeTracker, + program: Program, + preferences: UserPreferences, + host: LanguageServiceHost, + sourceFile: SourceFile, + info: Info, + ): void { const { declaration, constraint } = info; const checker = program.getTypeChecker(); @@ -86,9 +119,27 @@ namespace ts.codefix { const scriptTarget = getEmitScriptTarget(program.getCompilerOptions()); const tracker = getNoopSymbolTrackerWithResolver({ program, host }); const importAdder = createImportAdder(sourceFile, program, preferences, host); - const typeNode = typeToAutoImportableTypeNode(checker, importAdder, constraint, /*contextNode*/ undefined, scriptTarget, /*flags*/ undefined, tracker); + const typeNode = typeToAutoImportableTypeNode( + checker, + importAdder, + constraint, + /*contextNode*/ undefined, + scriptTarget, + /*flags*/ undefined, + tracker, + ); if (typeNode) { - changes.replaceNode(sourceFile, declaration, factory.updateTypeParameterDeclaration(declaration, /*modifiers*/ undefined, declaration.name, typeNode, declaration.default)); + changes.replaceNode( + sourceFile, + declaration, + factory.updateTypeParameterDeclaration( + declaration, + /*modifiers*/ undefined, + declaration.name, + typeNode, + declaration.default, + ), + ); importAdder.writeFixes(changes); } } diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 8e6198a724c05..94571a9e315e4 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -28,34 +28,84 @@ namespace ts.codefix { errorCodes, getCodeActions(context) { const typeChecker = context.program.getTypeChecker(); - const info = getInfo(context.sourceFile, context.span.start, context.errorCode, typeChecker, context.program); + const info = getInfo( + context.sourceFile, + context.span.start, + context.errorCode, + typeChecker, + context.program, + ); if (!info) { return undefined; } if (info.kind === InfoKind.ObjectLiteral) { - const changes = textChanges.ChangeTracker.with(context, t => addObjectLiteralProperties(t, context, info)); - return [createCodeFixAction(fixMissingProperties, changes, Diagnostics.Add_missing_properties, fixMissingProperties, Diagnostics.Add_all_missing_properties)]; + const changes = textChanges.ChangeTracker.with( + context, + t => addObjectLiteralProperties(t, context, info), + ); + return [ + createCodeFixAction( + fixMissingProperties, + changes, + Diagnostics.Add_missing_properties, + fixMissingProperties, + Diagnostics.Add_all_missing_properties, + ), + ]; } if (info.kind === InfoKind.JsxAttributes) { const changes = textChanges.ChangeTracker.with(context, t => addJsxAttributes(t, context, info)); - return [createCodeFixAction(fixMissingAttributes, changes, Diagnostics.Add_missing_attributes, fixMissingAttributes, Diagnostics.Add_all_missing_attributes)]; + return [ + createCodeFixAction( + fixMissingAttributes, + changes, + Diagnostics.Add_missing_attributes, + fixMissingAttributes, + Diagnostics.Add_all_missing_attributes, + ), + ]; } if (info.kind === InfoKind.Function || info.kind === InfoKind.Signature) { const changes = textChanges.ChangeTracker.with(context, t => addFunctionDeclaration(t, context, info)); - return [createCodeFixAction(fixMissingFunctionDeclaration, changes, [Diagnostics.Add_missing_function_declaration_0, info.token.text], fixMissingFunctionDeclaration, Diagnostics.Add_all_missing_function_declarations)]; + return [ + createCodeFixAction( + fixMissingFunctionDeclaration, + changes, + [Diagnostics.Add_missing_function_declaration_0, info.token.text], + fixMissingFunctionDeclaration, + Diagnostics.Add_all_missing_function_declarations, + ), + ]; } if (info.kind === InfoKind.Enum) { - const changes = textChanges.ChangeTracker.with(context, t => addEnumMemberDeclaration(t, context.program.getTypeChecker(), info)); - return [createCodeFixAction(fixMissingMember, changes, [Diagnostics.Add_missing_enum_member_0, info.token.text], fixMissingMember, Diagnostics.Add_all_missing_members)]; + const changes = textChanges.ChangeTracker.with( + context, + t => addEnumMemberDeclaration(t, context.program.getTypeChecker(), info), + ); + return [ + createCodeFixAction( + fixMissingMember, + changes, + [Diagnostics.Add_missing_enum_member_0, info.token.text], + fixMissingMember, + Diagnostics.Add_all_missing_members, + ), + ]; } - return concatenate(getActionsForMissingMethodDeclaration(context, info), getActionsForMissingMemberDeclaration(context, info)); + return concatenate( + getActionsForMissingMethodDeclaration(context, info), + getActionsForMissingMemberDeclaration(context, info), + ); }, fixIds: [fixMissingMember, fixMissingFunctionDeclaration, fixMissingProperties, fixMissingAttributes], getAllCodeActions: context => { const { program, fixId } = context; const checker = program.getTypeChecker(); const seen = new Map(); - const typeDeclToMembers = new Map(); + const typeDeclToMembers = new Map< + ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + TypeLikeDeclarationInfo[] + >(); return createCombinedCodeActions(textChanges.ChangeTracker.with(context, changes => { eachDiagnostic(context, errorCodes, diag => { @@ -63,7 +113,10 @@ namespace ts.codefix { if (!info || !addToSeen(seen, getNodeId(info.parentDeclaration) + "#" + info.token.text)) { return; } - if (fixId === fixMissingFunctionDeclaration && (info.kind === InfoKind.Function || info.kind === InfoKind.Signature)) { + if ( + fixId === fixMissingFunctionDeclaration + && (info.kind === InfoKind.Function || info.kind === InfoKind.Signature) + ) { addFunctionDeclaration(changes, context, info); } else if (fixId === fixMissingProperties && info.kind === InfoKind.ObjectLiteral) { @@ -100,15 +153,39 @@ namespace ts.codefix { const { parentDeclaration, declSourceFile, modifierFlags, token, call, isJSFile } = info; // Always prefer to add a method declaration if possible. if (call && !isPrivateIdentifier(token)) { - addMethodDeclaration(context, changes, call, token, modifierFlags & ModifierFlags.Static, parentDeclaration, declSourceFile); + addMethodDeclaration( + context, + changes, + call, + token, + modifierFlags & ModifierFlags.Static, + parentDeclaration, + declSourceFile, + ); } else { - if (isJSFile && !isInterfaceDeclaration(parentDeclaration) && !isTypeLiteralNode(parentDeclaration)) { - addMissingMemberInJs(changes, declSourceFile, parentDeclaration, token, !!(modifierFlags & ModifierFlags.Static)); + if ( + isJSFile && !isInterfaceDeclaration(parentDeclaration) + && !isTypeLiteralNode(parentDeclaration) + ) { + addMissingMemberInJs( + changes, + declSourceFile, + parentDeclaration, + token, + !!(modifierFlags & ModifierFlags.Static), + ); } else { const typeNode = getTypeNode(checker, parentDeclaration, token); - addPropertyDeclaration(changes, declSourceFile, parentDeclaration, token.text, typeNode, modifierFlags & ModifierFlags.Static); + addPropertyDeclaration( + changes, + declSourceFile, + parentDeclaration, + token.text, + typeNode, + modifierFlags & ModifierFlags.Static, + ); } } } @@ -117,7 +194,13 @@ namespace ts.codefix { }, }); - type Info = TypeLikeDeclarationInfo | EnumInfo | FunctionInfo | ObjectLiteralInfo | JsxAttributesInfo | SignatureInfo; + type Info = + | TypeLikeDeclarationInfo + | EnumInfo + | FunctionInfo + | ObjectLiteralInfo + | JsxAttributesInfo + | SignatureInfo; interface EnumInfo { readonly kind: InfoKind.Enum; @@ -167,7 +250,13 @@ namespace ts.codefix { readonly parentDeclaration: Node; } - function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, checker: TypeChecker, program: Program): Info | undefined { + function getInfo( + sourceFile: SourceFile, + tokenPos: number, + errorCode: number, + checker: TypeChecker, + program: Program, + ): Info | undefined { // The identifier of the missing property. eg: // this.missing = 1; // ^^^^^^^ @@ -175,7 +264,10 @@ namespace ts.codefix { const parent = token.parent; if (errorCode === Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code) { - if (!(token.kind === SyntaxKind.OpenBraceToken && isObjectLiteralExpression(parent) && isCallExpression(parent.parent))) return undefined; + if ( + !(token.kind === SyntaxKind.OpenBraceToken && isObjectLiteralExpression(parent) + && isCallExpression(parent.parent)) + ) return undefined; const argIndex = findIndex(parent.parent.arguments, arg => arg === parent); if (argIndex < 0) return undefined; @@ -186,15 +278,32 @@ namespace ts.codefix { const param = signature.parameters[argIndex].valueDeclaration; if (!(param && isParameter(param) && isIdentifier(param.name))) return undefined; - const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent), checker.getParameterType(signature, argIndex), /* requireOptionalProperties */ false, /* matchDiscriminantProperties */ false)); + const properties = arrayFrom( + checker.getUnmatchedProperties( + checker.getTypeAtLocation(parent), + checker.getParameterType(signature, argIndex), + /* requireOptionalProperties */ false, + /* matchDiscriminantProperties */ false, + ), + ); if (!length(properties)) return undefined; return { kind: InfoKind.ObjectLiteral, token: param.name, properties, parentDeclaration: parent }; } if (!isMemberName(token)) return undefined; - if (isIdentifier(token) && hasInitializer(parent) && parent.initializer && isObjectLiteralExpression(parent.initializer)) { - const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent.initializer), checker.getTypeAtLocation(token), /* requireOptionalProperties */ false, /* matchDiscriminantProperties */ false)); + if ( + isIdentifier(token) && hasInitializer(parent) && parent.initializer + && isObjectLiteralExpression(parent.initializer) + ) { + const properties = arrayFrom( + checker.getUnmatchedProperties( + checker.getTypeAtLocation(parent.initializer), + checker.getTypeAtLocation(token), + /* requireOptionalProperties */ false, + /* matchDiscriminantProperties */ false, + ), + ); if (!length(properties)) return undefined; return { kind: InfoKind.ObjectLiteral, token, properties, parentDeclaration: parent.initializer }; @@ -215,7 +324,14 @@ namespace ts.codefix { return { kind: InfoKind.Signature, token, signature, sourceFile, parentDeclaration: findScope(token) }; } if (isCallExpression(parent) && parent.expression === token) { - return { kind: InfoKind.Function, token, call: parent, sourceFile, modifierFlags: ModifierFlags.None, parentDeclaration: findScope(token) }; + return { + kind: InfoKind.Function, + token, + call: parent, + sourceFile, + modifierFlags: ModifierFlags.None, + parentDeclaration: findScope(token), + }; } } @@ -228,15 +344,32 @@ namespace ts.codefix { if (isIdentifier(token) && isCallExpression(parent.parent)) { const moduleDeclaration = find(symbol.declarations, isModuleDeclaration); const moduleDeclarationSourceFile = moduleDeclaration?.getSourceFile(); - if (moduleDeclaration && moduleDeclarationSourceFile && !isSourceFileFromLibrary(program, moduleDeclarationSourceFile)) { - return { kind: InfoKind.Function, token, call: parent.parent, sourceFile, modifierFlags: ModifierFlags.Export, parentDeclaration: moduleDeclaration }; + if ( + moduleDeclaration && moduleDeclarationSourceFile + && !isSourceFileFromLibrary(program, moduleDeclarationSourceFile) + ) { + return { + kind: InfoKind.Function, + token, + call: parent.parent, + sourceFile, + modifierFlags: ModifierFlags.Export, + parentDeclaration: moduleDeclaration, + }; } const moduleSourceFile = find(symbol.declarations, isSourceFile); if (sourceFile.commonJsModuleIndicator) return undefined; if (moduleSourceFile && !isSourceFileFromLibrary(program, moduleSourceFile)) { - return { kind: InfoKind.Function, token, call: parent.parent, sourceFile: moduleSourceFile, modifierFlags: ModifierFlags.Export, parentDeclaration: moduleSourceFile }; + return { + kind: InfoKind.Function, + token, + call: parent.parent, + sourceFile: moduleSourceFile, + modifierFlags: ModifierFlags.Export, + parentDeclaration: moduleSourceFile, + }; } } @@ -245,49 +378,95 @@ namespace ts.codefix { if (!classDeclaration && isPrivateIdentifier(token)) return undefined; // Prefer to change the class instead of the interface if they are merged - const declaration = classDeclaration || find(symbol.declarations, d => isInterfaceDeclaration(d) || isTypeLiteralNode(d)) as InterfaceDeclaration | TypeLiteralNode | undefined; + const declaration = classDeclaration + || find(symbol.declarations, d => isInterfaceDeclaration(d) || isTypeLiteralNode(d)) as + | InterfaceDeclaration + | TypeLiteralNode + | undefined; if (declaration && !isSourceFileFromLibrary(program, declaration.getSourceFile())) { - const makeStatic = !isTypeLiteralNode(declaration) && ((leftExpressionType as TypeReference).target || leftExpressionType) !== checker.getDeclaredTypeOfSymbol(symbol); + const makeStatic = !isTypeLiteralNode(declaration) + && ((leftExpressionType as TypeReference).target || leftExpressionType) + !== checker.getDeclaredTypeOfSymbol(symbol); if (makeStatic && (isPrivateIdentifier(token) || isInterfaceDeclaration(declaration))) return undefined; const declSourceFile = declaration.getSourceFile(); - const modifierFlags = isTypeLiteralNode(declaration) ? ModifierFlags.None : - (makeStatic ? ModifierFlags.Static : ModifierFlags.None) | (startsWithUnderscore(token.text) ? ModifierFlags.Private : ModifierFlags.None); + const modifierFlags = isTypeLiteralNode(declaration) ? ModifierFlags.None + : (makeStatic ? ModifierFlags.Static : ModifierFlags.None) + | (startsWithUnderscore(token.text) ? ModifierFlags.Private : ModifierFlags.None); const isJSFile = isSourceFileJS(declSourceFile); const call = tryCast(parent.parent, isCallExpression); - return { kind: InfoKind.TypeLikeDeclaration, token, call, modifierFlags, parentDeclaration: declaration, declSourceFile, isJSFile }; + return { + kind: InfoKind.TypeLikeDeclaration, + token, + call, + modifierFlags, + parentDeclaration: declaration, + declSourceFile, + isJSFile, + }; } const enumDeclaration = find(symbol.declarations, isEnumDeclaration); - if (enumDeclaration && !(leftExpressionType.flags & TypeFlags.EnumLike) && !isPrivateIdentifier(token) && !isSourceFileFromLibrary(program, enumDeclaration.getSourceFile())) { + if ( + enumDeclaration && !(leftExpressionType.flags & TypeFlags.EnumLike) && !isPrivateIdentifier(token) + && !isSourceFileFromLibrary(program, enumDeclaration.getSourceFile()) + ) { return { kind: InfoKind.Enum, token, parentDeclaration: enumDeclaration }; } return undefined; } - function getActionsForMissingMemberDeclaration(context: CodeFixContext, info: TypeLikeDeclarationInfo): CodeFixAction[] | undefined { - return info.isJSFile ? singleElementArray(createActionForAddMissingMemberInJavascriptFile(context, info)) : - createActionsForAddMissingMemberInTypeScriptFile(context, info); + function getActionsForMissingMemberDeclaration( + context: CodeFixContext, + info: TypeLikeDeclarationInfo, + ): CodeFixAction[] | undefined { + return info.isJSFile ? singleElementArray(createActionForAddMissingMemberInJavascriptFile(context, info)) + : createActionsForAddMissingMemberInTypeScriptFile(context, info); } - function createActionForAddMissingMemberInJavascriptFile(context: CodeFixContext, { parentDeclaration, declSourceFile, modifierFlags, token }: TypeLikeDeclarationInfo): CodeFixAction | undefined { + function createActionForAddMissingMemberInJavascriptFile( + context: CodeFixContext, + { parentDeclaration, declSourceFile, modifierFlags, token }: TypeLikeDeclarationInfo, + ): CodeFixAction | undefined { if (isInterfaceDeclaration(parentDeclaration) || isTypeLiteralNode(parentDeclaration)) { return undefined; } - const changes = textChanges.ChangeTracker.with(context, t => addMissingMemberInJs(t, declSourceFile, parentDeclaration, token, !!(modifierFlags & ModifierFlags.Static))); + const changes = textChanges.ChangeTracker.with( + context, + t => addMissingMemberInJs( + t, + declSourceFile, + parentDeclaration, + token, + !!(modifierFlags & ModifierFlags.Static), + ), + ); if (changes.length === 0) { return undefined; } - const diagnostic = modifierFlags & ModifierFlags.Static ? Diagnostics.Initialize_static_property_0 : - isPrivateIdentifier(token) ? Diagnostics.Declare_a_private_field_named_0 : Diagnostics.Initialize_property_0_in_the_constructor; + const diagnostic = modifierFlags & ModifierFlags.Static ? Diagnostics.Initialize_static_property_0 + : isPrivateIdentifier(token) ? Diagnostics.Declare_a_private_field_named_0 + : Diagnostics.Initialize_property_0_in_the_constructor; - return createCodeFixAction(fixMissingMember, changes, [diagnostic, token.text], fixMissingMember, Diagnostics.Add_all_missing_members); + return createCodeFixAction( + fixMissingMember, + changes, + [diagnostic, token.text], + fixMissingMember, + Diagnostics.Add_all_missing_members, + ); } - function addMissingMemberInJs(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, token: Identifier | PrivateIdentifier, makeStatic: boolean): void { + function addMissingMemberInJs( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + classDeclaration: ClassLikeDeclaration, + token: Identifier | PrivateIdentifier, + makeStatic: boolean, + ): void { const tokenName = token.text; if (makeStatic) { if (classDeclaration.kind === SyntaxKind.ClassExpression) { @@ -325,49 +504,103 @@ namespace ts.codefix { } function initializePropertyToUndefined(obj: Expression, propertyName: string) { - return factory.createExpressionStatement(factory.createAssignment(factory.createPropertyAccessExpression(obj, propertyName), createUndefined())); + return factory.createExpressionStatement( + factory.createAssignment(factory.createPropertyAccessExpression(obj, propertyName), createUndefined()), + ); } - function createActionsForAddMissingMemberInTypeScriptFile(context: CodeFixContext, { parentDeclaration, declSourceFile, modifierFlags, token }: TypeLikeDeclarationInfo): CodeFixAction[] | undefined { + function createActionsForAddMissingMemberInTypeScriptFile( + context: CodeFixContext, + { parentDeclaration, declSourceFile, modifierFlags, token }: TypeLikeDeclarationInfo, + ): CodeFixAction[] | undefined { const memberName = token.text; const isStatic = modifierFlags & ModifierFlags.Static; const typeNode = getTypeNode(context.program.getTypeChecker(), parentDeclaration, token); - const addPropertyDeclarationChanges = (modifierFlags: ModifierFlags) => textChanges.ChangeTracker.with(context, t => addPropertyDeclaration(t, declSourceFile, parentDeclaration, memberName, typeNode, modifierFlags)); + const addPropertyDeclarationChanges = (modifierFlags: ModifierFlags) => + textChanges.ChangeTracker.with( + context, + t => addPropertyDeclaration(t, declSourceFile, parentDeclaration, memberName, typeNode, modifierFlags), + ); - const actions = [createCodeFixAction(fixMissingMember, addPropertyDeclarationChanges(modifierFlags & ModifierFlags.Static), [isStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0, memberName], fixMissingMember, Diagnostics.Add_all_missing_members)]; + const actions = [ + createCodeFixAction( + fixMissingMember, + addPropertyDeclarationChanges(modifierFlags & ModifierFlags.Static), + [isStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0, memberName], + fixMissingMember, + Diagnostics.Add_all_missing_members, + ), + ]; if (isStatic || isPrivateIdentifier(token)) { return actions; } if (modifierFlags & ModifierFlags.Private) { - actions.unshift(createCodeFixActionWithoutFixAll(fixMissingMember, addPropertyDeclarationChanges(ModifierFlags.Private), [Diagnostics.Declare_private_property_0, memberName])); + actions.unshift( + createCodeFixActionWithoutFixAll( + fixMissingMember, + addPropertyDeclarationChanges(ModifierFlags.Private), + [Diagnostics.Declare_private_property_0, memberName], + ), + ); } actions.push(createAddIndexSignatureAction(context, declSourceFile, parentDeclaration, token.text, typeNode)); return actions; } - function getTypeNode(checker: TypeChecker, node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, token: Node) { + function getTypeNode( + checker: TypeChecker, + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + token: Node, + ) { let typeNode: TypeNode | undefined; if (token.parent.parent.kind === SyntaxKind.BinaryExpression) { const binaryExpression = token.parent.parent as BinaryExpression; - const otherExpression = token.parent === binaryExpression.left ? binaryExpression.right : binaryExpression.left; - const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(otherExpression))); + const otherExpression = token.parent === binaryExpression.left ? binaryExpression.right + : binaryExpression.left; + const widenedType = checker.getWidenedType( + checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(otherExpression)), + ); typeNode = checker.typeToTypeNode(widenedType, node, NodeBuilderFlags.NoTruncation); } else { const contextualType = checker.getContextualType(token.parent as Expression); - typeNode = contextualType ? checker.typeToTypeNode(contextualType, /*enclosingDeclaration*/ undefined, NodeBuilderFlags.NoTruncation) : undefined; + typeNode = contextualType + ? checker.typeToTypeNode( + contextualType, + /*enclosingDeclaration*/ undefined, + NodeBuilderFlags.NoTruncation, + ) : undefined; } return typeNode || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); } - function addPropertyDeclaration(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, tokenName: string, typeNode: TypeNode, modifierFlags: ModifierFlags): void { - const modifiers = modifierFlags ? factory.createNodeArray(factory.createModifiersFromModifierFlags(modifierFlags)) : undefined; + function addPropertyDeclaration( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + tokenName: string, + typeNode: TypeNode, + modifierFlags: ModifierFlags, + ): void { + const modifiers = modifierFlags + ? factory.createNodeArray(factory.createModifiersFromModifierFlags(modifierFlags)) : undefined; const property = isClassLike(node) - ? factory.createPropertyDeclaration(modifiers, tokenName, /*questionToken*/ undefined, typeNode, /*initializer*/ undefined) - : factory.createPropertySignature(/*modifiers*/ undefined, tokenName, /*questionToken*/ undefined, typeNode); + ? factory.createPropertyDeclaration( + modifiers, + tokenName, + /*questionToken*/ undefined, + typeNode, + /*initializer*/ undefined, + ) + : factory.createPropertySignature( + /*modifiers*/ undefined, + tokenName, + /*questionToken*/ undefined, + typeNode, + ); const lastProp = getNodeToInsertPropertyAfter(node); if (lastProp) { @@ -379,7 +612,9 @@ namespace ts.codefix { } // Gets the last of the first run of PropertyDeclarations, or undefined if the class does not start with a PropertyDeclaration. - function getNodeToInsertPropertyAfter(node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode): PropertyDeclaration | undefined { + function getNodeToInsertPropertyAfter( + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + ): PropertyDeclaration | undefined { let res: PropertyDeclaration | undefined; for (const member of node.members) { if (!isPropertyDeclaration(member)) break; @@ -388,7 +623,13 @@ namespace ts.codefix { return res; } - function createAddIndexSignatureAction(context: CodeFixContext, sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, tokenName: string, typeNode: TypeNode): CodeFixAction { + function createAddIndexSignatureAction( + context: CodeFixContext, + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + tokenName: string, + typeNode: TypeNode, + ): CodeFixAction { // Index signatures cannot have the static modifier. const stringTypeNode = factory.createKeywordTypeNode(SyntaxKind.StringKeyword); const indexingParameter = factory.createParameterDeclaration( @@ -405,12 +646,21 @@ namespace ts.codefix { typeNode, ); - const changes = textChanges.ChangeTracker.with(context, t => t.insertMemberAtStart(sourceFile, node, indexSignature)); + const changes = textChanges.ChangeTracker.with( + context, + t => t.insertMemberAtStart(sourceFile, node, indexSignature), + ); // No fixId here because code-fix-all currently only works on adding individual named properties. - return createCodeFixActionWithoutFixAll(fixMissingMember, changes, [Diagnostics.Add_index_signature_for_property_0, tokenName]); + return createCodeFixActionWithoutFixAll(fixMissingMember, changes, [ + Diagnostics.Add_index_signature_for_property_0, + tokenName, + ]); } - function getActionsForMissingMethodDeclaration(context: CodeFixContext, info: TypeLikeDeclarationInfo): CodeFixAction[] | undefined { + function getActionsForMissingMethodDeclaration( + context: CodeFixContext, + info: TypeLikeDeclarationInfo, + ): CodeFixAction[] | undefined { const { parentDeclaration, declSourceFile, modifierFlags, token, call } = info; if (call === undefined) { return undefined; @@ -422,10 +672,31 @@ namespace ts.codefix { } const methodName = token.text; - const addMethodDeclarationChanges = (modifierFlags: ModifierFlags) => textChanges.ChangeTracker.with(context, t => addMethodDeclaration(context, t, call, token, modifierFlags, parentDeclaration, declSourceFile)); - const actions = [createCodeFixAction(fixMissingMember, addMethodDeclarationChanges(modifierFlags & ModifierFlags.Static), [modifierFlags & ModifierFlags.Static ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0, methodName], fixMissingMember, Diagnostics.Add_all_missing_members)]; + const addMethodDeclarationChanges = (modifierFlags: ModifierFlags) => + textChanges.ChangeTracker.with( + context, + t => addMethodDeclaration(context, t, call, token, modifierFlags, parentDeclaration, declSourceFile), + ); + const actions = [ + createCodeFixAction( + fixMissingMember, + addMethodDeclarationChanges(modifierFlags & ModifierFlags.Static), + [ + modifierFlags & ModifierFlags.Static ? Diagnostics.Declare_static_method_0 + : Diagnostics.Declare_method_0, + methodName, + ], + fixMissingMember, + Diagnostics.Add_all_missing_members, + ), + ]; if (modifierFlags & ModifierFlags.Private) { - actions.unshift(createCodeFixActionWithoutFixAll(fixMissingMember, addMethodDeclarationChanges(ModifierFlags.Private), [Diagnostics.Declare_private_method_0, methodName])); + actions.unshift( + createCodeFixActionWithoutFixAll(fixMissingMember, addMethodDeclarationChanges(ModifierFlags.Private), [ + Diagnostics.Declare_private_method_0, + methodName, + ]), + ); } return actions; } @@ -441,7 +712,15 @@ namespace ts.codefix { ): void { const importAdder = createImportAdder(sourceFile, context.program, context.preferences, context.host); const kind = isClassLike(parentDeclaration) ? SyntaxKind.MethodDeclaration : SyntaxKind.MethodSignature; - const signatureDeclaration = createSignatureDeclarationFromCallExpression(kind, context, importAdder, callExpression, name, modifierFlags, parentDeclaration) as MethodDeclaration; + const signatureDeclaration = createSignatureDeclarationFromCallExpression( + kind, + context, + importAdder, + callExpression, + name, + modifierFlags, + parentDeclaration, + ) as MethodDeclaration; const containingMethodDeclaration = tryGetContainingMethodDeclaration(parentDeclaration, callExpression); if (containingMethodDeclaration) { changes.insertNodeAfter(sourceFile, containingMethodDeclaration, signatureDeclaration); @@ -452,7 +731,11 @@ namespace ts.codefix { importAdder.writeFixes(changes); } - function addEnumMemberDeclaration(changes: textChanges.ChangeTracker, checker: TypeChecker, { token, parentDeclaration }: EnumInfo) { + function addEnumMemberDeclaration( + changes: textChanges.ChangeTracker, + checker: TypeChecker, + { token, parentDeclaration }: EnumInfo, + ) { /** * create initializer only literal enum that has string initializer. * value of initializer is a string literal that equal to name of enum member. @@ -463,7 +746,10 @@ namespace ts.codefix { return !!(type && type.flags & TypeFlags.StringLike); }); - const enumMember = factory.createEnumMember(token, hasStringInitializer ? factory.createStringLiteral(token.text) : undefined); + const enumMember = factory.createEnumMember( + token, + hasStringInitializer ? factory.createStringLiteral(token.text) : undefined, + ); changes.replaceNode( parentDeclaration.getSourceFile(), parentDeclaration, @@ -480,61 +766,132 @@ namespace ts.codefix { ); } - function addFunctionDeclaration(changes: textChanges.ChangeTracker, context: CodeFixContextBase, info: FunctionInfo | SignatureInfo) { + function addFunctionDeclaration( + changes: textChanges.ChangeTracker, + context: CodeFixContextBase, + info: FunctionInfo | SignatureInfo, + ) { const quotePreference = getQuotePreference(context.sourceFile, context.preferences); const importAdder = createImportAdder(context.sourceFile, context.program, context.preferences, context.host); const functionDeclaration = info.kind === InfoKind.Function - ? createSignatureDeclarationFromCallExpression(SyntaxKind.FunctionDeclaration, context, importAdder, info.call, idText(info.token), info.modifierFlags, info.parentDeclaration) - : createSignatureDeclarationFromSignature(SyntaxKind.FunctionDeclaration, context, quotePreference, info.signature, createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), info.token, /*modifiers*/ undefined, /*optional*/ undefined, /*enclosingDeclaration*/ undefined, importAdder); + ? createSignatureDeclarationFromCallExpression( + SyntaxKind.FunctionDeclaration, + context, + importAdder, + info.call, + idText(info.token), + info.modifierFlags, + info.parentDeclaration, + ) + : createSignatureDeclarationFromSignature( + SyntaxKind.FunctionDeclaration, + context, + quotePreference, + info.signature, + createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), + info.token, + /*modifiers*/ undefined, + /*optional*/ undefined, + /*enclosingDeclaration*/ undefined, + importAdder, + ); if (functionDeclaration === undefined) { Debug.fail("fixMissingFunctionDeclaration codefix got unexpected error."); } isReturnStatement(info.parentDeclaration) - ? changes.insertNodeBefore(info.sourceFile, info.parentDeclaration, functionDeclaration, /*blankLineBetween*/ true) + ? changes.insertNodeBefore( + info.sourceFile, + info.parentDeclaration, + functionDeclaration, + /*blankLineBetween*/ true, + ) : changes.insertNodeAtEndOfScope(info.sourceFile, info.parentDeclaration, functionDeclaration); importAdder.writeFixes(changes); } - function addJsxAttributes(changes: textChanges.ChangeTracker, context: CodeFixContextBase, info: JsxAttributesInfo) { + function addJsxAttributes( + changes: textChanges.ChangeTracker, + context: CodeFixContextBase, + info: JsxAttributesInfo, + ) { const importAdder = createImportAdder(context.sourceFile, context.program, context.preferences, context.host); const quotePreference = getQuotePreference(context.sourceFile, context.preferences); const checker = context.program.getTypeChecker(); const jsxAttributesNode = info.parentDeclaration.attributes; const hasSpreadAttribute = some(jsxAttributesNode.properties, isJsxSpreadAttribute); const attrs = map(info.attributes, attr => { - const value = tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeOfSymbol(attr), info.parentDeclaration); + const value = tryGetValueFromType( + context, + checker, + importAdder, + quotePreference, + checker.getTypeOfSymbol(attr), + info.parentDeclaration, + ); const name = factory.createIdentifier(attr.name); - const jsxAttribute = factory.createJsxAttribute(name, factory.createJsxExpression(/*dotDotDotToken*/ undefined, value)); + const jsxAttribute = factory.createJsxAttribute( + name, + factory.createJsxExpression(/*dotDotDotToken*/ undefined, value), + ); // formattingScanner requires the Identifier to have a context for scanning attributes with "-" (data-foo). setParent(name, jsxAttribute); return jsxAttribute; }); - const jsxAttributes = factory.createJsxAttributes(hasSpreadAttribute ? [...attrs, ...jsxAttributesNode.properties] : [...jsxAttributesNode.properties, ...attrs]); + const jsxAttributes = factory.createJsxAttributes( + hasSpreadAttribute ? [...attrs, ...jsxAttributesNode.properties] + : [...jsxAttributesNode.properties, ...attrs], + ); const options = { prefix: jsxAttributesNode.pos === jsxAttributesNode.end ? " " : undefined }; changes.replaceNode(context.sourceFile, jsxAttributesNode, jsxAttributes, options); importAdder.writeFixes(changes); } - function addObjectLiteralProperties(changes: textChanges.ChangeTracker, context: CodeFixContextBase, info: ObjectLiteralInfo) { + function addObjectLiteralProperties( + changes: textChanges.ChangeTracker, + context: CodeFixContextBase, + info: ObjectLiteralInfo, + ) { const importAdder = createImportAdder(context.sourceFile, context.program, context.preferences, context.host); const quotePreference = getQuotePreference(context.sourceFile, context.preferences); const target = getEmitScriptTarget(context.program.getCompilerOptions()); const checker = context.program.getTypeChecker(); const props = map(info.properties, prop => { - const initializer = tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeOfSymbol(prop), info.parentDeclaration); - return factory.createPropertyAssignment(createPropertyNameFromSymbol(prop, target, quotePreference, checker), initializer); + const initializer = tryGetValueFromType( + context, + checker, + importAdder, + quotePreference, + checker.getTypeOfSymbol(prop), + info.parentDeclaration, + ); + return factory.createPropertyAssignment( + createPropertyNameFromSymbol(prop, target, quotePreference, checker), + initializer, + ); }); const options = { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, indentation: info.indentation, }; - changes.replaceNode(context.sourceFile, info.parentDeclaration, factory.createObjectLiteralExpression([...info.parentDeclaration.properties, ...props], /*multiLine*/ true), options); + changes.replaceNode( + context.sourceFile, + info.parentDeclaration, + factory.createObjectLiteralExpression([...info.parentDeclaration.properties, ...props], /*multiLine*/ true), + options, + ); importAdder.writeFixes(changes); } - function tryGetValueFromType(context: CodeFixContextBase, checker: TypeChecker, importAdder: ImportAdder, quotePreference: QuotePreference, type: Type, enclosingDeclaration: Node | undefined): Expression { + function tryGetValueFromType( + context: CodeFixContextBase, + checker: TypeChecker, + importAdder: ImportAdder, + quotePreference: QuotePreference, + type: Type, + enclosingDeclaration: Node | undefined, + ): Expression { if (type.flags & TypeFlags.AnyOrUnknown) { return createUndefined(); } @@ -551,9 +908,16 @@ namespace ts.codefix { return factory.createFalse(); } if (type.flags & TypeFlags.EnumLike) { - const enumMember = type.symbol.exports ? firstOrUndefined(arrayFrom(type.symbol.exports.values())) : type.symbol; - const name = checker.symbolToExpression(type.symbol.parent ? type.symbol.parent : type.symbol, SymbolFlags.Value, /*enclosingDeclaration*/ undefined, /*flags*/ undefined); - return enumMember === undefined || name === undefined ? factory.createNumericLiteral(0) : factory.createPropertyAccessExpression(name, checker.symbolToString(enumMember)); + const enumMember = type.symbol.exports ? firstOrUndefined(arrayFrom(type.symbol.exports.values())) + : type.symbol; + const name = checker.symbolToExpression( + type.symbol.parent ? type.symbol.parent : type.symbol, + SymbolFlags.Value, + /*enclosingDeclaration*/ undefined, + /*flags*/ undefined, + ); + return enumMember === undefined || name === undefined ? factory.createNumericLiteral(0) + : factory.createPropertyAccessExpression(name, checker.symbolToString(enumMember)); } if (type.flags & TypeFlags.NumberLiteral) { return factory.createNumericLiteral((type as NumberLiteralType).value); @@ -562,16 +926,23 @@ namespace ts.codefix { return factory.createBigIntLiteral((type as BigIntLiteralType).value); } if (type.flags & TypeFlags.StringLiteral) { - return factory.createStringLiteral((type as StringLiteralType).value, /* isSingleQuote */ quotePreference === QuotePreference.Single); + return factory.createStringLiteral( + (type as StringLiteralType).value, + /* isSingleQuote */ quotePreference === QuotePreference.Single, + ); } if (type.flags & TypeFlags.BooleanLiteral) { - return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) ? factory.createFalse() : factory.createTrue(); + return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) + ? factory.createFalse() : factory.createTrue(); } if (type.flags & TypeFlags.Null) { return factory.createNull(); } if (type.flags & TypeFlags.Union) { - const expression = firstDefined((type as UnionType).types, t => tryGetValueFromType(context, checker, importAdder, quotePreference, t, enclosingDeclaration)); + const expression = firstDefined( + (type as UnionType).types, + t => tryGetValueFromType(context, checker, importAdder, quotePreference, t, enclosingDeclaration), + ); return expression ?? createUndefined(); } if (checker.isArrayLikeType(type)) { @@ -579,19 +950,41 @@ namespace ts.codefix { } if (isObjectLiteralType(type)) { const props = map(checker.getPropertiesOfType(type), prop => { - const initializer = prop.valueDeclaration ? tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeAtLocation(prop.valueDeclaration), enclosingDeclaration) : createUndefined(); + const initializer = prop.valueDeclaration + ? tryGetValueFromType( + context, + checker, + importAdder, + quotePreference, + checker.getTypeAtLocation(prop.valueDeclaration), + enclosingDeclaration, + ) : createUndefined(); return factory.createPropertyAssignment(prop.name, initializer); }); return factory.createObjectLiteralExpression(props, /*multiLine*/ true); } if (getObjectFlags(type) & ObjectFlags.Anonymous) { - const decl = find(type.symbol.declarations || emptyArray, or(isFunctionTypeNode, isMethodSignature, isMethodDeclaration)); + const decl = find( + type.symbol.declarations || emptyArray, + or(isFunctionTypeNode, isMethodSignature, isMethodDeclaration), + ); if (decl === undefined) return createUndefined(); const signature = checker.getSignaturesOfType(type, SignatureKind.Call); if (signature === undefined) return createUndefined(); - const func = createSignatureDeclarationFromSignature(SyntaxKind.FunctionExpression, context, quotePreference, signature[0], createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), /*name*/ undefined, /*modifiers*/ undefined, /*optional*/ undefined, /*enclosingDeclaration*/ enclosingDeclaration, importAdder) as FunctionExpression | undefined; + const func = createSignatureDeclarationFromSignature( + SyntaxKind.FunctionExpression, + context, + quotePreference, + signature[0], + createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), + /*name*/ undefined, + /*modifiers*/ undefined, + /*optional*/ undefined, + /*enclosingDeclaration*/ enclosingDeclaration, + importAdder, + ) as FunctionExpression | undefined; return func ?? createUndefined(); } if (getObjectFlags(type) & ObjectFlags.Class) { @@ -601,7 +994,11 @@ namespace ts.codefix { const constructorDeclaration = getFirstConstructorWithBody(classDeclaration); if (constructorDeclaration && length(constructorDeclaration.parameters)) return createUndefined(); - return factory.createNewExpression(factory.createIdentifier(type.symbol.name), /*typeArguments*/ undefined, /*argumentsArray*/ undefined); + return factory.createNewExpression( + factory.createIdentifier(type.symbol.name), + /*typeArguments*/ undefined, + /*argumentsArray*/ undefined, + ); } return createUndefined(); } @@ -611,8 +1008,9 @@ namespace ts.codefix { } function isObjectLiteralType(type: Type) { - return (type.flags & TypeFlags.Object) && - ((getObjectFlags(type) & ObjectFlags.ObjectLiteral) || (type.symbol && tryCast(singleOrUndefined(type.symbol.declarations), isTypeLiteralNode))); + return (type.flags & TypeFlags.Object) + && ((getObjectFlags(type) & ObjectFlags.ObjectLiteral) + || (type.symbol && tryCast(singleOrUndefined(type.symbol.declarations), isTypeLiteralNode))); } function getUnmatchedAttributes(checker: TypeChecker, target: ScriptTarget, source: JsxOpeningLikeElement) { @@ -634,10 +1032,19 @@ namespace ts.codefix { } } } - return filter(targetProps, targetProp => isIdentifierText(targetProp.name, target, LanguageVariant.JSX) && !((targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial) || seenNames.has(targetProp.escapedName))); + return filter( + targetProps, + targetProp => + isIdentifierText(targetProp.name, target, LanguageVariant.JSX) + && !((targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial) + || seenNames.has(targetProp.escapedName)), + ); } - function tryGetContainingMethodDeclaration(node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, callExpression: CallExpression) { + function tryGetContainingMethodDeclaration( + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + callExpression: CallExpression, + ) { if (isTypeLiteralNode(node)) { return undefined; } @@ -645,12 +1052,26 @@ namespace ts.codefix { return declaration && declaration.parent === node ? declaration : undefined; } - function createPropertyNameFromSymbol(symbol: Symbol, target: ScriptTarget, quotePreference: QuotePreference, checker: TypeChecker) { + function createPropertyNameFromSymbol( + symbol: Symbol, + target: ScriptTarget, + quotePreference: QuotePreference, + checker: TypeChecker, + ) { if (isTransientSymbol(symbol)) { - const prop = checker.symbolToNode(symbol, SymbolFlags.Value, /*enclosingDeclaration*/ undefined, NodeBuilderFlags.WriteComputedProps); + const prop = checker.symbolToNode( + symbol, + SymbolFlags.Value, + /*enclosingDeclaration*/ undefined, + NodeBuilderFlags.WriteComputedProps, + ); if (prop && isComputedPropertyName(prop)) return prop; } - return createPropertyNameNodeForIdentifierOrLiteral(symbol.name, target, quotePreference === QuotePreference.Single); + return createPropertyNameNodeForIdentifierOrLiteral( + symbol.name, + target, + quotePreference === QuotePreference.Single, + ); } function findScope(node: Node) { diff --git a/src/services/codefixes/fixAddMissingNewOperator.ts b/src/services/codefixes/fixAddMissingNewOperator.ts index 4a292f657b0e3..40aac64fb3cc9 100644 --- a/src/services/codefixes/fixAddMissingNewOperator.ts +++ b/src/services/codefixes/fixAddMissingNewOperator.ts @@ -7,10 +7,23 @@ namespace ts.codefix { getCodeActions(context) { const { sourceFile, span } = context; const changes = textChanges.ChangeTracker.with(context, t => addMissingNewOperator(t, sourceFile, span)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_missing_new_operator_to_call, fixId, Diagnostics.Add_missing_new_operator_to_all_calls)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_missing_new_operator_to_call, + fixId, + Diagnostics.Add_missing_new_operator_to_all_calls, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => addMissingNewOperator(changes, context.sourceFile, diag)), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => addMissingNewOperator(changes, context.sourceFile, diag), + ), }); function addMissingNewOperator(changes: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan): void { diff --git a/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts b/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts index 62e026e4e6437..f1eb68f0f6ff3 100644 --- a/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts +++ b/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts @@ -2,7 +2,9 @@ namespace ts.codefix { const fixIdAddMissingTypeof = "fixAddModuleReferTypeMissingTypeof"; const fixId = fixIdAddMissingTypeof; - const errorCodes = [Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0.code]; + const errorCodes = [ + Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0.code, + ]; registerCodeFix({ errorCodes, @@ -10,10 +12,23 @@ namespace ts.codefix { const { sourceFile, span } = context; const importType = getImportTypeNode(sourceFile, span.start); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, importType)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_missing_typeof, fixId, Diagnostics.Add_missing_typeof)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_missing_typeof, + fixId, + Diagnostics.Add_missing_typeof, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, context.sourceFile, getImportTypeNode(diag.file, diag.start))), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => doChange(changes, context.sourceFile, getImportTypeNode(diag.file, diag.start)), + ), }); function getImportTypeNode(sourceFile: SourceFile, pos: number): ImportTypeNode { @@ -24,7 +39,14 @@ namespace ts.codefix { } function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importType: ImportTypeNode) { - const newTypeNode = factory.updateImportTypeNode(importType, importType.argument, importType.assertions, importType.qualifier, importType.typeArguments, /* isTypeOf */ true); + const newTypeNode = factory.updateImportTypeNode( + importType, + importType.argument, + importType.assertions, + importType.qualifier, + importType.typeArguments, + /* isTypeOf */ true, + ); changes.replaceNode(sourceFile, importType, newTypeNode); } } diff --git a/src/services/codefixes/fixAddVoidToPromise.ts b/src/services/codefixes/fixAddVoidToPromise.ts index d11838cdddef2..4f45afe2da883 100644 --- a/src/services/codefixes/fixAddVoidToPromise.ts +++ b/src/services/codefixes/fixAddVoidToPromise.ts @@ -3,26 +3,52 @@ namespace ts.codefix { const fixName = "addVoidToPromise"; const fixId = "addVoidToPromise"; const errorCodes = [ - Diagnostics.Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments.code, + Diagnostics + .Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments + .code, Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise.code, ]; registerCodeFix({ errorCodes, fixIds: [fixId], getCodeActions(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span, context.program)); + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span, context.program), + ); if (changes.length > 0) { - return [createCodeFixAction(fixName, changes, Diagnostics.Add_void_to_Promise_resolved_without_a_value, fixId, Diagnostics.Add_void_to_all_Promises_resolved_without_a_value)]; + return [ + createCodeFixAction( + fixName, + changes, + Diagnostics.Add_void_to_Promise_resolved_without_a_value, + fixId, + Diagnostics.Add_void_to_all_Promises_resolved_without_a_value, + ), + ]; } }, getAllCodeActions(context: CodeFixAllContext) { - return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag, context.program, new Set())); + return codeFixAll( + context, + errorCodes, + (changes, diag) => makeChange(changes, diag.file, diag, context.program, new Set()), + ); }, }); - function makeChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan, program: Program, seen?: Set) { + function makeChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + span: TextSpan, + program: Program, + seen?: Set, + ) { const node = getTokenAtPosition(sourceFile, span.start); - if (!isIdentifier(node) || !isCallExpression(node.parent) || node.parent.expression !== node || node.parent.arguments.length !== 0) return; + if ( + !isIdentifier(node) || !isCallExpression(node.parent) || node.parent.expression !== node + || node.parent.arguments.length !== 0 + ) return; const checker = program.getTypeChecker(); const symbol = checker.getSymbolAtLocation(node); @@ -39,8 +65,11 @@ namespace ts.codefix { if (some(typeArguments)) { // append ` | void` to type argument const typeArgument = typeArguments[0]; - const needsParens = !isUnionTypeNode(typeArgument) && !isParenthesizedTypeNode(typeArgument) && - isParenthesizedTypeNode(factory.createUnionTypeNode([typeArgument, factory.createKeywordTypeNode(SyntaxKind.VoidKeyword)]).types[0]); + const needsParens = !isUnionTypeNode(typeArgument) && !isParenthesizedTypeNode(typeArgument) + && isParenthesizedTypeNode( + factory.createUnionTypeNode([typeArgument, factory.createKeywordTypeNode(SyntaxKind.VoidKeyword)]) + .types[0], + ); if (needsParens) { changes.insertText(sourceFile, typeArgument.pos, "("); } @@ -55,7 +84,11 @@ namespace ts.codefix { if (!parameterType || parameterType.flags & TypeFlags.AnyOrUnknown) { // give the expression a type changes.insertText(sourceFile, decl.parent.parent.end, `)`); - changes.insertText(sourceFile, skipTrivia(sourceFile.text, decl.parent.parent.pos), `/** @type {Promise} */(`); + changes.insertText( + sourceFile, + skipTrivia(sourceFile.text, decl.parent.parent.pos), + `/** @type {Promise} */(`, + ); } } else { @@ -71,7 +104,10 @@ namespace ts.codefix { if (isInJSFile(node)) { if (isParenthesizedExpression(node.parent)) { const jsDocType = getJSDocTypeTag(node.parent)?.typeExpression.type; - if (jsDocType && isTypeReferenceNode(jsDocType) && isIdentifier(jsDocType.typeName) && idText(jsDocType.typeName) === "Promise") { + if ( + jsDocType && isTypeReferenceNode(jsDocType) && isIdentifier(jsDocType.typeName) + && idText(jsDocType.typeName) === "Promise" + ) { return jsDocType.typeArguments; } } diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts index 48573f554ef90..258c7b087c70b 100644 --- a/src/services/codefixes/fixAwaitInSyncFunction.ts +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -13,7 +13,15 @@ namespace ts.codefix { const nodes = getNodes(sourceFile, span.start); if (!nodes) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, nodes)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_async_modifier_to_containing_function, fixId, Diagnostics.Add_all_missing_async_modifiers)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_async_modifier_to_containing_function, + fixId, + Diagnostics.Add_all_missing_async_modifiers, + ), + ]; }, fixIds: [fixId], getAllCodeActions: function getAllCodeActionsToFixAwaitInSyncFunction(context) { @@ -31,15 +39,18 @@ namespace ts.codefix { return expr.type; } if ( - isVariableDeclaration(expr.parent) && - expr.parent.type && - isFunctionTypeNode(expr.parent.type) + isVariableDeclaration(expr.parent) + && expr.parent.type + && isFunctionTypeNode(expr.parent.type) ) { return expr.parent.type.type; } } - function getNodes(sourceFile: SourceFile, start: number): { insertBefore: Node; returnType: TypeNode | undefined; } | undefined { + function getNodes( + sourceFile: SourceFile, + start: number, + ): { insertBefore: Node; returnType: TypeNode | undefined; } | undefined { const token = getTokenAtPosition(sourceFile, start); const containingFunction = getContainingFunction(token); if (!containingFunction) { @@ -57,7 +68,8 @@ namespace ts.codefix { break; case SyntaxKind.ArrowFunction: const kind = containingFunction.typeParameters ? SyntaxKind.LessThanToken : SyntaxKind.OpenParenToken; - insertBefore = findChildOfKind(containingFunction, kind, sourceFile) || first(containingFunction.parameters); + insertBefore = findChildOfKind(containingFunction, kind, sourceFile) + || first(containingFunction.parameters); break; default: return; @@ -77,7 +89,11 @@ namespace ts.codefix { if (returnType) { const entityName = getEntityNameFromTypeNode(returnType); if (!entityName || entityName.kind !== SyntaxKind.Identifier || entityName.text !== "Promise") { - changes.replaceNode(sourceFile, returnType, factory.createTypeReferenceNode("Promise", factory.createNodeArray([returnType]))); + changes.replaceNode( + sourceFile, + returnType, + factory.createTypeReferenceNode("Promise", factory.createNodeArray([returnType])), + ); } } changes.insertModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, insertBefore); diff --git a/src/services/codefixes/fixCannotFindModule.ts b/src/services/codefixes/fixCannotFindModule.ts index 98c4f058d3f4f..4497a1246c51c 100644 --- a/src/services/codefixes/fixCannotFindModule.ts +++ b/src/services/codefixes/fixCannotFindModule.ts @@ -17,7 +17,14 @@ namespace ts.codefix { const typesPackageName = getTypesPackageNameToInstall(packageName, host, context.errorCode); return typesPackageName === undefined ? [] - : [createCodeFixAction(fixName, /*changes*/ [], [Diagnostics.Install_0, typesPackageName], fixIdInstallTypesPackage, Diagnostics.Install_all_missing_types_packages, getInstallCommand(sourceFile.fileName, typesPackageName))]; + : [createCodeFixAction( + fixName, + /*changes*/ [], + [Diagnostics.Install_0, typesPackageName], + fixIdInstallTypesPackage, + Diagnostics.Install_all_missing_types_packages, + getInstallCommand(sourceFile.fileName, typesPackageName), + )]; }, fixIds: [fixIdInstallTypesPackage], getAllCodeActions: context => { @@ -51,7 +58,11 @@ namespace ts.codefix { return isExternalModuleNameRelative(packageName) ? undefined : packageName; } - function getTypesPackageNameToInstall(packageName: string, host: LanguageServiceHost, diagCode: number): string | undefined { + function getTypesPackageNameToInstall( + packageName: string, + host: LanguageServiceHost, + diagCode: number, + ): string | undefined { return diagCode === errorCodeCannotFindModule ? (JsTyping.nodeCoreModules.has(packageName) ? "@types/node" : undefined) : (host.isKnownTypesPackageName?.(packageName) ? getTypesPackageName(packageName) : undefined); diff --git a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts index 162a7e0da442e..6e2d4d3e0f1a5 100644 --- a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts +++ b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts @@ -9,8 +9,18 @@ namespace ts.codefix { errorCodes, getCodeActions: function getCodeActionsToFixClassNotImplementingInheritedMembers(context) { const { sourceFile, span } = context; - const changes = textChanges.ChangeTracker.with(context, t => addMissingMembers(getClass(sourceFile, span.start), sourceFile, context, t, context.preferences)); - return changes.length === 0 ? undefined : [createCodeFixAction(fixId, changes, Diagnostics.Implement_inherited_abstract_class, fixId, Diagnostics.Implement_all_inherited_abstract_classes)]; + const changes = textChanges.ChangeTracker.with( + context, + t => addMissingMembers(getClass(sourceFile, span.start), sourceFile, context, t, context.preferences), + ); + return changes.length === 0 ? undefined + : [createCodeFixAction( + fixId, + changes, + Diagnostics.Implement_inherited_abstract_class, + fixId, + Diagnostics.Implement_all_inherited_abstract_classes, + )]; }, fixIds: [fixId], getAllCodeActions: function getAllCodeActionsToFixClassDoesntImplementInheritedAbstractMember(context) { @@ -31,17 +41,33 @@ namespace ts.codefix { return cast(token.parent, isClassLike); } - function addMissingMembers(classDeclaration: ClassLikeDeclaration, sourceFile: SourceFile, context: TypeConstructionContext, changeTracker: textChanges.ChangeTracker, preferences: UserPreferences): void { + function addMissingMembers( + classDeclaration: ClassLikeDeclaration, + sourceFile: SourceFile, + context: TypeConstructionContext, + changeTracker: textChanges.ChangeTracker, + preferences: UserPreferences, + ): void { const extendsNode = getEffectiveBaseTypeNode(classDeclaration)!; const checker = context.program.getTypeChecker(); const instantiatedExtendsType = checker.getTypeAtLocation(extendsNode); // Note that this is ultimately derived from a map indexed by symbol names, // so duplicates cannot occur. - const abstractAndNonPrivateExtendsSymbols = checker.getPropertiesOfType(instantiatedExtendsType).filter(symbolPointsToNonPrivateAndAbstractMember); + const abstractAndNonPrivateExtendsSymbols = checker.getPropertiesOfType(instantiatedExtendsType).filter( + symbolPointsToNonPrivateAndAbstractMember, + ); const importAdder = createImportAdder(sourceFile, context.program, preferences, context.host); - createMissingMemberNodes(classDeclaration, abstractAndNonPrivateExtendsSymbols, sourceFile, context, preferences, importAdder, member => changeTracker.insertMemberAtStart(sourceFile, classDeclaration, member as ClassElement)); + createMissingMemberNodes( + classDeclaration, + abstractAndNonPrivateExtendsSymbols, + sourceFile, + context, + preferences, + importAdder, + member => changeTracker.insertMemberAtStart(sourceFile, classDeclaration, member as ClassElement), + ); importAdder.writeFixes(changeTracker); } diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index d01f1287c6946..9ccd3426a5aec 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -2,7 +2,8 @@ namespace ts.codefix { const errorCodes = [ Diagnostics.Class_0_incorrectly_implements_interface_1.code, - Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code, + Diagnostics + .Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code, ]; const fixId = "fixClassIncorrectlyImplementsInterface"; // TODO: share a group with fixClassDoesntImplementInheritedAbstractMember? registerCodeFix({ @@ -10,10 +11,28 @@ namespace ts.codefix { getCodeActions(context) { const { sourceFile, span } = context; const classDeclaration = getClass(sourceFile, span.start); - return mapDefined(getEffectiveImplementsTypeNodes(classDeclaration), implementedTypeNode => { - const changes = textChanges.ChangeTracker.with(context, t => addMissingDeclarations(context, implementedTypeNode, sourceFile, classDeclaration, t, context.preferences)); - return changes.length === 0 ? undefined : createCodeFixAction(fixId, changes, [Diagnostics.Implement_interface_0, implementedTypeNode.getText(sourceFile)], fixId, Diagnostics.Implement_all_unimplemented_interfaces); - }); + return mapDefined( + getEffectiveImplementsTypeNodes(classDeclaration), + implementedTypeNode => { + const changes = textChanges.ChangeTracker.with(context, t => + addMissingDeclarations( + context, + implementedTypeNode, + sourceFile, + classDeclaration, + t, + context.preferences, + )); + return changes.length === 0 ? undefined + : createCodeFixAction( + fixId, + changes, + [Diagnostics.Implement_interface_0, implementedTypeNode.getText(sourceFile)], + fixId, + Diagnostics.Implement_all_unimplemented_interfaces, + ); + }, + ); }, fixIds: [fixId], getAllCodeActions(context) { @@ -22,7 +41,14 @@ namespace ts.codefix { const classDeclaration = getClass(diag.file, diag.start); if (addToSeen(seenClassDeclarations, getNodeId(classDeclaration))) { for (const implementedTypeNode of getEffectiveImplementsTypeNodes(classDeclaration)!) { - addMissingDeclarations(context, implementedTypeNode, diag.file, classDeclaration, changes, context.preferences); + addMissingDeclarations( + context, + implementedTypeNode, + diag.file, + classDeclaration, + changes, + context.preferences, + ); } } }); @@ -30,11 +56,15 @@ namespace ts.codefix { }); function getClass(sourceFile: SourceFile, pos: number): ClassLikeDeclaration { - return Debug.checkDefined(getContainingClass(getTokenAtPosition(sourceFile, pos)), "There should be a containing class"); + return Debug.checkDefined( + getContainingClass(getTokenAtPosition(sourceFile, pos)), + "There should be a containing class", + ); } function symbolPointsToNonPrivateMember(symbol: Symbol) { - return !symbol.valueDeclaration || !(getEffectiveModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private); + return !symbol.valueDeclaration + || !(getEffectiveModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private); } function addMissingDeclarations( @@ -51,7 +81,9 @@ namespace ts.codefix { // so duplicates cannot occur. const implementedType = checker.getTypeAtLocation(implementedTypeNode) as InterfaceType; const implementedTypeSymbols = checker.getPropertiesOfType(implementedType); - const nonPrivateAndNotExistedInHeritageClauseMembers = implementedTypeSymbols.filter(and(symbolPointsToNonPrivateMember, symbol => !maybeHeritageClauseSymbol.has(symbol.escapedName))); + const nonPrivateAndNotExistedInHeritageClauseMembers = implementedTypeSymbols.filter( + and(symbolPointsToNonPrivateMember, symbol => !maybeHeritageClauseSymbol.has(symbol.escapedName)), + ); const classType = checker.getTypeAtLocation(classDeclaration); const constructor = find(classDeclaration.members, m => isConstructorDeclaration(m)); @@ -64,18 +96,39 @@ namespace ts.codefix { } const importAdder = createImportAdder(sourceFile, context.program, preferences, context.host); - createMissingMemberNodes(classDeclaration, nonPrivateAndNotExistedInHeritageClauseMembers, sourceFile, context, preferences, importAdder, member => insertInterfaceMemberNode(sourceFile, classDeclaration, member as ClassElement)); + createMissingMemberNodes( + classDeclaration, + nonPrivateAndNotExistedInHeritageClauseMembers, + sourceFile, + context, + preferences, + importAdder, + member => insertInterfaceMemberNode(sourceFile, classDeclaration, member as ClassElement), + ); importAdder.writeFixes(changeTracker); function createMissingIndexSignatureDeclaration(type: InterfaceType, kind: IndexKind): void { const indexInfoOfKind = checker.getIndexInfoOfType(type, kind); if (indexInfoOfKind) { - insertInterfaceMemberNode(sourceFile, classDeclaration, checker.indexInfoToIndexSignatureDeclaration(indexInfoOfKind, classDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context))!); + insertInterfaceMemberNode( + sourceFile, + classDeclaration, + checker.indexInfoToIndexSignatureDeclaration( + indexInfoOfKind, + classDeclaration, + /*flags*/ undefined, + getNoopSymbolTrackerWithResolver(context), + )!, + ); } } // Either adds the node at the top of the class, or if there's a constructor right after that - function insertInterfaceMemberNode(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration, newElement: ClassElement): void { + function insertInterfaceMemberNode( + sourceFile: SourceFile, + cls: ClassLikeDeclaration | InterfaceDeclaration, + newElement: ClassElement, + ): void { if (constructor) { changeTracker.insertNodeAfter(sourceFile, constructor, newElement); } diff --git a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts index 05a56ee975e67..98ea3102e903f 100644 --- a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts +++ b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts @@ -1,7 +1,9 @@ /* @internal */ namespace ts.codefix { const fixId = "classSuperMustPrecedeThisAccess"; - const errorCodes = [Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class.code]; + const errorCodes = [ + Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class.code, + ]; registerCodeFix({ errorCodes, getCodeActions(context) { @@ -9,8 +11,19 @@ namespace ts.codefix { const nodes = getNodes(sourceFile, span.start); if (!nodes) return undefined; const { constructor, superCall } = nodes; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, constructor, superCall)); - return [createCodeFixAction(fixId, changes, Diagnostics.Make_super_call_the_first_statement_in_the_constructor, fixId, Diagnostics.Make_all_super_calls_the_first_statement_in_their_constructor)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, sourceFile, constructor, superCall), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Make_super_call_the_first_statement_in_the_constructor, + fixId, + Diagnostics.Make_all_super_calls_the_first_statement_in_their_constructor, + ), + ]; }, fixIds: [fixId], getAllCodeActions(context) { @@ -27,19 +40,30 @@ namespace ts.codefix { }, }); - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, constructor: ConstructorDeclaration, superCall: ExpressionStatement): void { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + constructor: ConstructorDeclaration, + superCall: ExpressionStatement, + ): void { changes.insertNodeAtConstructorStart(sourceFile, constructor, superCall); changes.delete(sourceFile, superCall); } - function getNodes(sourceFile: SourceFile, pos: number): { readonly constructor: ConstructorDeclaration; readonly superCall: ExpressionStatement; } | undefined { + function getNodes( + sourceFile: SourceFile, + pos: number, + ): { readonly constructor: ConstructorDeclaration; readonly superCall: ExpressionStatement; } | undefined { const token = getTokenAtPosition(sourceFile, pos); if (token.kind !== SyntaxKind.ThisKeyword) return undefined; const constructor = getContainingFunction(token) as ConstructorDeclaration; const superCall = findSuperCall(constructor.body!); // figure out if the `this` access is actually inside the supercall // i.e. super(this.a), since in that case we won't suggest a fix - return superCall && !superCall.expression.arguments.some(arg => isPropertyAccessExpression(arg) && arg.expression === token) ? { constructor, superCall } : undefined; + return superCall + && !superCall.expression.arguments.some(arg => + isPropertyAccessExpression(arg) && arg.expression === token + ) ? { constructor, superCall } : undefined; } function findSuperCall(n: Node): ExpressionStatement & { expression: CallExpression; } | undefined { diff --git a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts index 382ddb0a0162d..219eec261f533 100644 --- a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts +++ b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts @@ -8,10 +8,23 @@ namespace ts.codefix { const { sourceFile, span } = context; const ctr = getNode(sourceFile, span.start); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, ctr)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_missing_super_call, fixId, Diagnostics.Add_all_missing_super_calls)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_missing_super_call, + fixId, + Diagnostics.Add_all_missing_super_calls, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, context.sourceFile, getNode(diag.file, diag.start))), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => doChange(changes, context.sourceFile, getNode(diag.file, diag.start)), + ), }); function getNode(sourceFile: SourceFile, pos: number): ConstructorDeclaration { @@ -21,7 +34,13 @@ namespace ts.codefix { } function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, ctr: ConstructorDeclaration) { - const superCall = factory.createExpressionStatement(factory.createCallExpression(factory.createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ emptyArray)); + const superCall = factory.createExpressionStatement( + factory.createCallExpression( + factory.createSuper(), + /*typeArguments*/ undefined, + /*argumentsArray*/ emptyArray, + ), + ); changes.insertNodeAtConstructorStart(sourceFile, ctr, superCall); } } diff --git a/src/services/codefixes/fixEnableExperimentalDecorators.ts b/src/services/codefixes/fixEnableExperimentalDecorators.ts index 295aeebc6aa0b..6d51cf8608e13 100644 --- a/src/services/codefixes/fixEnableExperimentalDecorators.ts +++ b/src/services/codefixes/fixEnableExperimentalDecorators.ts @@ -2,7 +2,9 @@ namespace ts.codefix { const fixId = "enableExperimentalDecorators"; const errorCodes = [ - Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_in_your_tsconfig_or_jsconfig_to_remove_this_warning.code, + Diagnostics + .Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_in_your_tsconfig_or_jsconfig_to_remove_this_warning + .code, ]; registerCodeFix({ errorCodes, @@ -12,8 +14,17 @@ namespace ts.codefix { return undefined; } - const changes = textChanges.ChangeTracker.with(context, changeTracker => doChange(changeTracker, configFile)); - return [createCodeFixActionWithoutFixAll(fixId, changes, Diagnostics.Enable_the_experimentalDecorators_option_in_your_configuration_file)]; + const changes = textChanges.ChangeTracker.with( + context, + changeTracker => doChange(changeTracker, configFile), + ); + return [ + createCodeFixActionWithoutFixAll( + fixId, + changes, + Diagnostics.Enable_the_experimentalDecorators_option_in_your_configuration_file, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => diff --git a/src/services/codefixes/fixEnableJsxFlag.ts b/src/services/codefixes/fixEnableJsxFlag.ts index 2ebcb16ada5f6..bf3a5f055ec6e 100644 --- a/src/services/codefixes/fixEnableJsxFlag.ts +++ b/src/services/codefixes/fixEnableJsxFlag.ts @@ -10,9 +10,16 @@ namespace ts.codefix { return undefined; } - const changes = textChanges.ChangeTracker.with(context, changeTracker => doChange(changeTracker, configFile)); + const changes = textChanges.ChangeTracker.with( + context, + changeTracker => doChange(changeTracker, configFile), + ); return [ - createCodeFixActionWithoutFixAll(fixID, changes, Diagnostics.Enable_the_jsx_flag_in_your_configuration_file), + createCodeFixActionWithoutFixAll( + fixID, + changes, + Diagnostics.Enable_the_jsx_flag_in_your_configuration_file, + ), ]; }, fixIds: [fixID], diff --git a/src/services/codefixes/fixExpectedComma.ts b/src/services/codefixes/fixExpectedComma.ts index 2470ee4814e7e..96db8351f3b9a 100644 --- a/src/services/codefixes/fixExpectedComma.ts +++ b/src/services/codefixes/fixExpectedComma.ts @@ -36,10 +36,10 @@ namespace ts.codefix { function getInfo(sourceFile: SourceFile, pos: number, _: number): Info | undefined { const node = getTokenAtPosition(sourceFile, pos); - return (node.kind === SyntaxKind.SemicolonToken && - node.parent && - (isObjectLiteralExpression(node.parent) || - isArrayLiteralExpression(node.parent))) ? { node } : undefined; + return (node.kind === SyntaxKind.SemicolonToken + && node.parent + && (isObjectLiteralExpression(node.parent) + || isArrayLiteralExpression(node.parent))) ? { node } : undefined; } function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { node }: Info): void { diff --git a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts index 3c20bf9b8774c..e8125c1d11711 100644 --- a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts +++ b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts @@ -9,8 +9,19 @@ namespace ts.codefix { const nodes = getNodes(sourceFile, context.span.start); if (!nodes) return undefined; const { extendsToken, heritageClauses } = nodes; - const changes = textChanges.ChangeTracker.with(context, t => doChanges(t, sourceFile, extendsToken, heritageClauses)); - return [createCodeFixAction(fixId, changes, Diagnostics.Change_extends_to_implements, fixId, Diagnostics.Change_all_extended_interfaces_to_implements)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChanges(t, sourceFile, extendsToken, heritageClauses), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Change_extends_to_implements, + fixId, + Diagnostics.Change_all_extended_interfaces_to_implements, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -27,18 +38,27 @@ namespace ts.codefix { return extendsToken.kind === SyntaxKind.ExtendsKeyword ? { extendsToken, heritageClauses } : undefined; } - function doChanges(changes: textChanges.ChangeTracker, sourceFile: SourceFile, extendsToken: Node, heritageClauses: readonly HeritageClause[]): void { + function doChanges( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + extendsToken: Node, + heritageClauses: readonly HeritageClause[], + ): void { changes.replaceNode(sourceFile, extendsToken, factory.createToken(SyntaxKind.ImplementsKeyword)); // If there is already an implements clause, replace the implements keyword with a comma. if ( - heritageClauses.length === 2 && - heritageClauses[0].token === SyntaxKind.ExtendsKeyword && - heritageClauses[1].token === SyntaxKind.ImplementsKeyword + heritageClauses.length === 2 + && heritageClauses[0].token === SyntaxKind.ExtendsKeyword + && heritageClauses[1].token === SyntaxKind.ImplementsKeyword ) { const implementsToken = heritageClauses[1].getFirstToken()!; const implementsFullStart = implementsToken.getFullStart(); - changes.replaceRange(sourceFile, { pos: implementsFullStart, end: implementsFullStart }, factory.createToken(SyntaxKind.CommaToken)); + changes.replaceRange( + sourceFile, + { pos: implementsFullStart, end: implementsFullStart }, + factory.createToken(SyntaxKind.CommaToken), + ); // Rough heuristic: delete trailing whitespace after keyword so that it's not excessive. // (Trailing because leading might be indentation, which is more sensitive.) diff --git a/src/services/codefixes/fixForgottenThisPropertyAccess.ts b/src/services/codefixes/fixForgottenThisPropertyAccess.ts index 4ef1913bc0790..ce007aa5d703c 100644 --- a/src/services/codefixes/fixForgottenThisPropertyAccess.ts +++ b/src/services/codefixes/fixForgottenThisPropertyAccess.ts @@ -4,7 +4,9 @@ namespace ts.codefix { const didYouMeanStaticMemberCode = Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0.code; const errorCodes = [ Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code, - Diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression.code, + Diagnostics + .Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression + .code, didYouMeanStaticMemberCode, ]; registerCodeFix({ @@ -16,7 +18,15 @@ namespace ts.codefix { return undefined; } const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Add_0_to_unresolved_variable, info.className || "this"], fixId, Diagnostics.Add_qualifier_to_all_unresolved_variables_matching_a_member_name)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Add_0_to_unresolved_variable, info.className || "this"], + fixId, + Diagnostics.Add_qualifier_to_all_unresolved_variables_matching_a_member_name, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -34,13 +44,23 @@ namespace ts.codefix { function getInfo(sourceFile: SourceFile, pos: number, diagCode: number): Info | undefined { const node = getTokenAtPosition(sourceFile, pos); if (isIdentifier(node) || isPrivateIdentifier(node)) { - return { node, className: diagCode === didYouMeanStaticMemberCode ? getContainingClass(node)!.name!.text : undefined }; + return { + node, + className: diagCode === didYouMeanStaticMemberCode ? getContainingClass(node)!.name!.text : undefined, + }; } } function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { node, className }: Info): void { // TODO (https://github.com/Microsoft/TypeScript/issues/21246): use shared helper suppressLeadingAndTrailingTrivia(node); - changes.replaceNode(sourceFile, node, factory.createPropertyAccessExpression(className ? factory.createIdentifier(className) : factory.createThis(), node)); + changes.replaceNode( + sourceFile, + node, + factory.createPropertyAccessExpression( + className ? factory.createIdentifier(className) : factory.createThis(), + node, + ), + ); } } diff --git a/src/services/codefixes/fixImplicitThis.ts b/src/services/codefixes/fixImplicitThis.ts index 96735b1f69e44..115eee1476916 100644 --- a/src/services/codefixes/fixImplicitThis.ts +++ b/src/services/codefixes/fixImplicitThis.ts @@ -10,7 +10,9 @@ namespace ts.codefix { const changes = textChanges.ChangeTracker.with(context, t => { diagnostic = doChange(t, sourceFile, span.start, program.getTypeChecker()); }); - return diagnostic ? [createCodeFixAction(fixId, changes, diagnostic, fixId, Diagnostics.Fix_all_implicit_this_errors)] : emptyArray; + return diagnostic + ? [createCodeFixAction(fixId, changes, diagnostic, fixId, Diagnostics.Fix_all_implicit_this_errors)] + : emptyArray; }, fixIds: [fixId], getAllCodeActions: context => @@ -19,7 +21,12 @@ namespace ts.codefix { }), }); - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, checker: TypeChecker): DiagnosticAndArguments | undefined { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + pos: number, + checker: TypeChecker, + ): DiagnosticAndArguments | undefined { const token = getTokenAtPosition(sourceFile, pos); if (!isThis(token)) return undefined; diff --git a/src/services/codefixes/fixImportNonExportedMember.ts b/src/services/codefixes/fixImportNonExportedMember.ts index cfc4346a5f9e9..dc2fb5f961b0d 100644 --- a/src/services/codefixes/fixImportNonExportedMember.ts +++ b/src/services/codefixes/fixImportNonExportedMember.ts @@ -14,7 +14,15 @@ namespace ts.codefix { if (info === undefined) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, program, info)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Export_0_from_module_1, info.exportName.node.text, info.moduleSpecifier], fixId, Diagnostics.Export_all_referenced_locals)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Export_0_from_module_1, info.exportName.node.text, info.moduleSpecifier], + fixId, + Diagnostics.Export_all_referenced_locals, + ), + ]; }, getAllCodeActions(context) { const { program } = context; @@ -26,7 +34,10 @@ namespace ts.codefix { if (info === undefined) return undefined; const { exportName, node, moduleSourceFile } = info; - if (tryGetExportDeclaration(moduleSourceFile, exportName.isTypeOnly) === undefined && canHaveExportModifier(node)) { + if ( + tryGetExportDeclaration(moduleSourceFile, exportName.isTypeOnly) === undefined + && canHaveExportModifier(node) + ) { changes.insertExportModifier(moduleSourceFile, node); } else { @@ -45,10 +56,19 @@ namespace ts.codefix { const exportDeclaration = tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ true); if (exportDeclaration && exportDeclaration.isTypeOnly) { doChanges(changes, program, moduleSourceFile, moduleExports.typeOnlyExports, exportDeclaration); - doChanges(changes, program, moduleSourceFile, moduleExports.exports, tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ false)); + doChanges( + changes, + program, + moduleSourceFile, + moduleExports.exports, + tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ false), + ); } else { - doChanges(changes, program, moduleSourceFile, [...moduleExports.exports, ...moduleExports.typeOnlyExports], exportDeclaration); + doChanges(changes, program, moduleSourceFile, [ + ...moduleExports.exports, + ...moduleExports.typeOnlyExports, + ], exportDeclaration); } }); })); @@ -78,7 +98,8 @@ namespace ts.codefix { const importDeclaration = findAncestor(token, isImportDeclaration); if (importDeclaration === undefined) return undefined; - const moduleSpecifier = isStringLiteral(importDeclaration.moduleSpecifier) ? importDeclaration.moduleSpecifier.text : undefined; + const moduleSpecifier = isStringLiteral(importDeclaration.moduleSpecifier) + ? importDeclaration.moduleSpecifier.text : undefined; if (moduleSpecifier === undefined) return undefined; const resolvedModule = getResolvedModule(sourceFile, moduleSpecifier, /*mode*/ undefined); @@ -103,7 +124,11 @@ namespace ts.codefix { return undefined; } - function doChange(changes: textChanges.ChangeTracker, program: Program, { exportName, node, moduleSourceFile }: Info) { + function doChange( + changes: textChanges.ChangeTracker, + program: Program, + { exportName, node, moduleSourceFile }: Info, + ) { const exportDeclaration = tryGetExportDeclaration(moduleSourceFile, exportName.isTypeOnly); if (exportDeclaration) { updateExport(changes, program, moduleSourceFile, exportDeclaration, [exportName]); @@ -116,7 +141,13 @@ namespace ts.codefix { } } - function doChanges(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, moduleExports: ExportName[], node: ExportDeclaration | undefined) { + function doChanges( + changes: textChanges.ChangeTracker, + program: Program, + sourceFile: SourceFile, + moduleExports: ExportName[], + node: ExportDeclaration | undefined, + ) { if (length(moduleExports)) { if (node) { updateExport(changes, program, sourceFile, node, moduleExports); @@ -128,13 +159,22 @@ namespace ts.codefix { } function tryGetExportDeclaration(sourceFile: SourceFile, isTypeOnly: boolean) { - const predicate = (node: Node): node is ExportDeclaration => isExportDeclaration(node) && (isTypeOnly && node.isTypeOnly || !node.isTypeOnly); + const predicate = (node: Node): node is ExportDeclaration => + isExportDeclaration(node) && (isTypeOnly && node.isTypeOnly || !node.isTypeOnly); return findLast(sourceFile.statements, predicate); } - function updateExport(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, node: ExportDeclaration, names: ExportName[]) { - const namedExports = node.exportClause && isNamedExports(node.exportClause) ? node.exportClause.elements : factory.createNodeArray([]); - const allowTypeModifier = !node.isTypeOnly && !!(program.getCompilerOptions().isolatedModules || find(namedExports, e => e.isTypeOnly)); + function updateExport( + changes: textChanges.ChangeTracker, + program: Program, + sourceFile: SourceFile, + node: ExportDeclaration, + names: ExportName[], + ) { + const namedExports = node.exportClause && isNamedExports(node.exportClause) ? node.exportClause.elements + : factory.createNodeArray([]); + const allowTypeModifier = !node.isTypeOnly + && !!(program.getCompilerOptions().isolatedModules || find(namedExports, e => e.isTypeOnly)); changes.replaceNode( sourceFile, node, @@ -143,7 +183,10 @@ namespace ts.codefix { node.modifiers, node.isTypeOnly, factory.createNamedExports( - factory.createNodeArray([...namedExports, ...createExportSpecifiers(names, allowTypeModifier)], /*hasTrailingComma*/ namedExports.hasTrailingComma), + factory.createNodeArray( + [...namedExports, ...createExportSpecifiers(names, allowTypeModifier)], + /*hasTrailingComma*/ namedExports.hasTrailingComma, + ), ), node.moduleSpecifier, node.assertClause, @@ -151,12 +194,38 @@ namespace ts.codefix { ); } - function createExport(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, names: ExportName[]) { - changes.insertNodeAtEndOfScope(sourceFile, sourceFile, factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createNamedExports(createExportSpecifiers(names, /*allowTypeModifier*/ !!program.getCompilerOptions().isolatedModules)), /*moduleSpecifier*/ undefined, /*assertClause*/ undefined)); + function createExport( + changes: textChanges.ChangeTracker, + program: Program, + sourceFile: SourceFile, + names: ExportName[], + ) { + changes.insertNodeAtEndOfScope( + sourceFile, + sourceFile, + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports( + createExportSpecifiers(names, /*allowTypeModifier*/ !!program.getCompilerOptions().isolatedModules), + ), + /*moduleSpecifier*/ undefined, + /*assertClause*/ undefined, + ), + ); } function createExportSpecifiers(names: ExportName[], allowTypeModifier: boolean) { - return factory.createNodeArray(map(names, n => factory.createExportSpecifier(allowTypeModifier && n.isTypeOnly, /*propertyName*/ undefined, n.node))); + return factory.createNodeArray( + map( + names, + n => factory.createExportSpecifier( + allowTypeModifier && n.isTypeOnly, + /*propertyName*/ undefined, + n.node, + ), + ), + ); } function getNodeOfSymbol(symbol: Symbol) { @@ -164,7 +233,9 @@ namespace ts.codefix { return firstOrUndefined(symbol.declarations); } const declaration = symbol.valueDeclaration; - const variableStatement = isVariableDeclaration(declaration) ? tryCast(declaration.parent.parent, isVariableStatement) : undefined; - return variableStatement && length(variableStatement.declarationList.declarations) === 1 ? variableStatement : declaration; + const variableStatement = isVariableDeclaration(declaration) + ? tryCast(declaration.parent.parent, isVariableStatement) : undefined; + return variableStatement && length(variableStatement.declarationList.declarations) === 1 ? variableStatement + : declaration; } } diff --git a/src/services/codefixes/fixIncorrectNamedTupleSyntax.ts b/src/services/codefixes/fixIncorrectNamedTupleSyntax.ts index 59d78a36faac2..0c2fea2d8e037 100644 --- a/src/services/codefixes/fixIncorrectNamedTupleSyntax.ts +++ b/src/services/codefixes/fixIncorrectNamedTupleSyntax.ts @@ -2,7 +2,9 @@ namespace ts.codefix { const fixId = "fixIncorrectNamedTupleSyntax"; const errorCodes = [ - Diagnostics.A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type.code, + Diagnostics + .A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type + .code, Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type.code, ]; @@ -12,7 +14,15 @@ namespace ts.codefix { const { sourceFile, span } = context; const namedTupleMember = getNamedTupleMember(sourceFile, span.start); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, namedTupleMember)); - return [createCodeFixAction(fixId, changes, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels, fixId, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Move_labeled_tuple_element_modifiers_to_labels, + fixId, + Diagnostics.Move_labeled_tuple_element_modifiers_to_labels, + ), + ]; }, fixIds: [fixId], }); @@ -28,7 +38,10 @@ namespace ts.codefix { let unwrappedType = namedTupleMember.type; let sawOptional = false; let sawRest = false; - while (unwrappedType.kind === SyntaxKind.OptionalType || unwrappedType.kind === SyntaxKind.RestType || unwrappedType.kind === SyntaxKind.ParenthesizedType) { + while ( + unwrappedType.kind === SyntaxKind.OptionalType || unwrappedType.kind === SyntaxKind.RestType + || unwrappedType.kind === SyntaxKind.ParenthesizedType + ) { if (unwrappedType.kind === SyntaxKind.OptionalType) { sawOptional = true; } diff --git a/src/services/codefixes/fixInvalidImportSyntax.ts b/src/services/codefixes/fixInvalidImportSyntax.ts index f1d4f92c138f4..7ee55ba1c7ecd 100644 --- a/src/services/codefixes/fixInvalidImportSyntax.ts +++ b/src/services/codefixes/fixInvalidImportSyntax.ts @@ -9,7 +9,19 @@ namespace ts.codefix { const variations: CodeFixAction[] = []; // import Bluebird from "bluebird"; - variations.push(createAction(context, sourceFile, node, makeImport(namespace.name, /*namedImports*/ undefined, node.moduleSpecifier, getQuotePreference(sourceFile, context.preferences)))); + variations.push( + createAction( + context, + sourceFile, + node, + makeImport( + namespace.name, + /*namedImports*/ undefined, + node.moduleSpecifier, + getQuotePreference(sourceFile, context.preferences), + ), + ), + ); if (getEmitModuleKind(opts) === ModuleKind.CommonJS) { // import Bluebird = require("bluebird"); @@ -29,9 +41,17 @@ namespace ts.codefix { return variations; } - function createAction(context: CodeFixContext, sourceFile: SourceFile, node: Node, replacement: Node): CodeFixAction { + function createAction( + context: CodeFixContext, + sourceFile: SourceFile, + node: Node, + replacement: Node, + ): CodeFixAction { const changes = textChanges.ChangeTracker.with(context, t => t.replaceNode(sourceFile, node, replacement)); - return createCodeFixActionWithoutFixAll(fixName, changes, [Diagnostics.Replace_import_with_0, changes[0].textChanges[0].newText]); + return createCodeFixActionWithoutFixAll(fixName, changes, [ + Diagnostics.Replace_import_with_0, + changes[0].textChanges[0].newText, + ]); } registerCodeFix({ @@ -44,8 +64,11 @@ namespace ts.codefix { function getActionsForUsageOfInvalidImport(context: CodeFixContext): CodeFixAction[] | undefined { const sourceFile = context.sourceFile; - const targetKind = Diagnostics.This_expression_is_not_callable.code === context.errorCode ? SyntaxKind.CallExpression : SyntaxKind.NewExpression; - const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.kind === targetKind) as CallExpression | NewExpression; + const targetKind = Diagnostics.This_expression_is_not_callable.code === context.errorCode + ? SyntaxKind.CallExpression : SyntaxKind.NewExpression; + const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.kind === targetKind) as + | CallExpression + | NewExpression; if (!node) { return []; } @@ -59,7 +82,9 @@ namespace ts.codefix { Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code, Diagnostics.Type_0_does_not_satisfy_the_constraint_1.code, Diagnostics.Type_0_is_not_assignable_to_type_1.code, - Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated.code, + Diagnostics + .Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated + .code, Diagnostics.Type_predicate_0_is_not_assignable_to_1.code, Diagnostics.Property_0_of_type_1_is_not_assignable_to_2_index_type_3.code, Diagnostics._0_index_type_1_is_not_assignable_to_2_index_type_3.code, @@ -73,7 +98,10 @@ namespace ts.codefix { function getActionsForInvalidImportLocation(context: CodeFixContext): CodeFixAction[] | undefined { const sourceFile = context.sourceFile; - const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length)); + const node = findAncestor( + getTokenAtPosition(sourceFile, context.span.start), + a => a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length), + ); if (!node) { return []; } @@ -92,7 +120,10 @@ namespace ts.codefix { } if (isExpression(expr) && !(isNamedDeclaration(expr.parent) && expr.parent.name === expr)) { const sourceFile = context.sourceFile; - const changes = textChanges.ChangeTracker.with(context, t => t.replaceNode(sourceFile, expr, factory.createPropertyAccessExpression(expr, "default"), {})); + const changes = textChanges.ChangeTracker.with( + context, + t => t.replaceNode(sourceFile, expr, factory.createPropertyAccessExpression(expr, "default"), {}), + ); fixes.push(createCodeFixActionWithoutFixAll(fixName, changes, Diagnostics.Use_synthetic_default_member)); } return fixes; diff --git a/src/services/codefixes/fixInvalidJsxCharacters.ts b/src/services/codefixes/fixInvalidJsxCharacters.ts index b6167c1048ea6..3221dbbd6c9af 100644 --- a/src/services/codefixes/fixInvalidJsxCharacters.ts +++ b/src/services/codefixes/fixInvalidJsxCharacters.ts @@ -13,16 +13,45 @@ namespace ts.codefix { fixIds: [fixIdExpression, fixIdHtmlEntity], getCodeActions(context) { const { sourceFile, preferences, span } = context; - const changeToExpression = textChanges.ChangeTracker.with(context, t => doChange(t, preferences, sourceFile, span.start, /* useHtmlEntity */ false)); - const changeToHtmlEntity = textChanges.ChangeTracker.with(context, t => doChange(t, preferences, sourceFile, span.start, /* useHtmlEntity */ true)); + const changeToExpression = textChanges.ChangeTracker.with( + context, + t => doChange(t, preferences, sourceFile, span.start, /* useHtmlEntity */ false), + ); + const changeToHtmlEntity = textChanges.ChangeTracker.with( + context, + t => doChange(t, preferences, sourceFile, span.start, /* useHtmlEntity */ true), + ); return [ - createCodeFixAction(fixIdExpression, changeToExpression, Diagnostics.Wrap_invalid_character_in_an_expression_container, fixIdExpression, Diagnostics.Wrap_all_invalid_characters_in_an_expression_container), - createCodeFixAction(fixIdHtmlEntity, changeToHtmlEntity, Diagnostics.Convert_invalid_character_to_its_html_entity_code, fixIdHtmlEntity, Diagnostics.Convert_all_invalid_characters_to_HTML_entity_code), + createCodeFixAction( + fixIdExpression, + changeToExpression, + Diagnostics.Wrap_invalid_character_in_an_expression_container, + fixIdExpression, + Diagnostics.Wrap_all_invalid_characters_in_an_expression_container, + ), + createCodeFixAction( + fixIdHtmlEntity, + changeToHtmlEntity, + Diagnostics.Convert_invalid_character_to_its_html_entity_code, + fixIdHtmlEntity, + Diagnostics.Convert_all_invalid_characters_to_HTML_entity_code, + ), ]; }, getAllCodeActions(context) { - return codeFixAll(context, errorCodes, (changes, diagnostic) => doChange(changes, context.preferences, diagnostic.file, diagnostic.start, context.fixId === fixIdHtmlEntity)); + return codeFixAll( + context, + errorCodes, + (changes, diagnostic) => + doChange( + changes, + context.preferences, + diagnostic.file, + diagnostic.start, + context.fixId === fixIdHtmlEntity, + ), + ); }, }); @@ -35,7 +64,13 @@ namespace ts.codefix { return hasProperty(htmlEntity, character); } - function doChange(changes: textChanges.ChangeTracker, preferences: UserPreferences, sourceFile: SourceFile, start: number, useHtmlEntity: boolean) { + function doChange( + changes: textChanges.ChangeTracker, + preferences: UserPreferences, + sourceFile: SourceFile, + start: number, + useHtmlEntity: boolean, + ) { const character = sourceFile.getText()[start]; // sanity check if (!isValidCharacter(character)) { diff --git a/src/services/codefixes/fixJSDocTypes.ts b/src/services/codefixes/fixJSDocTypes.ts index 5168a004e87e4..49b075292704d 100644 --- a/src/services/codefixes/fixJSDocTypes.ts +++ b/src/services/codefixes/fixJSDocTypes.ts @@ -16,13 +16,28 @@ namespace ts.codefix { if (typeNode.kind === SyntaxKind.JSDocNullableType) { // for nullable types, suggest the flow-compatible `T | null | undefined` // in addition to the jsdoc/closure-compatible `T | null` - actions.push(fix(checker.getNullableType(type, TypeFlags.Undefined), fixIdNullable, Diagnostics.Change_all_jsdoc_style_types_to_TypeScript_and_add_undefined_to_nullable_types)); + actions.push( + fix( + checker.getNullableType(type, TypeFlags.Undefined), + fixIdNullable, + Diagnostics.Change_all_jsdoc_style_types_to_TypeScript_and_add_undefined_to_nullable_types, + ), + ); } return actions; function fix(type: Type, fixId: string, fixAllDescription: DiagnosticMessage): CodeFixAction { - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, typeNode, type, checker)); - return createCodeFixAction("jdocTypes", changes, [Diagnostics.Change_0_to_1, original, checker.typeToString(type)], fixId, fixAllDescription); + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, sourceFile, typeNode, type, checker), + ); + return createCodeFixAction( + "jdocTypes", + changes, + [Diagnostics.Change_0_to_1, original, checker.typeToString(type)], + fixId, + fixAllDescription, + ); } }, fixIds: [fixIdPlain, fixIdNullable], @@ -33,24 +48,55 @@ namespace ts.codefix { const info = getInfo(err.file, err.start, checker); if (!info) return; const { typeNode, type } = info; - const fixedType = typeNode.kind === SyntaxKind.JSDocNullableType && fixId === fixIdNullable ? checker.getNullableType(type, TypeFlags.Undefined) : type; + const fixedType = typeNode.kind === SyntaxKind.JSDocNullableType && fixId === fixIdNullable + ? checker.getNullableType(type, TypeFlags.Undefined) : type; doChange(changes, sourceFile, typeNode, fixedType, checker); }); }, }); - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, oldTypeNode: TypeNode, newType: Type, checker: TypeChecker): void { - changes.replaceNode(sourceFile, oldTypeNode, checker.typeToTypeNode(newType, /*enclosingDeclaration*/ oldTypeNode, /*flags*/ undefined)!); // TODO: GH#18217 + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + oldTypeNode: TypeNode, + newType: Type, + checker: TypeChecker, + ): void { + changes.replaceNode( + sourceFile, + oldTypeNode, + checker.typeToTypeNode(newType, /*enclosingDeclaration*/ oldTypeNode, /*flags*/ undefined)!, + ); // TODO: GH#18217 } - function getInfo(sourceFile: SourceFile, pos: number, checker: TypeChecker): { readonly typeNode: TypeNode; readonly type: Type; } | undefined { + function getInfo( + sourceFile: SourceFile, + pos: number, + checker: TypeChecker, + ): { readonly typeNode: TypeNode; readonly type: Type; } | undefined { const decl = findAncestor(getTokenAtPosition(sourceFile, pos), isTypeContainer); const typeNode = decl && decl.type; return typeNode && { typeNode, type: checker.getTypeFromTypeNode(typeNode) }; } // TODO: GH#19856 Node & { type: TypeNode } - type TypeContainer = AsExpression | CallSignatureDeclaration | ConstructSignatureDeclaration | FunctionDeclaration | GetAccessorDeclaration | IndexSignatureDeclaration | MappedTypeNode | MethodDeclaration | MethodSignature | ParameterDeclaration | PropertyDeclaration | PropertySignature | SetAccessorDeclaration | TypeAliasDeclaration | TypeAssertion | VariableDeclaration; + type TypeContainer = + | AsExpression + | CallSignatureDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration + | GetAccessorDeclaration + | IndexSignatureDeclaration + | MappedTypeNode + | MethodDeclaration + | MethodSignature + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature + | SetAccessorDeclaration + | TypeAliasDeclaration + | TypeAssertion + | VariableDeclaration; function isTypeContainer(node: Node): node is TypeContainer { // NOTE: Some locations are not handled yet: // MappedTypeNode.typeParameters and SignatureDeclaration.typeParameters, as well as CallExpression.typeArguments diff --git a/src/services/codefixes/fixMissingCallParentheses.ts b/src/services/codefixes/fixMissingCallParentheses.ts index aea042f45222a..930abfeec93f8 100644 --- a/src/services/codefixes/fixMissingCallParentheses.ts +++ b/src/services/codefixes/fixMissingCallParentheses.ts @@ -2,7 +2,9 @@ namespace ts.codefix { const fixId = "fixMissingCallParentheses"; const errorCodes = [ - Diagnostics.This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead.code, + Diagnostics + .This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead + .code, ]; registerCodeFix({ @@ -14,7 +16,15 @@ namespace ts.codefix { if (!callName) return; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, callName)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_missing_call_parentheses, fixId, Diagnostics.Add_all_missing_call_parentheses)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_missing_call_parentheses, + fixId, + Diagnostics.Add_all_missing_call_parentheses, + ), + ]; }, getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { @@ -23,7 +33,11 @@ namespace ts.codefix { }), }); - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, name: Identifier | PrivateIdentifier): void { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + name: Identifier | PrivateIdentifier, + ): void { changes.replaceNodeWithText(sourceFile, name, `${name.text}()`); } diff --git a/src/services/codefixes/fixModuleAndTargetOptions.ts b/src/services/codefixes/fixModuleAndTargetOptions.ts index d151d020b7611..5a14ce223e04b 100644 --- a/src/services/codefixes/fixModuleAndTargetOptions.ts +++ b/src/services/codefixes/fixModuleAndTargetOptions.ts @@ -2,8 +2,12 @@ namespace ts.codefix { registerCodeFix({ errorCodes: [ - Diagnostics.Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher.code, - Diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher.code, + Diagnostics + .Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher + .code, + Diagnostics + .Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher + .code, ], getCodeActions: function getCodeActionsToFixModuleAndTarget(context) { const compilerOptions = context.program.getCompilerOptions(); @@ -19,7 +23,12 @@ namespace ts.codefix { const changes = textChanges.ChangeTracker.with(context, changes => { setJsonCompilerOptionValue(changes, configFile, "module", factory.createStringLiteral("esnext")); }); - codeFixes.push(createCodeFixActionWithoutFixAll("fixModuleOption", changes, [Diagnostics.Set_the_module_option_in_your_configuration_file_to_0, "esnext"])); + codeFixes.push( + createCodeFixActionWithoutFixAll("fixModuleOption", changes, [ + Diagnostics.Set_the_module_option_in_your_configuration_file_to_0, + "esnext", + ]), + ); } const target = getEmitScriptTarget(compilerOptions); @@ -38,7 +47,12 @@ namespace ts.codefix { setJsonCompilerOptionValues(tracker, configFile, options); }); - codeFixes.push(createCodeFixActionWithoutFixAll("fixTargetOption", changes, [Diagnostics.Set_the_target_option_in_your_configuration_file_to_0, "es2017"])); + codeFixes.push( + createCodeFixActionWithoutFixAll("fixTargetOption", changes, [ + Diagnostics.Set_the_target_option_in_your_configuration_file_to_0, + "es2017", + ]), + ); } return codeFixes.length ? codeFixes : undefined; diff --git a/src/services/codefixes/fixNaNEquality.ts b/src/services/codefixes/fixNaNEquality.ts index 9acc9be1fbc76..4fbbc0fec4445 100644 --- a/src/services/codefixes/fixNaNEquality.ts +++ b/src/services/codefixes/fixNaNEquality.ts @@ -14,7 +14,15 @@ namespace ts.codefix { const { suggestion, expression, arg } = info; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, arg, expression)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Use_0, suggestion], fixId, Diagnostics.Use_Number_isNaN_in_all_conditions)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Use_0, suggestion], + fixId, + Diagnostics.Use_Number_isNaN_in_all_conditions, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => { @@ -34,11 +42,17 @@ namespace ts.codefix { } function getInfo(program: Program, sourceFile: SourceFile, span: TextSpan): Info | undefined { - const diag = find(program.getSemanticDiagnostics(sourceFile), diag => diag.start === span.start && diag.length === span.length); + const diag = find( + program.getSemanticDiagnostics(sourceFile), + diag => diag.start === span.start && diag.length === span.length, + ); if (diag === undefined || diag.relatedInformation === undefined) return; const related = find(diag.relatedInformation, related => related.code === Diagnostics.Did_you_mean_0.code); - if (related === undefined || related.file === undefined || related.start === undefined || related.length === undefined) return; + if ( + related === undefined || related.file === undefined || related.start === undefined + || related.length === undefined + ) return; const token = findAncestorMatchingSpan(related.file, createTextSpan(related.start, related.length)); if (token === undefined) return; @@ -49,9 +63,17 @@ namespace ts.codefix { return undefined; } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, arg: Expression, expression: BinaryExpression) { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + arg: Expression, + expression: BinaryExpression, + ) { const callExpression = factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier("Number"), factory.createIdentifier("isNaN")), + factory.createPropertyAccessExpression( + factory.createIdentifier("Number"), + factory.createIdentifier("isNaN"), + ), /*typeArguments*/ undefined, [arg], ); diff --git a/src/services/codefixes/fixNoPropertyAccessFromIndexSignature.ts b/src/services/codefixes/fixNoPropertyAccessFromIndexSignature.ts index 0e95e5e3757fb..4b10028df85de 100644 --- a/src/services/codefixes/fixNoPropertyAccessFromIndexSignature.ts +++ b/src/services/codefixes/fixNoPropertyAccessFromIndexSignature.ts @@ -11,21 +11,51 @@ namespace ts.codefix { getCodeActions(context) { const { sourceFile, span, preferences } = context; const property = getPropertyAccessExpression(sourceFile, span.start); - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, property, preferences)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Use_element_access_for_0, property.name.text], fixId, Diagnostics.Use_element_access_for_all_undeclared_properties)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, context.sourceFile, property, preferences), + ); + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Use_element_access_for_0, property.name.text], + fixId, + Diagnostics.Use_element_access_for_all_undeclared_properties, + ), + ]; }, - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, getPropertyAccessExpression(diag.file, diag.start), context.preferences)), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => + doChange( + changes, + diag.file, + getPropertyAccessExpression(diag.file, diag.start), + context.preferences, + ), + ), }); - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: PropertyAccessExpression, preferences: UserPreferences): void { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: PropertyAccessExpression, + preferences: UserPreferences, + ): void { const quotePreference = getQuotePreference(sourceFile, preferences); - const argumentsExpression = factory.createStringLiteral(node.name.text, quotePreference === QuotePreference.Single); + const argumentsExpression = factory.createStringLiteral( + node.name.text, + quotePreference === QuotePreference.Single, + ); changes.replaceNode( sourceFile, node, - isPropertyAccessChain(node) ? - factory.createElementAccessChain(node.expression, node.questionDotToken, argumentsExpression) : - factory.createElementAccessExpression(node.expression, argumentsExpression), + isPropertyAccessChain(node) + ? factory.createElementAccessChain(node.expression, node.questionDotToken, argumentsExpression) + : factory.createElementAccessExpression(node.expression, argumentsExpression), ); } diff --git a/src/services/codefixes/fixOverrideModifier.ts b/src/services/codefixes/fixOverrideModifier.ts index 62b891e8cd53d..c231fc0b4db56 100644 --- a/src/services/codefixes/fixOverrideModifier.ts +++ b/src/services/codefixes/fixOverrideModifier.ts @@ -14,14 +14,27 @@ namespace ts.codefix { const errorCodes = [ Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0.code, - Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code, - Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code, + Diagnostics + .This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class + .code, + Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0 + .code, Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code, - Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code, - Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code, - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class.code, - Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code, - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0.code, + Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 + .code, + Diagnostics + .This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code, + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class + .code, + Diagnostics + .This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code, + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 + .code, ]; interface ErrorCodeFixInfo { @@ -32,51 +45,81 @@ namespace ts.codefix { const errorCodeFixIdMap: Record = { // case #1: - [Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code]: { - descriptions: Diagnostics.Add_override_modifier, - fixId: fixAddOverrideId, - fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers, - }, - [Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code]: { + [Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code]: + { + descriptions: Diagnostics.Add_override_modifier, + fixId: fixAddOverrideId, + fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers, + }, + [ + Diagnostics + .This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code + ]: { descriptions: Diagnostics.Add_override_modifier, fixId: fixAddOverrideId, fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers, }, // case #2: - [Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code]: { + [ + Diagnostics + .This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class + .code + ]: { descriptions: Diagnostics.Remove_override_modifier, fixId: fixRemoveOverrideId, fixAllDescriptions: Diagnostics.Remove_all_unnecessary_override_modifiers, }, - [Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class.code]: { + [ + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class + .code + ]: { descriptions: Diagnostics.Remove_override_modifier, fixId: fixRemoveOverrideId, fixAllDescriptions: Diagnostics.Remove_override_modifier, }, // case #3: - [Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code]: { + [ + Diagnostics + .This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 + .code + ]: { descriptions: Diagnostics.Add_override_modifier, fixId: fixAddOverrideId, fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers, }, - [Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code]: { + [ + Diagnostics + .This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code + ]: { descriptions: Diagnostics.Add_override_modifier, fixId: fixAddOverrideId, fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers, }, // case #4: - [Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code]: { + [ + Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0 + .code + ]: { descriptions: Diagnostics.Add_override_modifier, fixId: fixAddOverrideId, fixAllDescriptions: Diagnostics.Remove_all_unnecessary_override_modifiers, }, // case #5: - [Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0.code]: { - descriptions: Diagnostics.Remove_override_modifier, - fixId: fixRemoveOverrideId, - fixAllDescriptions: Diagnostics.Remove_all_unnecessary_override_modifiers, - }, - [Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0.code]: { + [Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0.code]: + { + descriptions: Diagnostics.Remove_override_modifier, + fixId: fixRemoveOverrideId, + fixAllDescriptions: Diagnostics.Remove_all_unnecessary_override_modifiers, + }, + [ + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 + .code + ]: { descriptions: Diagnostics.Remove_override_modifier, fixId: fixRemoveOverrideId, fixAllDescriptions: Diagnostics.Remove_all_unnecessary_override_modifiers, @@ -92,7 +135,10 @@ namespace ts.codefix { if (!info) return emptyArray; const { descriptions, fixId, fixAllDescriptions } = info; - const changes = textChanges.ChangeTracker.with(context, changes => dispatchChanges(changes, context, errorCode, span.start)); + const changes = textChanges.ChangeTracker.with( + context, + changes => dispatchChanges(changes, context, errorCode, span.start), + ); return [ createCodeFixActionMaybeFixAll(fixName, changes, descriptions, fixId, fixAllDescriptions), @@ -118,26 +164,48 @@ namespace ts.codefix { pos: number, ) { switch (errorCode) { - case Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code: - case Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code: - case Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code: - case Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code: - case Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code: + case Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code: + case Diagnostics + .This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code: + case Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0 + .code: + case Diagnostics + .This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 + .code: + case Diagnostics + .This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code: return doAddOverrideModifierChange(changeTracker, context.sourceFile, pos); - case Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0.code: - case Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0.code: - case Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code: - case Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class.code: + case Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0 + .code: + case Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 + .code: + case Diagnostics + .This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class + .code: + case Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class + .code: return doRemoveOverrideModifierChange(changeTracker, context.sourceFile, pos); default: Debug.fail("Unexpected error code: " + errorCode); } } - function doAddOverrideModifierChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { + function doAddOverrideModifierChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + pos: number, + ) { const classElement = findContainerClassElementLike(sourceFile, pos); if (isSourceFileJS(sourceFile)) { - changeTracker.addJSDocTags(sourceFile, classElement, [factory.createJSDocOverrideTag(factory.createIdentifier("override"))]); + changeTracker.addJSDocTags(sourceFile, classElement, [ + factory.createJSDocOverrideTag(factory.createIdentifier("override")), + ]); return; } const modifiers = classElement.modifiers || emptyArray; @@ -145,15 +213,19 @@ namespace ts.codefix { const abstractModifier = find(modifiers, isAbstractModifier); const accessibilityModifier = find(modifiers, m => isAccessibilityModifier(m.kind)); const lastDecorator = findLast(modifiers, isDecorator); - const modifierPos = abstractModifier ? abstractModifier.end : - staticModifier ? staticModifier.end : - accessibilityModifier ? accessibilityModifier.end : - lastDecorator ? skipTrivia(sourceFile.text, lastDecorator.end) : classElement.getStart(sourceFile); + const modifierPos = abstractModifier ? abstractModifier.end + : staticModifier ? staticModifier.end + : accessibilityModifier ? accessibilityModifier.end + : lastDecorator ? skipTrivia(sourceFile.text, lastDecorator.end) : classElement.getStart(sourceFile); const options = accessibilityModifier || staticModifier || abstractModifier ? { prefix: " " } : { suffix: " " }; changeTracker.insertModifierAt(sourceFile, modifierPos, SyntaxKind.OverrideKeyword, options); } - function doRemoveOverrideModifierChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { + function doRemoveOverrideModifierChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + pos: number, + ) { const classElement = findContainerClassElementLike(sourceFile, pos); if (isSourceFileJS(sourceFile)) { changeTracker.filterJSDocTags(sourceFile, classElement, not(isJSDocOverrideTag)); diff --git a/src/services/codefixes/fixPropertyAssignment.ts b/src/services/codefixes/fixPropertyAssignment.ts index f5c5718be31f9..48d47f5fb3cf6 100644 --- a/src/services/codefixes/fixPropertyAssignment.ts +++ b/src/services/codefixes/fixPropertyAssignment.ts @@ -2,7 +2,9 @@ namespace ts.codefix { const fixId = "fixPropertyAssignment"; const errorCodes = [ - Diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern.code, + Diagnostics + .Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern + .code, ]; registerCodeFix({ @@ -12,13 +14,32 @@ namespace ts.codefix { const { sourceFile, span } = context; const property = getProperty(sourceFile, span.start); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, property)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Change_0_to_1, "=", ":"], fixId, [Diagnostics.Switch_each_misused_0_to_1, "=", ":"])]; + return [ + createCodeFixAction(fixId, changes, [Diagnostics.Change_0_to_1, "=", ":"], fixId, [ + Diagnostics.Switch_each_misused_0_to_1, + "=", + ":", + ]), + ]; }, - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, getProperty(diag.file, diag.start))), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => doChange(changes, diag.file, getProperty(diag.file, diag.start)), + ), }); - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: ShorthandPropertyAssignment): void { - changes.replaceNode(sourceFile, node, factory.createPropertyAssignment(node.name, node.objectAssignmentInitializer as Expression)); + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: ShorthandPropertyAssignment, + ): void { + changes.replaceNode( + sourceFile, + node, + factory.createPropertyAssignment(node.name, node.objectAssignmentInitializer as Expression), + ); } function getProperty(sourceFile: SourceFile, pos: number): ShorthandPropertyAssignment { diff --git a/src/services/codefixes/fixPropertyOverrideAccessor.ts b/src/services/codefixes/fixPropertyOverrideAccessor.ts index 7623511ab8859..88a8122334f56 100644 --- a/src/services/codefixes/fixPropertyOverrideAccessor.ts +++ b/src/services/codefixes/fixPropertyOverrideAccessor.ts @@ -8,9 +8,23 @@ namespace ts.codefix { registerCodeFix({ errorCodes, getCodeActions(context) { - const edits = doChange(context.sourceFile, context.span.start, context.span.length, context.errorCode, context); + const edits = doChange( + context.sourceFile, + context.span.start, + context.span.length, + context.errorCode, + context, + ); if (edits) { - return [createCodeFixAction(fixId, edits, Diagnostics.Generate_get_and_set_accessors, fixId, Diagnostics.Generate_get_and_set_accessors_for_all_overriding_properties)]; + return [ + createCodeFixAction( + fixId, + edits, + Diagnostics.Generate_get_and_set_accessors, + fixId, + Diagnostics.Generate_get_and_set_accessors_for_all_overriding_properties, + ), + ]; } }, fixIds: [fixId], @@ -26,14 +40,26 @@ namespace ts.codefix { }), }); - function doChange(file: SourceFile, start: number, length: number, code: number, context: CodeFixContext | CodeFixAllContext) { + function doChange( + file: SourceFile, + start: number, + length: number, + code: number, + context: CodeFixContext | CodeFixAllContext, + ) { let startPosition: number; let endPosition: number; - if (code === Diagnostics._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property.code) { + if ( + code + === Diagnostics + ._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property.code + ) { startPosition = start; endPosition = start + length; } - else if (code === Diagnostics._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor.code) { + else if ( + code === Diagnostics._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor.code + ) { const checker = context.program.getTypeChecker(); const node = getTokenAtPosition(file, start).parent; Debug.assert(isAccessor(node), "error span of fixPropertyOverrideAccessor should only be on an accessor"); @@ -53,6 +79,13 @@ namespace ts.codefix { else { Debug.fail("fixPropertyOverrideAccessor codefix got unexpected error code " + code); } - return generateAccessorFromProperty(file, context.program, startPosition, endPosition, context, Diagnostics.Generate_get_and_set_accessors.message); + return generateAccessorFromProperty( + file, + context.program, + startPosition, + endPosition, + context, + Diagnostics.Generate_get_and_set_accessors.message, + ); } } diff --git a/src/services/codefixes/fixReturnTypeInAsyncFunction.ts b/src/services/codefixes/fixReturnTypeInAsyncFunction.ts index 4b5ef3cfa419c..41faafc75ab2d 100644 --- a/src/services/codefixes/fixReturnTypeInAsyncFunction.ts +++ b/src/services/codefixes/fixReturnTypeInAsyncFunction.ts @@ -2,7 +2,9 @@ namespace ts.codefix { const fixId = "fixReturnTypeInAsyncFunction"; const errorCodes = [ - Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0.code, + Diagnostics + .The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0 + .code, ]; interface Info { @@ -23,11 +25,18 @@ namespace ts.codefix { return undefined; } const { returnTypeNode, returnType, promisedTypeNode, promisedType } = info; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, returnTypeNode, promisedTypeNode)); + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, sourceFile, returnTypeNode, promisedTypeNode), + ); return [createCodeFixAction( fixId, changes, - [Diagnostics.Replace_0_with_Promise_1, checker.typeToString(returnType), checker.typeToString(promisedType)], + [ + Diagnostics.Replace_0_with_Promise_1, + checker.typeToString(returnType), + checker.typeToString(promisedType), + ], fixId, Diagnostics.Fix_all_incorrect_return_type_of_an_async_functions, )]; @@ -55,13 +64,22 @@ namespace ts.codefix { const returnType = checker.getTypeFromTypeNode(returnTypeNode); const promisedType = checker.getAwaitedType(returnType) || checker.getVoidType(); - const promisedTypeNode = checker.typeToTypeNode(promisedType, /*enclosingDeclaration*/ returnTypeNode, /*flags*/ undefined); + const promisedTypeNode = checker.typeToTypeNode( + promisedType, + /*enclosingDeclaration*/ returnTypeNode, + /*flags*/ undefined, + ); if (promisedTypeNode) { return { returnTypeNode, returnType, promisedTypeNode, promisedType }; } } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, returnTypeNode: TypeNode, promisedTypeNode: TypeNode): void { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + returnTypeNode: TypeNode, + promisedTypeNode: TypeNode, + ): void { changes.replaceNode(sourceFile, returnTypeNode, factory.createTypeReferenceNode("Promise", [promisedTypeNode])); } } diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index e1ebd8b9a2d13..05275ffab4ef0 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -10,8 +10,12 @@ namespace ts.codefix { Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0.code, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2.code, - Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1.code, - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1.code, + Diagnostics + .This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1 + .code, + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1 + .code, // for JSX class components Diagnostics.No_overload_matches_this_call.code, // for JSX FC @@ -25,8 +29,19 @@ namespace ts.codefix { if (!info) return undefined; const { node, suggestedSymbol } = info; const target = getEmitScriptTarget(context.host.getCompilationSettings()); - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node, suggestedSymbol, target)); - return [createCodeFixAction("spelling", changes, [Diagnostics.Change_spelling_to_0, symbolName(suggestedSymbol)], fixId, Diagnostics.Fix_all_detected_spelling_errors)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, sourceFile, node, suggestedSymbol, target), + ); + return [ + createCodeFixAction( + "spelling", + changes, + [Diagnostics.Change_spelling_to_0, symbolName(suggestedSymbol)], + fixId, + Diagnostics.Fix_all_detected_spelling_errors, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -37,7 +52,12 @@ namespace ts.codefix { }), }); - function getInfo(sourceFile: SourceFile, pos: number, context: CodeFixContextBase, errorCode: number): { node: Node; suggestedSymbol: Symbol; } | undefined { + function getInfo( + sourceFile: SourceFile, + pos: number, + context: CodeFixContextBase, + errorCode: number, + ): { node: Node; suggestedSymbol: Symbol; } | undefined { // This is the identifier of the misspelled word. eg: // this.speling = 1; // ^^^^^^^ @@ -46,10 +66,10 @@ namespace ts.codefix { // Only fix spelling for No_overload_matches_this_call emitted on the React class component if ( ( - errorCode === Diagnostics.No_overload_matches_this_call.code || - errorCode === Diagnostics.Type_0_is_not_assignable_to_type_1.code - ) && - !isJsxAttribute(parent) + errorCode === Diagnostics.No_overload_matches_this_call.code + || errorCode === Diagnostics.Type_0_is_not_assignable_to_type_1.code + ) + && !isJsxAttribute(parent) ) return undefined; const checker = context.program.getTypeChecker(); @@ -62,7 +82,10 @@ namespace ts.codefix { } suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, containingType); } - else if (isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.InKeyword && parent.left === node && isPrivateIdentifier(node)) { + else if ( + isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.InKeyword && parent.left === node + && isPrivateIdentifier(node) + ) { const receiverType = checker.getTypeAtLocation(parent.right); suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, receiverType); } @@ -75,7 +98,11 @@ namespace ts.codefix { else if (isImportSpecifier(parent) && parent.name === node) { Debug.assertNode(node, isIdentifier, "Expected an identifier for spelling (import)"); const importDeclaration = findAncestor(node, isImportDeclaration)!; - const resolvedSourceFile = getResolvedSourceFileFromImportDeclaration(sourceFile, context, importDeclaration); + const resolvedSourceFile = getResolvedSourceFileFromImportDeclaration( + sourceFile, + context, + importDeclaration, + ); if (resolvedSourceFile && resolvedSourceFile.symbol) { suggestedSymbol = checker.getSuggestedSymbolForNonexistentModule(node, resolvedSourceFile.symbol); } @@ -86,7 +113,9 @@ namespace ts.codefix { const props = checker.getContextualTypeForArgumentAtIndex(tag, 0); suggestedSymbol = checker.getSuggestedSymbolForNonexistentJSXAttribute(node, props!); } - else if (hasSyntacticModifier(parent, ModifierFlags.Override) && isClassElement(parent) && parent.name === node) { + else if ( + hasSyntacticModifier(parent, ModifierFlags.Override) && isClassElement(parent) && parent.name === node + ) { const baseDeclaration = findAncestor(node, isClassLike); const baseTypeNode = baseDeclaration ? getEffectiveBaseTypeNode(baseDeclaration) : undefined; const baseType = baseTypeNode ? checker.getTypeAtLocation(baseTypeNode) : undefined; @@ -98,13 +127,23 @@ namespace ts.codefix { const meaning = getMeaningFromLocation(node); const name = getTextOfNode(node); Debug.assert(name !== undefined, "name should be defined"); - suggestedSymbol = checker.getSuggestedSymbolForNonexistentSymbol(node, name, convertSemanticMeaningToSymbolFlags(meaning)); + suggestedSymbol = checker.getSuggestedSymbolForNonexistentSymbol( + node, + name, + convertSemanticMeaningToSymbolFlags(meaning), + ); } return suggestedSymbol === undefined ? undefined : { node, suggestedSymbol }; } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: Node, suggestedSymbol: Symbol, target: ScriptTarget) { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: Node, + suggestedSymbol: Symbol, + target: ScriptTarget, + ) { const suggestion = symbolName(suggestedSymbol); if (!isIdentifierText(suggestion, target) && isPropertyAccessExpression(node.parent)) { const valDecl = suggestedSymbol.valueDeclaration; @@ -112,7 +151,14 @@ namespace ts.codefix { changes.replaceNode(sourceFile, node, factory.createIdentifier(suggestion)); } else { - changes.replaceNode(sourceFile, node.parent, factory.createElementAccessExpression(node.parent.expression, factory.createStringLiteral(suggestion))); + changes.replaceNode( + sourceFile, + node.parent, + factory.createElementAccessExpression( + node.parent.expression, + factory.createStringLiteral(suggestion), + ), + ); } } else { @@ -134,10 +180,18 @@ namespace ts.codefix { return flags; } - function getResolvedSourceFileFromImportDeclaration(sourceFile: SourceFile, context: CodeFixContextBase, importDeclaration: ImportDeclaration): SourceFile | undefined { + function getResolvedSourceFileFromImportDeclaration( + sourceFile: SourceFile, + context: CodeFixContextBase, + importDeclaration: ImportDeclaration, + ): SourceFile | undefined { if (!importDeclaration || !isStringLiteralLike(importDeclaration.moduleSpecifier)) return undefined; - const resolvedModule = getResolvedModule(sourceFile, importDeclaration.moduleSpecifier.text, getModeForUsageLocation(sourceFile, importDeclaration.moduleSpecifier)); + const resolvedModule = getResolvedModule( + sourceFile, + importDeclaration.moduleSpecifier.text, + getModeForUsageLocation(sourceFile, importDeclaration.moduleSpecifier), + ); if (!resolvedModule) return undefined; return context.program.getSourceFile(resolvedModule.resolvedFileName); diff --git a/src/services/codefixes/fixStrictClassInitialization.ts b/src/services/codefixes/fixStrictClassInitialization.ts index 29a297256ea97..57099a5e9dac3 100644 --- a/src/services/codefixes/fixStrictClassInitialization.ts +++ b/src/services/codefixes/fixStrictClassInitialization.ts @@ -4,7 +4,9 @@ namespace ts.codefix { const fixIdAddDefiniteAssignmentAssertions = "addMissingPropertyDefiniteAssignmentAssertions"; const fixIdAddUndefinedType = "addMissingPropertyUndefinedType"; const fixIdAddInitializer = "addMissingPropertyInitializer"; - const errorCodes = [Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor.code]; + const errorCodes = [ + Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor.code, + ]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsForStrictClassInitializationErrors(context) { @@ -60,13 +62,29 @@ namespace ts.codefix { return undefined; } - function getActionForAddMissingDefiniteAssignmentAssertion(context: CodeFixContext, info: Info): CodeFixAction | undefined { + function getActionForAddMissingDefiniteAssignmentAssertion( + context: CodeFixContext, + info: Info, + ): CodeFixAction | undefined { if (info.isJs) return undefined; - const changes = textChanges.ChangeTracker.with(context, t => addDefiniteAssignmentAssertion(t, context.sourceFile, info.prop)); - return createCodeFixAction(fixName, changes, [Diagnostics.Add_definite_assignment_assertion_to_property_0, info.prop.getText()], fixIdAddDefiniteAssignmentAssertions, Diagnostics.Add_definite_assignment_assertions_to_all_uninitialized_properties); + const changes = textChanges.ChangeTracker.with( + context, + t => addDefiniteAssignmentAssertion(t, context.sourceFile, info.prop), + ); + return createCodeFixAction( + fixName, + changes, + [Diagnostics.Add_definite_assignment_assertion_to_property_0, info.prop.getText()], + fixIdAddDefiniteAssignmentAssertions, + Diagnostics.Add_definite_assignment_assertions_to_all_uninitialized_properties, + ); } - function addDefiniteAssignmentAssertion(changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration): void { + function addDefiniteAssignmentAssertion( + changeTracker: textChanges.ChangeTracker, + propertyDeclarationSourceFile: SourceFile, + propertyDeclaration: PropertyDeclaration, + ): void { suppressLeadingAndTrailingTrivia(propertyDeclaration); const property = factory.updatePropertyDeclaration( propertyDeclaration, @@ -81,15 +99,24 @@ namespace ts.codefix { function getActionForAddMissingUndefinedType(context: CodeFixContext, info: Info): CodeFixAction { const changes = textChanges.ChangeTracker.with(context, t => addUndefinedType(t, context.sourceFile, info)); - return createCodeFixAction(fixName, changes, [Diagnostics.Add_undefined_type_to_property_0, info.prop.name.getText()], fixIdAddUndefinedType, Diagnostics.Add_undefined_type_to_all_uninitialized_properties); + return createCodeFixAction( + fixName, + changes, + [Diagnostics.Add_undefined_type_to_property_0, info.prop.name.getText()], + fixIdAddUndefinedType, + Diagnostics.Add_undefined_type_to_all_uninitialized_properties, + ); } function addUndefinedType(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info): void { const undefinedTypeNode = factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword); - const types = isUnionTypeNode(info.type) ? info.type.types.concat(undefinedTypeNode) : [info.type, undefinedTypeNode]; + const types = isUnionTypeNode(info.type) ? info.type.types.concat(undefinedTypeNode) + : [info.type, undefinedTypeNode]; const unionTypeNode = factory.createUnionTypeNode(types); if (info.isJs) { - changeTracker.addJSDocTags(sourceFile, info.prop, [factory.createJSDocTypeTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(unionTypeNode))]); + changeTracker.addJSDocTags(sourceFile, info.prop, [ + factory.createJSDocTypeTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(unionTypeNode)), + ]); } else { changeTracker.replaceNode(sourceFile, info.type, unionTypeNode); @@ -103,11 +130,25 @@ namespace ts.codefix { const initializer = getInitializer(checker, info.prop); if (!initializer) return undefined; - const changes = textChanges.ChangeTracker.with(context, t => addInitializer(t, context.sourceFile, info.prop, initializer)); - return createCodeFixAction(fixName, changes, [Diagnostics.Add_initializer_to_property_0, info.prop.name.getText()], fixIdAddInitializer, Diagnostics.Add_initializers_to_all_uninitialized_properties); + const changes = textChanges.ChangeTracker.with( + context, + t => addInitializer(t, context.sourceFile, info.prop, initializer), + ); + return createCodeFixAction( + fixName, + changes, + [Diagnostics.Add_initializer_to_property_0, info.prop.name.getText()], + fixIdAddInitializer, + Diagnostics.Add_initializers_to_all_uninitialized_properties, + ); } - function addInitializer(changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration, initializer: Expression): void { + function addInitializer( + changeTracker: textChanges.ChangeTracker, + propertyDeclarationSourceFile: SourceFile, + propertyDeclaration: PropertyDeclaration, + initializer: Expression, + ): void { suppressLeadingAndTrailingTrivia(propertyDeclaration); const property = factory.updatePropertyDeclaration( propertyDeclaration, @@ -126,7 +167,8 @@ namespace ts.codefix { function getDefaultValueFromType(checker: TypeChecker, type: Type): Expression | undefined { if (type.flags & TypeFlags.BooleanLiteral) { - return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) ? factory.createFalse() : factory.createTrue(); + return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) + ? factory.createFalse() : factory.createTrue(); } else if (type.isStringLiteral()) { return factory.createStringLiteral(type.value); @@ -147,7 +189,11 @@ namespace ts.codefix { const constructorDeclaration = getFirstConstructorWithBody(classDeclaration); if (constructorDeclaration && constructorDeclaration.parameters.length) return undefined; - return factory.createNewExpression(factory.createIdentifier(type.symbol.name), /*typeArguments*/ undefined, /*argumentsArray*/ undefined); + return factory.createNewExpression( + factory.createIdentifier(type.symbol.name), + /*typeArguments*/ undefined, + /*argumentsArray*/ undefined, + ); } else if (checker.isArrayLikeType(type)) { return factory.createArrayLiteralExpression(); diff --git a/src/services/codefixes/fixUnmatchedParameter.ts b/src/services/codefixes/fixUnmatchedParameter.ts index 5c7f7e5468df5..cac8c2bb17b8b 100644 --- a/src/services/codefixes/fixUnmatchedParameter.ts +++ b/src/services/codefixes/fixUnmatchedParameter.ts @@ -27,7 +27,10 @@ namespace ts.codefix { eachDiagnostic(context, errorCodes, ({ file, start }) => { const info = getInfo(file, start); if (info) { - tagsToSignature.set(info.signature, append(tagsToSignature.get(info.signature), info.jsDocParameterTag)); + tagsToSignature.set( + info.signature, + append(tagsToSignature.get(info.signature), info.jsDocParameterTag), + ); } }); @@ -42,7 +45,10 @@ namespace ts.codefix { }); function getDeleteAction(context: CodeFixContext, { name, signature, jsDocParameterTag }: Info) { - const changes = textChanges.ChangeTracker.with(context, changeTracker => changeTracker.filterJSDocTags(context.sourceFile, signature, t => t !== jsDocParameterTag)); + const changes = textChanges.ChangeTracker.with( + context, + changeTracker => changeTracker.filterJSDocTags(context.sourceFile, signature, t => t !== jsDocParameterTag), + ); return createCodeFixAction( deleteUnmatchedParameter, changes, @@ -65,7 +71,10 @@ namespace ts.codefix { } // @todo - match to all available names instead to the first parameter name // @see /codeFixRenameUnmatchedParameter3.ts - const parameterName = firstDefined(signature.parameters, p => isIdentifier(p.name) && !names.has(p.name.escapedText) ? p.name.getText(sourceFile) : undefined); + const parameterName = firstDefined( + signature.parameters, + p => isIdentifier(p.name) && !names.has(p.name.escapedText) ? p.name.getText(sourceFile) : undefined, + ); if (parameterName === undefined) return undefined; const newJSDocParameterTag = factory.updateJSDocParameterTag( @@ -77,8 +86,20 @@ namespace ts.codefix { jsDocParameterTag.isNameFirst, jsDocParameterTag.comment, ); - const changes = textChanges.ChangeTracker.with(context, changeTracker => changeTracker.replaceJSDocComment(sourceFile, signature, map(tags, t => t === jsDocParameterTag ? newJSDocParameterTag : t))); - return createCodeFixActionWithoutFixAll(renameUnmatchedParameter, changes, [Diagnostics.Rename_param_tag_name_0_to_1, name.getText(sourceFile), parameterName]); + const changes = textChanges.ChangeTracker.with( + context, + changeTracker => + changeTracker.replaceJSDocComment( + sourceFile, + signature, + map(tags, t => t === jsDocParameterTag ? newJSDocParameterTag : t), + ), + ); + return createCodeFixActionWithoutFixAll(renameUnmatchedParameter, changes, [ + Diagnostics.Rename_param_tag_name_0_to_1, + name.getText(sourceFile), + parameterName, + ]); } interface Info { diff --git a/src/services/codefixes/fixUnreachableCode.ts b/src/services/codefixes/fixUnreachableCode.ts index e8636da3c822c..5cb7e7d0bce0d 100644 --- a/src/services/codefixes/fixUnreachableCode.ts +++ b/src/services/codefixes/fixUnreachableCode.ts @@ -5,16 +5,41 @@ namespace ts.codefix { registerCodeFix({ errorCodes, getCodeActions(context) { - const syntacticDiagnostics = context.program.getSyntacticDiagnostics(context.sourceFile, context.cancellationToken); + const syntacticDiagnostics = context.program.getSyntacticDiagnostics( + context.sourceFile, + context.cancellationToken, + ); if (syntacticDiagnostics.length) return; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start, context.span.length, context.errorCode)); - return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unreachable_code, fixId, Diagnostics.Remove_all_unreachable_code)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, context.sourceFile, context.span.start, context.span.length, context.errorCode), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Remove_unreachable_code, + fixId, + Diagnostics.Remove_all_unreachable_code, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start, diag.length, diag.code)), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => doChange(changes, diag.file, diag.start, diag.length, diag.code), + ), }); - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number, length: number, errorCode: number): void { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + start: number, + length: number, + errorCode: number, + ): void { const token = getTokenAtPosition(sourceFile, start); const statement = findAncestor(token, isStatement)!; if (statement.getStart(sourceFile) !== token.getStart(sourceFile)) { @@ -51,7 +76,10 @@ namespace ts.codefix { if (isBlock(statement.parent)) { const end = start + length; - const lastStatement = Debug.checkDefined(lastWhere(sliceAfter(statement.parent.statements, statement), s => s.pos < end), "Some statement should be last"); + const lastStatement = Debug.checkDefined( + lastWhere(sliceAfter(statement.parent.statements, statement), s => s.pos < end), + "Some statement should be last", + ); changes.deleteNodeRange(sourceFile, statement, lastStatement); } else { diff --git a/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts b/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts index 30fefde64efed..1dfc35b040b3c 100644 --- a/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts +++ b/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts @@ -1,34 +1,64 @@ /* @internal */ namespace ts.codefix { const fixId = "fixUnreferenceableDecoratorMetadata"; - const errorCodes = [Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled.code]; + const errorCodes = [ + Diagnostics + .A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled + .code, + ]; registerCodeFix({ errorCodes, getCodeActions: context => { const importDeclaration = getImportDeclaration(context.sourceFile, context.program, context.span.start); if (!importDeclaration) return; - const namespaceChanges = textChanges.ChangeTracker.with(context, t => importDeclaration.kind === SyntaxKind.ImportSpecifier && doNamespaceImportChange(t, context.sourceFile, importDeclaration, context.program)); - const typeOnlyChanges = textChanges.ChangeTracker.with(context, t => doTypeOnlyImportChange(t, context.sourceFile, importDeclaration, context.program)); + const namespaceChanges = textChanges.ChangeTracker.with( + context, + t => importDeclaration.kind === SyntaxKind.ImportSpecifier + && doNamespaceImportChange(t, context.sourceFile, importDeclaration, context.program), + ); + const typeOnlyChanges = textChanges.ChangeTracker.with( + context, + t => doTypeOnlyImportChange(t, context.sourceFile, importDeclaration, context.program), + ); let actions: CodeFixAction[] | undefined; if (namespaceChanges.length) { - actions = append(actions, createCodeFixActionWithoutFixAll(fixId, namespaceChanges, Diagnostics.Convert_named_imports_to_namespace_import)); + actions = append( + actions, + createCodeFixActionWithoutFixAll( + fixId, + namespaceChanges, + Diagnostics.Convert_named_imports_to_namespace_import, + ), + ); } if (typeOnlyChanges.length) { - actions = append(actions, createCodeFixActionWithoutFixAll(fixId, typeOnlyChanges, Diagnostics.Convert_to_type_only_import)); + actions = append( + actions, + createCodeFixActionWithoutFixAll(fixId, typeOnlyChanges, Diagnostics.Convert_to_type_only_import), + ); } return actions; }, fixIds: [fixId], }); - function getImportDeclaration(sourceFile: SourceFile, program: Program, start: number): ImportClause | ImportSpecifier | ImportEqualsDeclaration | undefined { + function getImportDeclaration( + sourceFile: SourceFile, + program: Program, + start: number, + ): ImportClause | ImportSpecifier | ImportEqualsDeclaration | undefined { const identifier = tryCast(getTokenAtPosition(sourceFile, start), isIdentifier); if (!identifier || identifier.parent.kind !== SyntaxKind.TypeReference) return; const checker = program.getTypeChecker(); const symbol = checker.getSymbolAtLocation(identifier); - return find(symbol?.declarations || emptyArray, or(isImportClause, isImportSpecifier, isImportEqualsDeclaration) as (n: Node) => n is ImportClause | ImportSpecifier | ImportEqualsDeclaration); + return find( + symbol?.declarations || emptyArray, + or(isImportClause, isImportSpecifier, isImportEqualsDeclaration) as ( + n: Node, + ) => n is ImportClause | ImportSpecifier | ImportEqualsDeclaration, + ); } // Converts the import declaration of the offending import to a type-only import, @@ -36,13 +66,19 @@ namespace ts.codefix { // cannot be done cleanly, we could offer to *extract* the offending import to a // new type-only import declaration, but honestly I doubt anyone will ever use this // codefix at all, so it's probably not worth the lines of code. - function doTypeOnlyImportChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importDeclaration: ImportClause | ImportSpecifier | ImportEqualsDeclaration, program: Program) { + function doTypeOnlyImportChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + importDeclaration: ImportClause | ImportSpecifier | ImportEqualsDeclaration, + program: Program, + ) { if (importDeclaration.kind === SyntaxKind.ImportEqualsDeclaration) { changes.insertModifierBefore(sourceFile, SyntaxKind.TypeKeyword, importDeclaration.name); return; } - const importClause = importDeclaration.kind === SyntaxKind.ImportClause ? importDeclaration : importDeclaration.parent.parent; + const importClause = importDeclaration.kind === SyntaxKind.ImportClause ? importDeclaration + : importDeclaration.parent.parent; if (importClause.name && importClause.namedBindings) { // Cannot convert an import with a default import and named bindings to type-only // (it's a grammar error). @@ -64,7 +100,12 @@ namespace ts.codefix { changes.insertModifierBefore(sourceFile, SyntaxKind.TypeKeyword, importClause); } - function doNamespaceImportChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importDeclaration: ImportSpecifier, program: Program) { + function doNamespaceImportChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + importDeclaration: ImportSpecifier, + program: Program, + ) { refactor.doChangeNamedToNamespaceOrDefault(sourceFile, program, changes, importDeclaration.parent); } } diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index 9eeda3df3fa7f..60b27001f6bea 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -24,21 +24,57 @@ namespace ts.codefix { const token = getTokenAtPosition(sourceFile, context.span.start); if (isJSDocTemplateTag(token)) { - return [createDeleteFix(textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token)), Diagnostics.Remove_template_tag)]; + return [ + createDeleteFix( + textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token)), + Diagnostics.Remove_template_tag, + ), + ]; } if (token.kind === SyntaxKind.LessThanToken) { - const changes = textChanges.ChangeTracker.with(context, t => deleteTypeParameters(t, sourceFile, token)); + const changes = textChanges.ChangeTracker.with( + context, + t => deleteTypeParameters(t, sourceFile, token), + ); return [createDeleteFix(changes, Diagnostics.Remove_type_parameters)]; } const importDecl = tryGetFullImport(token); if (importDecl) { const changes = textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, importDecl)); - return [createCodeFixAction(fixName, changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)], fixIdDeleteImports, Diagnostics.Delete_all_unused_imports)]; + return [ + createCodeFixAction( + fixName, + changes, + [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)], + fixIdDeleteImports, + Diagnostics.Delete_all_unused_imports, + ), + ]; } else if (isImport(token)) { - const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(sourceFile, token, t, checker, sourceFiles, program, cancellationToken, /*isFixAll*/ false)); + const deletion = textChanges.ChangeTracker.with( + context, + t => tryDeleteDeclaration( + sourceFile, + token, + t, + checker, + sourceFiles, + program, + cancellationToken, + /*isFixAll*/ false, + ), + ); if (deletion.length) { - return [createCodeFixAction(fixName, deletion, [Diagnostics.Remove_unused_declaration_for_Colon_0, token.getText(sourceFile)], fixIdDeleteImports, Diagnostics.Delete_all_unused_imports)]; + return [ + createCodeFixAction( + fixName, + deletion, + [Diagnostics.Remove_unused_declaration_for_Colon_0, token.getText(sourceFile)], + fixIdDeleteImports, + Diagnostics.Delete_all_unused_imports, + ), + ]; } } @@ -46,41 +82,98 @@ namespace ts.codefix { if (isParameter(token.parent.parent)) { const elements = token.parent.elements; const diagnostic: [DiagnosticMessage, string] = [ - elements.length > 1 ? Diagnostics.Remove_unused_declarations_for_Colon_0 : Diagnostics.Remove_unused_declaration_for_Colon_0, + elements.length > 1 ? Diagnostics.Remove_unused_declarations_for_Colon_0 + : Diagnostics.Remove_unused_declaration_for_Colon_0, map(elements, e => e.getText(sourceFile)).join(", "), ]; return [ - createDeleteFix(textChanges.ChangeTracker.with(context, t => deleteDestructuringElements(t, sourceFile, token.parent as ObjectBindingPattern | ArrayBindingPattern)), diagnostic), + createDeleteFix( + textChanges.ChangeTracker.with(context, t => + deleteDestructuringElements( + t, + sourceFile, + token.parent as ObjectBindingPattern | ArrayBindingPattern, + )), + diagnostic, + ), ]; } return [ - createDeleteFix(textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token.parent.parent)), Diagnostics.Remove_unused_destructuring_declaration), + createDeleteFix( + textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token.parent.parent)), + Diagnostics.Remove_unused_destructuring_declaration, + ), ]; } if (canDeleteEntireVariableStatement(sourceFile, token)) { return [ - createDeleteFix(textChanges.ChangeTracker.with(context, t => deleteEntireVariableStatement(t, sourceFile, token.parent as VariableDeclarationList)), Diagnostics.Remove_variable_statement), + createDeleteFix( + textChanges.ChangeTracker.with( + context, + t => deleteEntireVariableStatement(t, sourceFile, token.parent as VariableDeclarationList), + ), + Diagnostics.Remove_variable_statement, + ), ]; } const result: CodeFixAction[] = []; if (token.kind === SyntaxKind.InferKeyword) { - const changes = textChanges.ChangeTracker.with(context, t => changeInferToUnknown(t, sourceFile, token)); + const changes = textChanges.ChangeTracker.with( + context, + t => changeInferToUnknown(t, sourceFile, token), + ); const name = cast(token.parent, isInferTypeNode).typeParameter.name.text; - result.push(createCodeFixAction(fixName, changes, [Diagnostics.Replace_infer_0_with_unknown, name], fixIdInfer, Diagnostics.Replace_all_unused_infer_with_unknown)); + result.push( + createCodeFixAction( + fixName, + changes, + [Diagnostics.Replace_infer_0_with_unknown, name], + fixIdInfer, + Diagnostics.Replace_all_unused_infer_with_unknown, + ), + ); } else { - const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(sourceFile, token, t, checker, sourceFiles, program, cancellationToken, /*isFixAll*/ false)); + const deletion = textChanges.ChangeTracker.with( + context, + t => tryDeleteDeclaration( + sourceFile, + token, + t, + checker, + sourceFiles, + program, + cancellationToken, + /*isFixAll*/ false, + ), + ); if (deletion.length) { const name = isComputedPropertyName(token.parent) ? token.parent : token; - result.push(createDeleteFix(deletion, [Diagnostics.Remove_unused_declaration_for_Colon_0, name.getText(sourceFile)])); + result.push( + createDeleteFix(deletion, [ + Diagnostics.Remove_unused_declaration_for_Colon_0, + name.getText(sourceFile), + ]), + ); } } - const prefix = textChanges.ChangeTracker.with(context, t => tryPrefixDeclaration(t, errorCode, sourceFile, token)); + const prefix = textChanges.ChangeTracker.with( + context, + t => tryPrefixDeclaration(t, errorCode, sourceFile, token), + ); if (prefix.length) { - result.push(createCodeFixAction(fixName, prefix, [Diagnostics.Prefix_0_with_an_underscore, token.getText(sourceFile)], fixIdPrefix, Diagnostics.Prefix_all_unused_declarations_with_where_possible)); + result.push( + createCodeFixAction( + fixName, + prefix, + [Diagnostics.Prefix_0_with_an_underscore, token.getText(sourceFile)], + fixIdPrefix, + Diagnostics.Prefix_all_unused_declarations_with_where_possible, + ), + ); } return result; @@ -102,7 +195,16 @@ namespace ts.codefix { changes.delete(sourceFile, importDecl); } else if (isImport(token)) { - tryDeleteDeclaration(sourceFile, token, changes, checker, sourceFiles, program, cancellationToken, /*isFixAll*/ true); + tryDeleteDeclaration( + sourceFile, + token, + changes, + checker, + sourceFiles, + program, + cancellationToken, + /*isFixAll*/ true, + ); } break; } @@ -120,7 +222,10 @@ namespace ts.codefix { if (token.parent.parent.initializer) { break; } - else if (!isParameter(token.parent.parent) || isNotProvidedArguments(token.parent.parent, checker, sourceFiles)) { + else if ( + !isParameter(token.parent.parent) + || isNotProvidedArguments(token.parent.parent, checker, sourceFiles) + ) { changes.delete(sourceFile, token.parent.parent); } } @@ -131,7 +236,16 @@ namespace ts.codefix { deleteEntireVariableStatement(changes, sourceFile, token.parent as VariableDeclarationList); } else { - tryDeleteDeclaration(sourceFile, token, changes, checker, sourceFiles, program, cancellationToken, /*isFixAll*/ true); + tryDeleteDeclaration( + sourceFile, + token, + changes, + checker, + sourceFiles, + program, + cancellationToken, + /*isFixAll*/ true, + ); } break; } @@ -156,12 +270,19 @@ namespace ts.codefix { } function deleteTypeParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node): void { - changes.delete(sourceFile, Debug.checkDefined(cast(token.parent, isDeclarationWithTypeParameterChildren).typeParameters, "The type parameter to delete should exist")); + changes.delete( + sourceFile, + Debug.checkDefined( + cast(token.parent, isDeclarationWithTypeParameterChildren).typeParameters, + "The type parameter to delete should exist", + ), + ); } function isImport(token: Node) { return token.kind === SyntaxKind.ImportKeyword - || token.kind === SyntaxKind.Identifier && (token.parent.kind === SyntaxKind.ImportSpecifier || token.parent.kind === SyntaxKind.ImportClause); + || token.kind === SyntaxKind.Identifier + && (token.parent.kind === SyntaxKind.ImportSpecifier || token.parent.kind === SyntaxKind.ImportClause); } /** Sometimes the diagnostic span is an entire ImportDeclaration, so we should remove the whole thing. */ @@ -173,15 +294,28 @@ namespace ts.codefix { return isVariableDeclarationList(token.parent) && first(token.parent.getChildren(sourceFile)) === token; } - function deleteEntireVariableStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: VariableDeclarationList) { + function deleteEntireVariableStatement( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: VariableDeclarationList, + ) { changes.delete(sourceFile, node.parent.kind === SyntaxKind.VariableStatement ? node.parent : node); } - function deleteDestructuringElements(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: ObjectBindingPattern | ArrayBindingPattern) { + function deleteDestructuringElements( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: ObjectBindingPattern | ArrayBindingPattern, + ) { forEach(node.elements, n => changes.delete(sourceFile, n)); } - function tryPrefixDeclaration(changes: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, token: Node): void { + function tryPrefixDeclaration( + changes: textChanges.ChangeTracker, + errorCode: number, + sourceFile: SourceFile, + token: Node, + ): void { // Don't offer to prefix a property. if (errorCode === Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code) return; if (token.kind === SyntaxKind.InferKeyword) { @@ -216,8 +350,26 @@ namespace ts.codefix { return false; } - function tryDeleteDeclaration(sourceFile: SourceFile, token: Node, changes: textChanges.ChangeTracker, checker: TypeChecker, sourceFiles: readonly SourceFile[], program: Program, cancellationToken: CancellationToken, isFixAll: boolean) { - tryDeleteDeclarationWorker(token, changes, sourceFile, checker, sourceFiles, program, cancellationToken, isFixAll); + function tryDeleteDeclaration( + sourceFile: SourceFile, + token: Node, + changes: textChanges.ChangeTracker, + checker: TypeChecker, + sourceFiles: readonly SourceFile[], + program: Program, + cancellationToken: CancellationToken, + isFixAll: boolean, + ) { + tryDeleteDeclarationWorker( + token, + changes, + sourceFile, + checker, + sourceFiles, + program, + cancellationToken, + isFixAll, + ); if (isIdentifier(token)) { FindAllReferences.Core.eachSymbolReferenceInFile(token, checker, sourceFile, (ref: Node) => { if (isPropertyAccessExpression(ref.parent) && ref.parent.name === ref) ref = ref.parent; @@ -228,12 +380,24 @@ namespace ts.codefix { } } - function tryDeleteDeclarationWorker(token: Node, changes: textChanges.ChangeTracker, sourceFile: SourceFile, checker: TypeChecker, sourceFiles: readonly SourceFile[], program: Program, cancellationToken: CancellationToken, isFixAll: boolean): void { + function tryDeleteDeclarationWorker( + token: Node, + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + checker: TypeChecker, + sourceFiles: readonly SourceFile[], + program: Program, + cancellationToken: CancellationToken, + isFixAll: boolean, + ): void { const { parent } = token; if (isParameter(parent)) { tryDeleteParameter(changes, sourceFile, parent, checker, sourceFiles, program, cancellationToken, isFixAll); } - else if (!(isFixAll && isIdentifier(token) && FindAllReferences.Core.isSymbolReferencedInFile(token, checker, sourceFile))) { + else if ( + !(isFixAll && isIdentifier(token) + && FindAllReferences.Core.isSymbolReferencedInFile(token, checker, sourceFile)) + ) { const node = isImportClause(parent) ? token : isComputedPropertyName(parent) ? parent.parent : parent; Debug.assert(node !== sourceFile, "should not delete whole source file"); changes.delete(sourceFile, node); @@ -252,8 +416,9 @@ namespace ts.codefix { ): void { if (mayDeleteParameter(checker, sourceFile, parameter, sourceFiles, program, cancellationToken, isFixAll)) { if ( - parameter.modifiers && parameter.modifiers.length > 0 && - (!isIdentifier(parameter.name) || FindAllReferences.Core.isSymbolReferencedInFile(parameter.name, checker, sourceFile)) + parameter.modifiers && parameter.modifiers.length > 0 + && (!isIdentifier(parameter.name) + || FindAllReferences.Core.isSymbolReferencedInFile(parameter.name, checker, sourceFile)) ) { for (const modifier of parameter.modifiers) { if (isModifier(modifier)) { @@ -267,20 +432,43 @@ namespace ts.codefix { } } - function isNotProvidedArguments(parameter: ParameterDeclaration, checker: TypeChecker, sourceFiles: readonly SourceFile[]) { + function isNotProvidedArguments( + parameter: ParameterDeclaration, + checker: TypeChecker, + sourceFiles: readonly SourceFile[], + ) { const index = parameter.parent.parameters.indexOf(parameter); // Just in case the call didn't provide enough arguments. - return !FindAllReferences.Core.someSignatureUsage(parameter.parent, sourceFiles, checker, (_, call) => !call || call.arguments.length > index); + return !FindAllReferences.Core.someSignatureUsage( + parameter.parent, + sourceFiles, + checker, + (_, call) => !call || call.arguments.length > index, + ); } - function mayDeleteParameter(checker: TypeChecker, sourceFile: SourceFile, parameter: ParameterDeclaration, sourceFiles: readonly SourceFile[], program: Program, cancellationToken: CancellationToken, isFixAll: boolean): boolean { + function mayDeleteParameter( + checker: TypeChecker, + sourceFile: SourceFile, + parameter: ParameterDeclaration, + sourceFiles: readonly SourceFile[], + program: Program, + cancellationToken: CancellationToken, + isFixAll: boolean, + ): boolean { const { parent } = parameter; switch (parent.kind) { case SyntaxKind.MethodDeclaration: case SyntaxKind.Constructor: const index = parent.parameters.indexOf(parameter); const referent = isMethodDeclaration(parent) ? parent.name : parent; - const entries = FindAllReferences.Core.getReferencedSymbolsForNode(parent.pos, referent, program, sourceFiles, cancellationToken); + const entries = FindAllReferences.Core.getReferencedSymbolsForNode( + parent.pos, + referent, + program, + sourceFiles, + cancellationToken, + ); if (entries) { for (const entry of entries) { for (const reference of entry.references) { @@ -295,7 +483,8 @@ namespace ts.codefix { && isCallExpression(reference.node.parent.parent) && reference.node.parent.parent.arguments.length > index; // parameter in overridden or overriding method - const isOverriddenMethod = (isMethodDeclaration(reference.node.parent) || isMethodSignature(reference.node.parent)) + const isOverriddenMethod = (isMethodDeclaration(reference.node.parent) + || isMethodSignature(reference.node.parent)) && reference.node.parent !== parameter.parent && reference.node.parent.parameters.length > index; if (isSuperCall || isSuperMethodCall || isOverriddenMethod) return false; @@ -329,20 +518,32 @@ namespace ts.codefix { } function isCallbackLike(checker: TypeChecker, sourceFile: SourceFile, name: Identifier): boolean { - return !!FindAllReferences.Core.eachSymbolReferenceInFile(name, checker, sourceFile, reference => isIdentifier(reference) && isCallExpression(reference.parent) && reference.parent.arguments.indexOf(reference) >= 0); + return !!FindAllReferences.Core.eachSymbolReferenceInFile( + name, + checker, + sourceFile, + reference => + isIdentifier(reference) && isCallExpression(reference.parent) + && reference.parent.arguments.indexOf(reference) >= 0, + ); } - function isLastParameter(func: FunctionLikeDeclaration, parameter: ParameterDeclaration, isFixAll: boolean): boolean { + function isLastParameter( + func: FunctionLikeDeclaration, + parameter: ParameterDeclaration, + isFixAll: boolean, + ): boolean { const parameters = func.parameters; const index = parameters.indexOf(parameter); Debug.assert(index !== -1, "The parameter should already be in the list"); - return isFixAll ? - parameters.slice(index + 1).every(p => isIdentifier(p.name) && !p.symbol.isReferenced) : - index === parameters.length - 1; + return isFixAll + ? parameters.slice(index + 1).every(p => isIdentifier(p.name) && !p.symbol.isReferenced) + : index === parameters.length - 1; } function mayDeleteExpression(node: Node) { - return ((isBinaryExpression(node.parent) && node.parent.left === node) || - ((isPostfixUnaryExpression(node.parent) || isPrefixUnaryExpression(node.parent)) && node.parent.operand === node)) && isExpressionStatement(node.parent.parent); + return ((isBinaryExpression(node.parent) && node.parent.left === node) + || ((isPostfixUnaryExpression(node.parent) || isPrefixUnaryExpression(node.parent)) + && node.parent.operand === node)) && isExpressionStatement(node.parent.parent); } } diff --git a/src/services/codefixes/fixUnusedLabel.ts b/src/services/codefixes/fixUnusedLabel.ts index 49f334720ed53..0e2e2cab6d5eb 100644 --- a/src/services/codefixes/fixUnusedLabel.ts +++ b/src/services/codefixes/fixUnusedLabel.ts @@ -5,11 +5,23 @@ namespace ts.codefix { registerCodeFix({ errorCodes, getCodeActions(context) { - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start)); - return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unused_label, fixId, Diagnostics.Remove_all_unused_labels)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, context.sourceFile, context.span.start), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Remove_unused_label, + fixId, + Diagnostics.Remove_all_unused_labels, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start)), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start)), }); function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number): void { @@ -19,7 +31,11 @@ namespace ts.codefix { const statementPos = labeledStatement.statement.getStart(sourceFile); // If label is on a separate line, just delete the rest of that line, but not the indentation of the labeled statement. const end = positionsAreOnSameLine(pos, statementPos, sourceFile) ? statementPos - : skipTrivia(sourceFile.text, findChildOfKind(labeledStatement, SyntaxKind.ColonToken, sourceFile)!.end, /*stopAfterLineBreak*/ true); + : skipTrivia( + sourceFile.text, + findChildOfKind(labeledStatement, SyntaxKind.ColonToken, sourceFile)!.end, + /*stopAfterLineBreak*/ true, + ); changes.deleteRange(sourceFile, { pos, end }); } } diff --git a/src/services/codefixes/generateAccessors.ts b/src/services/codefixes/generateAccessors.ts index e43b144665178..ee5cbd1338b71 100644 --- a/src/services/codefixes/generateAccessors.ts +++ b/src/services/codefixes/generateAccessors.ts @@ -17,7 +17,14 @@ namespace ts.codefix { readonly renameAccessor: boolean; } - export function generateAccessorFromProperty(file: SourceFile, program: Program, start: number, end: number, context: textChanges.TextChangesContext, _actionName: string): FileTextChanges[] | undefined { + export function generateAccessorFromProperty( + file: SourceFile, + program: Program, + start: number, + end: number, + context: textChanges.TextChangesContext, + _actionName: string, + ): FileTextChanges[] | undefined { const fieldInfo = getAccessorConvertiblePropertyAtPosition(file, program, start, end); if (!fieldInfo || refactor.isRefactorErrorInfo(fieldInfo)) return undefined; @@ -39,7 +46,9 @@ namespace ts.codefix { fieldModifiers = modifiers; } else { - accessorModifiers = factory.createModifiersFromModifierFlags(prepareModifierFlagsForAccessor(modifierFlags)); + accessorModifiers = factory.createModifiersFromModifierFlags( + prepareModifierFlagsForAccessor(modifierFlags), + ); fieldModifiers = factory.createModifiersFromModifierFlags(prepareModifierFlagsForField(modifierFlags)); } if (canHaveDecorators(declaration)) { @@ -57,11 +66,24 @@ namespace ts.codefix { // readonly modifier only existed in classLikeDeclaration const constructor = getFirstConstructorWithBody(container as ClassLikeDeclaration); if (constructor) { - updateReadonlyPropertyInitializerStatementConstructor(changeTracker, file, constructor, fieldName.text, originalName); + updateReadonlyPropertyInitializerStatementConstructor( + changeTracker, + file, + constructor, + fieldName.text, + originalName, + ); } } else { - const setAccessor = generateSetAccessor(fieldName, accessorName, type, accessorModifiers, isStatic, container); + const setAccessor = generateSetAccessor( + fieldName, + accessorName, + type, + accessorModifiers, + isStatic, + container, + ); suppressLeadingAndTrailingTrivia(setAccessor); insertAccessor(changeTracker, file, setAccessor, declaration, container); } @@ -74,16 +96,22 @@ namespace ts.codefix { } function isAcceptedDeclaration(node: Node): node is AcceptedDeclaration { - return isParameterPropertyDeclaration(node, node.parent) || isPropertyDeclaration(node) || isPropertyAssignment(node); + return isParameterPropertyDeclaration(node, node.parent) || isPropertyDeclaration(node) + || isPropertyAssignment(node); } function createPropertyName(name: string, originalName: AcceptedNameType) { return isIdentifier(originalName) ? factory.createIdentifier(name) : factory.createStringLiteral(name); } - function createAccessorAccessExpression(fieldName: AcceptedNameType, isStatic: boolean, container: ContainerDeclaration) { + function createAccessorAccessExpression( + fieldName: AcceptedNameType, + isStatic: boolean, + container: ContainerDeclaration, + ) { const leftHead = isStatic ? (container as ClassLikeDeclaration).name! : factory.createThis(); // TODO: GH#18217 - return isIdentifier(fieldName) ? factory.createPropertyAccessExpression(leftHead, fieldName) : factory.createElementAccessExpression(leftHead, factory.createStringLiteralFromNode(fieldName)); + return isIdentifier(fieldName) ? factory.createPropertyAccessExpression(leftHead, fieldName) + : factory.createElementAccessExpression(leftHead, factory.createStringLiteralFromNode(fieldName)); } function prepareModifierFlagsForAccessor(modifierFlags: ModifierFlags): ModifierFlags { @@ -104,7 +132,13 @@ namespace ts.codefix { return modifierFlags; } - export function getAccessorConvertiblePropertyAtPosition(file: SourceFile, program: Program, start: number, end: number, considerEmptySpans = true): Info | undefined { + export function getAccessorConvertiblePropertyAtPosition( + file: SourceFile, + program: Program, + start: number, + end: number, + considerEmptySpans = true, + ): Info | undefined { const node = getTokenAtPosition(file, start); const cursorRequest = start === end && considerEmptySpans; const declaration = findAncestor(node.parent, isAcceptedDeclaration); @@ -131,8 +165,14 @@ namespace ts.codefix { const name = declaration.name.text; const startWithUnderscore = startsWithUnderscore(name); - const fieldName = createPropertyName(startWithUnderscore ? name : getUniqueName(`_${name}`, file), declaration.name); - const accessorName = createPropertyName(startWithUnderscore ? getUniqueName(name.substring(1), file) : name, declaration.name); + const fieldName = createPropertyName( + startWithUnderscore ? name : getUniqueName(`_${name}`, file), + declaration.name, + ); + const accessorName = createPropertyName( + startWithUnderscore ? getUniqueName(name.substring(1), file) : name, + declaration.name, + ); return { isStatic: hasStaticModifier(declaration), isReadonly: hasEffectiveReadonlyModifier(declaration), @@ -146,7 +186,14 @@ namespace ts.codefix { }; } - function generateGetAccessor(fieldName: AcceptedNameType, accessorName: AcceptedNameType, type: TypeNode | undefined, modifiers: readonly ModifierLike[] | undefined, isStatic: boolean, container: ContainerDeclaration) { + function generateGetAccessor( + fieldName: AcceptedNameType, + accessorName: AcceptedNameType, + type: TypeNode | undefined, + modifiers: readonly ModifierLike[] | undefined, + isStatic: boolean, + container: ContainerDeclaration, + ) { return factory.createGetAccessorDeclaration( modifiers, accessorName, @@ -160,7 +207,14 @@ namespace ts.codefix { ); } - function generateSetAccessor(fieldName: AcceptedNameType, accessorName: AcceptedNameType, type: TypeNode | undefined, modifiers: readonly ModifierLike[] | undefined, isStatic: boolean, container: ContainerDeclaration) { + function generateSetAccessor( + fieldName: AcceptedNameType, + accessorName: AcceptedNameType, + type: TypeNode | undefined, + modifiers: readonly ModifierLike[] | undefined, + isStatic: boolean, + container: ContainerDeclaration, + ) { return factory.createSetAccessorDeclaration( modifiers, accessorName, @@ -182,7 +236,14 @@ namespace ts.codefix { ); } - function updatePropertyDeclaration(changeTracker: textChanges.ChangeTracker, file: SourceFile, declaration: PropertyDeclaration, type: TypeNode | undefined, fieldName: AcceptedNameType, modifiers: readonly ModifierLike[] | undefined) { + function updatePropertyDeclaration( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + declaration: PropertyDeclaration, + type: TypeNode | undefined, + fieldName: AcceptedNameType, + modifiers: readonly ModifierLike[] | undefined, + ) { const property = factory.updatePropertyDeclaration( declaration, modifiers, @@ -194,12 +255,24 @@ namespace ts.codefix { changeTracker.replaceNode(file, declaration, property); } - function updatePropertyAssignmentDeclaration(changeTracker: textChanges.ChangeTracker, file: SourceFile, declaration: PropertyAssignment, fieldName: AcceptedNameType) { + function updatePropertyAssignmentDeclaration( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + declaration: PropertyAssignment, + fieldName: AcceptedNameType, + ) { const assignment = factory.updatePropertyAssignment(declaration, fieldName, declaration.initializer); changeTracker.replacePropertyAssignment(file, declaration, assignment); } - function updateFieldDeclaration(changeTracker: textChanges.ChangeTracker, file: SourceFile, declaration: AcceptedDeclaration, type: TypeNode | undefined, fieldName: AcceptedNameType, modifiers: readonly ModifierLike[] | undefined) { + function updateFieldDeclaration( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + declaration: AcceptedDeclaration, + type: TypeNode | undefined, + fieldName: AcceptedNameType, + modifiers: readonly ModifierLike[] | undefined, + ) { if (isPropertyDeclaration(declaration)) { updatePropertyDeclaration(changeTracker, file, declaration, type, fieldName, modifiers); } @@ -207,29 +280,57 @@ namespace ts.codefix { updatePropertyAssignmentDeclaration(changeTracker, file, declaration, fieldName); } else { - changeTracker.replaceNode(file, declaration, factory.updateParameterDeclaration(declaration, modifiers, declaration.dotDotDotToken, cast(fieldName, isIdentifier), declaration.questionToken, declaration.type, declaration.initializer)); + changeTracker.replaceNode( + file, + declaration, + factory.updateParameterDeclaration( + declaration, + modifiers, + declaration.dotDotDotToken, + cast(fieldName, isIdentifier), + declaration.questionToken, + declaration.type, + declaration.initializer, + ), + ); } } - function insertAccessor(changeTracker: textChanges.ChangeTracker, file: SourceFile, accessor: AccessorDeclaration, declaration: AcceptedDeclaration, container: ContainerDeclaration) { - isParameterPropertyDeclaration(declaration, declaration.parent) ? changeTracker.insertMemberAtStart(file, container as ClassLikeDeclaration, accessor) : - isPropertyAssignment(declaration) ? changeTracker.insertNodeAfterComma(file, declaration, accessor) : - changeTracker.insertNodeAfter(file, declaration, accessor); + function insertAccessor( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + accessor: AccessorDeclaration, + declaration: AcceptedDeclaration, + container: ContainerDeclaration, + ) { + isParameterPropertyDeclaration(declaration, declaration.parent) + ? changeTracker.insertMemberAtStart(file, container as ClassLikeDeclaration, accessor) + : isPropertyAssignment(declaration) ? changeTracker.insertNodeAfterComma(file, declaration, accessor) + : changeTracker.insertNodeAfter(file, declaration, accessor); } - function updateReadonlyPropertyInitializerStatementConstructor(changeTracker: textChanges.ChangeTracker, file: SourceFile, constructor: ConstructorDeclaration, fieldName: string, originalName: string) { + function updateReadonlyPropertyInitializerStatementConstructor( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + constructor: ConstructorDeclaration, + fieldName: string, + originalName: string, + ) { if (!constructor.body) return; constructor.body.forEachChild(function recur(node) { if ( - isElementAccessExpression(node) && - node.expression.kind === SyntaxKind.ThisKeyword && - isStringLiteral(node.argumentExpression) && - node.argumentExpression.text === originalName && - isWriteAccess(node) + isElementAccessExpression(node) + && node.expression.kind === SyntaxKind.ThisKeyword + && isStringLiteral(node.argumentExpression) + && node.argumentExpression.text === originalName + && isWriteAccess(node) ) { changeTracker.replaceNode(file, node.argumentExpression, factory.createStringLiteral(fieldName)); } - if (isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword && node.name.text === originalName && isWriteAccess(node)) { + if ( + isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword + && node.name.text === originalName && isWriteAccess(node) + ) { changeTracker.replaceNode(file, node.name, factory.createIdentifier(fieldName)); } if (!isFunctionLike(node) && !isClassLike(node)) { @@ -245,13 +346,19 @@ namespace ts.codefix { const type = typeChecker.getTypeFromTypeNode(typeNode); if (!typeChecker.isTypeAssignableTo(typeChecker.getUndefinedType(), type)) { const types = isUnionTypeNode(typeNode) ? typeNode.types : [typeNode]; - return factory.createUnionTypeNode([...types, factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]); + return factory.createUnionTypeNode([ + ...types, + factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword), + ]); } } return typeNode; } - export function getAllSupers(decl: ClassOrInterface | undefined, checker: TypeChecker): readonly ClassOrInterface[] { + export function getAllSupers( + decl: ClassOrInterface | undefined, + checker: TypeChecker, + ): readonly ClassOrInterface[] { const res: ClassLikeDeclaration[] = []; while (decl) { const superElement = getClassExtendsHeritageElement(decl); diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 7e7f270626f72..7cd620c12d9f0 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -19,7 +19,16 @@ namespace ts.codefix { const classMembers = classDeclaration.symbol.members!; for (const symbol of possiblyMissingSymbols) { if (!classMembers.has(symbol.escapedName)) { - addNewNodeForMemberSymbol(symbol, classDeclaration, sourceFile, context, preferences, importAdder, addClassElement, /* body */ undefined); + addNewNodeForMemberSymbol( + symbol, + classDeclaration, + sourceFile, + context, + preferences, + importAdder, + addClassElement, + /* body */ undefined, + ); } } } @@ -36,7 +45,13 @@ namespace ts.codefix { host: LanguageServiceHost; } - type AddNode = PropertyDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction; + type AddNode = + | PropertyDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration + | MethodDeclaration + | FunctionExpression + | ArrowFunction; export const enum PreserveOptionalFlags { Method = 1 << 0, @@ -80,15 +95,19 @@ namespace ts.codefix { * In such cases, we assume the declaration to be a `PropertySignature`. */ const kind = declaration?.kind ?? SyntaxKind.PropertySignature; - const declarationName = getSynthesizedDeepClone(getNameOfDeclaration(declaration), /*includeTrivia*/ false) as PropertyName; + const declarationName = getSynthesizedDeepClone( + getNameOfDeclaration(declaration), + /*includeTrivia*/ false, + ) as PropertyName; const effectiveModifierFlags = declaration ? getEffectiveModifierFlags(declaration) : ModifierFlags.None; - let modifierFlags = effectiveModifierFlags & ModifierFlags.Public ? ModifierFlags.Public : - effectiveModifierFlags & ModifierFlags.Protected ? ModifierFlags.Protected : - ModifierFlags.None; + let modifierFlags = effectiveModifierFlags & ModifierFlags.Public ? ModifierFlags.Public + : effectiveModifierFlags & ModifierFlags.Protected ? ModifierFlags.Protected + : ModifierFlags.None; if (declaration && isAutoAccessorPropertyDeclaration(declaration)) { modifierFlags |= ModifierFlags.Accessor; } - const modifiers = modifierFlags ? factory.createNodeArray(factory.createModifiersFromModifierFlags(modifierFlags)) : undefined; + const modifiers = modifierFlags + ? factory.createNodeArray(factory.createModifiersFromModifierFlags(modifierFlags)) : undefined; const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration)); const optional = !!(symbol.flags & SymbolFlags.Optional); const ambient = !!(enclosingDeclaration.flags & NodeFlags.Ambient) || isAmbient; @@ -97,8 +116,14 @@ namespace ts.codefix { switch (kind) { case SyntaxKind.PropertySignature: case SyntaxKind.PropertyDeclaration: - const flags = quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : undefined; - let typeNode = checker.typeToTypeNode(type, enclosingDeclaration, flags, getNoopSymbolTrackerWithResolver(context)); + const flags = quotePreference === QuotePreference.Single + ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : undefined; + let typeNode = checker.typeToTypeNode( + type, + enclosingDeclaration, + flags, + getNoopSymbolTrackerWithResolver(context), + ); if (importAdder) { const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget); if (importableReference) { @@ -109,7 +134,8 @@ namespace ts.codefix { addClassElement(factory.createPropertyDeclaration( modifiers, declaration ? createName(declarationName) : symbol.getName(), - optional && (preserveOptional & PreserveOptionalFlags.Property) ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + optional && (preserveOptional & PreserveOptionalFlags.Property) + ? factory.createToken(SyntaxKind.QuestionToken) : undefined, typeNode, /*initializer*/ undefined, )); @@ -117,7 +143,12 @@ namespace ts.codefix { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: { Debug.assertIsDefined(declarations); - let typeNode = checker.typeToTypeNode(type, enclosingDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context)); + let typeNode = checker.typeToTypeNode( + type, + enclosingDeclaration, + /*flags*/ undefined, + getNoopSymbolTrackerWithResolver(context), + ); const allAccessors = getAllAccessorDeclarations(declarations, declaration as AccessorDeclaration); const orderedAccessors = allAccessors.secondAccessor ? [allAccessors.firstAccessor, allAccessors.secondAccessor] @@ -140,9 +171,14 @@ namespace ts.codefix { )); } else { - Debug.assertNode(accessor, isSetAccessorDeclaration, "The counterpart to a getter should be a setter"); + Debug.assertNode( + accessor, + isSetAccessorDeclaration, + "The counterpart to a getter should be a setter", + ); const parameter = getSetAccessorValueParameter(accessor); - const parameterName = parameter && isIdentifier(parameter.name) ? idText(parameter.name) : undefined; + const parameterName = parameter && isIdentifier(parameter.name) ? idText(parameter.name) + : undefined; addClassElement(factory.createSetAccessorDeclaration( modifiers, createName(declarationName), @@ -163,7 +199,8 @@ namespace ts.codefix { // (eg: an abstract method or interface declaration), there is a 1-1 // correspondence of declarations and signatures. Debug.assertIsDefined(declarations); - const signatures = type.isUnion() ? flatMap(type.types, t => t.getCallSignatures()) : type.getCallSignatures(); + const signatures = type.isUnion() ? flatMap(type.types, t => t.getCallSignatures()) + : type.getCallSignatures(); if (!some(signatures)) { break; } @@ -171,7 +208,13 @@ namespace ts.codefix { if (declarations.length === 1) { Debug.assert(signatures.length === 1, "One declaration implies one signature"); const signature = signatures[0]; - outputMethod(quotePreference, signature, modifiers, createName(declarationName), createBody(body, quotePreference, ambient)); + outputMethod( + quotePreference, + signature, + modifiers, + createName(declarationName), + createBody(body, quotePreference, ambient), + ); break; } @@ -182,19 +225,59 @@ namespace ts.codefix { if (!ambient) { if (declarations.length > signatures.length) { - const signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration)!; - outputMethod(quotePreference, signature, modifiers, createName(declarationName), createBody(body, quotePreference)); + const signature = checker.getSignatureFromDeclaration( + declarations[declarations.length - 1] as SignatureDeclaration, + )!; + outputMethod( + quotePreference, + signature, + modifiers, + createName(declarationName), + createBody(body, quotePreference), + ); } else { - Debug.assert(declarations.length === signatures.length, "Declarations and signatures should match count"); - addClassElement(createMethodImplementingSignatures(checker, context, enclosingDeclaration, signatures, createName(declarationName), optional && !!(preserveOptional & PreserveOptionalFlags.Method), modifiers, quotePreference, body)); + Debug.assert( + declarations.length === signatures.length, + "Declarations and signatures should match count", + ); + addClassElement( + createMethodImplementingSignatures( + checker, + context, + enclosingDeclaration, + signatures, + createName(declarationName), + optional && !!(preserveOptional & PreserveOptionalFlags.Method), + modifiers, + quotePreference, + body, + ), + ); } } break; } - function outputMethod(quotePreference: QuotePreference, signature: Signature, modifiers: NodeArray | undefined, name: PropertyName, body?: Block): void { - const method = createSignatureDeclarationFromSignature(SyntaxKind.MethodDeclaration, context, quotePreference, signature, body, name, modifiers, optional && !!(preserveOptional & PreserveOptionalFlags.Method), enclosingDeclaration, importAdder) as MethodDeclaration; + function outputMethod( + quotePreference: QuotePreference, + signature: Signature, + modifiers: NodeArray | undefined, + name: PropertyName, + body?: Block, + ): void { + const method = createSignatureDeclarationFromSignature( + SyntaxKind.MethodDeclaration, + context, + quotePreference, + signature, + body, + name, + modifiers, + optional && !!(preserveOptional & PreserveOptionalFlags.Method), + enclosingDeclaration, + importAdder, + ) as MethodDeclaration; if (method) addClassElement(method); } @@ -203,8 +286,8 @@ namespace ts.codefix { } function createBody(block: Block | undefined, quotePreference: QuotePreference, ambient?: boolean) { - return ambient ? undefined : - getSynthesizedDeepClone(block, /*includeTrivia*/ false) || createStubbedMethodBody(quotePreference); + return ambient ? undefined + : getSynthesizedDeepClone(block, /*includeTrivia*/ false) || createStubbedMethodBody(quotePreference); } function createTypeNode(typeNode: TypeNode | undefined) { @@ -234,8 +317,15 @@ namespace ts.codefix { const flags = NodeBuilderFlags.NoTruncation | NodeBuilderFlags.SuppressAnyReturnType | NodeBuilderFlags.AllowEmptyTuple - | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : NodeBuilderFlags.None); - const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, kind, enclosingDeclaration, flags, getNoopSymbolTrackerWithResolver(context)) as ArrowFunction | FunctionExpression | MethodDeclaration | FunctionDeclaration; + | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType + : NodeBuilderFlags.None); + const signatureDeclaration = checker.signatureToSignatureDeclaration( + signature, + kind, + enclosingDeclaration, + flags, + getNoopSymbolTrackerWithResolver(context), + ) as ArrowFunction | FunctionExpression | MethodDeclaration | FunctionDeclaration; if (!signatureDeclaration) { return undefined; } @@ -256,7 +346,10 @@ namespace ts.codefix { } } if (defaultType) { - const importableReference = tryGetAutoImportableReferenceFromTypeNode(defaultType, scriptTarget); + const importableReference = tryGetAutoImportableReferenceFromTypeNode( + defaultType, + scriptTarget, + ); if (importableReference) { defaultType = importableReference.typeNode; importSymbols(importAdder, importableReference.symbols); @@ -271,7 +364,10 @@ namespace ts.codefix { ); }); if (typeParameters !== newTypeParameters) { - typeParameters = setTextRange(factory.createNodeArray(newTypeParameters, typeParameters.hasTrailingComma), typeParameters); + typeParameters = setTextRange( + factory.createNodeArray(newTypeParameters, typeParameters.hasTrailingComma), + typeParameters, + ); } } const newParameters = sameMap(parameters, parameterDecl => { @@ -292,7 +388,10 @@ namespace ts.codefix { ); }); if (parameters !== newParameters) { - parameters = setTextRange(factory.createNodeArray(newParameters, parameters.hasTrailingComma), parameters); + parameters = setTextRange( + factory.createNodeArray(newParameters, parameters.hasTrailingComma), + parameters, + ); } if (type) { const importableReference = tryGetAutoImportableReferenceFromTypeNode(type, scriptTarget); @@ -306,16 +405,52 @@ namespace ts.codefix { const questionToken = optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; const asteriskToken = signatureDeclaration.asteriskToken; if (isFunctionExpression(signatureDeclaration)) { - return factory.updateFunctionExpression(signatureDeclaration, modifiers, signatureDeclaration.asteriskToken, tryCast(name, isIdentifier), typeParameters, parameters, type, body ?? signatureDeclaration.body); + return factory.updateFunctionExpression( + signatureDeclaration, + modifiers, + signatureDeclaration.asteriskToken, + tryCast(name, isIdentifier), + typeParameters, + parameters, + type, + body ?? signatureDeclaration.body, + ); } if (isArrowFunction(signatureDeclaration)) { - return factory.updateArrowFunction(signatureDeclaration, modifiers, typeParameters, parameters, type, signatureDeclaration.equalsGreaterThanToken, body ?? signatureDeclaration.body); + return factory.updateArrowFunction( + signatureDeclaration, + modifiers, + typeParameters, + parameters, + type, + signatureDeclaration.equalsGreaterThanToken, + body ?? signatureDeclaration.body, + ); } if (isMethodDeclaration(signatureDeclaration)) { - return factory.updateMethodDeclaration(signatureDeclaration, modifiers, asteriskToken, name ?? factory.createIdentifier(""), questionToken, typeParameters, parameters, type, body); + return factory.updateMethodDeclaration( + signatureDeclaration, + modifiers, + asteriskToken, + name ?? factory.createIdentifier(""), + questionToken, + typeParameters, + parameters, + type, + body, + ); } if (isFunctionDeclaration(signatureDeclaration)) { - return factory.updateFunctionDeclaration(signatureDeclaration, modifiers, signatureDeclaration.asteriskToken, tryCast(name, isIdentifier), typeParameters, parameters, type, body ?? signatureDeclaration.body); + return factory.updateFunctionDeclaration( + signatureDeclaration, + modifiers, + signatureDeclaration.asteriskToken, + tryCast(name, isIdentifier), + typeParameters, + parameters, + type, + body ?? signatureDeclaration.body, + ); } return undefined; } @@ -337,7 +472,12 @@ namespace ts.codefix { const { typeArguments, arguments: args, parent } = call; const contextualType = isJs ? undefined : checker.getContextualType(call); - const names = map(args, arg => isIdentifier(arg) ? arg.text : isPropertyAccessExpression(arg) && isIdentifier(arg.name) ? arg.name.text : undefined); + const names = map( + args, + arg => + isIdentifier(arg) ? arg.text + : isPropertyAccessExpression(arg) && isIdentifier(arg.name) ? arg.name.text : undefined, + ); const instanceTypes = isJs ? [] : map(args, arg => checker.getTypeAtLocation(arg)); const { argumentTypeNodes, argumentTypeParameters } = getArgumentTypesAndTypeParameters( checker, @@ -355,8 +495,15 @@ namespace ts.codefix { const asteriskToken = isYieldExpression(parent) ? factory.createToken(SyntaxKind.AsteriskToken) : undefined; - const typeParameters = isJs ? undefined : createTypeParametersForArguments(checker, argumentTypeParameters, typeArguments); - const parameters = createDummyParameters(args.length, names, argumentTypeNodes, /*minArgumentCount*/ undefined, isJs); + const typeParameters = isJs ? undefined + : createTypeParametersForArguments(checker, argumentTypeParameters, typeArguments); + const parameters = createDummyParameters( + args.length, + names, + argumentTypeNodes, + /*minArgumentCount*/ undefined, + isJs, + ); const type = isJs || contextualType === undefined ? undefined : checker.typeToTypeNode(contextualType, contextNode, /*flags*/ undefined, tracker); @@ -402,12 +549,18 @@ namespace ts.codefix { constraint?: TypeNode; } - function createTypeParametersForArguments(checker: TypeChecker, argumentTypeParameters: [string, ArgumentTypeParameterAndConstraint | undefined][], typeArguments: NodeArray | undefined) { + function createTypeParametersForArguments( + checker: TypeChecker, + argumentTypeParameters: [string, ArgumentTypeParameterAndConstraint | undefined][], + typeArguments: NodeArray | undefined, + ) { const usedNames = new Set(argumentTypeParameters.map(pair => pair[0])); const constraintsByName = new Map(argumentTypeParameters); if (typeArguments) { - const typeArgumentsWithNewTypes = typeArguments.filter(typeArgument => !argumentTypeParameters.some(pair => checker.getTypeAtLocation(typeArgument) === pair[1]?.argumentType)); + const typeArgumentsWithNewTypes = typeArguments.filter(typeArgument => + !argumentTypeParameters.some(pair => checker.getTypeAtLocation(typeArgument) === pair[1]?.argumentType) + ); const targetSize = usedNames.size + typeArgumentsWithNewTypes.length; for (let i = 0; usedNames.size < targetSize; i += 1) { usedNames.add(createTypeParameterName(i)); @@ -416,7 +569,12 @@ namespace ts.codefix { return map( arrayFrom(usedNames.values()), - usedName => factory.createTypeParameterDeclaration(/*modifiers*/ undefined, usedName, constraintsByName.get(usedName)?.constraint), + usedName => + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + usedName, + constraintsByName.get(usedName)?.constraint, + ), ); } @@ -426,7 +584,15 @@ namespace ts.codefix { : `T${index}`; } - export function typeToAutoImportableTypeNode(checker: TypeChecker, importAdder: ImportAdder, type: Type, contextNode: Node | undefined, scriptTarget: ScriptTarget, flags?: NodeBuilderFlags, tracker?: SymbolTracker): TypeNode | undefined { + export function typeToAutoImportableTypeNode( + checker: TypeChecker, + importAdder: ImportAdder, + type: Type, + contextNode: Node | undefined, + scriptTarget: ScriptTarget, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ): TypeNode | undefined { let typeNode = checker.typeToTypeNode(type, contextNode, flags, tracker); if (typeNode && isImportTypeNode(typeNode)) { const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget); @@ -448,7 +614,15 @@ namespace ts.codefix { return type.flags & TypeFlags.TypeParameter; } - export function getArgumentTypesAndTypeParameters(checker: TypeChecker, importAdder: ImportAdder, instanceTypes: Type[], contextNode: Node | undefined, scriptTarget: ScriptTarget, flags?: NodeBuilderFlags, tracker?: SymbolTracker) { + export function getArgumentTypesAndTypeParameters( + checker: TypeChecker, + importAdder: ImportAdder, + instanceTypes: Type[], + contextNode: Node | undefined, + scriptTarget: ScriptTarget, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) { // Types to be used as the types of the parameters in the new function // E.g. from this source: // added("", 0) @@ -491,7 +665,15 @@ namespace ts.codefix { // Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {" const widenedInstanceType = checker.getBaseTypeOfLiteralType(instanceType); - const argumentTypeNode = typeToAutoImportableTypeNode(checker, importAdder, widenedInstanceType, contextNode, scriptTarget, flags, tracker); + const argumentTypeNode = typeToAutoImportableTypeNode( + checker, + importAdder, + widenedInstanceType, + contextNode, + scriptTarget, + flags, + tracker, + ); if (!argumentTypeNode) { continue; } @@ -508,12 +690,24 @@ namespace ts.codefix { // function added(value: T) { ... } // We instead want to output: // function added(value: T) { ... } - const instanceTypeConstraint = instanceType.isTypeParameter() && instanceType.constraint && !isAnonymousObjectConstraintType(instanceType.constraint) - ? typeToAutoImportableTypeNode(checker, importAdder, instanceType.constraint, contextNode, scriptTarget, flags, tracker) + const instanceTypeConstraint = instanceType.isTypeParameter() && instanceType.constraint + && !isAnonymousObjectConstraintType(instanceType.constraint) + ? typeToAutoImportableTypeNode( + checker, + importAdder, + instanceType.constraint, + contextNode, + scriptTarget, + flags, + tracker, + ) : undefined; if (argumentTypeParameter) { - argumentTypeParameters.set(argumentTypeParameter, { argumentType: instanceType, constraint: instanceTypeConstraint }); + argumentTypeParameters.set(argumentTypeParameter, { + argumentType: instanceType, + constraint: instanceTypeConstraint, + }); } } @@ -539,7 +733,13 @@ namespace ts.codefix { : undefined; } - function createDummyParameters(argCount: number, names: (string | undefined)[] | undefined, types: (TypeNode | undefined)[] | undefined, minArgumentCount: number | undefined, inJs: boolean): ParameterDeclaration[] { + function createDummyParameters( + argCount: number, + names: (string | undefined)[] | undefined, + types: (TypeNode | undefined)[] | undefined, + minArgumentCount: number | undefined, + inJs: boolean, + ): ParameterDeclaration[] { const parameters: ParameterDeclaration[] = []; const parameterNameCounts = new Map(); for (let i = 0; i < argCount; i++) { @@ -551,7 +751,8 @@ namespace ts.codefix { /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ parameterName + (parameterNameCount || ""), - /*questionToken*/ minArgumentCount !== undefined && i >= minArgumentCount ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + /*questionToken*/ minArgumentCount !== undefined && i >= minArgumentCount + ? factory.createToken(SyntaxKind.QuestionToken) : undefined, /*type*/ inJs ? undefined : types?.[i] || factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword), /*initializer*/ undefined, ); @@ -583,20 +784,31 @@ namespace ts.codefix { if (signatureHasRestParameter(sig)) { someSigHasRestParameter = true; } - if (sig.parameters.length >= maxArgsSignature.parameters.length && (!signatureHasRestParameter(sig) || signatureHasRestParameter(maxArgsSignature))) { + if ( + sig.parameters.length >= maxArgsSignature.parameters.length + && (!signatureHasRestParameter(sig) || signatureHasRestParameter(maxArgsSignature)) + ) { maxArgsSignature = sig; } } - const maxNonRestArgs = maxArgsSignature.parameters.length - (signatureHasRestParameter(maxArgsSignature) ? 1 : 0); + const maxNonRestArgs = maxArgsSignature.parameters.length + - (signatureHasRestParameter(maxArgsSignature) ? 1 : 0); const maxArgsParameterSymbolNames = maxArgsSignature.parameters.map(symbol => symbol.name); - const parameters = createDummyParameters(maxNonRestArgs, maxArgsParameterSymbolNames, /* types */ undefined, minArgumentCount, /*inJs*/ false); + const parameters = createDummyParameters( + maxNonRestArgs, + maxArgsParameterSymbolNames, + /* types */ undefined, + minArgumentCount, + /*inJs*/ false, + ); if (someSigHasRestParameter) { const restParameter = factory.createParameterDeclaration( /*modifiers*/ undefined, factory.createToken(SyntaxKind.DotDotDotToken), maxArgsParameterSymbolNames[maxNonRestArgs] || "rest", - /*questionToken*/ maxNonRestArgs >= minArgumentCount ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + /*questionToken*/ maxNonRestArgs >= minArgumentCount ? factory.createToken(SyntaxKind.QuestionToken) + : undefined, factory.createArrayTypeNode(factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword)), /*initializer*/ undefined, ); @@ -615,10 +827,20 @@ namespace ts.codefix { ); } - function getReturnTypeFromSignatures(signatures: readonly Signature[], checker: TypeChecker, context: TypeConstructionContext, enclosingDeclaration: ClassLikeDeclaration): TypeNode | undefined { + function getReturnTypeFromSignatures( + signatures: readonly Signature[], + checker: TypeChecker, + context: TypeConstructionContext, + enclosingDeclaration: ClassLikeDeclaration, + ): TypeNode | undefined { if (length(signatures)) { const type = checker.getUnionType(map(signatures, checker.getReturnTypeOfSignature)); - return checker.typeToTypeNode(type, enclosingDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context)); + return checker.typeToTypeNode( + type, + enclosingDeclaration, + /*flags*/ undefined, + getNoopSymbolTrackerWithResolver(context), + ); } } @@ -677,7 +899,12 @@ namespace ts.codefix { tsconfigObjectLiteral, createJsonPropertyAssignment( "compilerOptions", - factory.createObjectLiteralExpression(options.map(([optionName, optionValue]) => createJsonPropertyAssignment(optionName, optionValue)), /*multiLine*/ true), + factory.createObjectLiteralExpression( + options.map(([optionName, optionValue]) => + createJsonPropertyAssignment(optionName, optionValue) + ), + /*multiLine*/ true, + ), ), ); return; @@ -691,7 +918,11 @@ namespace ts.codefix { for (const [optionName, optionValue] of options) { const optionProperty = findJsonProperty(compilerOptions, optionName); if (optionProperty === undefined) { - changeTracker.insertNodeAtObjectStart(configFile, compilerOptions, createJsonPropertyAssignment(optionName, optionValue)); + changeTracker.insertNodeAtObjectStart( + configFile, + compilerOptions, + createJsonPropertyAssignment(optionName, optionValue), + ); } else { changeTracker.replaceNode(configFile, optionProperty.initializer, optionValue); @@ -713,7 +944,11 @@ namespace ts.codefix { } export function findJsonProperty(obj: ObjectLiteralExpression, name: string): PropertyAssignment | undefined { - return find(obj.properties, (p): p is PropertyAssignment => isPropertyAssignment(p) && !!p.name && isStringLiteral(p.name) && p.name.text === name); + return find( + obj.properties, + (p): p is PropertyAssignment => + isPropertyAssignment(p) && !!p.name && isStringLiteral(p.name) && p.name.text === name, + ); } /** @@ -721,7 +956,10 @@ namespace ts.codefix { * returns an equivalent type reference node with any nested ImportTypeNodes also replaced * with type references, and a list of symbols that must be imported to use the type reference. */ - export function tryGetAutoImportableReferenceFromTypeNode(importTypeNode: TypeNode | undefined, scriptTarget: ScriptTarget) { + export function tryGetAutoImportableReferenceFromTypeNode( + importTypeNode: TypeNode | undefined, + scriptTarget: ScriptTarget, + ) { let symbols: Symbol[] | undefined; const typeNode = visitNode(importTypeNode, visit); if (symbols && typeNode) { diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 62ec32bd06e5a..a1f7c323a3284 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -10,7 +10,8 @@ namespace ts.codefix { Diagnostics.Cannot_find_namespace_0.code, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here.code, - Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer.code, + Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer + .code, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type.code, ]; @@ -36,7 +37,14 @@ namespace ts.codefix { fixIds: [importFixId], getAllCodeActions: context => { const { sourceFile, program, preferences, host, cancellationToken } = context; - const importAdder = createImportAdderWorker(sourceFile, program, /*useAutoImportProvider*/ true, preferences, host, cancellationToken); + const importAdder = createImportAdderWorker( + sourceFile, + program, + /*useAutoImportProvider*/ true, + preferences, + host, + cancellationToken, + ); eachDiagnostic(context, errorCodes, diag => importAdder.addImportFromDiagnostic(diag, context)); return createCombinedCodeActions(textChanges.ChangeTracker.with(context, importAdder.writeFixes)); }, @@ -52,8 +60,21 @@ namespace ts.codefix { writeFixes: (changeTracker: textChanges.ChangeTracker) => void; } - export function createImportAdder(sourceFile: SourceFile, program: Program, preferences: UserPreferences, host: LanguageServiceHost, cancellationToken?: CancellationToken): ImportAdder { - return createImportAdderWorker(sourceFile, program, /*useAutoImportProvider*/ false, preferences, host, cancellationToken); + export function createImportAdder( + sourceFile: SourceFile, + program: Program, + preferences: UserPreferences, + host: LanguageServiceHost, + cancellationToken?: CancellationToken, + ): ImportAdder { + return createImportAdderWorker( + sourceFile, + program, + /*useAutoImportProvider*/ false, + preferences, + host, + cancellationToken, + ); } interface AddToExistingState { @@ -62,7 +83,14 @@ namespace ts.codefix { readonly namedImports: ESMap; } - function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAutoImportProvider: boolean, preferences: UserPreferences, host: LanguageServiceHost, cancellationToken: CancellationToken | undefined): ImportAdder { + function createImportAdderWorker( + sourceFile: SourceFile, + program: Program, + useAutoImportProvider: boolean, + preferences: UserPreferences, + host: LanguageServiceHost, + cancellationToken: CancellationToken | undefined, + ): ImportAdder { const compilerOptions = program.getCompilerOptions(); // Namespace fixes don't conflict, so just build a list. const addToNamespace: FixUseNamespaceImport[] = []; @@ -86,9 +114,28 @@ namespace ts.codefix { const symbolName = getNameForExportedSymbol(exportedSymbol, getEmitScriptTarget(compilerOptions)); const checker = program.getTypeChecker(); const symbol = checker.getMergedSymbol(skipAlias(exportedSymbol, checker)); - const exportInfo = getAllExportInfoForSymbol(sourceFile, symbol, symbolName, /*isJsxTagName*/ false, program, host, preferences, cancellationToken); + const exportInfo = getAllExportInfoForSymbol( + sourceFile, + symbol, + symbolName, + /*isJsxTagName*/ false, + program, + host, + preferences, + cancellationToken, + ); const useRequire = shouldUseRequire(sourceFile, program); - const fix = getImportFixForSymbol(sourceFile, Debug.checkDefined(exportInfo), moduleSymbol, program, /*useNamespaceInfo*/ undefined, !!isValidTypeOnlyUseSite, useRequire, host, preferences); + const fix = getImportFixForSymbol( + sourceFile, + Debug.checkDefined(exportInfo), + moduleSymbol, + program, + /*useNamespaceInfo*/ undefined, + !!isValidTypeOnlyUseSite, + useRequire, + host, + preferences, + ); if (fix) { addImport({ fix, symbolName, errorIdentifierText: undefined }); } @@ -108,14 +155,20 @@ namespace ts.codefix { const key = String(getNodeId(importClauseOrBindingPattern)); let entry = addToExisting.get(key); if (!entry) { - addToExisting.set(key, entry = { importClauseOrBindingPattern, defaultImport: undefined, namedImports: new Map() }); + addToExisting.set( + key, + entry = { importClauseOrBindingPattern, defaultImport: undefined, namedImports: new Map() }, + ); } if (importKind === ImportKind.Named) { const prevValue = entry?.namedImports.get(symbolName); entry.namedImports.set(symbolName, reduceAddAsTypeOnlyValues(prevValue, addAsTypeOnly)); } else { - Debug.assert(entry.defaultImport === undefined || entry.defaultImport.name === symbolName, "(Add to Existing) Default import should be missing or match symbolName"); + Debug.assert( + entry.defaultImport === undefined || entry.defaultImport.name === symbolName, + "(Add to Existing) Default import should be missing or match symbolName", + ); entry.defaultImport = { name: symbolName, addAsTypeOnly: reduceAddAsTypeOnlyValues(entry.defaultImport?.addAsTypeOnly, addAsTypeOnly), @@ -126,12 +179,24 @@ namespace ts.codefix { case ImportFixKind.AddNew: { const { moduleSpecifier, importKind, useRequire, addAsTypeOnly } = fix; const entry = getNewImportEntry(moduleSpecifier, importKind, useRequire, addAsTypeOnly); - Debug.assert(entry.useRequire === useRequire, "(Add new) Tried to add an `import` and a `require` for the same module"); + Debug.assert( + entry.useRequire === useRequire, + "(Add new) Tried to add an `import` and a `require` for the same module", + ); switch (importKind) { case ImportKind.Default: - Debug.assert(entry.defaultImport === undefined || entry.defaultImport.name === symbolName, "(Add new) Default import should be missing or match symbolName"); - entry.defaultImport = { name: symbolName, addAsTypeOnly: reduceAddAsTypeOnlyValues(entry.defaultImport?.addAsTypeOnly, addAsTypeOnly) }; + Debug.assert( + entry.defaultImport === undefined || entry.defaultImport.name === symbolName, + "(Add new) Default import should be missing or match symbolName", + ); + entry.defaultImport = { + name: symbolName, + addAsTypeOnly: reduceAddAsTypeOnlyValues( + entry.defaultImport?.addAsTypeOnly, + addAsTypeOnly, + ), + }; break; case ImportKind.Named: const prevValue = (entry.namedImports ||= new Map()).get(symbolName); @@ -139,7 +204,11 @@ namespace ts.codefix { break; case ImportKind.CommonJS: case ImportKind.Namespace: - Debug.assert(entry.namespaceLikeImport === undefined || entry.namespaceLikeImport.name === symbolName, "Namespacelike import shoudl be missing or match symbolName"); + Debug.assert( + entry.namespaceLikeImport === undefined + || entry.namespaceLikeImport.name === symbolName, + "Namespacelike import shoudl be missing or match symbolName", + ); entry.namespaceLikeImport = { importKind, name: symbolName, addAsTypeOnly }; break; } @@ -152,7 +221,10 @@ namespace ts.codefix { Debug.assertNever(fix, `fix wasn't never - got kind ${(fix as ImportFix).kind}`); } - function reduceAddAsTypeOnlyValues(prevValue: AddAsTypeOnly | undefined, newValue: AddAsTypeOnly): AddAsTypeOnly { + function reduceAddAsTypeOnlyValues( + prevValue: AddAsTypeOnly | undefined, + newValue: AddAsTypeOnly, + ): AddAsTypeOnly { // `NotAllowed` overrides `Required` because one addition of a new import might be required to be type-only // because of `--importsNotUsedAsValues=error`, but if a second addition of the same import is `NotAllowed` // to be type-only, the reason the first one was `Required` - the unused runtime dependency - is now moot. @@ -162,7 +234,12 @@ namespace ts.codefix { return Math.max(prevValue ?? 0, newValue); } - function getNewImportEntry(moduleSpecifier: string, importKind: ImportKind, useRequire: boolean, addAsTypeOnly: AddAsTypeOnly): Mutable { + function getNewImportEntry( + moduleSpecifier: string, + importKind: ImportKind, + useRequire: boolean, + addAsTypeOnly: AddAsTypeOnly, + ): Mutable { // A default import that requires type-only makes the whole import type-only. // (We could add `default` as a named import, but that style seems undesirable.) // Under `--preserveValueImports` and `--importsNotUsedAsValues=error`, if a @@ -226,7 +303,8 @@ namespace ts.codefix { moduleSpecifier, quotePreference, defaultImport, - namedImports && arrayFrom(namedImports.entries(), ([name, addAsTypeOnly]) => ({ addAsTypeOnly, name })), + namedImports + && arrayFrom(namedImports.entries(), ([name, addAsTypeOnly]) => ({ addAsTypeOnly, name })), namespaceLikeImport, ); newDeclarations = combine(newDeclarations, declarations); @@ -254,9 +332,18 @@ namespace ts.codefix { ): { exportInfo?: SymbolExportInfo; moduleSpecifier: string; computedWithoutCacheCount: number; } | undefined; } - export function createImportSpecifierResolver(importingFile: SourceFile, program: Program, host: LanguageServiceHost, preferences: UserPreferences): ImportSpecifierResolver { + export function createImportSpecifierResolver( + importingFile: SourceFile, + program: Program, + host: LanguageServiceHost, + preferences: UserPreferences, + ): ImportSpecifierResolver { const packageJsonImportFilter = createPackageJsonImportFilter(importingFile, preferences, host); - const importMap = createExistingImportMap(program.getTypeChecker(), importingFile, program.getCompilerOptions()); + const importMap = createExistingImportMap( + program.getTypeChecker(), + importingFile, + program.getCompilerOptions(), + ); return { getModuleSpecifierForBestExportInfo }; function getModuleSpecifierForBestExportInfo( @@ -300,8 +387,17 @@ namespace ts.codefix { Required = 1 << 1, NotAllowed = 1 << 2, } - type ImportFix = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport | FixPromoteTypeOnlyImport; - type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; + type ImportFix = + | FixUseNamespaceImport + | FixAddJsdocTypeImport + | FixAddToExistingImport + | FixAddNewImport + | FixPromoteTypeOnlyImport; + type ImportFixWithModuleSpecifier = + | FixUseNamespaceImport + | FixAddJsdocTypeImport + | FixAddToExistingImport + | FixAddNewImport; // Properties are be undefined if fix is derived from an existing import interface ImportFixBase { @@ -362,12 +458,33 @@ namespace ts.codefix { const exportInfos = pathIsBareSpecifier(stripQuotes(moduleSymbol.name)) ? [getSingleExportInfoForSymbol(targetSymbol, moduleSymbol, program, host)] - : getAllExportInfoForSymbol(sourceFile, targetSymbol, symbolName, isJsxTagName, program, host, preferences, cancellationToken); + : getAllExportInfoForSymbol( + sourceFile, + targetSymbol, + symbolName, + isJsxTagName, + program, + host, + preferences, + cancellationToken, + ); Debug.assertIsDefined(exportInfos); const useRequire = shouldUseRequire(sourceFile, program); const isValidTypeOnlyUseSite = isValidTypeOnlyAliasUseSite(getTokenAtPosition(sourceFile, position)); - const fix = Debug.checkDefined(getImportFixForSymbol(sourceFile, exportInfos, moduleSymbol, program, { symbolName, position }, isValidTypeOnlyUseSite, useRequire, host, preferences)); + const fix = Debug.checkDefined( + getImportFixForSymbol( + sourceFile, + exportInfos, + moduleSymbol, + program, + { symbolName, position }, + isValidTypeOnlyUseSite, + useRequire, + host, + preferences, + ), + ); return { moduleSpecifier: fix.moduleSpecifier, codeAction: codeFixActionToCodeAction(codeActionForFix( @@ -382,25 +499,82 @@ namespace ts.codefix { }; } - export function getPromoteTypeOnlyCompletionAction(sourceFile: SourceFile, symbolToken: Identifier, program: Program, host: LanguageServiceHost, formatContext: formatting.FormatContext, preferences: UserPreferences) { + export function getPromoteTypeOnlyCompletionAction( + sourceFile: SourceFile, + symbolToken: Identifier, + program: Program, + host: LanguageServiceHost, + formatContext: formatting.FormatContext, + preferences: UserPreferences, + ) { const compilerOptions = program.getCompilerOptions(); - const symbolName = single(getSymbolNamesToImport(sourceFile, program.getTypeChecker(), symbolToken, compilerOptions)); + const symbolName = single( + getSymbolNamesToImport(sourceFile, program.getTypeChecker(), symbolToken, compilerOptions), + ); const fix = getTypeOnlyPromotionFix(sourceFile, symbolToken, symbolName, program); const includeSymbolNameInDescription = symbolName !== symbolToken.text; - return fix && codeFixActionToCodeAction(codeActionForFix({ host, formatContext, preferences }, sourceFile, symbolName, fix, includeSymbolNameInDescription, QuotePreference.Double, compilerOptions)); + return fix + && codeFixActionToCodeAction( + codeActionForFix( + { host, formatContext, preferences }, + sourceFile, + symbolName, + fix, + includeSymbolNameInDescription, + QuotePreference.Double, + compilerOptions, + ), + ); } - function getImportFixForSymbol(sourceFile: SourceFile, exportInfos: readonly SymbolExportInfo[], moduleSymbol: Symbol, program: Program, useNamespaceInfo: { position: number; symbolName: string; } | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, host: LanguageServiceHost, preferences: UserPreferences) { - Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol || info.symbol.parent === moduleSymbol), "Some exportInfo should match the specified moduleSymbol"); + function getImportFixForSymbol( + sourceFile: SourceFile, + exportInfos: readonly SymbolExportInfo[], + moduleSymbol: Symbol, + program: Program, + useNamespaceInfo: { position: number; symbolName: string; } | undefined, + isValidTypeOnlyUseSite: boolean, + useRequire: boolean, + host: LanguageServiceHost, + preferences: UserPreferences, + ) { + Debug.assert( + exportInfos.some(info => info.moduleSymbol === moduleSymbol || info.symbol.parent === moduleSymbol), + "Some exportInfo should match the specified moduleSymbol", + ); const packageJsonImportFilter = createPackageJsonImportFilter(sourceFile, preferences, host); - return getBestFix(getImportFixes(exportInfos, useNamespaceInfo, isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences).fixes, sourceFile, program, packageJsonImportFilter, host); + return getBestFix( + getImportFixes( + exportInfos, + useNamespaceInfo, + isValidTypeOnlyUseSite, + useRequire, + program, + sourceFile, + host, + preferences, + ).fixes, + sourceFile, + program, + packageJsonImportFilter, + host, + ); } function codeFixActionToCodeAction({ description, changes, commands }: CodeFixAction): CodeAction { return { description, changes, commands }; } - function getAllExportInfoForSymbol(importingFile: SourceFile, symbol: Symbol, symbolName: string, preferCapitalized: boolean, program: Program, host: LanguageServiceHost, preferences: UserPreferences, cancellationToken: CancellationToken | undefined): readonly SymbolExportInfo[] | undefined { + function getAllExportInfoForSymbol( + importingFile: SourceFile, + symbol: Symbol, + symbolName: string, + preferCapitalized: boolean, + program: Program, + host: LanguageServiceHost, + preferences: UserPreferences, + cancellationToken: CancellationToken | undefined, + ): readonly SymbolExportInfo[] | undefined { const getChecker = createGetChecker(program, host); return getExportInfoMap(importingFile, host, program, preferences, cancellationToken) .search(importingFile.path, preferCapitalized, name => name === symbolName, info => { @@ -410,23 +584,45 @@ namespace ts.codefix { }); } - function getSingleExportInfoForSymbol(symbol: Symbol, moduleSymbol: Symbol, program: Program, host: LanguageServiceHost): SymbolExportInfo { + function getSingleExportInfoForSymbol( + symbol: Symbol, + moduleSymbol: Symbol, + program: Program, + host: LanguageServiceHost, + ): SymbolExportInfo { const compilerOptions = program.getCompilerOptions(); const mainProgramInfo = getInfoWithChecker(program.getTypeChecker(), /*isFromPackageJson*/ false); if (mainProgramInfo) { return mainProgramInfo; } const autoImportProvider = host.getPackageJsonAutoImportProvider?.()?.getTypeChecker(); - return Debug.checkDefined(autoImportProvider && getInfoWithChecker(autoImportProvider, /*isFromPackageJson*/ true), `Could not find symbol in specified module for code actions`); + return Debug.checkDefined( + autoImportProvider && getInfoWithChecker(autoImportProvider, /*isFromPackageJson*/ true), + `Could not find symbol in specified module for code actions`, + ); function getInfoWithChecker(checker: TypeChecker, isFromPackageJson: boolean): SymbolExportInfo | undefined { const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); if (defaultInfo && skipAlias(defaultInfo.symbol, checker) === symbol) { - return { symbol: defaultInfo.symbol, moduleSymbol, moduleFileName: undefined, exportKind: defaultInfo.exportKind, targetFlags: skipAlias(symbol, checker).flags, isFromPackageJson }; + return { + symbol: defaultInfo.symbol, + moduleSymbol, + moduleFileName: undefined, + exportKind: defaultInfo.exportKind, + targetFlags: skipAlias(symbol, checker).flags, + isFromPackageJson, + }; } const named = checker.tryGetMemberInModuleExportsAndProperties(symbol.name, moduleSymbol); if (named && skipAlias(named, checker) === symbol) { - return { symbol: named, moduleSymbol, moduleFileName: undefined, exportKind: ExportKind.Named, targetFlags: skipAlias(symbol, checker).flags, isFromPackageJson }; + return { + symbol: named, + moduleSymbol, + moduleFileName: undefined, + exportKind: ExportKind.Named, + targetFlags: skipAlias(symbol, checker).flags, + isFromPackageJson, + }; } } } @@ -449,8 +645,19 @@ namespace ts.codefix { ): { computedWithoutCacheCount: number; fixes: readonly ImportFixWithModuleSpecifier[]; } { const checker = program.getTypeChecker(); const existingImports = flatMap(exportInfos, importMap.getImportsForExportInfo); - const useNamespace = useNamespaceInfo && tryUseExistingNamespaceImport(existingImports, useNamespaceInfo.symbolName, useNamespaceInfo.position, checker); - const addToExisting = tryAddToExistingImport(existingImports, isValidTypeOnlyUseSite, checker, program.getCompilerOptions()); + const useNamespace = useNamespaceInfo + && tryUseExistingNamespaceImport( + existingImports, + useNamespaceInfo.symbolName, + useNamespaceInfo.position, + checker, + ); + const addToExisting = tryAddToExistingImport( + existingImports, + isValidTypeOnlyUseSite, + checker, + program.getCompilerOptions(), + ); if (addToExisting) { // Don't bother providing an action to add a new import if we can add to an existing one. return { @@ -477,7 +684,12 @@ namespace ts.codefix { }; } - function tryUseExistingNamespaceImport(existingImports: readonly FixAddToExistingImportInfo[], symbolName: string, position: number, checker: TypeChecker): FixUseNamespaceImport | undefined { + function tryUseExistingNamespaceImport( + existingImports: readonly FixAddToExistingImportInfo[], + symbolName: string, + position: number, + checker: TypeChecker, + ): FixUseNamespaceImport | undefined { // It is possible that multiple import statements with the same specifier exist in the file. // e.g. // @@ -546,8 +758,8 @@ namespace ts.codefix { return AddAsTypeOnly.Required; } if ( - compilerOptions.isolatedModules && compilerOptions.preserveValueImports && - (!(targetFlags & SymbolFlags.Value) || !!checker.getTypeOnlyAliasDeclaration(symbol)) + compilerOptions.isolatedModules && compilerOptions.preserveValueImports + && (!(targetFlags & SymbolFlags.Value) || !!checker.getTypeOnlyAliasDeclaration(symbol)) ) { // A type-only import is required for this symbol if under these settings if the symbol will // be erased, which will happen if the target symbol is purely a type or if it was exported/imported @@ -557,53 +769,82 @@ namespace ts.codefix { return AddAsTypeOnly.Allowed; } - function tryAddToExistingImport(existingImports: readonly FixAddToExistingImportInfo[], isValidTypeOnlyUseSite: boolean, checker: TypeChecker, compilerOptions: CompilerOptions): FixAddToExistingImport | undefined { - return firstDefined(existingImports, ({ declaration, importKind, symbol, targetFlags }): FixAddToExistingImport | undefined => { - if (importKind === ImportKind.CommonJS || importKind === ImportKind.Namespace || declaration.kind === SyntaxKind.ImportEqualsDeclaration) { - // These kinds of imports are not combinable with anything - return undefined; - } - - if (declaration.kind === SyntaxKind.VariableDeclaration) { - return (importKind === ImportKind.Named || importKind === ImportKind.Default) && declaration.name.kind === SyntaxKind.ObjectBindingPattern - ? { kind: ImportFixKind.AddToExisting, importClauseOrBindingPattern: declaration.name, importKind, moduleSpecifier: declaration.initializer.arguments[0].text, addAsTypeOnly: AddAsTypeOnly.NotAllowed } - : undefined; - } - - const { importClause } = declaration; - if (!importClause || !isStringLiteralLike(declaration.moduleSpecifier)) return undefined; - const { name, namedBindings } = importClause; - // A type-only import may not have both a default and named imports, so the only way a name can - // be added to an existing type-only import is adding a named import to existing named bindings. - if (importClause.isTypeOnly && !(importKind === ImportKind.Named && namedBindings)) return undefined; + function tryAddToExistingImport( + existingImports: readonly FixAddToExistingImportInfo[], + isValidTypeOnlyUseSite: boolean, + checker: TypeChecker, + compilerOptions: CompilerOptions, + ): FixAddToExistingImport | undefined { + return firstDefined( + existingImports, + ({ declaration, importKind, symbol, targetFlags }): FixAddToExistingImport | undefined => { + if ( + importKind === ImportKind.CommonJS || importKind === ImportKind.Namespace + || declaration.kind === SyntaxKind.ImportEqualsDeclaration + ) { + // These kinds of imports are not combinable with anything + return undefined; + } - // N.B. we don't have to figure out whether to use the main program checker - // or the AutoImportProvider checker because we're adding to an existing import; the existence of - // the import guarantees the symbol came from the main program. - const addAsTypeOnly = getAddAsTypeOnly(isValidTypeOnlyUseSite, /*isForNewImportDeclaration*/ false, symbol, targetFlags, checker, compilerOptions); + if (declaration.kind === SyntaxKind.VariableDeclaration) { + return (importKind === ImportKind.Named || importKind === ImportKind.Default) + && declaration.name.kind === SyntaxKind.ObjectBindingPattern + ? { + kind: ImportFixKind.AddToExisting, + importClauseOrBindingPattern: declaration.name, + importKind, + moduleSpecifier: declaration.initializer.arguments[0].text, + addAsTypeOnly: AddAsTypeOnly.NotAllowed, + } + : undefined; + } - if ( - importKind === ImportKind.Default && ( - name || // Cannot add a default import to a declaration that already has one - addAsTypeOnly === AddAsTypeOnly.Required && namedBindings // Cannot add a default import as type-only if the import already has named bindings - ) - ) return undefined; - if ( - importKind === ImportKind.Named && - namedBindings?.kind === SyntaxKind.NamespaceImport // Cannot add a named import to a declaration that has a namespace import - ) return undefined; + const { importClause } = declaration; + if (!importClause || !isStringLiteralLike(declaration.moduleSpecifier)) return undefined; + const { name, namedBindings } = importClause; + // A type-only import may not have both a default and named imports, so the only way a name can + // be added to an existing type-only import is adding a named import to existing named bindings. + if (importClause.isTypeOnly && !(importKind === ImportKind.Named && namedBindings)) return undefined; + + // N.B. we don't have to figure out whether to use the main program checker + // or the AutoImportProvider checker because we're adding to an existing import; the existence of + // the import guarantees the symbol came from the main program. + const addAsTypeOnly = getAddAsTypeOnly( + isValidTypeOnlyUseSite, + /*isForNewImportDeclaration*/ false, + symbol, + targetFlags, + checker, + compilerOptions, + ); - return { - kind: ImportFixKind.AddToExisting, - importClauseOrBindingPattern: importClause, - importKind, - moduleSpecifier: declaration.moduleSpecifier.text, - addAsTypeOnly, - }; - }); + if ( + importKind === ImportKind.Default && ( + name // Cannot add a default import to a declaration that already has one + || addAsTypeOnly === AddAsTypeOnly.Required && namedBindings // Cannot add a default import as type-only if the import already has named bindings + ) + ) return undefined; + if ( + importKind === ImportKind.Named + && namedBindings?.kind === SyntaxKind.NamespaceImport // Cannot add a named import to a declaration that has a namespace import + ) return undefined; + + return { + kind: ImportFixKind.AddToExisting, + importClauseOrBindingPattern: importClause, + importKind, + moduleSpecifier: declaration.moduleSpecifier.text, + addAsTypeOnly, + }; + }, + ); } - function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile, compilerOptions: CompilerOptions) { + function createExistingImportMap( + checker: TypeChecker, + importingFile: SourceFile, + compilerOptions: CompilerOptions, + ) { let importMap: MultiMap | undefined; for (const moduleSpecifier of importingFile.imports) { const i = importFromModuleSpecifier(moduleSpecifier); @@ -622,7 +863,9 @@ namespace ts.codefix { } return { - getImportsForExportInfo: ({ moduleSymbol, exportKind, targetFlags, symbol }: SymbolExportInfo): readonly FixAddToExistingImportInfo[] => { + getImportsForExportInfo: ( + { moduleSymbol, exportKind, targetFlags, symbol }: SymbolExportInfo, + ): readonly FixAddToExistingImportInfo[] => { // Can't use an es6 import for a type in JS. if (!(targetFlags & SymbolFlags.Value) && isSourceFileJS(importingFile)) return emptyArray; const matchingDeclarations = importMap?.get(getSymbolId(moduleSymbol)); @@ -651,7 +894,10 @@ namespace ts.codefix { // 4. Match the first other JS file in the program that's unambiguously CJS or ESM for (const otherFile of program.getSourceFiles()) { - if (otherFile === sourceFile || !isSourceFileJS(otherFile) || program.isSourceFileFromExternalLibrary(otherFile)) continue; + if ( + otherFile === sourceFile || !isSourceFileJS(otherFile) + || program.isSourceFileFromExternalLibrary(otherFile) + ) continue; if (otherFile.commonJsModuleIndicator && !otherFile.externalModuleIndicator) return true; if (otherFile.externalModuleIndicator && !otherFile.commonJsModuleIndicator) return false; } @@ -661,7 +907,9 @@ namespace ts.codefix { } function createGetChecker(program: Program, host: LanguageServiceHost) { - return memoizeOne((isFromPackageJson: boolean) => isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() : program.getTypeChecker()); + return memoizeOne((isFromPackageJson: boolean) => + isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() : program.getTypeChecker() + ); } function getNewImportFixes( @@ -679,31 +927,66 @@ namespace ts.codefix { const compilerOptions = program.getCompilerOptions(); const moduleSpecifierResolutionHost = createModuleSpecifierResolutionHost(program, host); const getChecker = createGetChecker(program, host); - const rejectNodeModulesRelativePaths = moduleResolutionUsesNodeModules(getEmitModuleResolutionKind(compilerOptions)); + const rejectNodeModulesRelativePaths = moduleResolutionUsesNodeModules( + getEmitModuleResolutionKind(compilerOptions), + ); const getModuleSpecifiers = fromCacheOnly - ? (moduleSymbol: Symbol) => ({ moduleSpecifiers: moduleSpecifiers.tryGetModuleSpecifiersFromCache(moduleSymbol, sourceFile, moduleSpecifierResolutionHost, preferences), computedWithoutCache: false }) - : (moduleSymbol: Symbol, checker: TypeChecker) => moduleSpecifiers.getModuleSpecifiersWithCacheInfo(moduleSymbol, checker, compilerOptions, sourceFile, moduleSpecifierResolutionHost, preferences); + ? (moduleSymbol: Symbol) => ({ + moduleSpecifiers: moduleSpecifiers.tryGetModuleSpecifiersFromCache( + moduleSymbol, + sourceFile, + moduleSpecifierResolutionHost, + preferences, + ), + computedWithoutCache: false, + }) + : (moduleSymbol: Symbol, checker: TypeChecker) => + moduleSpecifiers.getModuleSpecifiersWithCacheInfo( + moduleSymbol, + checker, + compilerOptions, + sourceFile, + moduleSpecifierResolutionHost, + preferences, + ); let computedWithoutCacheCount = 0; const fixes = flatMap(exportInfo, (exportInfo, i) => { const checker = getChecker(exportInfo.isFromPackageJson); const { computedWithoutCache, moduleSpecifiers } = getModuleSpecifiers(exportInfo.moduleSymbol, checker); const importedSymbolHasValueMeaning = !!(exportInfo.targetFlags & SymbolFlags.Value); - const addAsTypeOnly = getAddAsTypeOnly(isValidTypeOnlyUseSite, /*isForNewImportDeclaration*/ true, exportInfo.symbol, exportInfo.targetFlags, checker, compilerOptions); + const addAsTypeOnly = getAddAsTypeOnly( + isValidTypeOnlyUseSite, + /*isForNewImportDeclaration*/ true, + exportInfo.symbol, + exportInfo.targetFlags, + checker, + compilerOptions, + ); computedWithoutCacheCount += computedWithoutCache ? 1 : 0; - return mapDefined(moduleSpecifiers, (moduleSpecifier): FixAddNewImport | FixAddJsdocTypeImport | undefined => - rejectNodeModulesRelativePaths && pathContainsNodeModules(moduleSpecifier) ? undefined : - // `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types. - !importedSymbolHasValueMeaning && isJs && position !== undefined ? { kind: ImportFixKind.JsdocTypeImport, moduleSpecifier, position, exportInfo, isReExport: i > 0 } : - { - kind: ImportFixKind.AddNew, - moduleSpecifier, - importKind: getImportKind(sourceFile, exportInfo.exportKind, compilerOptions), - useRequire, - addAsTypeOnly, - exportInfo, - isReExport: i > 0, - }); + return mapDefined( + moduleSpecifiers, + (moduleSpecifier): FixAddNewImport | FixAddJsdocTypeImport | undefined => + rejectNodeModulesRelativePaths && pathContainsNodeModules(moduleSpecifier) ? undefined + // `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types. + : !importedSymbolHasValueMeaning && isJs && position !== undefined + ? { + kind: ImportFixKind.JsdocTypeImport, + moduleSpecifier, + position, + exportInfo, + isReExport: i > 0, + } + : { + kind: ImportFixKind.AddNew, + moduleSpecifier, + importKind: getImportKind(sourceFile, exportInfo.exportKind, compilerOptions), + useRequire, + addAsTypeOnly, + exportInfo, + isReExport: i > 0, + }, + ); }); return { computedWithoutCacheCount, fixes }; @@ -721,8 +1004,29 @@ namespace ts.codefix { preferences: UserPreferences, fromCacheOnly?: boolean, ): { computedWithoutCacheCount?: number; fixes: readonly (FixAddNewImport | FixAddJsdocTypeImport)[]; } { - const existingDeclaration = firstDefined(existingImports, info => newImportInfoFromExistingSpecifier(info, isValidTypeOnlyUseSite, useRequire, program.getTypeChecker(), program.getCompilerOptions())); - return existingDeclaration ? { fixes: [existingDeclaration] } : getNewImportFixes(program, sourceFile, position, isValidTypeOnlyUseSite, useRequire, exportInfos, host, preferences, fromCacheOnly); + const existingDeclaration = firstDefined( + existingImports, + info => + newImportInfoFromExistingSpecifier( + info, + isValidTypeOnlyUseSite, + useRequire, + program.getTypeChecker(), + program.getCompilerOptions(), + ), + ); + return existingDeclaration ? { fixes: [existingDeclaration] } + : getNewImportFixes( + program, + sourceFile, + position, + isValidTypeOnlyUseSite, + useRequire, + exportInfos, + host, + preferences, + fromCacheOnly, + ); } function newImportInfoFromExistingSpecifier( @@ -736,7 +1040,14 @@ namespace ts.codefix { if (moduleSpecifier) { const addAsTypeOnly = useRequire ? AddAsTypeOnly.NotAllowed - : getAddAsTypeOnly(isValidTypeOnlyUseSite, /*isForNewImportDeclaration*/ true, symbol, targetFlags, checker, compilerOptions); + : getAddAsTypeOnly( + isValidTypeOnlyUseSite, + /*isForNewImportDeclaration*/ true, + symbol, + targetFlags, + checker, + compilerOptions, + ); return { kind: ImportFixKind.AddNew, moduleSpecifier, importKind, addAsTypeOnly, useRequire }; } } @@ -747,17 +1058,35 @@ namespace ts.codefix { readonly errorIdentifierText: string | undefined; readonly isJsxNamespaceFix?: boolean; } - function getFixInfos(context: CodeFixContextBase, errorCode: number, pos: number, useAutoImportProvider: boolean): readonly FixInfo[] | undefined { + function getFixInfos( + context: CodeFixContextBase, + errorCode: number, + pos: number, + useAutoImportProvider: boolean, + ): readonly FixInfo[] | undefined { const symbolToken = getTokenAtPosition(context.sourceFile, pos); let info; - if (errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code) { + if ( + errorCode + === Diagnostics + ._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code + ) { info = getFixesInfoForUMDImport(context, symbolToken); } else if (!isIdentifier(symbolToken)) { return undefined; } - else if (errorCode === Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type.code) { - const symbolName = single(getSymbolNamesToImport(context.sourceFile, context.program.getTypeChecker(), symbolToken, context.program.getCompilerOptions())); + else if ( + errorCode === Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type.code + ) { + const symbolName = single( + getSymbolNamesToImport( + context.sourceFile, + context.program.getTypeChecker(), + symbolToken, + context.program.getCompilerOptions(), + ), + ); const fix = getTypeOnlyPromotionFix(context.sourceFile, symbolToken, symbolName, context.program); return fix && [{ fix, symbolName, errorIdentifierText: symbolToken.text }]; } @@ -765,19 +1094,43 @@ namespace ts.codefix { info = getFixesInfoForNonUMDImport(context, symbolToken, useAutoImportProvider); } - const packageJsonImportFilter = createPackageJsonImportFilter(context.sourceFile, context.preferences, context.host); + const packageJsonImportFilter = createPackageJsonImportFilter( + context.sourceFile, + context.preferences, + context.host, + ); return info && sortFixInfo(info, context.sourceFile, context.program, packageJsonImportFilter, context.host); } - function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] { - const _toPath = (fileName: string) => toPath(fileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host)); + function sortFixInfo( + fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[], + sourceFile: SourceFile, + program: Program, + packageJsonImportFilter: PackageJsonImportFilter, + host: LanguageServiceHost, + ): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] { + const _toPath = (fileName: string) => + toPath(fileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host)); return sort(fixes, (a, b) => - compareBooleans(!!a.isJsxNamespaceFix, !!b.isJsxNamespaceFix) || - compareValues(a.fix.kind, b.fix.kind) || - compareModuleSpecifiers(a.fix, b.fix, sourceFile, program, packageJsonImportFilter.allowsImportingSpecifier, _toPath)); + compareBooleans(!!a.isJsxNamespaceFix, !!b.isJsxNamespaceFix) + || compareValues(a.fix.kind, b.fix.kind) + || compareModuleSpecifiers( + a.fix, + b.fix, + sourceFile, + program, + packageJsonImportFilter.allowsImportingSpecifier, + _toPath, + )); } - function getBestFix(fixes: readonly ImportFixWithModuleSpecifier[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost): ImportFixWithModuleSpecifier | undefined { + function getBestFix( + fixes: readonly ImportFixWithModuleSpecifier[], + sourceFile: SourceFile, + program: Program, + packageJsonImportFilter: PackageJsonImportFilter, + host: LanguageServiceHost, + ): ImportFixWithModuleSpecifier | undefined { if (!some(fixes)) return; // These will always be placed first if available, and are better than other kinds if (fixes[0].kind === ImportFixKind.UseNamespace || fixes[0].kind === ImportFixKind.AddToExisting) { @@ -807,7 +1160,10 @@ namespace ts.codefix { toPath: (fileName: string) => Path, ): Comparison { if (a.kind !== ImportFixKind.UseNamespace && b.kind !== ImportFixKind.UseNamespace) { - return compareBooleans(allowsImportingSpecifier(b.moduleSpecifier), allowsImportingSpecifier(a.moduleSpecifier)) + return compareBooleans( + allowsImportingSpecifier(b.moduleSpecifier), + allowsImportingSpecifier(a.moduleSpecifier), + ) || compareNodeCoreModuleSpecifiers(a.moduleSpecifier, b.moduleSpecifier, importingFile, program) || compareBooleans( isFixPossiblyReExportingImportingFile(a, importingFile, program.getCompilerOptions(), toPath), @@ -823,12 +1179,17 @@ namespace ts.codefix { // This can produce false positives or negatives if re-exports cross into sibling directories // (e.g. `export * from "../whatever"`) or are not named "index" (we don't even try to consider // this if we're in a resolution mode where you can't drop trailing "/index" from paths). - function isFixPossiblyReExportingImportingFile(fix: ImportFixWithModuleSpecifier, importingFile: SourceFile, compilerOptions: CompilerOptions, toPath: (fileName: string) => Path): boolean { + function isFixPossiblyReExportingImportingFile( + fix: ImportFixWithModuleSpecifier, + importingFile: SourceFile, + compilerOptions: CompilerOptions, + toPath: (fileName: string) => Path, + ): boolean { if ( - fix.isReExport && - fix.exportInfo?.moduleFileName && - getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs && - isIndexFileName(fix.exportInfo.moduleFileName) + fix.isReExport + && fix.exportInfo?.moduleFileName + && getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs + && isIndexFileName(fix.exportInfo.moduleFileName) ) { const reExportDir = toPath(getDirectoryPath(fix.exportInfo.moduleFileName)); return startsWith(importingFile.path, reExportDir); @@ -840,22 +1201,52 @@ namespace ts.codefix { return getBaseFileName(fileName, [".js", ".jsx", ".d.ts", ".ts", ".tsx"], /*ignoreCase*/ true) === "index"; } - function compareNodeCoreModuleSpecifiers(a: string, b: string, importingFile: SourceFile, program: Program): Comparison { - if (startsWith(a, "node:") && !startsWith(b, "node:")) return shouldUseUriStyleNodeCoreModules(importingFile, program) ? Comparison.LessThan : Comparison.GreaterThan; - if (startsWith(b, "node:") && !startsWith(a, "node:")) return shouldUseUriStyleNodeCoreModules(importingFile, program) ? Comparison.GreaterThan : Comparison.LessThan; + function compareNodeCoreModuleSpecifiers( + a: string, + b: string, + importingFile: SourceFile, + program: Program, + ): Comparison { + if (startsWith(a, "node:") && !startsWith(b, "node:")) { + return shouldUseUriStyleNodeCoreModules(importingFile, program) ? Comparison.LessThan + : Comparison.GreaterThan; + } + if (startsWith(b, "node:") && !startsWith(a, "node:")) { + return shouldUseUriStyleNodeCoreModules(importingFile, program) ? Comparison.GreaterThan + : Comparison.LessThan; + } return Comparison.EqualTo; } - function getFixesInfoForUMDImport({ sourceFile, program, host, preferences }: CodeFixContextBase, token: Node): (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { + function getFixesInfoForUMDImport( + { sourceFile, program, host, preferences }: CodeFixContextBase, + token: Node, + ): (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { const checker = program.getTypeChecker(); const umdSymbol = getUmdSymbol(token, checker); if (!umdSymbol) return undefined; const symbol = checker.getAliasedSymbol(umdSymbol); const symbolName = umdSymbol.name; - const exportInfo: readonly SymbolExportInfo[] = [{ symbol: umdSymbol, moduleSymbol: symbol, moduleFileName: undefined, exportKind: ExportKind.UMD, targetFlags: symbol.flags, isFromPackageJson: false }]; + const exportInfo: readonly SymbolExportInfo[] = [{ + symbol: umdSymbol, + moduleSymbol: symbol, + moduleFileName: undefined, + exportKind: ExportKind.UMD, + targetFlags: symbol.flags, + isFromPackageJson: false, + }]; const useRequire = shouldUseRequire(sourceFile, program); const position = isIdentifier(token) ? token.getStart(sourceFile) : undefined; - const fixes = getImportFixes(exportInfo, position ? { position, symbolName } : undefined, /*isValidTypeOnlyUseSite*/ false, useRequire, program, sourceFile, host, preferences).fixes; + const fixes = getImportFixes( + exportInfo, + position ? { position, symbolName } : undefined, + /*isValidTypeOnlyUseSite*/ false, + useRequire, + program, + sourceFile, + host, + preferences, + ).fixes; return fixes.map(fix => ({ fix, symbolName, errorIdentifierText: tryCast(token, isIdentifier)?.text })); } function getUmdSymbol(token: Node, checker: TypeChecker): Symbol | undefined { @@ -866,7 +1257,15 @@ namespace ts.codefix { // The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`. const { parent } = token; return (isJsxOpeningLikeElement(parent) && parent.tagName === token) || isJsxOpeningFragment(parent) - ? tryCast(checker.resolveName(checker.getJsxNamespace(parent), isJsxOpeningLikeElement(parent) ? token : parent, SymbolFlags.Value, /*excludeGlobals*/ false), isUMDExportSymbol) + ? tryCast( + checker.resolveName( + checker.getJsxNamespace(parent), + isJsxOpeningLikeElement(parent) ? token : parent, + SymbolFlags.Value, + /*excludeGlobals*/ false, + ), + isUMDExportSymbol, + ) : undefined; } @@ -874,7 +1273,12 @@ namespace ts.codefix { * @param forceImportKeyword Indicates that the user has already typed `import`, so the result must start with `import`. * (In other words, do not allow `const x = require("...")` for JS files.) */ - export function getImportKind(importingFile: SourceFile, exportKind: ExportKind, compilerOptions: CompilerOptions, forceImportKeyword?: boolean): ImportKind { + export function getImportKind( + importingFile: SourceFile, + exportKind: ExportKind, + compilerOptions: CompilerOptions, + forceImportKeyword?: boolean, + ): ImportKind { switch (exportKind) { case ExportKind.Named: return ImportKind.Named; @@ -889,7 +1293,11 @@ namespace ts.codefix { } } - function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions, forceImportKeyword: boolean): ImportKind { + function getUmdImportKind( + importingFile: SourceFile, + compilerOptions: CompilerOptions, + forceImportKeyword: boolean, + ): ImportKind { // Import a synthetic `default` if enabled. if (getAllowSyntheticDefaultImports(compilerOptions)) { return ImportKind.Default; @@ -902,7 +1310,8 @@ namespace ts.codefix { case ModuleKind.CommonJS: case ModuleKind.UMD: if (isInJSFile(importingFile)) { - return isExternalModule(importingFile) || forceImportKeyword ? ImportKind.Namespace : ImportKind.CommonJS; + return isExternalModule(importingFile) || forceImportKeyword ? ImportKind.Namespace + : ImportKind.CommonJS; } return ImportKind.CommonJS; case ModuleKind.System: @@ -915,13 +1324,18 @@ namespace ts.codefix { return ImportKind.Namespace; case ModuleKind.Node16: case ModuleKind.NodeNext: - return importingFile.impliedNodeFormat === ModuleKind.ESNext ? ImportKind.Namespace : ImportKind.CommonJS; + return importingFile.impliedNodeFormat === ModuleKind.ESNext ? ImportKind.Namespace + : ImportKind.CommonJS; default: return Debug.assertNever(moduleKind, `Unexpected moduleKind ${moduleKind}`); } } - function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { + function getFixesInfoForNonUMDImport( + { sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, + symbolToken: Identifier, + useAutoImportProvider: boolean, + ): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { const checker = program.getTypeChecker(); const compilerOptions = program.getCompilerOptions(); return flatMap(getSymbolNamesToImport(sourceFile, checker, symbolToken, compilerOptions), symbolName => { @@ -931,13 +1345,45 @@ namespace ts.codefix { } const isValidTypeOnlyUseSite = isValidTypeOnlyAliasUseSite(symbolToken); const useRequire = shouldUseRequire(sourceFile, program); - const exportInfo = getExportInfos(symbolName, isJSXTagName(symbolToken), getMeaningFromLocation(symbolToken), cancellationToken, sourceFile, program, useAutoImportProvider, host, preferences); - const fixes = arrayFrom(flatMapIterator(exportInfo.entries(), ([_, exportInfos]) => getImportFixes(exportInfos, { symbolName, position: symbolToken.getStart(sourceFile) }, isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences).fixes)); - return fixes.map(fix => ({ fix, symbolName, errorIdentifierText: symbolToken.text, isJsxNamespaceFix: symbolName !== symbolToken.text })); + const exportInfo = getExportInfos( + symbolName, + isJSXTagName(symbolToken), + getMeaningFromLocation(symbolToken), + cancellationToken, + sourceFile, + program, + useAutoImportProvider, + host, + preferences, + ); + const fixes = arrayFrom( + flatMapIterator(exportInfo.entries(), ([_, exportInfos]) => + getImportFixes( + exportInfos, + { symbolName, position: symbolToken.getStart(sourceFile) }, + isValidTypeOnlyUseSite, + useRequire, + program, + sourceFile, + host, + preferences, + ).fixes), + ); + return fixes.map(fix => ({ + fix, + symbolName, + errorIdentifierText: symbolToken.text, + isJsxNamespaceFix: symbolName !== symbolToken.text, + })); }); } - function getTypeOnlyPromotionFix(sourceFile: SourceFile, symbolToken: Identifier, symbolName: string, program: Program): FixPromoteTypeOnlyImport | undefined { + function getTypeOnlyPromotionFix( + sourceFile: SourceFile, + symbolToken: Identifier, + symbolName: string, + program: Program, + ): FixPromoteTypeOnlyImport | undefined { const checker = program.getTypeChecker(); const symbol = checker.resolveName(symbolName, symbolToken, SymbolFlags.Value, /*excludeGlobals*/ true); if (!symbol) return undefined; @@ -948,12 +1394,21 @@ namespace ts.codefix { return { kind: ImportFixKind.PromoteTypeOnly, typeOnlyAliasDeclaration }; } - function getSymbolNamesToImport(sourceFile: SourceFile, checker: TypeChecker, symbolToken: Identifier, compilerOptions: CompilerOptions): string[] { + function getSymbolNamesToImport( + sourceFile: SourceFile, + checker: TypeChecker, + symbolToken: Identifier, + compilerOptions: CompilerOptions, + ): string[] { const parent = symbolToken.parent; - if ((isJsxOpeningLikeElement(parent) || isJsxClosingElement(parent)) && parent.tagName === symbolToken && jsxModeNeedsExplicitImport(compilerOptions.jsx)) { + if ( + (isJsxOpeningLikeElement(parent) || isJsxClosingElement(parent)) && parent.tagName === symbolToken + && jsxModeNeedsExplicitImport(compilerOptions.jsx) + ) { const jsxNamespace = checker.getJsxNamespace(sourceFile); if (needsJsxNamespaceFix(jsxNamespace, symbolToken, checker)) { - const needsComponentNameFix = !isIntrinsicJsxName(symbolToken.text) && !checker.resolveName(symbolToken.text, symbolToken, SymbolFlags.Value, /*excludeGlobals*/ false); + const needsComponentNameFix = !isIntrinsicJsxName(symbolToken.text) + && !checker.resolveName(symbolToken.text, symbolToken, SymbolFlags.Value, /*excludeGlobals*/ false); return needsComponentNameFix ? [symbolToken.text, jsxNamespace] : [jsxNamespace]; } } @@ -962,8 +1417,15 @@ namespace ts.codefix { function needsJsxNamespaceFix(jsxNamespace: string, symbolToken: Identifier, checker: TypeChecker) { if (isIntrinsicJsxName(symbolToken.text)) return true; // If we were triggered by a matching error code on an intrinsic, the error must have been about missing the JSX factory - const namespaceSymbol = checker.resolveName(jsxNamespace, symbolToken, SymbolFlags.Value, /*excludeGlobals*/ true); - return !namespaceSymbol || some(namespaceSymbol.declarations, isTypeOnlyImportOrExportDeclaration) && !(namespaceSymbol.flags & SymbolFlags.Value); + const namespaceSymbol = checker.resolveName( + jsxNamespace, + symbolToken, + SymbolFlags.Value, + /*excludeGlobals*/ true, + ); + return !namespaceSymbol + || some(namespaceSymbol.declarations, isTypeOnlyImportOrExportDeclaration) + && !(namespaceSymbol.flags & SymbolFlags.Value); } // Returns a map from an exported symbol's ID to a list of every way it's (re-)exported. @@ -984,38 +1446,104 @@ namespace ts.codefix { const packageJsonFilter = createPackageJsonImportFilter(fromFile, preferences, host); const moduleSpecifierCache = host.getModuleSpecifierCache?.(); const getModuleSpecifierResolutionHost = memoizeOne((isFromPackageJson: boolean) => { - return createModuleSpecifierResolutionHost(isFromPackageJson ? host.getPackageJsonAutoImportProvider!()! : program, host); + return createModuleSpecifierResolutionHost( + isFromPackageJson ? host.getPackageJsonAutoImportProvider!()! : program, + host, + ); }); - function addSymbol(moduleSymbol: Symbol, toFile: SourceFile | undefined, exportedSymbol: Symbol, exportKind: ExportKind, program: Program, isFromPackageJson: boolean): void { + function addSymbol( + moduleSymbol: Symbol, + toFile: SourceFile | undefined, + exportedSymbol: Symbol, + exportKind: ExportKind, + program: Program, + isFromPackageJson: boolean, + ): void { const moduleSpecifierResolutionHost = getModuleSpecifierResolutionHost(isFromPackageJson); if ( - toFile && isImportableFile(program, fromFile, toFile, preferences, packageJsonFilter, moduleSpecifierResolutionHost, moduleSpecifierCache) || - !toFile && packageJsonFilter.allowsImportingAmbientModule(moduleSymbol, moduleSpecifierResolutionHost) + toFile + && isImportableFile( + program, + fromFile, + toFile, + preferences, + packageJsonFilter, + moduleSpecifierResolutionHost, + moduleSpecifierCache, + ) + || !toFile + && packageJsonFilter.allowsImportingAmbientModule(moduleSymbol, moduleSpecifierResolutionHost) ) { const checker = program.getTypeChecker(); - originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { symbol: exportedSymbol, moduleSymbol, moduleFileName: toFile?.fileName, exportKind, targetFlags: skipAlias(exportedSymbol, checker).flags, isFromPackageJson }); + originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { + symbol: exportedSymbol, + moduleSymbol, + moduleFileName: toFile?.fileName, + exportKind, + targetFlags: skipAlias(exportedSymbol, checker).flags, + isFromPackageJson, + }); } } - forEachExternalModuleToImportFrom(program, host, preferences, useAutoImportProvider, (moduleSymbol, sourceFile, program, isFromPackageJson) => { - const checker = program.getTypeChecker(); - cancellationToken.throwIfCancellationRequested(); - - const compilerOptions = program.getCompilerOptions(); - const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); - if (defaultInfo && (defaultInfo.name === symbolName || moduleSymbolToValidIdentifier(moduleSymbol, getEmitScriptTarget(compilerOptions), isJsxTagName) === symbolName) && symbolHasMeaning(defaultInfo.symbolForMeaning, currentTokenMeaning)) { - addSymbol(moduleSymbol, sourceFile, defaultInfo.symbol, defaultInfo.exportKind, program, isFromPackageJson); - } + forEachExternalModuleToImportFrom( + program, + host, + preferences, + useAutoImportProvider, + (moduleSymbol, sourceFile, program, isFromPackageJson) => { + const checker = program.getTypeChecker(); + cancellationToken.throwIfCancellationRequested(); + + const compilerOptions = program.getCompilerOptions(); + const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); + if ( + defaultInfo + && (defaultInfo.name === symbolName + || moduleSymbolToValidIdentifier( + moduleSymbol, + getEmitScriptTarget(compilerOptions), + isJsxTagName, + ) === symbolName) + && symbolHasMeaning(defaultInfo.symbolForMeaning, currentTokenMeaning) + ) { + addSymbol( + moduleSymbol, + sourceFile, + defaultInfo.symbol, + defaultInfo.exportKind, + program, + isFromPackageJson, + ); + } - // check exports with the same name - const exportSymbolWithIdenticalName = checker.tryGetMemberInModuleExportsAndProperties(symbolName, moduleSymbol); - if (exportSymbolWithIdenticalName && symbolHasMeaning(exportSymbolWithIdenticalName, currentTokenMeaning)) { - addSymbol(moduleSymbol, sourceFile, exportSymbolWithIdenticalName, ExportKind.Named, program, isFromPackageJson); - } - }); + // check exports with the same name + const exportSymbolWithIdenticalName = checker.tryGetMemberInModuleExportsAndProperties( + symbolName, + moduleSymbol, + ); + if ( + exportSymbolWithIdenticalName + && symbolHasMeaning(exportSymbolWithIdenticalName, currentTokenMeaning) + ) { + addSymbol( + moduleSymbol, + sourceFile, + exportSymbolWithIdenticalName, + ExportKind.Named, + program, + isFromPackageJson, + ); + } + }, + ); return originalSymbolToExportInfos; } - function getExportEqualsImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions, forceImportKeyword: boolean): ImportKind { + function getExportEqualsImportKind( + importingFile: SourceFile, + compilerOptions: CompilerOptions, + forceImportKeyword: boolean, + ): ImportKind { const allowSyntheticDefaults = getAllowSyntheticDefaultImports(compilerOptions); const isJS = isInJSFile(importingFile); // 1. 'import =' will not work in es2015+ TS files, so the decision is between a default @@ -1044,21 +1572,49 @@ namespace ts.codefix { return allowSyntheticDefaults ? ImportKind.Default : ImportKind.CommonJS; } - function codeActionForFix(context: textChanges.TextChangesContext, sourceFile: SourceFile, symbolName: string, fix: ImportFix, includeSymbolNameInDescription: boolean, quotePreference: QuotePreference, compilerOptions: CompilerOptions): CodeFixAction { + function codeActionForFix( + context: textChanges.TextChangesContext, + sourceFile: SourceFile, + symbolName: string, + fix: ImportFix, + includeSymbolNameInDescription: boolean, + quotePreference: QuotePreference, + compilerOptions: CompilerOptions, + ): CodeFixAction { let diag!: DiagnosticAndArguments; const changes = textChanges.ChangeTracker.with(context, tracker => { - diag = codeActionForFixWorker(tracker, sourceFile, symbolName, fix, includeSymbolNameInDescription, quotePreference, compilerOptions); + diag = codeActionForFixWorker( + tracker, + sourceFile, + symbolName, + fix, + includeSymbolNameInDescription, + quotePreference, + compilerOptions, + ); }); return createCodeFixAction(importFixName, changes, diag, importFixId, Diagnostics.Add_all_missing_imports); } - function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: SourceFile, symbolName: string, fix: ImportFix, includeSymbolNameInDescription: boolean, quotePreference: QuotePreference, compilerOptions: CompilerOptions): DiagnosticAndArguments { + function codeActionForFixWorker( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + symbolName: string, + fix: ImportFix, + includeSymbolNameInDescription: boolean, + quotePreference: QuotePreference, + compilerOptions: CompilerOptions, + ): DiagnosticAndArguments { switch (fix.kind) { case ImportFixKind.UseNamespace: addNamespaceQualifier(changes, sourceFile, fix); return [Diagnostics.Change_0_to_1, symbolName, `${fix.namespacePrefix}.${symbolName}`]; case ImportFixKind.JsdocTypeImport: addImportType(changes, sourceFile, fix, quotePreference); - return [Diagnostics.Change_0_to_1, symbolName, getImportTypePrefix(fix.moduleSpecifier, quotePreference) + symbolName]; + return [ + Diagnostics.Change_0_to_1, + symbolName, + getImportTypePrefix(fix.moduleSpecifier, quotePreference) + symbolName, + ]; case ImportFixKind.AddToExisting: { const { importClauseOrBindingPattern, importKind, addAsTypeOnly, moduleSpecifier } = fix; doAddExistingFix( @@ -1077,20 +1633,40 @@ namespace ts.codefix { case ImportFixKind.AddNew: { const { importKind, moduleSpecifier, addAsTypeOnly, useRequire } = fix; const getDeclarations = useRequire ? getNewRequires : getNewImports; - const defaultImport: Import | undefined = importKind === ImportKind.Default ? { name: symbolName, addAsTypeOnly } : undefined; - const namedImports: Import[] | undefined = importKind === ImportKind.Named ? [{ name: symbolName, addAsTypeOnly }] : undefined; - const namespaceLikeImport = importKind === ImportKind.Namespace || importKind === ImportKind.CommonJS ? { importKind, name: symbolName, addAsTypeOnly } : undefined; - insertImports(changes, sourceFile, getDeclarations(moduleSpecifier, quotePreference, defaultImport, namedImports, namespaceLikeImport), /*blankLineBetween*/ true); + const defaultImport: Import | undefined = importKind === ImportKind.Default + ? { name: symbolName, addAsTypeOnly } : undefined; + const namedImports: Import[] | undefined = importKind === ImportKind.Named + ? [{ name: symbolName, addAsTypeOnly }] : undefined; + const namespaceLikeImport = importKind === ImportKind.Namespace || importKind === ImportKind.CommonJS + ? { importKind, name: symbolName, addAsTypeOnly } : undefined; + insertImports( + changes, + sourceFile, + getDeclarations(moduleSpecifier, quotePreference, defaultImport, namedImports, namespaceLikeImport), + /*blankLineBetween*/ true, + ); return includeSymbolNameInDescription ? [Diagnostics.Import_0_from_1, symbolName, moduleSpecifier] : [Diagnostics.Add_import_from_0, moduleSpecifier]; } case ImportFixKind.PromoteTypeOnly: { const { typeOnlyAliasDeclaration } = fix; - const promotedDeclaration = promoteFromTypeOnly(changes, typeOnlyAliasDeclaration, compilerOptions, sourceFile); + const promotedDeclaration = promoteFromTypeOnly( + changes, + typeOnlyAliasDeclaration, + compilerOptions, + sourceFile, + ); return promotedDeclaration.kind === SyntaxKind.ImportSpecifier - ? [Diagnostics.Remove_type_from_import_of_0_from_1, symbolName, getModuleSpecifierText(promotedDeclaration.parent.parent)] - : [Diagnostics.Remove_type_from_import_declaration_from_0, getModuleSpecifierText(promotedDeclaration)]; + ? [ + Diagnostics.Remove_type_from_import_of_0_from_1, + symbolName, + getModuleSpecifierText(promotedDeclaration.parent.parent), + ] + : [ + Diagnostics.Remove_type_from_import_declaration_from_0, + getModuleSpecifierText(promotedDeclaration), + ]; } default: return Debug.assertNever(fix, `Unexpected fix kind ${(fix as ImportFix).kind}`); @@ -1099,21 +1675,45 @@ namespace ts.codefix { function getModuleSpecifierText(promotedDeclaration: ImportClause | ImportEqualsDeclaration): string { return promotedDeclaration.kind === SyntaxKind.ImportEqualsDeclaration - ? tryCast(tryCast(promotedDeclaration.moduleReference, isExternalModuleReference)?.expression, isStringLiteralLike)?.text || promotedDeclaration.moduleReference.getText() + ? tryCast( + tryCast(promotedDeclaration.moduleReference, isExternalModuleReference)?.expression, + isStringLiteralLike, + )?.text || promotedDeclaration.moduleReference.getText() : cast(promotedDeclaration.parent.moduleSpecifier, isStringLiteral).text; } - function promoteFromTypeOnly(changes: textChanges.ChangeTracker, aliasDeclaration: TypeOnlyAliasDeclaration, compilerOptions: CompilerOptions, sourceFile: SourceFile) { + function promoteFromTypeOnly( + changes: textChanges.ChangeTracker, + aliasDeclaration: TypeOnlyAliasDeclaration, + compilerOptions: CompilerOptions, + sourceFile: SourceFile, + ) { // See comment in `doAddExistingFix` on constant with the same name. const convertExistingToTypeOnly = compilerOptions.preserveValueImports && compilerOptions.isolatedModules; switch (aliasDeclaration.kind) { case SyntaxKind.ImportSpecifier: if (aliasDeclaration.isTypeOnly) { - if (aliasDeclaration.parent.elements.length > 1 && OrganizeImports.importSpecifiersAreSorted(aliasDeclaration.parent.elements)) { + if ( + aliasDeclaration.parent.elements.length > 1 + && OrganizeImports.importSpecifiersAreSorted(aliasDeclaration.parent.elements) + ) { changes.delete(sourceFile, aliasDeclaration); - const newSpecifier = factory.updateImportSpecifier(aliasDeclaration, /*isTypeOnly*/ false, aliasDeclaration.propertyName, aliasDeclaration.name); - const insertionIndex = OrganizeImports.getImportSpecifierInsertionIndex(aliasDeclaration.parent.elements, newSpecifier); - changes.insertImportSpecifierAtIndex(sourceFile, newSpecifier, aliasDeclaration.parent, insertionIndex); + const newSpecifier = factory.updateImportSpecifier( + aliasDeclaration, + /*isTypeOnly*/ false, + aliasDeclaration.propertyName, + aliasDeclaration.name, + ); + const insertionIndex = OrganizeImports.getImportSpecifierInsertionIndex( + aliasDeclaration.parent.elements, + newSpecifier, + ); + changes.insertImportSpecifierAtIndex( + sourceFile, + newSpecifier, + aliasDeclaration.parent, + insertionIndex, + ); } else { changes.deleteRange(sourceFile, aliasDeclaration.getFirstToken()!); @@ -1144,9 +1744,9 @@ namespace ts.codefix { const namedImports = tryCast(importClause.namedBindings, isNamedImports); if (namedImports && namedImports.elements.length > 1) { if ( - OrganizeImports.importSpecifiersAreSorted(namedImports.elements) && - aliasDeclaration.kind === SyntaxKind.ImportSpecifier && - namedImports.elements.indexOf(aliasDeclaration) !== 0 + OrganizeImports.importSpecifiersAreSorted(namedImports.elements) + && aliasDeclaration.kind === SyntaxKind.ImportSpecifier + && namedImports.elements.indexOf(aliasDeclaration) !== 0 ) { // The import specifier being promoted will be the only non-type-only, // import in the NamedImports, so it should be moved to the front. @@ -1181,7 +1781,8 @@ namespace ts.codefix { return; } - const promoteFromTypeOnly = clause.isTypeOnly && some([defaultImport, ...namedImports], i => i?.addAsTypeOnly === AddAsTypeOnly.NotAllowed); + const promoteFromTypeOnly = clause.isTypeOnly + && some([defaultImport, ...namedImports], i => i?.addAsTypeOnly === AddAsTypeOnly.NotAllowed); const existingSpecifiers = clause.namedBindings && tryCast(clause.namedBindings, isNamedImports)?.elements; // If we are promoting from a type-only import and `--isolatedModules` and `--preserveValueImports` // are enabled, we need to make every existing import specifier type-only. It may be possible that @@ -1189,11 +1790,17 @@ namespace ts.codefix { // never used in an emitting position). These are allowed to be imported without being type-only, // but the user has clearly already signified that they don't need them to be present at runtime // by placing them in a type-only import. So, just mark each specifier as type-only. - const convertExistingToTypeOnly = promoteFromTypeOnly && compilerOptions.preserveValueImports && compilerOptions.isolatedModules; + const convertExistingToTypeOnly = promoteFromTypeOnly && compilerOptions.preserveValueImports + && compilerOptions.isolatedModules; if (defaultImport) { Debug.assert(!clause.name, "Cannot add a default import to an import clause that already has one"); - changes.insertNodeAt(sourceFile, clause.getStart(sourceFile), factory.createIdentifier(defaultImport.name), { suffix: ", " }); + changes.insertNodeAt( + sourceFile, + clause.getStart(sourceFile), + factory.createIdentifier(defaultImport.name), + { suffix: ", " }, + ); } if (namedImports.length) { @@ -1216,7 +1823,12 @@ namespace ts.codefix { const insertionIndex = convertExistingToTypeOnly && !spec.isTypeOnly ? 0 : OrganizeImports.getImportSpecifierInsertionIndex(existingSpecifiers, spec); - changes.insertImportSpecifierAtIndex(sourceFile, spec, clause.namedBindings as NamedImports, insertionIndex); + changes.insertImportSpecifierAtIndex( + sourceFile, + spec, + clause.namedBindings as NamedImports, + insertionIndex, + ); } } else if (existingSpecifiers?.length) { @@ -1231,7 +1843,14 @@ namespace ts.codefix { changes.replaceNode(sourceFile, clause.namedBindings, namedImports); } else { - changes.insertNodeAfter(sourceFile, Debug.checkDefined(clause.name, "Import clause must have either named imports or a default import"), namedImports); + changes.insertNodeAfter( + sourceFile, + Debug.checkDefined( + clause.name, + "Import clause must have either named imports or a default import", + ), + namedImports, + ); } } } @@ -1246,7 +1865,11 @@ namespace ts.codefix { } } - function addElementToBindingPattern(bindingPattern: ObjectBindingPattern, name: string, propertyName: string | undefined) { + function addElementToBindingPattern( + bindingPattern: ObjectBindingPattern, + name: string, + propertyName: string | undefined, + ) { const element = factory.createBindingElement(/*dotDotDotToken*/ undefined, propertyName, name); if (bindingPattern.elements.length) { changes.insertNodeInListAfter(sourceFile, last(bindingPattern.elements), element); @@ -1257,11 +1880,20 @@ namespace ts.codefix { } } - function addNamespaceQualifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { namespacePrefix, position }: FixUseNamespaceImport): void { + function addNamespaceQualifier( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { namespacePrefix, position }: FixUseNamespaceImport, + ): void { changes.insertText(sourceFile, position, namespacePrefix + "."); } - function addImportType(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { moduleSpecifier, position }: FixAddJsdocTypeImport, quotePreference: QuotePreference): void { + function addImportType( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { moduleSpecifier, position }: FixAddJsdocTypeImport, + quotePreference: QuotePreference, + ): void { changes.insertText(sourceFile, position, getImportTypePrefix(moduleSpecifier, quotePreference)); } @@ -1299,7 +1931,8 @@ namespace ts.codefix { const quotedModuleSpecifier = makeStringLiteral(moduleSpecifier, quotePreference); let statements: AnyImportSyntax | readonly AnyImportSyntax[] | undefined; if (defaultImport !== undefined || namedImports?.length) { - const topLevelTypeOnly = (!defaultImport || needsTypeOnly(defaultImport)) && every(namedImports, needsTypeOnly); + const topLevelTypeOnly = (!defaultImport || needsTypeOnly(defaultImport)) + && every(namedImports, needsTypeOnly); statements = combine( statements, makeImport( @@ -1341,16 +1974,29 @@ namespace ts.codefix { return Debug.checkDefined(statements); } - function getNewRequires(moduleSpecifier: string, quotePreference: QuotePreference, defaultImport: Import | undefined, namedImports: readonly Import[] | undefined, namespaceLikeImport: Import | undefined): RequireVariableStatement | readonly RequireVariableStatement[] { + function getNewRequires( + moduleSpecifier: string, + quotePreference: QuotePreference, + defaultImport: Import | undefined, + namedImports: readonly Import[] | undefined, + namespaceLikeImport: Import | undefined, + ): RequireVariableStatement | readonly RequireVariableStatement[] { const quotedModuleSpecifier = makeStringLiteral(moduleSpecifier, quotePreference); let statements: RequireVariableStatement | readonly RequireVariableStatement[] | undefined; // const { default: foo, bar, etc } = require('./mod'); if (defaultImport || namedImports?.length) { - const bindingElements = namedImports?.map(({ name }) => factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, name)) || []; + const bindingElements = namedImports?.map(({ name }) => + factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, name) + ) || []; if (defaultImport) { - bindingElements.unshift(factory.createBindingElement(/*dotDotDotToken*/ undefined, "default", defaultImport.name)); + bindingElements.unshift( + factory.createBindingElement(/*dotDotDotToken*/ undefined, "default", defaultImport.name), + ); } - const declaration = createConstEqualsRequireDeclaration(factory.createObjectBindingPattern(bindingElements), quotedModuleSpecifier); + const declaration = createConstEqualsRequireDeclaration( + factory.createObjectBindingPattern(bindingElements), + quotedModuleSpecifier, + ); statements = combine(statements, declaration); } // const foo = require('./mod'); @@ -1361,7 +2007,10 @@ namespace ts.codefix { return Debug.checkDefined(statements); } - function createConstEqualsRequireDeclaration(name: string | ObjectBindingPattern, quotedModuleSpecifier: StringLiteral): RequireVariableStatement { + function createConstEqualsRequireDeclaration( + name: string | ObjectBindingPattern, + quotedModuleSpecifier: StringLiteral, + ): RequireVariableStatement { return factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList([ @@ -1369,7 +2018,9 @@ namespace ts.codefix { typeof name === "string" ? factory.createIdentifier(name) : name, /*exclamationToken*/ undefined, /*type*/ undefined, - factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [quotedModuleSpecifier]), + factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [ + quotedModuleSpecifier, + ]), ), ], NodeFlags.Const), ) as RequireVariableStatement; @@ -1379,11 +2030,23 @@ namespace ts.codefix { return some(declarations, decl => !!(getMeaningFromDeclaration(decl) & meaning)); } - export function moduleSymbolToValidIdentifier(moduleSymbol: Symbol, target: ScriptTarget | undefined, forceCapitalize: boolean): string { - return moduleSpecifierToValidIdentifier(removeFileExtension(stripQuotes(moduleSymbol.name)), target, forceCapitalize); + export function moduleSymbolToValidIdentifier( + moduleSymbol: Symbol, + target: ScriptTarget | undefined, + forceCapitalize: boolean, + ): string { + return moduleSpecifierToValidIdentifier( + removeFileExtension(stripQuotes(moduleSymbol.name)), + target, + forceCapitalize, + ); } - export function moduleSpecifierToValidIdentifier(moduleSpecifier: string, target: ScriptTarget | undefined, forceCapitalize?: boolean): string { + export function moduleSpecifierToValidIdentifier( + moduleSpecifier: string, + target: ScriptTarget | undefined, + forceCapitalize?: boolean, + ): string { const baseName = getBaseFileName(removeSuffix(moduleSpecifier, "/index")); let res = ""; let lastCharWasValid = true; diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 2fde171a61dff..31d259810a6c5 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -24,7 +24,8 @@ namespace ts.codefix { //// Suggestions // Variable declarations - Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage.code, + Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage + .code, // Variable uses Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code, @@ -34,11 +35,13 @@ namespace ts.codefix { Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code, // Get Accessor declarations - Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage.code, + Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage + .code, Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage.code, // Set Accessor declarations - Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage.code, + Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage + .code, // Property declarations Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code, @@ -54,18 +57,44 @@ namespace ts.codefix { const token = getTokenAtPosition(sourceFile, start); let declaration: Declaration | undefined; const changes = textChanges.ChangeTracker.with(context, changes => { - declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken, /*markSeen*/ returnTrue, host, preferences); + declaration = doChange( + changes, + sourceFile, + token, + errorCode, + program, + cancellationToken, + /*markSeen*/ returnTrue, + host, + preferences, + ); }); const name = declaration && getNameOfDeclaration(declaration); return !name || changes.length === 0 ? undefined - : [createCodeFixAction(fixId, changes, [getDiagnostic(errorCode, token), getTextOfNode(name)], fixId, Diagnostics.Infer_all_types_from_usage)]; + : [createCodeFixAction( + fixId, + changes, + [getDiagnostic(errorCode, token), getTextOfNode(name)], + fixId, + Diagnostics.Infer_all_types_from_usage, + )]; }, fixIds: [fixId], getAllCodeActions(context) { const { sourceFile, program, cancellationToken, host, preferences } = context; const markSeen = nodeSeenTracker(); return codeFixAll(context, errorCodes, (changes, err) => { - doChange(changes, sourceFile, getTokenAtPosition(err.file, err.start), err.code, program, cancellationToken, markSeen, host, preferences); + doChange( + changes, + sourceFile, + getTokenAtPosition(err.file, err.start), + err.code, + program, + cancellationToken, + markSeen, + host, + preferences, + ); }); }, }); @@ -74,9 +103,11 @@ namespace ts.codefix { switch (errorCode) { case Diagnostics.Parameter_0_implicitly_has_an_1_type.code: case Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code: - return isSetAccessorDeclaration(getContainingFunction(token)!) ? Diagnostics.Infer_type_of_0_from_usage : Diagnostics.Infer_parameter_types_from_usage; // TODO: GH#18217 + return isSetAccessorDeclaration(getContainingFunction(token)!) ? Diagnostics.Infer_type_of_0_from_usage + : Diagnostics.Infer_parameter_types_from_usage; // TODO: GH#18217 case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code: - case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code: + case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage + .code: return Diagnostics.Infer_parameter_types_from_usage; case Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation.code: return Diagnostics.Infer_this_type_of_0_from_usage; @@ -88,28 +119,50 @@ namespace ts.codefix { /** Map suggestion code to error code */ function mapSuggestionDiagnostic(errorCode: number) { switch (errorCode) { - case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage.code: - return Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code; + case Diagnostics + .Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage.code: + return Diagnostics + .Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code; case Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics.Variable_0_implicitly_has_an_1_type.code; case Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics.Parameter_0_implicitly_has_an_1_type.code; - case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code: + case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage + .code: return Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code; - case Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage.code: - return Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation.code; + case Diagnostics + .Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage + .code: + return Diagnostics + .Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation.code; case Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type.code; - case Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage.code: - return Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code; + case Diagnostics + .Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage + .code: + return Diagnostics + .Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code; case Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics.Member_0_implicitly_has_an_1_type.code; } return errorCode; } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, markSeen: NodeSeenTracker, host: LanguageServiceHost, preferences: UserPreferences): Declaration | undefined { - if (!isParameterPropertyModifier(token.kind) && token.kind !== SyntaxKind.Identifier && token.kind !== SyntaxKind.DotDotDotToken && token.kind !== SyntaxKind.ThisKeyword) { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + token: Node, + errorCode: number, + program: Program, + cancellationToken: CancellationToken, + markSeen: NodeSeenTracker, + host: LanguageServiceHost, + preferences: UserPreferences, + ): Declaration | undefined { + if ( + !isParameterPropertyModifier(token.kind) && token.kind !== SyntaxKind.Identifier + && token.kind !== SyntaxKind.DotDotDotToken && token.kind !== SyntaxKind.ThisKeyword + ) { return undefined; } @@ -119,9 +172,21 @@ namespace ts.codefix { switch (errorCode) { // Variable and Property declarations case Diagnostics.Member_0_implicitly_has_an_1_type.code: - case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code: - if ((isVariableDeclaration(parent) && markSeen(parent)) || isPropertyDeclaration(parent) || isPropertySignature(parent)) { // handle bad location - annotateVariableDeclaration(changes, importAdder, sourceFile, parent, program, host, cancellationToken); + case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined + .code: + if ( + (isVariableDeclaration(parent) && markSeen(parent)) || isPropertyDeclaration(parent) + || isPropertySignature(parent) + ) { // handle bad location + annotateVariableDeclaration( + changes, + importAdder, + sourceFile, + parent, + program, + host, + cancellationToken, + ); importAdder.writeFixes(changes); return parent; } @@ -130,7 +195,11 @@ namespace ts.codefix { const typeNode = getTypeNodeIfAccessible(type, parent, program, host); if (typeNode) { // Note that the codefix will never fire with an existing `@type` tag, so there is no need to merge tags - const typeTag = factory.createJSDocTypeTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(typeNode), /*comment*/ undefined); + const typeTag = factory.createJSDocTypeTag( + /*tagName*/ undefined, + factory.createJSDocTypeExpression(typeNode), + /*comment*/ undefined, + ); changes.addJSDocTags(sourceFile, cast(parent.parent.parent, isExpressionStatement), [typeTag]); } importAdder.writeFixes(changes); @@ -140,8 +209,19 @@ namespace ts.codefix { case Diagnostics.Variable_0_implicitly_has_an_1_type.code: { const symbol = program.getTypeChecker().getSymbolAtLocation(token); - if (symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && markSeen(symbol.valueDeclaration)) { - annotateVariableDeclaration(changes, importAdder, getSourceFileOfNode(symbol.valueDeclaration), symbol.valueDeclaration, program, host, cancellationToken); + if ( + symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) + && markSeen(symbol.valueDeclaration) + ) { + annotateVariableDeclaration( + changes, + importAdder, + getSourceFileOfNode(symbol.valueDeclaration), + symbol.valueDeclaration, + program, + host, + cancellationToken, + ); importAdder.writeFixes(changes); return symbol.valueDeclaration; } @@ -159,7 +239,15 @@ namespace ts.codefix { // Parameter declarations case Diagnostics.Parameter_0_implicitly_has_an_1_type.code: if (isSetAccessorDeclaration(containingFunction)) { - annotateSetAccessor(changes, importAdder, sourceFile, containingFunction, program, host, cancellationToken); + annotateSetAccessor( + changes, + importAdder, + sourceFile, + containingFunction, + program, + host, + cancellationToken, + ); declaration = containingFunction; break; } @@ -167,24 +255,51 @@ namespace ts.codefix { case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code: if (markSeen(containingFunction)) { const param = cast(parent, isParameter); - annotateParameters(changes, importAdder, sourceFile, param, containingFunction, program, host, cancellationToken); + annotateParameters( + changes, + importAdder, + sourceFile, + param, + containingFunction, + program, + host, + cancellationToken, + ); declaration = param; } break; // Get Accessor declarations - case Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation.code: + case Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation + .code: case Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type.code: if (isGetAccessorDeclaration(containingFunction) && isIdentifier(containingFunction.name)) { - annotate(changes, importAdder, sourceFile, containingFunction, inferTypeForVariableFromUsage(containingFunction.name, program, cancellationToken), program, host); + annotate( + changes, + importAdder, + sourceFile, + containingFunction, + inferTypeForVariableFromUsage(containingFunction.name, program, cancellationToken), + program, + host, + ); declaration = containingFunction; } break; // Set Accessor declarations - case Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code: + case Diagnostics + .Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code: if (isSetAccessorDeclaration(containingFunction)) { - annotateSetAccessor(changes, importAdder, sourceFile, containingFunction, program, host, cancellationToken); + annotateSetAccessor( + changes, + importAdder, + sourceFile, + containingFunction, + program, + host, + cancellationToken, + ); declaration = containingFunction; } break; @@ -215,7 +330,15 @@ namespace ts.codefix { cancellationToken: CancellationToken, ): void { if (isIdentifier(declaration.name)) { - annotate(changes, importAdder, sourceFile, declaration, inferTypeForVariableFromUsage(declaration.name, program, cancellationToken), program, host); + annotate( + changes, + importAdder, + sourceFile, + declaration, + inferTypeForVariableFromUsage(declaration.name, program, cancellationToken), + program, + host, + ); } } @@ -233,25 +356,53 @@ namespace ts.codefix { return; } - const parameterInferences = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken); - Debug.assert(containingFunction.parameters.length === parameterInferences.length, "Parameter count and inference count should match"); + const parameterInferences = inferTypeForParametersFromUsage( + containingFunction, + sourceFile, + program, + cancellationToken, + ); + Debug.assert( + containingFunction.parameters.length === parameterInferences.length, + "Parameter count and inference count should match", + ); if (isInJSFile(containingFunction)) { annotateJSDocParameters(changes, sourceFile, parameterInferences, program, host); } else { - const needParens = isArrowFunction(containingFunction) && !findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile); - if (needParens) changes.insertNodeBefore(sourceFile, first(containingFunction.parameters), factory.createToken(SyntaxKind.OpenParenToken)); + const needParens = isArrowFunction(containingFunction) + && !findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile); + if (needParens) { + changes.insertNodeBefore( + sourceFile, + first(containingFunction.parameters), + factory.createToken(SyntaxKind.OpenParenToken), + ); + } for (const { declaration, type } of parameterInferences) { if (declaration && !declaration.type && !declaration.initializer) { annotate(changes, importAdder, sourceFile, declaration, type, program, host); } } - if (needParens) changes.insertNodeAfter(sourceFile, last(containingFunction.parameters), factory.createToken(SyntaxKind.CloseParenToken)); + if (needParens) { + changes.insertNodeAfter( + sourceFile, + last(containingFunction.parameters), + factory.createToken(SyntaxKind.CloseParenToken), + ); + } } } - function annotateThis(changes: textChanges.ChangeTracker, sourceFile: SourceFile, containingFunction: textChanges.ThisTypeAnnotatable, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken) { + function annotateThis( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + containingFunction: textChanges.ThisTypeAnnotatable, + program: Program, + host: LanguageServiceHost, + cancellationToken: CancellationToken, + ) { const references = getFunctionReferences(containingFunction, sourceFile, program, cancellationToken); if (!references || !references.length) { return; @@ -270,7 +421,12 @@ namespace ts.codefix { } } - function annotateJSDocThis(changes: textChanges.ChangeTracker, sourceFile: SourceFile, containingFunction: SignatureDeclaration, typeNode: TypeNode) { + function annotateJSDocThis( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + containingFunction: SignatureDeclaration, + typeNode: TypeNode, + ) { changes.addJSDocTags(sourceFile, containingFunction, [ factory.createJSDocThisTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(typeNode)), ]); @@ -300,19 +456,39 @@ namespace ts.codefix { } } - function annotate(changes: textChanges.ChangeTracker, importAdder: ImportAdder, sourceFile: SourceFile, declaration: textChanges.TypeAnnotatable, type: Type, program: Program, host: LanguageServiceHost): void { + function annotate( + changes: textChanges.ChangeTracker, + importAdder: ImportAdder, + sourceFile: SourceFile, + declaration: textChanges.TypeAnnotatable, + type: Type, + program: Program, + host: LanguageServiceHost, + ): void { const typeNode = getTypeNodeIfAccessible(type, declaration, program, host); if (typeNode) { if (isInJSFile(sourceFile) && declaration.kind !== SyntaxKind.PropertySignature) { - const parent = isVariableDeclaration(declaration) ? tryCast(declaration.parent.parent, isVariableStatement) : declaration; + const parent = isVariableDeclaration(declaration) + ? tryCast(declaration.parent.parent, isVariableStatement) : declaration; if (!parent) { return; } const typeExpression = factory.createJSDocTypeExpression(typeNode); - const typeTag = isGetAccessorDeclaration(declaration) ? factory.createJSDocReturnTag(/*tagName*/ undefined, typeExpression, /*comment*/ undefined) : factory.createJSDocTypeTag(/*tagName*/ undefined, typeExpression, /*comment*/ undefined); + const typeTag = isGetAccessorDeclaration(declaration) + ? factory.createJSDocReturnTag(/*tagName*/ undefined, typeExpression, /*comment*/ undefined) + : factory.createJSDocTypeTag(/*tagName*/ undefined, typeExpression, /*comment*/ undefined); changes.addJSDocTags(sourceFile, parent, [typeTag]); } - else if (!tryReplaceImportTypeNodeWithAutoImport(typeNode, declaration, sourceFile, changes, importAdder, getEmitScriptTarget(program.getCompilerOptions()))) { + else if ( + !tryReplaceImportTypeNodeWithAutoImport( + typeNode, + declaration, + sourceFile, + changes, + importAdder, + getEmitScriptTarget(program.getCompilerOptions()), + ) + ) { changes.tryInsertTypeAnnotation(sourceFile, declaration, typeNode); } } @@ -327,14 +503,26 @@ namespace ts.codefix { scriptTarget: ScriptTarget, ): boolean { const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget); - if (importableReference && changes.tryInsertTypeAnnotation(sourceFile, declaration, importableReference.typeNode)) { - forEach(importableReference.symbols, s => importAdder.addImportFromExportedSymbol(s, /*usageIsTypeOnly*/ true)); + if ( + importableReference + && changes.tryInsertTypeAnnotation(sourceFile, declaration, importableReference.typeNode) + ) { + forEach( + importableReference.symbols, + s => importAdder.addImportFromExportedSymbol(s, /*usageIsTypeOnly*/ true), + ); return true; } return false; } - function annotateJSDocParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, parameterInferences: readonly ParameterInference[], program: Program, host: LanguageServiceHost): void { + function annotateJSDocParameters( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + parameterInferences: readonly ParameterInference[], + program: Program, + host: LanguageServiceHost, + ): void { const signature = parameterInferences.length && parameterInferences[0].declaration.parent; if (!signature) { return; @@ -359,58 +547,114 @@ namespace ts.codefix { } if (isArrowFunction(signature) || isFunctionExpression(signature)) { - const needParens = isArrowFunction(signature) && !findChildOfKind(signature, SyntaxKind.OpenParenToken, sourceFile); + const needParens = isArrowFunction(signature) + && !findChildOfKind(signature, SyntaxKind.OpenParenToken, sourceFile); if (needParens) { - changes.insertNodeBefore(sourceFile, first(signature.parameters), factory.createToken(SyntaxKind.OpenParenToken)); + changes.insertNodeBefore( + sourceFile, + first(signature.parameters), + factory.createToken(SyntaxKind.OpenParenToken), + ); } forEach(inferences, ({ typeNode, param }) => { - const typeTag = factory.createJSDocTypeTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(typeNode)); + const typeTag = factory.createJSDocTypeTag( + /*tagName*/ undefined, + factory.createJSDocTypeExpression(typeNode), + ); const jsDoc = factory.createJSDocComment(/*comment*/ undefined, [typeTag]); changes.insertNodeAt(sourceFile, param.getStart(sourceFile), jsDoc, { suffix: " " }); }); if (needParens) { - changes.insertNodeAfter(sourceFile, last(signature.parameters), factory.createToken(SyntaxKind.CloseParenToken)); + changes.insertNodeAfter( + sourceFile, + last(signature.parameters), + factory.createToken(SyntaxKind.CloseParenToken), + ); } } else { - const paramTags = map(inferences, ({ name, typeNode, isOptional }) => factory.createJSDocParameterTag(/*tagName*/ undefined, name, /*isBracketed*/ !!isOptional, factory.createJSDocTypeExpression(typeNode), /* isNameFirst */ false, /*comment*/ undefined)); + const paramTags = map( + inferences, + ({ name, typeNode, isOptional }) => + factory.createJSDocParameterTag( + /*tagName*/ undefined, + name, + /*isBracketed*/ !!isOptional, + factory.createJSDocTypeExpression(typeNode), + /* isNameFirst */ false, + /*comment*/ undefined, + ), + ); changes.addJSDocTags(sourceFile, signature, paramTags); } } - function getReferences(token: PropertyName | Token, program: Program, cancellationToken: CancellationToken): readonly Identifier[] { + function getReferences( + token: PropertyName | Token, + program: Program, + cancellationToken: CancellationToken, + ): readonly Identifier[] { // Position shouldn't matter since token is not a SourceFile. - return mapDefined(FindAllReferences.getReferenceEntriesForNode(-1, token, program, program.getSourceFiles(), cancellationToken), entry => entry.kind !== FindAllReferences.EntryKind.Span ? tryCast(entry.node, isIdentifier) : undefined); + return mapDefined( + FindAllReferences.getReferenceEntriesForNode( + -1, + token, + program, + program.getSourceFiles(), + cancellationToken, + ), + entry => entry.kind !== FindAllReferences.EntryKind.Span ? tryCast(entry.node, isIdentifier) : undefined, + ); } - function inferTypeForVariableFromUsage(token: Identifier | PrivateIdentifier, program: Program, cancellationToken: CancellationToken): Type { + function inferTypeForVariableFromUsage( + token: Identifier | PrivateIdentifier, + program: Program, + cancellationToken: CancellationToken, + ): Type { const references = getReferences(token, program, cancellationToken); return inferTypeFromReferences(program, references, cancellationToken).single(); } - function inferTypeForParametersFromUsage(func: SignatureDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken) { + function inferTypeForParametersFromUsage( + func: SignatureDeclaration, + sourceFile: SourceFile, + program: Program, + cancellationToken: CancellationToken, + ) { const references = getFunctionReferences(func, sourceFile, program, cancellationToken); - return references && inferTypeFromReferences(program, references, cancellationToken).parameters(func) || - func.parameters.map(p => ({ + return references && inferTypeFromReferences(program, references, cancellationToken).parameters(func) + || func.parameters.map(p => ({ declaration: p, - type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : program.getTypeChecker().getAnyType(), + type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) + : program.getTypeChecker().getAnyType(), })); } - function getFunctionReferences(containingFunction: SignatureDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): readonly Identifier[] | undefined { + function getFunctionReferences( + containingFunction: SignatureDeclaration, + sourceFile: SourceFile, + program: Program, + cancellationToken: CancellationToken, + ): readonly Identifier[] | undefined { let searchToken; switch (containingFunction.kind) { case SyntaxKind.Constructor: - searchToken = findChildOfKind>(containingFunction, SyntaxKind.ConstructorKeyword, sourceFile); + searchToken = findChildOfKind>( + containingFunction, + SyntaxKind.ConstructorKeyword, + sourceFile, + ); break; case SyntaxKind.ArrowFunction: case SyntaxKind.FunctionExpression: const parent = containingFunction.parent; - searchToken = (isVariableDeclaration(parent) || isPropertyDeclaration(parent)) && isIdentifier(parent.name) ? - parent.name : - containingFunction.name; + searchToken = + (isVariableDeclaration(parent) || isPropertyDeclaration(parent)) && isIdentifier(parent.name) + ? parent.name + : containingFunction.name; break; case SyntaxKind.FunctionDeclaration: case SyntaxKind.MethodDeclaration: @@ -432,7 +676,11 @@ namespace ts.codefix { readonly isOptional?: boolean; } - function inferTypeFromReferences(program: Program, references: readonly Identifier[], cancellationToken: CancellationToken) { + function inferTypeFromReferences( + program: Program, + references: readonly Identifier[], + cancellationToken: CancellationToken, + ) { const checker = program.getTypeChecker(); const builtinConstructors: { [s: string]: (t: Type) => Type; } = { string: () => checker.getStringType(), @@ -555,7 +803,9 @@ namespace ts.codefix { } } if (isIdentifier(parameter.name)) { - const inferred = inferTypesFromReferencesSingle(getReferences(parameter.name, program, cancellationToken)); + const inferred = inferTypesFromReferencesSingle( + getReferences(parameter.name, program, cancellationToken), + ); types.push(...(isRest ? mapDefined(inferred, checker.getElementTypeOfArrayType) : inferred)); } const type = combineTypes(types); @@ -625,7 +875,10 @@ namespace ts.codefix { break; case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - inferTypeFromPropertyAssignment(node.parent as PropertyAssignment | ShorthandPropertyAssignment, usage); + inferTypeFromPropertyAssignment( + node.parent as PropertyAssignment | ShorthandPropertyAssignment, + usage, + ); break; case SyntaxKind.PropertyDeclaration: inferTypeFromPropertyDeclaration(node.parent as PropertyDeclaration, usage); @@ -731,7 +984,9 @@ namespace ts.codefix { case SyntaxKind.PlusEqualsToken: case SyntaxKind.PlusToken: - const otherOperandType = checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left); + const otherOperandType = checker.getTypeAtLocation( + parent.left === node ? parent.right : parent.left, + ); if (otherOperandType.flags & TypeFlags.EnumLike) { addCandidateType(usage, otherOperandType); } @@ -755,7 +1010,10 @@ namespace ts.codefix { case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: - addCandidateType(usage, checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left)); + addCandidateType( + usage, + checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left), + ); break; case SyntaxKind.InKeyword: @@ -768,8 +1026,9 @@ namespace ts.codefix { case SyntaxKind.BarBarToken: case SyntaxKind.QuestionQuestionToken: if ( - node === parent.left && - (node.parent.parent.kind === SyntaxKind.VariableDeclaration || isAssignmentExpression(node.parent.parent, /*excludeCompoundAssignment*/ true)) + node === parent.left + && (node.parent.parent.kind === SyntaxKind.VariableDeclaration + || isAssignmentExpression(node.parent.parent, /*excludeCompoundAssignment*/ true)) ) { // var x = x || {}; // TODO: use getFalsyflagsOfType @@ -820,7 +1079,11 @@ namespace ts.codefix { usage.properties.set(name, propertyUsage); } - function inferTypeFromPropertyElementExpression(parent: ElementAccessExpression, node: Expression, usage: Usage): void { + function inferTypeFromPropertyElementExpression( + parent: ElementAccessExpression, + node: Expression, + usage: Usage, + ): void { if (node === parent.argumentExpression) { usage.isNumberOrString = true; return; @@ -838,10 +1101,13 @@ namespace ts.codefix { } } - function inferTypeFromPropertyAssignment(assignment: PropertyAssignment | ShorthandPropertyAssignment, usage: Usage) { - const nodeWithRealType = isVariableDeclaration(assignment.parent.parent) ? - assignment.parent.parent : - assignment.parent; + function inferTypeFromPropertyAssignment( + assignment: PropertyAssignment | ShorthandPropertyAssignment, + usage: Usage, + ) { + const nodeWithRealType = isVariableDeclaration(assignment.parent.parent) + ? assignment.parent.parent + : assignment.parent; addCandidateThisType(usage, checker.getTypeAtLocation(nodeWithRealType)); } @@ -888,7 +1154,9 @@ namespace ts.codefix { low: t => !!(t.flags & (TypeFlags.Any | TypeFlags.Void)), }, { - high: t => !(t.flags & (TypeFlags.Nullable | TypeFlags.Any | TypeFlags.Void)) && !(getObjectFlags(t) & ObjectFlags.Anonymous), + high: t => + !(t.flags & (TypeFlags.Nullable | TypeFlags.Any | TypeFlags.Void)) + && !(getObjectFlags(t) & ObjectFlags.Anonymous), low: t => !!(getObjectFlags(t) & ObjectFlags.Anonymous), }, ]; @@ -898,7 +1166,9 @@ namespace ts.codefix { good = good.filter(i => !(getObjectFlags(i) & ObjectFlags.Anonymous)); good.push(combineAnonymousTypes(anons)); } - return checker.getWidenedType(checker.getUnionType(good.map(checker.getBaseTypeOfLiteralType), UnionReduction.Subtype)); + return checker.getWidenedType( + checker.getUnionType(good.map(checker.getBaseTypeOfLiteralType), UnionReduction.Subtype), + ); } function combineAnonymousTypes(anons: AnonymousType[]) { @@ -914,7 +1184,11 @@ namespace ts.codefix { const props = createMultiMap(); for (const anon of anons) { for (const p of checker.getPropertiesOfType(anon)) { - props.add(p.name, p.valueDeclaration ? checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration) : checker.getAnyType()); + props.add( + p.name, + p.valueDeclaration ? checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration) + : checker.getAnyType(), + ); } calls.push(...checker.getSignaturesOfType(anon, SignatureKind.Call)); constructs.push(...checker.getSignaturesOfType(anon, SignatureKind.Construct)); @@ -936,8 +1210,24 @@ namespace ts.codefix { return [name, s]; }); const indexInfos = []; - if (stringIndices.length) indexInfos.push(checker.createIndexInfo(checker.getStringType(), checker.getUnionType(stringIndices), stringIndexReadonly)); - if (numberIndices.length) indexInfos.push(checker.createIndexInfo(checker.getNumberType(), checker.getUnionType(numberIndices), numberIndexReadonly)); + if (stringIndices.length) { + indexInfos.push( + checker.createIndexInfo( + checker.getStringType(), + checker.getUnionType(stringIndices), + stringIndexReadonly, + ), + ); + } + if (numberIndices.length) { + indexInfos.push( + checker.createIndexInfo( + checker.getNumberType(), + checker.getUnionType(numberIndices), + numberIndexReadonly, + ), + ); + } return checker.createAnonymousType( anons[0].symbol, members as UnderscoreEscapedMap, @@ -995,8 +1285,19 @@ namespace ts.codefix { } const callSignatures: Signature[] = usage.calls ? [getSignatureFromCalls(usage.calls)] : []; const constructSignatures: Signature[] = usage.constructs ? [getSignatureFromCalls(usage.constructs)] : []; - const indexInfos = usage.stringIndex ? [checker.createIndexInfo(checker.getStringType(), combineFromUsage(usage.stringIndex), /*isReadonly*/ false)] : []; - return checker.createAnonymousType(/*symbol*/ undefined, members, callSignatures, constructSignatures, indexInfos); + const indexInfos = usage.stringIndex + ? [checker.createIndexInfo( + checker.getStringType(), + combineFromUsage(usage.stringIndex), + /*isReadonly*/ false, + )] : []; + return checker.createAnonymousType( + /*symbol*/ undefined, + members, + callSignatures, + constructSignatures, + indexInfos, + ); } function inferNamedTypesFromProperties(usage: Usage): Type[] { @@ -1042,7 +1343,9 @@ namespace ts.codefix { usage.properties.forEach((propUsage, name) => { const genericPropertyType = checker.getTypeOfPropertyOfType(generic, name as string); Debug.assert(!!genericPropertyType, "generic should have all the properties of its reference."); - types.push(...inferTypeParameters(genericPropertyType, combineFromUsage(propUsage), singleTypeParameter)); + types.push( + ...inferTypeParameters(genericPropertyType, combineFromUsage(propUsage), singleTypeParameter), + ); }); return builtinConstructors[type.symbol.escapedName as string](combineTypes(types)); } @@ -1052,9 +1355,14 @@ namespace ts.codefix { return [usageType]; } else if (genericType.flags & TypeFlags.UnionOrIntersection) { - return flatMap((genericType as UnionOrIntersectionType).types, t => inferTypeParameters(t, usageType, typeParameter)); + return flatMap( + (genericType as UnionOrIntersectionType).types, + t => inferTypeParameters(t, usageType, typeParameter), + ); } - else if (getObjectFlags(genericType) & ObjectFlags.Reference && getObjectFlags(usageType) & ObjectFlags.Reference) { + else if ( + getObjectFlags(genericType) & ObjectFlags.Reference && getObjectFlags(usageType) & ObjectFlags.Reference + ) { // this is wrong because we need a reference to the targetType to, so we can check that it's also a reference const genericArgs = checker.getTypeArguments(genericType as TypeReference); const usageArgs = checker.getTypeArguments(usageType as TypeReference); @@ -1085,13 +1393,17 @@ namespace ts.codefix { if (!usageParam) { break; } - let genericParamType = genericParam.valueDeclaration ? checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration) : checker.getAnyType(); + let genericParamType = genericParam.valueDeclaration + ? checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration) + : checker.getAnyType(); const elementType = isRest && checker.getElementTypeOfArrayType(genericParamType); if (elementType) { genericParamType = elementType; } const targetType = (usageParam as SymbolLinks).type - || (usageParam.valueDeclaration ? checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration) : checker.getAnyType()); + || (usageParam.valueDeclaration + ? checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration) + : checker.getAnyType()); types.push(...inferTypeParameters(genericParamType, targetType, typeParameter)); } const genericReturn = checker.getReturnTypeOfSignature(genericSig); @@ -1101,14 +1413,23 @@ namespace ts.codefix { } function getFunctionFromCalls(calls: CallUsage[]) { - return checker.createAnonymousType(/*symbol*/ undefined, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, emptyArray); + return checker.createAnonymousType( + /*symbol*/ undefined, + createSymbolTable(), + [getSignatureFromCalls(calls)], + emptyArray, + emptyArray, + ); } function getSignatureFromCalls(calls: CallUsage[]): Signature { const parameters: Symbol[] = []; const length = Math.max(...calls.map(c => c.argumentTypes.length)); for (let i = 0; i < length; i++) { - const symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, escapeLeadingUnderscores(`arg${i}`)); + const symbol = checker.createSymbol( + SymbolFlags.FunctionScopedVariable, + escapeLeadingUnderscores(`arg${i}`), + ); symbol.type = combineTypes(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType())); if (calls.some(call => call.argumentTypes[i] === undefined)) { symbol.flags |= SymbolFlags.Optional; @@ -1116,7 +1437,16 @@ namespace ts.codefix { parameters.push(symbol); } const returnType = combineFromUsage(combineUsages(calls.map(call => call.return_))); - return checker.createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, SignatureFlags.None); + return checker.createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + parameters, + returnType, + /*typePredicate*/ undefined, + length, + SignatureFlags.None, + ); } function addCandidateType(usage: Usage, type: Type | undefined) { diff --git a/src/services/codefixes/removeAccidentalCallParentheses.ts b/src/services/codefixes/removeAccidentalCallParentheses.ts index 32a7d4606f02a..54cfaae62b354 100644 --- a/src/services/codefixes/removeAccidentalCallParentheses.ts +++ b/src/services/codefixes/removeAccidentalCallParentheses.ts @@ -7,7 +7,10 @@ namespace ts.codefix { registerCodeFix({ errorCodes, getCodeActions(context) { - const callExpression = findAncestor(getTokenAtPosition(context.sourceFile, context.span.start), isCallExpression); + const callExpression = findAncestor( + getTokenAtPosition(context.sourceFile, context.span.start), + isCallExpression, + ); if (!callExpression) { return undefined; } diff --git a/src/services/codefixes/removeUnnecessaryAwait.ts b/src/services/codefixes/removeUnnecessaryAwait.ts index 59e786ccd2cb8..c19ef13be1176 100644 --- a/src/services/codefixes/removeUnnecessaryAwait.ts +++ b/src/services/codefixes/removeUnnecessaryAwait.ts @@ -8,9 +8,20 @@ namespace ts.codefix { registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToRemoveUnnecessaryAwait(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span)); + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span), + ); if (changes.length > 0) { - return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unnecessary_await, fixId, Diagnostics.Remove_all_unnecessary_uses_of_await)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Remove_unnecessary_await, + fixId, + Diagnostics.Remove_all_unnecessary_uses_of_await, + ), + ]; } }, fixIds: [fixId], @@ -20,7 +31,10 @@ namespace ts.codefix { }); function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan) { - const awaitKeyword = tryCast(getTokenAtPosition(sourceFile, span.start), (node): node is AwaitKeywordToken => node.kind === SyntaxKind.AwaitKeyword); + const awaitKeyword = tryCast( + getTokenAtPosition(sourceFile, span.start), + (node): node is AwaitKeywordToken => node.kind === SyntaxKind.AwaitKeyword, + ); const awaitExpression = awaitKeyword && tryCast(awaitKeyword.parent, isAwaitExpression); if (!awaitExpression) { return; @@ -29,7 +43,10 @@ namespace ts.codefix { let expressionToReplace: Node = awaitExpression; const hasSurroundingParens = isParenthesizedExpression(awaitExpression.parent); if (hasSurroundingParens) { - const leftMostExpression = getLeftmostExpression(awaitExpression.expression, /*stopAtCallExpressions*/ false); + const leftMostExpression = getLeftmostExpression( + awaitExpression.expression, + /*stopAtCallExpressions*/ false, + ); if (isIdentifier(leftMostExpression)) { const precedingToken = findPrecedingToken(awaitExpression.parent.pos, sourceFile); if (precedingToken && precedingToken.kind !== SyntaxKind.NewKeyword) { diff --git a/src/services/codefixes/requireInTs.ts b/src/services/codefixes/requireInTs.ts index ff400611ee8b4..38366f01fdda8 100644 --- a/src/services/codefixes/requireInTs.ts +++ b/src/services/codefixes/requireInTs.ts @@ -10,7 +10,15 @@ namespace ts.codefix { return undefined; } const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, info)); - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_require_to_import, fixId, Diagnostics.Convert_all_require_to_import)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_require_to_import, + fixId, + Diagnostics.Convert_all_require_to_import, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -28,8 +36,18 @@ namespace ts.codefix { sourceFile, statement, defaultImportName && !allowSyntheticDefaults - ? factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, defaultImportName, factory.createExternalModuleReference(required)) - : factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), required, /*assertClause*/ undefined), + ? factory.createImportEqualsDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + defaultImportName, + factory.createExternalModuleReference(required), + ) + : factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), + required, + /*assertClause*/ undefined, + ), ); } @@ -49,7 +67,8 @@ namespace ts.codefix { const decl = cast(parent.parent, isVariableDeclaration); const defaultImportName = tryCast(decl.name, isIdentifier); - const namedImports = isObjectBindingPattern(decl.name) ? tryCreateNamedImportsFromObjectBindingPattern(decl.name) : undefined; + const namedImports = isObjectBindingPattern(decl.name) + ? tryCreateNamedImportsFromObjectBindingPattern(decl.name) : undefined; if (defaultImportName || namedImports) { return { allowSyntheticDefaults: getAllowSyntheticDefaultImports(program.getCompilerOptions()), @@ -67,7 +86,13 @@ namespace ts.codefix { if (!isIdentifier(element.name) || element.initializer) { return undefined; } - importSpecifiers.push(factory.createImportSpecifier(/*isTypeOnly*/ false, tryCast(element.propertyName, isIdentifier), element.name)); + importSpecifiers.push( + factory.createImportSpecifier( + /*isTypeOnly*/ false, + tryCast(element.propertyName, isIdentifier), + element.name, + ), + ); } if (importSpecifiers.length) { diff --git a/src/services/codefixes/returnValueCorrect.ts b/src/services/codefixes/returnValueCorrect.ts index 20417534c268f..eeb7015c963b7 100644 --- a/src/services/codefixes/returnValueCorrect.ts +++ b/src/services/codefixes/returnValueCorrect.ts @@ -44,7 +44,13 @@ namespace ts.codefix { if (info.kind === ProblemKind.MissingReturnStatement) { return append( [getActionForfixAddReturnStatement(context, info.expression, info.statement)], - isArrowFunction(info.declaration) ? getActionForFixRemoveBracesFromArrowFunctionBody(context, info.declaration, info.expression, info.commentSource) : undefined, + isArrowFunction(info.declaration) + ? getActionForFixRemoveBracesFromArrowFunctionBody( + context, + info.declaration, + info.expression, + info.commentSource, + ) : undefined, ); } else { @@ -62,7 +68,14 @@ namespace ts.codefix { break; case fixRemoveBracesFromArrowFunctionBody: if (!isArrowFunction(info.declaration)) return undefined; - removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, info.commentSource, /* withParen */ false); + removeBlockBodyBrace( + changes, + diag.file, + info.declaration, + info.expression, + info.commentSource, + /* withParen */ false, + ); break; case fixIdWrapTheBlockWithParen: if (!isArrowFunction(info.declaration)) return undefined; @@ -81,11 +94,27 @@ namespace ts.codefix { return checker.createAnonymousType(/*symbol*/ undefined, members, [], [], []); } - function getFixInfo(checker: TypeChecker, declaration: FunctionLikeDeclaration, expectType: Type, isFunctionType: boolean): Info | undefined { - if (!declaration.body || !isBlock(declaration.body) || length(declaration.body.statements) !== 1) return undefined; + function getFixInfo( + checker: TypeChecker, + declaration: FunctionLikeDeclaration, + expectType: Type, + isFunctionType: boolean, + ): Info | undefined { + if (!declaration.body || !isBlock(declaration.body) || length(declaration.body.statements) !== 1) { + return undefined; + } const firstStatement = first(declaration.body.statements); - if (isExpressionStatement(firstStatement) && checkFixedAssignableTo(checker, declaration, checker.getTypeAtLocation(firstStatement.expression), expectType, isFunctionType)) { + if ( + isExpressionStatement(firstStatement) + && checkFixedAssignableTo( + checker, + declaration, + checker.getTypeAtLocation(firstStatement.expression), + expectType, + isFunctionType, + ) + ) { return { declaration, kind: ProblemKind.MissingReturnStatement, @@ -95,8 +124,14 @@ namespace ts.codefix { }; } else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { - const node = factory.createObjectLiteralExpression([factory.createPropertyAssignment(firstStatement.label, firstStatement.statement.expression)]); - const nodeType = createObjectTypeFromLabeledExpression(checker, firstStatement.label, firstStatement.statement.expression); + const node = factory.createObjectLiteralExpression([ + factory.createPropertyAssignment(firstStatement.label, firstStatement.statement.expression), + ]); + const nodeType = createObjectTypeFromLabeledExpression( + checker, + firstStatement.label, + firstStatement.statement.expression, + ); if (checkFixedAssignableTo(checker, declaration, nodeType, expectType, isFunctionType)) { return isArrowFunction(declaration) ? { declaration, @@ -116,8 +151,17 @@ namespace ts.codefix { else if (isBlock(firstStatement) && length(firstStatement.statements) === 1) { const firstBlockStatement = first(firstStatement.statements); if (isLabeledStatement(firstBlockStatement) && isExpressionStatement(firstBlockStatement.statement)) { - const node = factory.createObjectLiteralExpression([factory.createPropertyAssignment(firstBlockStatement.label, firstBlockStatement.statement.expression)]); - const nodeType = createObjectTypeFromLabeledExpression(checker, firstBlockStatement.label, firstBlockStatement.statement.expression); + const node = factory.createObjectLiteralExpression([ + factory.createPropertyAssignment( + firstBlockStatement.label, + firstBlockStatement.statement.expression, + ), + ]); + const nodeType = createObjectTypeFromLabeledExpression( + checker, + firstBlockStatement.label, + firstBlockStatement.statement.expression, + ); if (checkFixedAssignableTo(checker, declaration, nodeType, expectType, isFunctionType)) { return { declaration, @@ -133,7 +177,13 @@ namespace ts.codefix { return undefined; } - function checkFixedAssignableTo(checker: TypeChecker, declaration: FunctionLikeDeclaration, exprType: Type, type: Type, isFunctionType: boolean) { + function checkFixedAssignableTo( + checker: TypeChecker, + declaration: FunctionLikeDeclaration, + exprType: Type, + type: Type, + isFunctionType: boolean, + ) { if (isFunctionType) { const sig = checker.getSignatureFromDeclaration(declaration); if (sig) { @@ -165,15 +215,28 @@ namespace ts.codefix { return checker.isTypeAssignableTo(exprType, type); } - function getInfo(checker: TypeChecker, sourceFile: SourceFile, position: number, errorCode: number): Info | undefined { + function getInfo( + checker: TypeChecker, + sourceFile: SourceFile, + position: number, + errorCode: number, + ): Info | undefined { const node = getTokenAtPosition(sourceFile, position); if (!node.parent) return undefined; const declaration = findAncestor(node.parent, isFunctionLikeDeclaration); switch (errorCode) { case Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code: - if (!declaration || !declaration.body || !declaration.type || !rangeContainsRange(declaration.type, node)) return undefined; - return getFixInfo(checker, declaration, checker.getTypeFromTypeNode(declaration.type), /* isFunctionType */ false); + if ( + !declaration || !declaration.body || !declaration.type + || !rangeContainsRange(declaration.type, node) + ) return undefined; + return getFixInfo( + checker, + declaration, + checker.getTypeFromTypeNode(declaration.type), + /* isFunctionType */ false, + ); case Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code: if (!declaration || !isCallExpression(declaration.parent) || !declaration.body) return undefined; const pos = declaration.parent.arguments.indexOf(declaration as Expression); @@ -181,10 +244,17 @@ namespace ts.codefix { if (!type) return undefined; return getFixInfo(checker, declaration, type, /* isFunctionType */ true); case Diagnostics.Type_0_is_not_assignable_to_type_1.code: - if (!isDeclarationName(node) || !isVariableLike(node.parent) && !isJsxAttribute(node.parent)) return undefined; + if (!isDeclarationName(node) || !isVariableLike(node.parent) && !isJsxAttribute(node.parent)) { + return undefined; + } const initializer = getVariableLikeInitializer(node.parent); if (!initializer || !isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; - return getFixInfo(checker, initializer, checker.getTypeAtLocation(node.parent), /* isFunctionType */ true); + return getFixInfo( + checker, + initializer, + checker.getTypeAtLocation(node.parent), + /* isFunctionType */ true, + ); } return undefined; } @@ -198,7 +268,8 @@ namespace ts.codefix { case SyntaxKind.PropertyAssignment: return declaration.initializer; case SyntaxKind.JsxAttribute: - return declaration.initializer && (isJsxExpression(declaration.initializer) ? declaration.initializer.expression : undefined); + return declaration.initializer + && (isJsxExpression(declaration.initializer) ? declaration.initializer.expression : undefined); case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.PropertySignature: case SyntaxKind.EnumMember: @@ -208,7 +279,12 @@ namespace ts.codefix { } } - function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, expression: Expression, statement: Statement) { + function addReturnStatement( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + expression: Expression, + statement: Statement, + ) { suppressLeadingAndTrailingTrivia(expression); const probablyNeedSemi = probablyUsesSemicolons(sourceFile); changes.replaceNode(sourceFile, statement, factory.createReturnStatement(expression), { @@ -218,30 +294,86 @@ namespace ts.codefix { }); } - function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression, commentSource: Node, withParen: boolean) { - const newBody = (withParen || needsParentheses(expression)) ? factory.createParenthesizedExpression(expression) : expression; + function removeBlockBodyBrace( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + declaration: ArrowFunction, + expression: Expression, + commentSource: Node, + withParen: boolean, + ) { + const newBody = (withParen || needsParentheses(expression)) ? factory.createParenthesizedExpression(expression) + : expression; suppressLeadingAndTrailingTrivia(commentSource); copyComments(commentSource, newBody); changes.replaceNode(sourceFile, declaration.body, newBody); } - function wrapBlockWithParen(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression) { + function wrapBlockWithParen( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + declaration: ArrowFunction, + expression: Expression, + ) { changes.replaceNode(sourceFile, declaration.body, factory.createParenthesizedExpression(expression)); } function getActionForfixAddReturnStatement(context: CodeFixContext, expression: Expression, statement: Statement) { - const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, expression, statement)); - return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Add_all_missing_return_statement); + const changes = textChanges.ChangeTracker.with( + context, + t => addReturnStatement(t, context.sourceFile, expression, statement), + ); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Add_a_return_statement, + fixIdAddReturnStatement, + Diagnostics.Add_all_missing_return_statement, + ); } - function getActionForFixRemoveBracesFromArrowFunctionBody(context: CodeFixContext, declaration: ArrowFunction, expression: Expression, commentSource: Node) { - const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, commentSource, /* withParen */ false)); - return createCodeFixAction(fixId, changes, Diagnostics.Remove_braces_from_arrow_function_body, fixRemoveBracesFromArrowFunctionBody, Diagnostics.Remove_braces_from_all_arrow_function_bodies_with_relevant_issues); + function getActionForFixRemoveBracesFromArrowFunctionBody( + context: CodeFixContext, + declaration: ArrowFunction, + expression: Expression, + commentSource: Node, + ) { + const changes = textChanges.ChangeTracker.with( + context, + t => removeBlockBodyBrace( + t, + context.sourceFile, + declaration, + expression, + commentSource, + /* withParen */ false, + ), + ); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Remove_braces_from_arrow_function_body, + fixRemoveBracesFromArrowFunctionBody, + Diagnostics.Remove_braces_from_all_arrow_function_bodies_with_relevant_issues, + ); } - function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { - const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration, expression)); - return createCodeFixAction(fixId, changes, Diagnostics.Wrap_the_following_body_with_parentheses_which_should_be_an_object_literal, fixIdWrapTheBlockWithParen, Diagnostics.Wrap_all_object_literal_with_parentheses); + function getActionForfixWrapTheBlockWithParen( + context: CodeFixContext, + declaration: ArrowFunction, + expression: Expression, + ) { + const changes = textChanges.ChangeTracker.with( + context, + t => wrapBlockWithParen(t, context.sourceFile, declaration, expression), + ); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Wrap_the_following_body_with_parentheses_which_should_be_an_object_literal, + fixIdWrapTheBlockWithParen, + Diagnostics.Wrap_all_object_literal_with_parentheses, + ); } } diff --git a/src/services/codefixes/splitTypeOnlyImport.ts b/src/services/codefixes/splitTypeOnlyImport.ts index 852189a0ced2a..6a4a5c03c7e8a 100644 --- a/src/services/codefixes/splitTypeOnlyImport.ts +++ b/src/services/codefixes/splitTypeOnlyImport.ts @@ -1,6 +1,8 @@ /* @internal */ namespace ts.codefix { - const errorCodes = [Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both.code]; + const errorCodes = [ + Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both.code, + ]; const fixId = "splitTypeOnlyImport"; registerCodeFix({ errorCodes, @@ -10,7 +12,15 @@ namespace ts.codefix { return splitTypeOnlyImport(t, getImportDeclaration(context.sourceFile, context.span), context); }); if (changes.length) { - return [createCodeFixAction(fixId, changes, Diagnostics.Split_into_two_separate_import_declarations, fixId, Diagnostics.Split_all_invalid_type_only_imports)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Split_into_two_separate_import_declarations, + fixId, + Diagnostics.Split_all_invalid_type_only_imports, + ), + ]; } }, getAllCodeActions: context => @@ -23,7 +33,11 @@ namespace ts.codefix { return findAncestor(getTokenAtPosition(sourceFile, span.start), isImportDeclaration); } - function splitTypeOnlyImport(changes: textChanges.ChangeTracker, importDeclaration: ImportDeclaration | undefined, context: CodeFixContextBase) { + function splitTypeOnlyImport( + changes: textChanges.ChangeTracker, + importDeclaration: ImportDeclaration | undefined, + context: CodeFixContextBase, + ) { if (!importDeclaration) { return; } @@ -34,7 +48,12 @@ namespace ts.codefix { factory.updateImportDeclaration( importDeclaration, importDeclaration.modifiers, - factory.updateImportClause(importClause, importClause.isTypeOnly, importClause.name, /*namedBindings*/ undefined), + factory.updateImportClause( + importClause, + importClause.isTypeOnly, + importClause.name, + /*namedBindings*/ undefined, + ), importDeclaration.moduleSpecifier, importDeclaration.assertClause, ), @@ -45,7 +64,12 @@ namespace ts.codefix { importDeclaration, factory.createImportDeclaration( /*modifiers*/ undefined, - factory.updateImportClause(importClause, importClause.isTypeOnly, /*name*/ undefined, importClause.namedBindings), + factory.updateImportClause( + importClause, + importClause.isTypeOnly, + /*name*/ undefined, + importClause.namedBindings, + ), importDeclaration.moduleSpecifier, importDeclaration.assertClause, ), diff --git a/src/services/codefixes/useBigintLiteral.ts b/src/services/codefixes/useBigintLiteral.ts index 0b174e5915e1f..b855529413210 100644 --- a/src/services/codefixes/useBigintLiteral.ts +++ b/src/services/codefixes/useBigintLiteral.ts @@ -2,15 +2,28 @@ namespace ts.codefix { const fixId = "useBigintLiteral"; const errorCodes = [ - Diagnostics.Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers.code, + Diagnostics + .Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers + .code, ]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToUseBigintLiteral(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span)); + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span), + ); if (changes.length > 0) { - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_a_bigint_numeric_literal, fixId, Diagnostics.Convert_all_to_bigint_numeric_literals)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_to_a_bigint_numeric_literal, + fixId, + Diagnostics.Convert_all_to_bigint_numeric_literals, + ), + ]; } }, fixIds: [fixId], diff --git a/src/services/codefixes/useDefaultImport.ts b/src/services/codefixes/useDefaultImport.ts index d3a5ac26ec72b..d3031853c5ff5 100644 --- a/src/services/codefixes/useDefaultImport.ts +++ b/src/services/codefixes/useDefaultImport.ts @@ -8,8 +8,19 @@ namespace ts.codefix { const { sourceFile, span: { start } } = context; const info = getInfo(sourceFile, start); if (!info) return undefined; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info, context.preferences)); - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_default_import, fixId, Diagnostics.Convert_all_to_default_imports)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, sourceFile, info, context.preferences), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_to_default_import, + fixId, + Diagnostics.Convert_all_to_default_imports, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => @@ -37,7 +48,21 @@ namespace ts.codefix { } } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info, preferences: UserPreferences): void { - changes.replaceNode(sourceFile, info.importNode, makeImport(info.name, /*namedImports*/ undefined, info.moduleSpecifier, getQuotePreference(sourceFile, preferences))); + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + info: Info, + preferences: UserPreferences, + ): void { + changes.replaceNode( + sourceFile, + info.importNode, + makeImport( + info.name, + /*namedImports*/ undefined, + info.moduleSpecifier, + getQuotePreference(sourceFile, preferences), + ), + ); } } diff --git a/src/services/codefixes/wrapJsxInFragment.ts b/src/services/codefixes/wrapJsxInFragment.ts index cb42312d7b875..538c7ac19a071 100644 --- a/src/services/codefixes/wrapJsxInFragment.ts +++ b/src/services/codefixes/wrapJsxInFragment.ts @@ -9,7 +9,15 @@ namespace ts.codefix { const node = findNodeToFix(sourceFile, span.start); if (!node) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node)); - return [createCodeFixAction(fixID, changes, Diagnostics.Wrap_in_JSX_fragment, fixID, Diagnostics.Wrap_all_unparented_JSX_in_JSX_fragment)]; + return [ + createCodeFixAction( + fixID, + changes, + Diagnostics.Wrap_in_JSX_fragment, + fixID, + Diagnostics.Wrap_all_unparented_JSX_in_JSX_fragment, + ), + ]; }, fixIds: [fixID], getAllCodeActions: context => @@ -37,7 +45,17 @@ namespace ts.codefix { function doChange(changeTracker: textChanges.ChangeTracker, sf: SourceFile, node: Node) { const jsx = flattenInvalidBinaryExpr(node); - if (jsx) changeTracker.replaceNode(sf, node, factory.createJsxFragment(factory.createJsxOpeningFragment(), jsx, factory.createJsxJsxClosingFragment())); + if (jsx) { + changeTracker.replaceNode( + sf, + node, + factory.createJsxFragment( + factory.createJsxOpeningFragment(), + jsx, + factory.createJsxJsxClosingFragment(), + ), + ); + } } // The invalid syntax is constructed as // InvalidJsxTree :: One of @@ -47,7 +65,10 @@ namespace ts.codefix { const children: JsxChild[] = []; let current = node; while (true) { - if (isBinaryExpression(current) && nodeIsMissing(current.operatorToken) && current.operatorToken.kind === SyntaxKind.CommaToken) { + if ( + isBinaryExpression(current) && nodeIsMissing(current.operatorToken) + && current.operatorToken.kind === SyntaxKind.CommaToken + ) { children.push(current.left as JsxChild); if (isJsxChild(current.right)) { children.push(current.right); diff --git a/src/services/completions.ts b/src/services/completions.ts index 39ca0da736cb7..fa9332a05faa5 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -117,7 +117,9 @@ namespace ts.Completions { return !!(origin && origin.kind === SymbolOriginInfoKind.ResolvedExport); } - function originIncludesSymbolName(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoExport | SymbolOriginInfoResolvedExport { + function originIncludesSymbolName( + origin: SymbolOriginInfo | undefined, + ): origin is SymbolOriginInfoExport | SymbolOriginInfoResolvedExport { return originIsExport(origin) || originIsResolvedExport(origin); } @@ -137,7 +139,9 @@ namespace ts.Completions { return !!(origin && origin.kind & SymbolOriginInfoKind.TypeOnlyAlias); } - function originIsObjectLiteralMethod(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoObjectLiteralMethod { + function originIsObjectLiteralMethod( + origin: SymbolOriginInfo | undefined, + ): origin is SymbolOriginInfoObjectLiteralMethod { return !!(origin && origin.kind & SymbolOriginInfoKind.ObjectLiteralMethod); } @@ -174,7 +178,11 @@ namespace ts.Completions { } interface ModuleSpecifierResolutioContext { - tryResolve: (exportInfo: readonly SymbolExportInfo[], symbolName: string, isFromAmbientModule: boolean) => ModuleSpecifierResolutionResult; + tryResolve: ( + exportInfo: readonly SymbolExportInfo[], + symbolName: string, + isFromAmbientModule: boolean, + ) => ModuleSpecifierResolutionResult; resolvedAny: () => boolean; skippedAny: () => boolean; resolvedBeyondLimit: () => boolean; @@ -202,7 +210,8 @@ namespace ts.Completions { // relative path into node_modules), and we want to filter those completions out entirely. // Import statement completions always need specifier resolution because the module specifier is // part of their `insertText`, not the `codeActions` creating edits away from the cursor. - const needsFullResolution = isForImportStatementCompletion || moduleResolutionRespectsExports(getEmitModuleResolutionKind(program.getCompilerOptions())); + const needsFullResolution = isForImportStatementCompletion + || moduleResolutionRespectsExports(getEmitModuleResolutionKind(program.getCompilerOptions())); let skippedAny = false; let ambientCount = 0; let resolvedCount = 0; @@ -216,27 +225,51 @@ namespace ts.Completions { resolvedBeyondLimit: () => resolvedCount > moduleSpecifierResolutionLimit, }); - const hitRateMessage = cacheAttemptCount ? ` (${(resolvedFromCacheCount / cacheAttemptCount * 100).toFixed(1)}% hit rate)` : ""; - host.log?.(`${logPrefix}: resolved ${resolvedCount} module specifiers, plus ${ambientCount} ambient and ${resolvedFromCacheCount} from cache${hitRateMessage}`); + const hitRateMessage = cacheAttemptCount + ? ` (${(resolvedFromCacheCount / cacheAttemptCount * 100).toFixed(1)}% hit rate)` : ""; + host.log?.( + `${logPrefix}: resolved ${resolvedCount} module specifiers, plus ${ambientCount} ambient and ${resolvedFromCacheCount} from cache${hitRateMessage}`, + ); host.log?.(`${logPrefix}: response is ${skippedAny ? "incomplete" : "complete"}`); host.log?.(`${logPrefix}: ${timestamp() - start}`); return result; - function tryResolve(exportInfo: readonly SymbolExportInfo[], symbolName: string, isFromAmbientModule: boolean): ModuleSpecifierResolutionResult { + function tryResolve( + exportInfo: readonly SymbolExportInfo[], + symbolName: string, + isFromAmbientModule: boolean, + ): ModuleSpecifierResolutionResult { if (isFromAmbientModule) { - const result = resolver.getModuleSpecifierForBestExportInfo(exportInfo, symbolName, position, isValidTypeOnlyUseSite); + const result = resolver.getModuleSpecifierForBestExportInfo( + exportInfo, + symbolName, + position, + isValidTypeOnlyUseSite, + ); if (result) { ambientCount++; } return result || "failed"; } - const shouldResolveModuleSpecifier = needsFullResolution || preferences.allowIncompleteCompletions && resolvedCount < moduleSpecifierResolutionLimit; - const shouldGetModuleSpecifierFromCache = !shouldResolveModuleSpecifier && preferences.allowIncompleteCompletions && cacheAttemptCount < moduleSpecifierResolutionCacheAttemptLimit; + const shouldResolveModuleSpecifier = needsFullResolution + || preferences.allowIncompleteCompletions && resolvedCount < moduleSpecifierResolutionLimit; + const shouldGetModuleSpecifierFromCache = !shouldResolveModuleSpecifier + && preferences.allowIncompleteCompletions + && cacheAttemptCount < moduleSpecifierResolutionCacheAttemptLimit; const result = (shouldResolveModuleSpecifier || shouldGetModuleSpecifierFromCache) - ? resolver.getModuleSpecifierForBestExportInfo(exportInfo, symbolName, position, isValidTypeOnlyUseSite, shouldGetModuleSpecifierFromCache) + ? resolver.getModuleSpecifierForBestExportInfo( + exportInfo, + symbolName, + position, + isValidTypeOnlyUseSite, + shouldGetModuleSpecifierFromCache, + ) : undefined; - if (!shouldResolveModuleSpecifier && !shouldGetModuleSpecifierFromCache || shouldGetModuleSpecifierFromCache && !result) { + if ( + !shouldResolveModuleSpecifier && !shouldGetModuleSpecifierFromCache + || shouldGetModuleSpecifierFromCache && !result + ) { skippedAny = true; } @@ -263,14 +296,23 @@ namespace ts.Completions { formatContext?: formatting.FormatContext, ): CompletionInfo | undefined { const { previousToken } = getRelevantTokens(position, sourceFile); - if (triggerCharacter && !isInString(sourceFile, position, previousToken) && !isValidTrigger(sourceFile, triggerCharacter, previousToken, position)) { + if ( + triggerCharacter && !isInString(sourceFile, position, previousToken) + && !isValidTrigger(sourceFile, triggerCharacter, previousToken, position) + ) { return undefined; } if (triggerCharacter === " ") { // `isValidTrigger` ensures we are at `import |` if (preferences.includeCompletionsForImportStatements && preferences.includeCompletionsWithInsertText) { - return { isGlobalCompletion: true, isMemberCompletion: false, isNewIdentifierLocation: true, isIncomplete: true, entries: [] }; + return { + isGlobalCompletion: true, + isMemberCompletion: false, + isNewIdentifierLocation: true, + isIncomplete: true, + entries: [], + }; } return undefined; } @@ -278,9 +320,21 @@ namespace ts.Completions { // If the request is a continuation of an earlier `isIncomplete` response, // we can continue it from the cached previous response. const compilerOptions = program.getCompilerOptions(); - const incompleteCompletionsCache = preferences.allowIncompleteCompletions ? host.getIncompleteCompletionsCache?.() : undefined; - if (incompleteCompletionsCache && completionKind === CompletionTriggerKind.TriggerForIncompleteCompletions && previousToken && isIdentifier(previousToken)) { - const incompleteContinuation = continuePreviousIncompleteResponse(incompleteCompletionsCache, sourceFile, previousToken, program, host, preferences, cancellationToken); + const incompleteCompletionsCache = preferences.allowIncompleteCompletions + ? host.getIncompleteCompletionsCache?.() : undefined; + if ( + incompleteCompletionsCache && completionKind === CompletionTriggerKind.TriggerForIncompleteCompletions + && previousToken && isIdentifier(previousToken) + ) { + const incompleteContinuation = continuePreviousIncompleteResponse( + incompleteCompletionsCache, + sourceFile, + previousToken, + program, + host, + preferences, + cancellationToken, + ); if (incompleteContinuation) { return incompleteContinuation; } @@ -289,26 +343,57 @@ namespace ts.Completions { incompleteCompletionsCache?.clear(); } - const stringCompletions = StringCompletions.getStringLiteralCompletions(sourceFile, position, previousToken, compilerOptions, host, program, log, preferences); + const stringCompletions = StringCompletions.getStringLiteralCompletions( + sourceFile, + position, + previousToken, + compilerOptions, + host, + program, + log, + preferences, + ); if (stringCompletions) { return stringCompletions; } if ( previousToken && isBreakOrContinueStatement(previousToken.parent) - && (previousToken.kind === SyntaxKind.BreakKeyword || previousToken.kind === SyntaxKind.ContinueKeyword || previousToken.kind === SyntaxKind.Identifier) + && (previousToken.kind === SyntaxKind.BreakKeyword || previousToken.kind === SyntaxKind.ContinueKeyword + || previousToken.kind === SyntaxKind.Identifier) ) { return getLabelCompletionAtPosition(previousToken.parent); } - const completionData = getCompletionData(program, log, sourceFile, compilerOptions, position, preferences, /*detailsEntryId*/ undefined, host, formatContext, cancellationToken); + const completionData = getCompletionData( + program, + log, + sourceFile, + compilerOptions, + position, + preferences, + /*detailsEntryId*/ undefined, + host, + formatContext, + cancellationToken, + ); if (!completionData) { return undefined; } switch (completionData.kind) { case CompletionDataKind.Data: - const response = completionInfoFromData(sourceFile, host, program, compilerOptions, log, completionData, preferences, formatContext, position); + const response = completionInfoFromData( + sourceFile, + host, + program, + compilerOptions, + log, + completionData, + preferences, + formatContext, + position, + ); if (response?.isIncomplete) { incompleteCompletionsCache?.set(response); } @@ -322,7 +407,10 @@ namespace ts.Completions { case CompletionDataKind.JsDocParameterName: return jsdocCompletionInfo(JsDoc.getJSDocParameterNameCompletions(completionData.tag)); case CompletionDataKind.Keywords: - return specificKeywordCompletionInfo(completionData.keywordCompletions, completionData.isNewIdentifierLocation); + return specificKeywordCompletionInfo( + completionData.keywordCompletions, + completionData.isNewIdentifierLocation, + ); default: return Debug.assertNever(completionData); } @@ -340,7 +428,9 @@ namespace ts.Completions { if (result === Comparison.EqualTo) { result = compareStringsCaseSensitiveUI(entryInArray.name, entryToInsert.name); } - if (result === Comparison.EqualTo && entryInArray.data?.moduleSpecifier && entryToInsert.data?.moduleSpecifier) { + if ( + result === Comparison.EqualTo && entryInArray.data?.moduleSpecifier && entryToInsert.data?.moduleSpecifier + ) { // Sort same-named auto-imports by module specifier result = compareNumberOfDirectorySeparators( (entryInArray.data as CompletionEntryDataResolved).moduleSpecifier, @@ -354,7 +444,9 @@ namespace ts.Completions { return result; } - function completionEntryDataIsResolved(data: CompletionEntryDataAutoImport | undefined): data is CompletionEntryDataResolved { + function completionEntryDataIsResolved( + data: CompletionEntryDataAutoImport | undefined, + ): data is CompletionEntryDataResolved { return !!data?.moduleSpecifier; } @@ -392,13 +484,22 @@ namespace ts.Completions { return undefined; } - const { origin } = Debug.checkDefined(getAutoImportSymbolFromCompletionEntryData(entry.name, entry.data, program, host)); + const { origin } = Debug.checkDefined( + getAutoImportSymbolFromCompletionEntryData(entry.name, entry.data, program, host), + ); const info = exportMap.get(file.path, entry.data.exportMapKey); - const result = info && context.tryResolve(info, entry.name, !isExternalModuleNameRelative(stripQuotes(origin.moduleSymbol.name))); + const result = info + && context.tryResolve( + info, + entry.name, + !isExternalModuleNameRelative(stripQuotes(origin.moduleSymbol.name)), + ); if (result === "skipped") return entry; if (!result || result === "failed") { - host.log?.(`Unexpected failure resolving auto import for '${entry.name}' from '${entry.source}'`); + host.log?.( + `Unexpected failure resolving auto import for '${entry.name}' from '${entry.source}'`, + ); return undefined; } @@ -441,7 +542,10 @@ namespace ts.Completions { }; } - function specificKeywordCompletionInfo(entries: readonly CompletionEntry[], isNewIdentifierLocation: boolean): CompletionInfo { + function specificKeywordCompletionInfo( + entries: readonly CompletionEntry[], + isNewIdentifierLocation: boolean, + ): CompletionInfo { return { isGlobalCompletion: false, isMemberCompletion: false, @@ -450,7 +554,11 @@ namespace ts.Completions { }; } - function keywordCompletionData(keywordFilters: KeywordCompletionFilters, filterOutTsOnlyKeywords: boolean, isNewIdentifierLocation: boolean): Request { + function keywordCompletionData( + keywordFilters: KeywordCompletionFilters, + filterOutTsOnlyKeywords: boolean, + isNewIdentifierLocation: boolean, + ): Request { return { kind: CompletionDataKind.Keywords, keywordCompletions: getKeywordCompletions(keywordFilters, filterOutTsOnlyKeywords), @@ -515,7 +623,10 @@ namespace ts.Completions { const entries = createSortedArray(); const isChecked = isCheckedFile(sourceFile, compilerOptions); - if (isChecked && !isNewIdentifierLocation && (!symbols || symbols.length === 0) && keywordFilters === KeywordCompletionFilters.None) { + if ( + isChecked && !isNewIdentifierLocation && (!symbols || symbols.length === 0) + && keywordFilters === KeywordCompletionFilters.None + ) { return undefined; } const uniqueNames = getCompletionEntriesFromSymbols( @@ -546,8 +657,16 @@ namespace ts.Completions { ); if (keywordFilters !== KeywordCompletionFilters.None) { - for (const keywordEntry of getKeywordCompletions(keywordFilters, !insideJsDocTagTypeExpression && isSourceFileJS(sourceFile))) { - if (isTypeOnlyLocation && isTypeKeyword(stringToToken(keywordEntry.name)!) || !uniqueNames.has(keywordEntry.name)) { + for ( + const keywordEntry of getKeywordCompletions( + keywordFilters, + !insideJsDocTagTypeExpression && isSourceFileJS(sourceFile), + ) + ) { + if ( + isTypeOnlyLocation && isTypeKeyword(stringToToken(keywordEntry.name)!) + || !uniqueNames.has(keywordEntry.name) + ) { uniqueNames.add(keywordEntry.name); insertSorted(entries, keywordEntry, compareCompletionEntries, /*allowDuplicates*/ true); } @@ -568,7 +687,13 @@ namespace ts.Completions { } if (!isChecked) { - getJSCompletionEntries(sourceFile, location.pos, uniqueNames, getEmitScriptTarget(compilerOptions), entries); + getJSCompletionEntries( + sourceFile, + location.pos, + uniqueNames, + getEmitScriptTarget(compilerOptions), + entries, + ); } return { @@ -597,7 +722,10 @@ namespace ts.Completions { } } - function getJsxClosingTagCompletion(location: Node | undefined, sourceFile: SourceFile): CompletionInfo | undefined { + function getJsxClosingTagCompletion( + location: Node | undefined, + sourceFile: SourceFile, + ): CompletionInfo | undefined { // We wanna walk up the tree till we find a JSX closing element const jsxClosingElement = findAncestor(location, node => { switch (node.kind) { @@ -626,7 +754,11 @@ namespace ts.Completions { // var x = // var y = // the completion list at "1" and "2" will contain "MainComponent.Child" with a replacement span of closing tag name - const hasClosingAngleBracket = !!findChildOfKind(jsxClosingElement, SyntaxKind.GreaterThanToken, sourceFile); + const hasClosingAngleBracket = !!findChildOfKind( + jsxClosingElement, + SyntaxKind.GreaterThanToken, + sourceFile, + ); const tagName = jsxClosingElement.parent.openingElement.tagName; const closingTag = tagName.getText(sourceFile); const fullClosingTag = closingTag + (hasClosingAngleBracket ? "" : ">"); @@ -638,7 +770,13 @@ namespace ts.Completions { kindModifiers: undefined, sortText: SortText.LocationPriority, }; - return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: false, optionalReplacementSpan: replacementSpan, entries: [entry] }; + return { + isGlobalCompletion: false, + isMemberCompletion: true, + isNewIdentifierLocation: false, + optionalReplacementSpan: replacementSpan, + entries: [entry], + }; } return; } @@ -669,13 +807,26 @@ namespace ts.Completions { }); } - function completionNameForLiteral(sourceFile: SourceFile, preferences: UserPreferences, literal: string | number | PseudoBigInt): string { - return typeof literal === "object" ? pseudoBigIntToString(literal) + "n" : - isString(literal) ? quote(sourceFile, preferences, literal) : JSON.stringify(literal); + function completionNameForLiteral( + sourceFile: SourceFile, + preferences: UserPreferences, + literal: string | number | PseudoBigInt, + ): string { + return typeof literal === "object" ? pseudoBigIntToString(literal) + "n" + : isString(literal) ? quote(sourceFile, preferences, literal) : JSON.stringify(literal); } - function createCompletionEntryForLiteral(sourceFile: SourceFile, preferences: UserPreferences, literal: string | number | PseudoBigInt): CompletionEntry { - return { name: completionNameForLiteral(sourceFile, preferences, literal), kind: ScriptElementKind.string, kindModifiers: ScriptElementKindModifier.none, sortText: SortText.LocationPriority }; + function createCompletionEntryForLiteral( + sourceFile: SourceFile, + preferences: UserPreferences, + literal: string | number | PseudoBigInt, + ): CompletionEntry { + return { + name: completionNameForLiteral(sourceFile, preferences, literal), + kind: ScriptElementKind.string, + kindModifiers: ScriptElementKindModifier.none, + sortText: SortText.LocationPriority, + }; } function createCompletionEntry( @@ -722,18 +873,21 @@ namespace ts.Completions { // We should only have needsConvertPropertyAccess if there's a property access to convert. But see #21790. // Somehow there was a global with a non-identifier name. Hopefully someone will complain about getting a "foo bar" global completion and provide a repro. else if ((useBraces || insertQuestionDot) && propertyAccessToConvert) { - insertText = useBraces ? needsConvertPropertyAccess ? `[${quotePropertyName(sourceFile, preferences, name)}]` : `[${name}]` : name; + insertText = useBraces + ? needsConvertPropertyAccess ? `[${quotePropertyName(sourceFile, preferences, name)}]` : `[${name}]` + : name; if (insertQuestionDot || propertyAccessToConvert.questionDotToken) { insertText = `?.${insertText}`; } - const dot = findChildOfKind(propertyAccessToConvert, SyntaxKind.DotToken, sourceFile) || - findChildOfKind(propertyAccessToConvert, SyntaxKind.QuestionDotToken, sourceFile); + const dot = findChildOfKind(propertyAccessToConvert, SyntaxKind.DotToken, sourceFile) + || findChildOfKind(propertyAccessToConvert, SyntaxKind.QuestionDotToken, sourceFile); if (!dot) { return undefined; } // If the text after the '.' starts with this name, write over it. Else, add new text. - const end = startsWith(name, propertyAccessToConvert.name.text) ? propertyAccessToConvert.name.end : dot.end; + const end = startsWith(name, propertyAccessToConvert.name.text) ? propertyAccessToConvert.name.end + : dot.end; replacementSpan = createTextSpanFromBounds(dot.getStart(sourceFile), end); } @@ -753,14 +907,26 @@ namespace ts.Completions { } awaitText += `(await ${propertyAccessToConvert.expression.getText()})`; - insertText = needsConvertPropertyAccess ? `${awaitText}${insertText}` : `${awaitText}${insertQuestionDot ? "?." : "."}${insertText}`; - replacementSpan = createTextSpanFromBounds(propertyAccessToConvert.getStart(sourceFile), propertyAccessToConvert.end); + insertText = needsConvertPropertyAccess ? `${awaitText}${insertText}` + : `${awaitText}${insertQuestionDot ? "?." : "."}${insertText}`; + replacementSpan = createTextSpanFromBounds( + propertyAccessToConvert.getStart(sourceFile), + propertyAccessToConvert.end, + ); } if (originIsResolvedExport(origin)) { sourceDisplay = [textPart(origin.moduleSpecifier)]; if (importStatementCompletion) { - ({ insertText, replacementSpan } = getInsertTextAndReplacementSpanForImportCompletion(name, importStatementCompletion, origin, useSemicolons, sourceFile, options, preferences)); + ({ insertText, replacementSpan } = getInsertTextAndReplacementSpanForImportCompletion( + name, + importStatementCompletion, + origin, + useSemicolons, + sourceFile, + options, + preferences, + )); isSnippet = preferences.includeCompletionsWithSnippetText ? true : undefined; } } @@ -770,13 +936,23 @@ namespace ts.Completions { } if ( - preferences.includeCompletionsWithClassMemberSnippets && - preferences.includeCompletionsWithInsertText && - completionKind === CompletionKind.MemberLike && - isClassLikeMemberCompletion(symbol, location) + preferences.includeCompletionsWithClassMemberSnippets + && preferences.includeCompletionsWithInsertText + && completionKind === CompletionKind.MemberLike + && isClassLikeMemberCompletion(symbol, location) ) { let importAdder; - ({ insertText, isSnippet, importAdder, replacementSpan } = getEntryForMemberCompletion(host, program, options, preferences, name, symbol, location, contextToken, formatContext)); + ({ insertText, isSnippet, importAdder, replacementSpan } = getEntryForMemberCompletion( + host, + program, + options, + preferences, + name, + symbol, + location, + contextToken, + formatContext, + )); sortText = SortText.ClassMemberSnippets; // sortText has to be lower priority than the sortText for keywords. See #47852. if (importAdder?.hasFixes()) { hasAction = true; @@ -794,7 +970,10 @@ namespace ts.Completions { sortText = SortText.SortBelow(sortText); } - if (isJsxIdentifierExpected && !isRightOfOpenTag && preferences.includeCompletionsWithSnippetText && preferences.jsxAttributeCompletionStyle && preferences.jsxAttributeCompletionStyle !== "none") { + if ( + isJsxIdentifierExpected && !isRightOfOpenTag && preferences.includeCompletionsWithSnippetText + && preferences.jsxAttributeCompletionStyle && preferences.jsxAttributeCompletionStyle !== "none" + ) { let useBraces = preferences.jsxAttributeCompletionStyle === "braces"; const type = typeChecker.getTypeOfSymbolAtLocation(symbol, location); @@ -802,9 +981,17 @@ namespace ts.Completions { if ( preferences.jsxAttributeCompletionStyle === "auto" && !(type.flags & TypeFlags.BooleanLike) - && !(type.flags & TypeFlags.Union && find((type as UnionType).types, type => !!(type.flags & TypeFlags.BooleanLike))) + && !(type.flags & TypeFlags.Union + && find((type as UnionType).types, type => !!(type.flags & TypeFlags.BooleanLike))) ) { - if (type.flags & TypeFlags.StringLike || (type.flags & TypeFlags.Union && every((type as UnionType).types, type => !!(type.flags & (TypeFlags.StringLike | TypeFlags.Undefined))))) { + if ( + type.flags & TypeFlags.StringLike + || (type.flags & TypeFlags.Union + && every( + (type as UnionType).types, + type => !!(type.flags & (TypeFlags.StringLike | TypeFlags.Undefined)), + )) + ) { // If is string like or undefined use quotes insertText = `${escapeSnippetText(name)}=${quote(sourceFile, preferences, "$1")}`; isSnippet = true; @@ -886,20 +1073,20 @@ namespace ts.Completions { `location` is a syntax list (with modifiers as children), and `location.parent` is a class-like declaration. */ - return !!(symbol.flags & memberFlags) && - ( - isClassLike(location) || - ( - location.parent && - location.parent.parent && - isClassElement(location.parent) && - location === location.parent.name && - isClassLike(location.parent.parent) - ) || - ( - location.parent && - isSyntaxList(location) && - isClassLike(location.parent) + return !!(symbol.flags & memberFlags) + && ( + isClassLike(location) + || ( + location.parent + && location.parent.parent + && isClassElement(location.parent) + && location === location.parent.name + && isClassLike(location.parent.parent) + ) + || ( + location.parent + && isSyntaxList(location) + && isClassLike(location.parent) ) ); } @@ -977,7 +1164,8 @@ namespace ts.Completions { } if ( isClassElement(node) - && checker.getMemberOverrideModifierStatus(classLikeDeclaration, node) === MemberOverrideStatus.NeedsOverride + && checker.getMemberOverrideModifierStatus(classLikeDeclaration, node) + === MemberOverrideStatus.NeedsOverride ) { requiredModifiers |= ModifierFlags.Override; } @@ -1097,10 +1285,19 @@ namespace ts.Completions { newLine: getNewLineKind(getNewLineCharacter(options, maybeBind(host, host.getNewLine))), }); if (formatContext) { - insertText = printer.printAndFormatSnippetList(ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, factory.createNodeArray([method], /*hasTrailingComma*/ true), sourceFile, formatContext); + insertText = printer.printAndFormatSnippetList( + ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, + factory.createNodeArray([method], /*hasTrailingComma*/ true), + sourceFile, + formatContext, + ); } else { - insertText = printer.printSnippetList(ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, factory.createNodeArray([method], /*hasTrailingComma*/ true), sourceFile); + insertText = printer.printSnippetList( + ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, + factory.createNodeArray([method], /*hasTrailingComma*/ true), + sourceFile, + ); } const signaturePrinter = createPrinter({ @@ -1138,10 +1335,15 @@ namespace ts.Completions { } const checker = program.getTypeChecker(); const declaration = declarations[0]; - const name = getSynthesizedDeepClone(getNameOfDeclaration(declaration), /*includeTrivia*/ false) as PropertyName; + const name = getSynthesizedDeepClone( + getNameOfDeclaration(declaration), + /*includeTrivia*/ false, + ) as PropertyName; const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration)); const quotePreference = getQuotePreference(sourceFile, preferences); - const builderFlags = NodeBuilderFlags.OmitThisParameter | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : NodeBuilderFlags.None); + const builderFlags = NodeBuilderFlags.OmitThisParameter + | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType + : NodeBuilderFlags.None); switch (declaration.kind) { case SyntaxKind.PropertySignature: @@ -1153,7 +1355,10 @@ namespace ts.Completions { : type; if (effectiveType.flags & TypeFlags.Union) { // Only offer the completion if there's a single function type component. - const functionTypes = filter((effectiveType as UnionType).types, type => checker.getSignaturesOfType(type, SignatureKind.Call).length > 0); + const functionTypes = filter( + (effectiveType as UnionType).types, + type => checker.getSignaturesOfType(type, SignatureKind.Call).length > 0, + ); if (functionTypes.length === 1) { effectiveType = functionTypes[0]; } @@ -1166,7 +1371,12 @@ namespace ts.Completions { // We don't support overloads in object literals. return undefined; } - const typeNode = checker.typeToTypeNode(effectiveType, enclosingDeclaration, builderFlags, codefix.getNoopSymbolTrackerWithResolver({ program, host })); + const typeNode = checker.typeToTypeNode( + effectiveType, + enclosingDeclaration, + builderFlags, + codefix.getNoopSymbolTrackerWithResolver({ program, host }), + ); if (!typeNode || !isFunctionTypeNode(typeNode)) { return undefined; } @@ -1305,7 +1515,9 @@ namespace ts.Completions { } } - function originToCompletionEntryData(origin: SymbolOriginInfoExport | SymbolOriginInfoResolvedExport): CompletionEntryData | undefined { + function originToCompletionEntryData( + origin: SymbolOriginInfoExport | SymbolOriginInfoResolvedExport, + ): CompletionEntryData | undefined { const ambientModuleName = origin.fileName ? undefined : stripQuotes(origin.moduleSymbol.name); const isPackageJsonImport = origin.isFromPackageJson ? true : undefined; if (originIsResolvedExport(origin)) { @@ -1328,7 +1540,11 @@ namespace ts.Completions { return unresolvedData; } - function completionEntryDataToSymbolOriginInfo(data: CompletionEntryData, completionName: string, moduleSymbol: Symbol): SymbolOriginInfoExport | SymbolOriginInfoResolvedExport { + function completionEntryDataToSymbolOriginInfo( + data: CompletionEntryData, + completionName: string, + moduleSymbol: Symbol, + ): SymbolOriginInfoExport | SymbolOriginInfoResolvedExport { const isDefaultExport = data.exportName === InternalSymbolName.Default; const isFromPackageJson = !!data.isPackageJsonImport; if (completionEntryDataIsResolved(data)) { @@ -1357,27 +1573,57 @@ namespace ts.Completions { return unresolvedOrigin; } - function getInsertTextAndReplacementSpanForImportCompletion(name: string, importStatementCompletion: ImportStatementCompletionInfo, origin: SymbolOriginInfoResolvedExport, useSemicolons: boolean, sourceFile: SourceFile, options: CompilerOptions, preferences: UserPreferences) { + function getInsertTextAndReplacementSpanForImportCompletion( + name: string, + importStatementCompletion: ImportStatementCompletionInfo, + origin: SymbolOriginInfoResolvedExport, + useSemicolons: boolean, + sourceFile: SourceFile, + options: CompilerOptions, + preferences: UserPreferences, + ) { const replacementSpan = importStatementCompletion.replacementSpan; const quotedModuleSpecifier = quote(sourceFile, preferences, origin.moduleSpecifier); - const exportKind = origin.isDefaultExport ? ExportKind.Default : - origin.exportName === InternalSymbolName.ExportEquals ? ExportKind.ExportEquals : - ExportKind.Named; + const exportKind = origin.isDefaultExport ? ExportKind.Default + : origin.exportName === InternalSymbolName.ExportEquals ? ExportKind.ExportEquals + : ExportKind.Named; const tabStop = preferences.includeCompletionsWithSnippetText ? "$1" : ""; const importKind = codefix.getImportKind(sourceFile, exportKind, options, /*forceImportKeyword*/ true); const isImportSpecifierTypeOnly = importStatementCompletion.couldBeTypeOnlyImportSpecifier; - const topLevelTypeOnlyText = importStatementCompletion.isTopLevelTypeOnly ? ` ${tokenToString(SyntaxKind.TypeKeyword)} ` : " "; - const importSpecifierTypeOnlyText = isImportSpecifierTypeOnly ? `${tokenToString(SyntaxKind.TypeKeyword)} ` : ""; + const topLevelTypeOnlyText = importStatementCompletion.isTopLevelTypeOnly + ? ` ${tokenToString(SyntaxKind.TypeKeyword)} ` : " "; + const importSpecifierTypeOnlyText = isImportSpecifierTypeOnly ? `${tokenToString(SyntaxKind.TypeKeyword)} ` + : ""; const suffix = useSemicolons ? ";" : ""; switch (importKind) { case ImportKind.CommonJS: - return { replacementSpan, insertText: `import${topLevelTypeOnlyText}${escapeSnippetText(name)}${tabStop} = require(${quotedModuleSpecifier})${suffix}` }; + return { + replacementSpan, + insertText: `import${topLevelTypeOnlyText}${ + escapeSnippetText(name) + }${tabStop} = require(${quotedModuleSpecifier})${suffix}`, + }; case ImportKind.Default: - return { replacementSpan, insertText: `import${topLevelTypeOnlyText}${escapeSnippetText(name)}${tabStop} from ${quotedModuleSpecifier}${suffix}` }; + return { + replacementSpan, + insertText: `import${topLevelTypeOnlyText}${ + escapeSnippetText(name) + }${tabStop} from ${quotedModuleSpecifier}${suffix}`, + }; case ImportKind.Namespace: - return { replacementSpan, insertText: `import${topLevelTypeOnlyText}* as ${escapeSnippetText(name)} from ${quotedModuleSpecifier}${suffix}` }; + return { + replacementSpan, + insertText: `import${topLevelTypeOnlyText}* as ${ + escapeSnippetText(name) + } from ${quotedModuleSpecifier}${suffix}`, + }; case ImportKind.Named: - return { replacementSpan, insertText: `import${topLevelTypeOnlyText}{ ${importSpecifierTypeOnlyText}${escapeSnippetText(name)}${tabStop} } from ${quotedModuleSpecifier}${suffix}` }; + return { + replacementSpan, + insertText: `import${topLevelTypeOnlyText}{ ${importSpecifierTypeOnlyText}${ + escapeSnippetText(name) + }${tabStop} } from ${quotedModuleSpecifier}${suffix}`, + }; } } @@ -1389,9 +1635,14 @@ namespace ts.Completions { return quote(sourceFile, preferences, name); } - function isRecommendedCompletionMatch(localSymbol: Symbol, recommendedCompletion: Symbol | undefined, checker: TypeChecker): boolean { - return localSymbol === recommendedCompletion || - !!(localSymbol.flags & SymbolFlags.ExportValue) && checker.getExportSymbolOfSymbol(localSymbol) === recommendedCompletion; + function isRecommendedCompletionMatch( + localSymbol: Symbol, + recommendedCompletion: Symbol | undefined, + checker: TypeChecker, + ): boolean { + return localSymbol === recommendedCompletion + || !!(localSymbol.flags & SymbolFlags.ExportValue) + && checker.getExportSymbolOfSymbol(localSymbol) === recommendedCompletion; } function getSourceFromOrigin(origin: SymbolOriginInfo | undefined): string | undefined { @@ -1448,13 +1699,18 @@ namespace ts.Completions { const symbol = symbols[i]; const origin = symbolToOriginInfoMap?.[i]; const info = getCompletionEntryDisplayNameForSymbol(symbol, target, origin, kind, !!jsxIdentifierExpected); - if (!info || (uniques.get(info.name) && (!origin || !originIsObjectLiteralMethod(origin))) || kind === CompletionKind.Global && symbolToSortTextMap && !shouldIncludeSymbol(symbol, symbolToSortTextMap)) { + if ( + !info || (uniques.get(info.name) && (!origin || !originIsObjectLiteralMethod(origin))) + || kind === CompletionKind.Global && symbolToSortTextMap + && !shouldIncludeSymbol(symbol, symbolToSortTextMap) + ) { continue; } const { name, needsConvertPropertyAccess } = info; const originalSortText = symbolToSortTextMap?.[getSymbolId(symbol)] ?? SortText.LocationPriority; - const sortText = (isDeprecated(symbol, typeChecker) ? SortText.Deprecated(originalSortText) : originalSortText); + const sortText = + (isDeprecated(symbol, typeChecker) ? SortText.Deprecated(originalSortText) : originalSortText); const entry = createCompletionEntry( symbol, sortText, @@ -1484,7 +1740,9 @@ namespace ts.Completions { } /** True for locals; false for globals, module exports from other files, `this.` completions. */ - const shouldShadowLaterSymbols = (!origin || originIsTypeOnlyAlias(origin)) && !(symbol.parent === undefined && !some(symbol.declarations, d => d.getSourceFile() === location.getSourceFile())); + const shouldShadowLaterSymbols = (!origin || originIsTypeOnlyAlias(origin)) + && !(symbol.parent === undefined + && !some(symbol.declarations, d => d.getSourceFile() === location.getSourceFile())); uniques.set(name, shouldShadowLaterSymbols); insertSorted(entries, entry, compareCompletionEntries, /*allowDuplicates*/ true); } @@ -1599,7 +1857,10 @@ namespace ts.Completions { entryId: CompletionEntryIdentifier, host: LanguageServiceHost, preferences: UserPreferences, - ): SymbolCompletion | { type: "request"; request: Request; } | { type: "literal"; literal: string | number | PseudoBigInt; } | { type: "none"; } { + ): SymbolCompletion | { type: "request"; request: Request; } | { + type: "literal"; + literal: string | number | PseudoBigInt; + } | { type: "none"; } { if (entryId.data) { const autoImport = getAutoImportSymbolFromCompletionEntryData(entryId.name, entryId.data, program, host); if (autoImport) { @@ -1618,7 +1879,17 @@ namespace ts.Completions { } const compilerOptions = program.getCompilerOptions(); - const completionData = getCompletionData(program, log, sourceFile, compilerOptions, position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, entryId, host, /*formatContext*/ undefined); + const completionData = getCompletionData( + program, + log, + sourceFile, + compilerOptions, + position, + { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, + entryId, + host, + /*formatContext*/ undefined, + ); if (!completionData) { return { type: "none" }; } @@ -1626,7 +1897,17 @@ namespace ts.Completions { return { type: "request", request: completionData }; } - const { symbols, literals, location, completionKind, symbolToOriginInfoMap, contextToken, previousToken, isJsxInitializer, isTypeOnlyLocation } = completionData; + const { + symbols, + literals, + location, + completionKind, + symbolToOriginInfoMap, + contextToken, + previousToken, + isJsxInitializer, + isTypeOnlyLocation, + } = completionData; const literal = find(literals, l => completionNameForLiteral(sourceFile, preferences, l) === entryId.name); if (literal !== undefined) return { type: "literal", literal }; @@ -1637,13 +1918,29 @@ namespace ts.Completions { // completion entry. return firstDefined(symbols, (symbol, index): SymbolCompletion | undefined => { const origin = symbolToOriginInfoMap[index]; - const info = getCompletionEntryDisplayNameForSymbol(symbol, getEmitScriptTarget(compilerOptions), origin, completionKind, completionData.isJsxIdentifierExpected); + const info = getCompletionEntryDisplayNameForSymbol( + symbol, + getEmitScriptTarget(compilerOptions), + origin, + completionKind, + completionData.isJsxIdentifierExpected, + ); return info && info.name === entryId.name && ( entryId.source === CompletionSource.ClassMemberSnippet && symbol.flags & SymbolFlags.ClassMember - || entryId.source === CompletionSource.ObjectLiteralMethodSnippet && symbol.flags & (SymbolFlags.Property | SymbolFlags.Method) + || entryId.source === CompletionSource.ObjectLiteralMethodSnippet + && symbol.flags & (SymbolFlags.Property | SymbolFlags.Method) || getSourceFromOrigin(origin) === entryId.source ) - ? { type: "symbol" as const, symbol, location, origin, contextToken, previousToken, isJsxInitializer, isTypeOnlyLocation } + ? { + type: "symbol" as const, + symbol, + location, + origin, + contextToken, + previousToken, + isJsxInitializer, + isTypeOnlyLocation, + } : undefined; }) || { type: "none" }; } @@ -1671,11 +1968,29 @@ namespace ts.Completions { const contextToken = findPrecedingToken(position, sourceFile); if (isInString(sourceFile, position, contextToken)) { - return StringCompletions.getStringLiteralCompletionDetails(name, sourceFile, position, contextToken, typeChecker, compilerOptions, host, cancellationToken, preferences); + return StringCompletions.getStringLiteralCompletionDetails( + name, + sourceFile, + position, + contextToken, + typeChecker, + compilerOptions, + host, + cancellationToken, + preferences, + ); } // Compute all the completion symbols again. - const symbolCompletion = getSymbolCompletionFromEntryId(program, log, sourceFile, position, entryId, host, preferences); + const symbolCompletion = getSymbolCompletionFromEntryId( + program, + log, + sourceFile, + position, + entryId, + host, + preferences, + ); switch (symbolCompletion.type) { case "request": { const { request } = symbolCompletion; @@ -1687,39 +2002,123 @@ namespace ts.Completions { case CompletionDataKind.JsDocParameterName: return JsDoc.getJSDocParameterNameCompletionDetails(name); case CompletionDataKind.Keywords: - return some(request.keywordCompletions, c => c.name === name) ? createSimpleDetails(name, ScriptElementKind.keyword, SymbolDisplayPartKind.keyword) : undefined; + return some(request.keywordCompletions, c => c.name === name) + ? createSimpleDetails(name, ScriptElementKind.keyword, SymbolDisplayPartKind.keyword) + : undefined; default: return Debug.assertNever(request); } } case "symbol": { const { symbol, location, contextToken, origin, previousToken } = symbolCompletion; - const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay(name, location, contextToken, origin, symbol, program, host, compilerOptions, sourceFile, position, previousToken, formatContext, preferences, data, source, cancellationToken); - return createCompletionDetailsForSymbol(symbol, typeChecker, sourceFile, location, cancellationToken, codeActions, sourceDisplay); // TODO: GH#18217 + const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay( + name, + location, + contextToken, + origin, + symbol, + program, + host, + compilerOptions, + sourceFile, + position, + previousToken, + formatContext, + preferences, + data, + source, + cancellationToken, + ); + return createCompletionDetailsForSymbol( + symbol, + typeChecker, + sourceFile, + location, + cancellationToken, + codeActions, + sourceDisplay, + ); // TODO: GH#18217 } case "literal": { const { literal } = symbolCompletion; - return createSimpleDetails(completionNameForLiteral(sourceFile, preferences, literal), ScriptElementKind.string, typeof literal === "string" ? SymbolDisplayPartKind.stringLiteral : SymbolDisplayPartKind.numericLiteral); + return createSimpleDetails( + completionNameForLiteral(sourceFile, preferences, literal), + ScriptElementKind.string, + typeof literal === "string" ? SymbolDisplayPartKind.stringLiteral + : SymbolDisplayPartKind.numericLiteral, + ); } case "none": // Didn't find a symbol with this name. See if we can find a keyword instead. - return allKeywordsCompletions().some(c => c.name === name) ? createSimpleDetails(name, ScriptElementKind.keyword, SymbolDisplayPartKind.keyword) : undefined; + return allKeywordsCompletions().some(c => c.name === name) + ? createSimpleDetails(name, ScriptElementKind.keyword, SymbolDisplayPartKind.keyword) : undefined; default: Debug.assertNever(symbolCompletion); } } - function createSimpleDetails(name: string, kind: ScriptElementKind, kind2: SymbolDisplayPartKind): CompletionEntryDetails { + function createSimpleDetails( + name: string, + kind: ScriptElementKind, + kind2: SymbolDisplayPartKind, + ): CompletionEntryDetails { return createCompletionDetails(name, ScriptElementKindModifier.none, kind, [displayPart(name, kind2)]); } - export function createCompletionDetailsForSymbol(symbol: Symbol, checker: TypeChecker, sourceFile: SourceFile, location: Node, cancellationToken: CancellationToken, codeActions?: CodeAction[], sourceDisplay?: SymbolDisplayPart[]): CompletionEntryDetails { - const { displayParts, documentation, symbolKind, tags } = checker.runWithCancellationToken(cancellationToken, checker => SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, sourceFile, location, location, SemanticMeaning.All)); - return createCompletionDetails(symbol.name, SymbolDisplay.getSymbolModifiers(checker, symbol), symbolKind, displayParts, documentation, tags, codeActions, sourceDisplay); + export function createCompletionDetailsForSymbol( + symbol: Symbol, + checker: TypeChecker, + sourceFile: SourceFile, + location: Node, + cancellationToken: CancellationToken, + codeActions?: CodeAction[], + sourceDisplay?: SymbolDisplayPart[], + ): CompletionEntryDetails { + const { displayParts, documentation, symbolKind, tags } = checker.runWithCancellationToken( + cancellationToken, + checker => + SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind( + checker, + symbol, + sourceFile, + location, + location, + SemanticMeaning.All, + ), + ); + return createCompletionDetails( + symbol.name, + SymbolDisplay.getSymbolModifiers(checker, symbol), + symbolKind, + displayParts, + documentation, + tags, + codeActions, + sourceDisplay, + ); } - export function createCompletionDetails(name: string, kindModifiers: string, kind: ScriptElementKind, displayParts: SymbolDisplayPart[], documentation?: SymbolDisplayPart[], tags?: JSDocTagInfo[], codeActions?: CodeAction[], source?: SymbolDisplayPart[]): CompletionEntryDetails { - return { name, kindModifiers, kind, displayParts, documentation, tags, codeActions, source, sourceDisplay: source }; + export function createCompletionDetails( + name: string, + kindModifiers: string, + kind: ScriptElementKind, + displayParts: SymbolDisplayPart[], + documentation?: SymbolDisplayPart[], + tags?: JSDocTagInfo[], + codeActions?: CodeAction[], + source?: SymbolDisplayPart[], + ): CompletionEntryDetails { + return { + name, + kindModifiers, + kind, + displayParts, + documentation, + tags, + codeActions, + source, + sourceDisplay: source, + }; } interface CodeActionsAndSourceDisplay { @@ -1796,10 +2195,12 @@ namespace ts.Completions { return { codeActions: undefined, sourceDisplay: undefined }; } - const checker = origin.isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() : program.getTypeChecker(); + const checker = origin.isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() + : program.getTypeChecker(); const { moduleSymbol } = origin; const targetSymbol = checker.getMergedSymbol(skipAlias(symbol.exportSymbol || symbol, checker)); - const isJsxOpeningTagName = contextToken?.kind === SyntaxKind.LessThanToken && isJsxOpeningLikeElement(contextToken.parent); + const isJsxOpeningTagName = contextToken?.kind === SyntaxKind.LessThanToken + && isJsxOpeningLikeElement(contextToken.parent); const { moduleSpecifier, codeAction } = codefix.getImportCompletionAction( targetSymbol, moduleSymbol, @@ -1826,7 +2227,15 @@ namespace ts.Completions { host: LanguageServiceHost, preferences: UserPreferences, ): Symbol | undefined { - const completion = getSymbolCompletionFromEntryId(program, log, sourceFile, position, entryId, host, preferences); + const completion = getSymbolCompletionFromEntryId( + program, + log, + sourceFile, + position, + entryId, + host, + preferences, + ); return completion.type === "symbol" ? completion.symbol : undefined; } @@ -1868,7 +2277,11 @@ namespace ts.Completions { type Request = | { readonly kind: CompletionDataKind.JsDocTagName | CompletionDataKind.JsDocTag; } | { readonly kind: CompletionDataKind.JsDocParameterName; tag: JSDocParameterTag; } - | { readonly kind: CompletionDataKind.Keywords; keywordCompletions: readonly CompletionEntry[]; isNewIdentifierLocation: boolean; }; + | { + readonly kind: CompletionDataKind.Keywords; + keywordCompletions: readonly CompletionEntry[]; + isNewIdentifierLocation: boolean; + }; export const enum CompletionKind { ObjectPropertyDeclaration, @@ -1879,18 +2292,32 @@ namespace ts.Completions { None, } - function getRecommendedCompletion(previousToken: Node, contextualType: Type, checker: TypeChecker): Symbol | undefined { + function getRecommendedCompletion( + previousToken: Node, + contextualType: Type, + checker: TypeChecker, + ): Symbol | undefined { // For a union, return the first one with a recommended completion. - return firstDefined(contextualType && (contextualType.isUnion() ? contextualType.types : [contextualType]), type => { - const symbol = type && type.symbol; - // Don't include make a recommended completion for an abstract class - return symbol && (symbol.flags & (SymbolFlags.EnumMember | SymbolFlags.Enum | SymbolFlags.Class) && !isAbstractConstructorSymbol(symbol)) - ? getFirstSymbolInChain(symbol, previousToken, checker) - : undefined; - }); + return firstDefined( + contextualType && (contextualType.isUnion() ? contextualType.types : [contextualType]), + type => { + const symbol = type && type.symbol; + // Don't include make a recommended completion for an abstract class + return symbol + && (symbol.flags & (SymbolFlags.EnumMember | SymbolFlags.Enum | SymbolFlags.Class) + && !isAbstractConstructorSymbol(symbol)) + ? getFirstSymbolInChain(symbol, previousToken, checker) + : undefined; + }, + ); } - function getContextualType(previousToken: Node, position: number, sourceFile: SourceFile, checker: TypeChecker): Type | undefined { + function getContextualType( + previousToken: Node, + position: number, + sourceFile: SourceFile, + checker: TypeChecker, + ): Type | undefined { const { parent } = previousToken; switch (previousToken.kind) { case SyntaxKind.Identifier: @@ -1912,23 +2339,39 @@ namespace ts.Completions { const caseClause = tryCast(parent, isCaseClause); return caseClause ? getSwitchedType(caseClause, checker) : undefined; case SyntaxKind.OpenBraceToken: - return isJsxExpression(parent) && !isJsxElement(parent.parent) && !isJsxFragment(parent.parent) ? checker.getContextualTypeForJsxAttribute(parent.parent) : undefined; + return isJsxExpression(parent) && !isJsxElement(parent.parent) && !isJsxFragment(parent.parent) + ? checker.getContextualTypeForJsxAttribute(parent.parent) : undefined; default: const argInfo = SignatureHelp.getArgumentInfoForCompletions(previousToken, position, sourceFile); - return argInfo ? + return argInfo // At `,`, treat this as the next argument after the comma. - checker.getContextualTypeForArgumentAtIndex(argInfo.invocation, argInfo.argumentIndex + (previousToken.kind === SyntaxKind.CommaToken ? 1 : 0)) : - isEqualityOperatorKind(previousToken.kind) && isBinaryExpression(parent) && isEqualityOperatorKind(parent.operatorToken.kind) ? + ? checker.getContextualTypeForArgumentAtIndex( + argInfo.invocation, + argInfo.argumentIndex + (previousToken.kind === SyntaxKind.CommaToken ? 1 : 0), + ) + : isEqualityOperatorKind(previousToken.kind) && isBinaryExpression(parent) + && isEqualityOperatorKind(parent.operatorToken.kind) // completion at `x ===/**/` should be for the right side - checker.getTypeAtLocation(parent.left) : - checker.getContextualType(previousToken as Expression); + ? checker.getTypeAtLocation(parent.left) + : checker.getContextualType(previousToken as Expression); } } - function getFirstSymbolInChain(symbol: Symbol, enclosingDeclaration: Node, checker: TypeChecker): Symbol | undefined { - const chain = checker.getAccessibleSymbolChain(symbol, enclosingDeclaration, /*meaning*/ SymbolFlags.All, /*useOnlyExternalAliasing*/ false); + function getFirstSymbolInChain( + symbol: Symbol, + enclosingDeclaration: Node, + checker: TypeChecker, + ): Symbol | undefined { + const chain = checker.getAccessibleSymbolChain( + symbol, + enclosingDeclaration, + /*meaning*/ SymbolFlags.All, + /*useOnlyExternalAliasing*/ false, + ); if (chain) return first(chain); - return symbol.parent && (isModuleSymbol(symbol.parent) ? symbol : getFirstSymbolInChain(symbol.parent, enclosingDeclaration, checker)); + return symbol.parent + && (isModuleSymbol(symbol.parent) ? symbol + : getFirstSymbolInChain(symbol.parent, enclosingDeclaration, checker)); } function isModuleSymbol(symbol: Symbol): boolean { @@ -2004,16 +2447,19 @@ namespace ts.Completions { if (typeExpression) { currentToken = getTokenAtPosition(sourceFile, position); if ( - !currentToken || - (!isDeclarationName(currentToken) && - (currentToken.parent.kind !== SyntaxKind.JSDocPropertyTag || - (currentToken.parent as JSDocPropertyTag).name !== currentToken)) + !currentToken + || (!isDeclarationName(currentToken) + && (currentToken.parent.kind !== SyntaxKind.JSDocPropertyTag + || (currentToken.parent as JSDocPropertyTag).name !== currentToken)) ) { // Use as type location if inside tag's type expression insideJsDocTagTypeExpression = isCurrentlyEditingNode(typeExpression); } } - if (!insideJsDocTagTypeExpression && isJSDocParameterTag(tag) && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end)) { + if ( + !insideJsDocTagTypeExpression && isJSDocParameterTag(tag) + && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end) + ) { return { kind: CompletionDataKind.JsDocParameterName, tag }; } } @@ -2064,7 +2510,10 @@ namespace ts.Completions { } keywordFilters = keywordFiltersFromSyntaxKind(importStatementCompletionInfo.keywordCompletion); } - if (importStatementCompletionInfo.replacementSpan && preferences.includeCompletionsForImportStatements && preferences.includeCompletionsWithInsertText) { + if ( + importStatementCompletionInfo.replacementSpan && preferences.includeCompletionsForImportStatements + && preferences.includeCompletionsWithInsertText + ) { // Import statement completions use `insertText`, and also require the `data` property of `CompletionEntryIdentifier` // added in TypeScript 4.3 to be sent back from the client during `getCompletionEntryDetails`. Since this feature // is not backward compatible with older clients, the language service defaults to disabling it, allowing newer clients @@ -2091,11 +2540,11 @@ namespace ts.Completions { node = propertyAccessToConvert.expression; const leftmostAccessExpression = getLeftmostAccessExpression(propertyAccessToConvert); if ( - nodeIsMissing(leftmostAccessExpression) || - ((isCallExpression(node) || isFunctionLike(node)) && - node.end === contextToken.pos && - node.getChildCount(sourceFile) && - last(node.getChildren(sourceFile)).kind !== SyntaxKind.CloseParenToken) + nodeIsMissing(leftmostAccessExpression) + || ((isCallExpression(node) || isFunctionLike(node)) + && node.end === contextToken.pos + && node.getChildCount(sourceFile) + && last(node.getChildren(sourceFile)).kind !== SyntaxKind.CloseParenToken) ) { // This is likely dot from incorrectly parsed expression and user is starting to write spread // eg: Math.min(./**/) @@ -2136,7 +2585,10 @@ namespace ts.Completions { if (currentToken.parent === location) { switch (currentToken.kind) { case SyntaxKind.GreaterThanToken: - if (currentToken.parent.kind === SyntaxKind.JsxElement || currentToken.parent.kind === SyntaxKind.JsxOpeningElement) { + if ( + currentToken.parent.kind === SyntaxKind.JsxElement + || currentToken.parent.kind === SyntaxKind.JsxOpeningElement + ) { location = currentToken; } break; @@ -2176,7 +2628,10 @@ namespace ts.Completions { case SyntaxKind.JsxExpression: case SyntaxKind.JsxSpreadAttribute: // For `
`, `parent` will be `{true}` and `previousToken` will be `}` - if (previousToken.kind === SyntaxKind.CloseBraceToken && currentToken.kind === SyntaxKind.GreaterThanToken) { + if ( + previousToken.kind === SyntaxKind.CloseBraceToken + && currentToken.kind === SyntaxKind.GreaterThanToken + ) { isJsxIdentifierExpected = true; } break; @@ -2184,8 +2639,8 @@ namespace ts.Completions { case SyntaxKind.JsxAttribute: // For `
`, `parent` will be JsxAttribute and `previousToken` will be its initializer if ( - (parent as JsxAttribute).initializer === previousToken && - previousToken.end < position + (parent as JsxAttribute).initializer === previousToken + && previousToken.end < position ) { isJsxIdentifierExpected = true; break; @@ -2199,9 +2654,9 @@ namespace ts.Completions { // For `
` we don't want to treat this as a jsx inializer, instead it's the attribute name. if ( - parent !== previousToken.parent && - !(parent as JsxAttribute).initializer && - findChildOfKind(parent, SyntaxKind.EqualsToken, sourceFile) + parent !== previousToken.parent + && !(parent as JsxAttribute).initializer + && findChildOfKind(parent, SyntaxKind.EqualsToken, sourceFile) ) { isJsxInitializer = previousToken as Identifier; } @@ -2223,7 +2678,10 @@ namespace ts.Completions { const seenPropertySymbols = new Map(); const isTypeOnlyLocation = isTypeOnlyCompletion(); const getModuleSpecifierResolutionHost = memoizeOne((isFromPackageJson: boolean) => { - return createModuleSpecifierResolutionHost(isFromPackageJson ? host.getPackageJsonAutoImportProvider!()! : program, host); + return createModuleSpecifierResolutionHost( + isFromPackageJson ? host.getPackageJsonAutoImportProvider!()! : program, + host, + ); }); if (isRightOfDot || isRightOfQuestionDot) { @@ -2264,7 +2722,8 @@ namespace ts.Completions { t => t.isLiteral() && !(t.flags & TypeFlags.EnumLiteral) ? t.value : undefined, ); - const recommendedCompletion = previousToken && contextualType && getRecommendedCompletion(previousToken, contextualType, typeChecker); + const recommendedCompletion = previousToken && contextualType + && getRecommendedCompletion(previousToken, contextualType, typeChecker); return { kind: CompletionDataKind.Data, symbols, @@ -2290,7 +2749,13 @@ namespace ts.Completions { flags, }; - type JSDocTagWithTypeExpression = JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag | JSDocTemplateTag; + type JSDocTagWithTypeExpression = + | JSDocParameterTag + | JSDocPropertyTag + | JSDocReturnTag + | JSDocTypeTag + | JSDocTypedefTag + | JSDocTemplateTag; function isTagWithTypeExpression(tag: JSDocTag): tag is JSDocTagWithTypeExpression { switch (tag.kind) { @@ -2310,7 +2775,8 @@ namespace ts.Completions { function tryGetTypeExpressionFromTag(tag: JSDocTag): JSDocTypeExpression | undefined { if (isTagWithTypeExpression(tag)) { const typeExpression = isJSDocTemplateTag(tag) ? tag.constraint : tag.typeExpression; - return typeExpression && typeExpression.kind === SyntaxKind.JSDocTypeExpression ? typeExpression : undefined; + return typeExpression && typeExpression.kind === SyntaxKind.JSDocTypeExpression ? typeExpression + : undefined; } return undefined; } @@ -2336,15 +2802,22 @@ namespace ts.Completions { // Extract module or enum members const exportedSymbols = typeChecker.getExportsOfModule(symbol); Debug.assertEachIsDefined(exportedSymbols, "getExportsOfModule() should all be defined"); - const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(isImportType ? node as ImportTypeNode : (node.parent as PropertyAccessExpression), symbol.name); - const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol, typeChecker); + const isValidValueAccess = (symbol: Symbol) => + typeChecker.isValidPropertyAccess( + isImportType ? node as ImportTypeNode : (node.parent as PropertyAccessExpression), + symbol.name, + ); + const isValidTypeAccess = (symbol: Symbol) => + symbolCanBeReferencedAtTypeLocation(symbol, typeChecker); const isValidAccess: (symbol: Symbol) => boolean = isNamespaceName // At `namespace N.M/**/`, if this is the only declaration of `M`, don't include `M` as a completion. - ? symbol => !!(symbol.flags & SymbolFlags.Namespace) && !symbol.declarations?.every(d => d.parent === node.parent) - : isRhsOfImportDeclaration ? + ? symbol => + !!(symbol.flags & SymbolFlags.Namespace) + && !symbol.declarations?.every(d => d.parent === node.parent) + : isRhsOfImportDeclaration // Any kind is allowed when dotting off namespace in internal import equals declaration - symbol => isValidTypeAccess(symbol) || isValidValueAccess(symbol) : - isTypeLocation ? isValidTypeAccess : isValidValueAccess; + ? symbol => isValidTypeAccess(symbol) || isValidValueAccess(symbol) + : isTypeLocation ? isValidTypeAccess : isValidValueAccess; for (const exportedSymbol of exportedSymbols) { if (isValidAccess(exportedSymbol)) { symbols.push(exportedSymbol); @@ -2353,16 +2826,19 @@ namespace ts.Completions { // If the module is merged with a value, we must get the type of the class and add its propertes (for inherited static methods). if ( - !isTypeLocation && - symbol.declarations && - symbol.declarations.some(d => d.kind !== SyntaxKind.SourceFile && d.kind !== SyntaxKind.ModuleDeclaration && d.kind !== SyntaxKind.EnumDeclaration) + !isTypeLocation + && symbol.declarations + && symbol.declarations.some(d => + d.kind !== SyntaxKind.SourceFile && d.kind !== SyntaxKind.ModuleDeclaration + && d.kind !== SyntaxKind.EnumDeclaration + ) ) { let type = typeChecker.getTypeOfSymbolAtLocation(symbol, node).getNonOptionalType(); let insertQuestionDot = false; if (type.isNullableType()) { - const canCorrectToQuestionDot = isRightOfDot && - !isRightOfQuestionDot && - preferences.includeAutomaticOptionalChainCompletions !== false; + const canCorrectToQuestionDot = isRightOfDot + && !isRightOfQuestionDot + && preferences.includeAutomaticOptionalChainCompletions !== false; if (canCorrectToQuestionDot || isRightOfQuestionDot) { type = type.getNonNullableType(); @@ -2388,9 +2864,9 @@ namespace ts.Completions { let type = typeChecker.getTypeAtLocation(node).getNonOptionalType(); let insertQuestionDot = false; if (type.isNullableType()) { - const canCorrectToQuestionDot = isRightOfDot && - !isRightOfQuestionDot && - preferences.includeAutomaticOptionalChainCompletions !== false; + const canCorrectToQuestionDot = isRightOfDot + && !isRightOfQuestionDot + && preferences.includeAutomaticOptionalChainCompletions !== false; if (canCorrectToQuestionDot || isRightOfQuestionDot) { type = type.getNonNullableType(); @@ -2409,7 +2885,8 @@ namespace ts.Completions { isNewIdentifierLocation = true; } - const propertyAccess = node.kind === SyntaxKind.ImportType ? node as ImportTypeNode : node.parent as PropertyAccessExpression | QualifiedName; + const propertyAccess = node.kind === SyntaxKind.ImportType ? node as ImportTypeNode + : node.parent as PropertyAccessExpression | QualifiedName; if (inCheckedFile) { for (const symbol of type.getApparentProperties()) { if (typeChecker.isValidPropertyAccessForCompletions(propertyAccess, type, symbol)) { @@ -2423,7 +2900,12 @@ namespace ts.Completions { // each individual type has. This is because we're going to add all identifiers // anyways. So we might as well elevate the members that were at least part // of the individual types to a higher status since we know what they are. - symbols.push(...filter(getPropertiesForCompletion(type, typeChecker), s => typeChecker.isValidPropertyAccessForCompletions(propertyAccess, type, s))); + symbols.push( + ...filter( + getPropertiesForCompletion(type, typeChecker), + s => typeChecker.isValidPropertyAccessForCompletions(propertyAccess, type, s), + ), + ); } if (insertAwait && preferences.includeCompletionsWithInsertText) { @@ -2442,26 +2924,41 @@ namespace ts.Completions { // For a computed property with an accessible name like `Symbol.iterator`, // we'll add a completion for the *name* `Symbol` instead of for the property. // If this is e.g. [Symbol.iterator], add a completion for `Symbol`. - const computedPropertyName = firstDefined(symbol.declarations, decl => tryCast(getNameOfDeclaration(decl), isComputedPropertyName)); + const computedPropertyName = firstDefined( + symbol.declarations, + decl => tryCast(getNameOfDeclaration(decl), isComputedPropertyName), + ); if (computedPropertyName) { const leftMostName = getLeftMostName(computedPropertyName.expression); // The completion is for `Symbol`, not `iterator`. const nameSymbol = leftMostName && typeChecker.getSymbolAtLocation(leftMostName); // If this is nested like for `namespace N { export const sym = Symbol(); }`, we'll add the completion for `N`. - const firstAccessibleSymbol = nameSymbol && getFirstSymbolInChain(nameSymbol, contextToken, typeChecker); + const firstAccessibleSymbol = nameSymbol + && getFirstSymbolInChain(nameSymbol, contextToken, typeChecker); if (firstAccessibleSymbol && addToSeen(seenPropertySymbols, getSymbolId(firstAccessibleSymbol))) { const index = symbols.length; symbols.push(firstAccessibleSymbol); const moduleSymbol = firstAccessibleSymbol.parent; if ( - !moduleSymbol || - !isExternalModuleSymbol(moduleSymbol) || - typeChecker.tryGetMemberInModuleExportsAndProperties(firstAccessibleSymbol.name, moduleSymbol) !== firstAccessibleSymbol + !moduleSymbol + || !isExternalModuleSymbol(moduleSymbol) + || typeChecker.tryGetMemberInModuleExportsAndProperties( + firstAccessibleSymbol.name, + moduleSymbol, + ) !== firstAccessibleSymbol ) { - symbolToOriginInfoMap[index] = { kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberNoExport) }; + symbolToOriginInfoMap[index] = { + kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberNoExport), + }; } else { - const fileName = isExternalModuleNameRelative(stripQuotes(moduleSymbol.name)) ? getSourceFileOfModule(moduleSymbol)?.fileName : undefined; - const { moduleSpecifier } = (importSpecifierResolver ||= codefix.createImportSpecifierResolver(sourceFile, program, host, preferences)).getModuleSpecifierForBestExportInfo( + const fileName = isExternalModuleNameRelative(stripQuotes(moduleSymbol.name)) + ? getSourceFileOfModule(moduleSymbol)?.fileName : undefined; + const { moduleSpecifier } = (importSpecifierResolver ||= codefix.createImportSpecifierResolver( + sourceFile, + program, + host, + preferences, + )).getModuleSpecifierForBestExportInfo( [{ exportKind: ExportKind.Named, moduleFileName: fileName, @@ -2510,7 +3007,9 @@ namespace ts.Completions { function addSymbolOriginInfo(symbol: Symbol) { if (preferences.includeCompletionsWithInsertText) { if (insertAwait && addToSeen(seenPropertySymbols, getSymbolId(symbol))) { - symbolToOriginInfoMap[symbols.length] = { kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.Promise) }; + symbolToOriginInfoMap[symbols.length] = { + kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.Promise), + }; } else if (insertQuestionDot) { symbolToOriginInfoMap[symbols.length] = { kind: SymbolOriginInfoKind.Nullable }; @@ -2557,8 +3056,15 @@ namespace ts.Completions { // Cursor is inside a JSX self-closing element or opening element const attrsType = jsxContainer && typeChecker.getContextualType(jsxContainer.attributes); if (!attrsType) return GlobalsSearch.Continue; - const completionsType = jsxContainer && typeChecker.getContextualType(jsxContainer.attributes, ContextFlags.Completions); - symbols = concatenate(symbols, filterJsxAttributes(getPropertiesForObjectExpression(attrsType, completionsType, jsxContainer.attributes, typeChecker), jsxContainer.attributes.properties)); + const completionsType = jsxContainer + && typeChecker.getContextualType(jsxContainer.attributes, ContextFlags.Completions); + symbols = concatenate( + symbols, + filterJsxAttributes( + getPropertiesForObjectExpression(attrsType, completionsType, jsxContainer.attributes, typeChecker), + jsxContainer.attributes.properties, + ), + ); setSortTextToOptionalMember(); completionKind = CompletionKind.MemberLike; isNewIdentifierLocation = false; @@ -2573,14 +3079,18 @@ namespace ts.Completions { } function getGlobalCompletions(): void { - keywordFilters = tryGetFunctionLikeBodyCompletionContainer(contextToken) ? KeywordCompletionFilters.FunctionLikeBodyKeywords : KeywordCompletionFilters.All; + keywordFilters = tryGetFunctionLikeBodyCompletionContainer(contextToken) + ? KeywordCompletionFilters.FunctionLikeBodyKeywords : KeywordCompletionFilters.All; // Get all entities in the current scope. completionKind = CompletionKind.Global; isNewIdentifierLocation = isNewIdentifierDefinitionLocation(); if (previousToken !== contextToken) { - Debug.assert(!!previousToken, "Expected 'contextToken' to be defined when different from 'previousToken'."); + Debug.assert( + !!previousToken, + "Expected 'contextToken' to be defined when different from 'previousToken'.", + ); } // We need to find the node that will give us an appropriate scope to begin // aggregating completion candidates. This is achieved in 'getScopeNode' @@ -2607,14 +3117,15 @@ namespace ts.Completions { // - 'contextToken' was adjusted to the token prior to 'previousToken' // because we were at the end of an identifier. // - 'previousToken' is defined. - const adjustedPosition = previousToken !== contextToken ? - previousToken.getStart() : - position; + const adjustedPosition = previousToken !== contextToken + ? previousToken.getStart() + : position; const scopeNode = getScopeNode(contextToken, adjustedPosition, sourceFile) || sourceFile; isInSnippetScope = isSnippetScope(scopeNode); - const symbolMeanings = (isTypeOnlyLocation ? SymbolFlags.None : SymbolFlags.Value) | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias; + const symbolMeanings = (isTypeOnlyLocation ? SymbolFlags.None : SymbolFlags.Value) | SymbolFlags.Type + | SymbolFlags.Namespace | SymbolFlags.Alias; const typeOnlyAliasNeedsPromotion = previousToken && !isValidTypeOnlyAliasUseSite(previousToken); symbols = concatenate(symbols, typeChecker.getSymbolsInScope(scopeNode, symbolMeanings)); @@ -2622,15 +3133,19 @@ namespace ts.Completions { for (let i = 0; i < symbols.length; i++) { const symbol = symbols[i]; if ( - !typeChecker.isArgumentsSymbol(symbol) && - !some(symbol.declarations, d => d.getSourceFile() === sourceFile) + !typeChecker.isArgumentsSymbol(symbol) + && !some(symbol.declarations, d => d.getSourceFile() === sourceFile) ) { symbolToSortTextMap[getSymbolId(symbol)] = SortText.GlobalsOrKeywords; } if (typeOnlyAliasNeedsPromotion && !(symbol.flags & SymbolFlags.Value)) { - const typeOnlyAliasDeclaration = symbol.declarations && find(symbol.declarations, isTypeOnlyImportOrExportDeclaration); + const typeOnlyAliasDeclaration = symbol.declarations + && find(symbol.declarations, isTypeOnlyImportOrExportDeclaration); if (typeOnlyAliasDeclaration) { - const origin: SymbolOriginInfoTypeOnlyAlias = { kind: SymbolOriginInfoKind.TypeOnlyAlias, declaration: typeOnlyAliasDeclaration }; + const origin: SymbolOriginInfoTypeOnlyAlias = { + kind: SymbolOriginInfoKind.TypeOnlyAlias, + declaration: typeOnlyAliasDeclaration, + }; symbolToOriginInfoMap[i] = origin; } } @@ -2638,7 +3153,11 @@ namespace ts.Completions { // Need to insert 'this.' before properties of `this` type, so only do that if `includeInsertTextCompletions` if (preferences.includeCompletionsWithInsertText && scopeNode.kind !== SyntaxKind.SourceFile) { - const thisType = typeChecker.tryGetThisTypeAt(scopeNode, /*includeGlobalThis*/ false, isClassLike(scopeNode.parent) ? scopeNode : undefined); + const thisType = typeChecker.tryGetThisTypeAt( + scopeNode, + /*includeGlobalThis*/ false, + isClassLike(scopeNode.parent) ? scopeNode : undefined, + ); if (thisType && !isProbablyGlobalType(thisType, sourceFile, typeChecker)) { for (const symbol of getPropertiesForCompletion(thisType, typeChecker)) { symbolToOriginInfoMap[symbols.length] = { kind: SymbolOriginInfoKind.ThisType }; @@ -2685,17 +3204,18 @@ namespace ts.Completions { function isTypeOnlyCompletion(): boolean { return insideJsDocTagTypeExpression || !!importStatementCompletion && isTypeOnlyImportOrExportDeclaration(location.parent) - || !isContextTokenValueLocation(contextToken) && - (isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker) + || !isContextTokenValueLocation(contextToken) + && (isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker) || isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken)); } function isContextTokenValueLocation(contextToken: Node) { - return contextToken && - ((contextToken.kind === SyntaxKind.TypeOfKeyword && - (contextToken.parent.kind === SyntaxKind.TypeQuery || isTypeOfExpression(contextToken.parent))) || - (contextToken.kind === SyntaxKind.AssertsKeyword && contextToken.parent.kind === SyntaxKind.TypePredicate)); + return contextToken + && ((contextToken.kind === SyntaxKind.TypeOfKeyword + && (contextToken.parent.kind === SyntaxKind.TypeQuery || isTypeOfExpression(contextToken.parent))) + || (contextToken.kind === SyntaxKind.AssertsKeyword + && contextToken.parent.kind === SyntaxKind.TypePredicate)); } function isContextTokenTypeLocation(contextToken: Node): boolean { @@ -2703,11 +3223,11 @@ namespace ts.Completions { const parentKind = contextToken.parent.kind; switch (contextToken.kind) { case SyntaxKind.ColonToken: - return parentKind === SyntaxKind.PropertyDeclaration || - parentKind === SyntaxKind.PropertySignature || - parentKind === SyntaxKind.Parameter || - parentKind === SyntaxKind.VariableDeclaration || - isFunctionLikeKind(parentKind); + return parentKind === SyntaxKind.PropertyDeclaration + || parentKind === SyntaxKind.PropertySignature + || parentKind === SyntaxKind.Parameter + || parentKind === SyntaxKind.VariableDeclaration + || isFunctionLikeKind(parentKind); case SyntaxKind.EqualsToken: return parentKind === SyntaxKind.TypeAliasDeclaration; @@ -2716,8 +3236,8 @@ namespace ts.Completions { return parentKind === SyntaxKind.AsExpression; case SyntaxKind.LessThanToken: - return parentKind === SyntaxKind.TypeReference || - parentKind === SyntaxKind.TypeAssertionExpression; + return parentKind === SyntaxKind.TypeReference + || parentKind === SyntaxKind.TypeAssertionExpression; case SyntaxKind.ExtendsKeyword: return parentKind === SyntaxKind.TypeParameter; @@ -2732,7 +3252,10 @@ namespace ts.Completions { /** Mutates `symbols`, `symbolToOriginInfoMap`, and `symbolToSortTextMap` */ function collectAutoImports() { if (!shouldOfferImportCompletions()) return; - Debug.assert(!detailsEntryId?.data, "Should not run 'collectAutoImports' when faster path is available via `data`"); + Debug.assert( + !detailsEntryId?.data, + "Should not run 'collectAutoImports' when faster path is available via `data`", + ); if (detailsEntryId && !detailsEntryId.source) { // Asking for completion details for an item that is not an auto-import return; @@ -2743,18 +3266,24 @@ namespace ts.Completions { const isAfterTypeOnlyImportSpecifierModifier = previousToken === contextToken && importStatementCompletion; - const lowerCaseTokenText = isAfterTypeOnlyImportSpecifierModifier ? "" : - previousToken && isIdentifier(previousToken) ? previousToken.text.toLowerCase() : - ""; + const lowerCaseTokenText = isAfterTypeOnlyImportSpecifierModifier ? "" + : previousToken && isIdentifier(previousToken) ? previousToken.text.toLowerCase() + : ""; const moduleSpecifierCache = host.getModuleSpecifierCache?.(); const exportInfo = getExportInfoMap(sourceFile, host, program, preferences, cancellationToken); const packageJsonAutoImportProvider = host.getPackageJsonAutoImportProvider?.(); - const packageJsonFilter = detailsEntryId ? undefined : createPackageJsonImportFilter(sourceFile, preferences, host); + const packageJsonFilter = detailsEntryId ? undefined + : createPackageJsonImportFilter(sourceFile, preferences, host); resolvingModuleSpecifiers( "collectAutoImports", host, - importSpecifierResolver ||= codefix.createImportSpecifierResolver(sourceFile, program, host, preferences), + importSpecifierResolver ||= codefix.createImportSpecifierResolver( + sourceFile, + program, + host, + preferences, + ), program, position, preferences, @@ -2765,19 +3294,30 @@ namespace ts.Completions { sourceFile.path, /*preferCapitalized*/ isRightOfOpenTag, (symbolName, targetFlags) => { - if (!isIdentifierText(symbolName, getEmitScriptTarget(host.getCompilationSettings()))) return false; + if (!isIdentifierText(symbolName, getEmitScriptTarget(host.getCompilationSettings()))) { + return false; + } if (!detailsEntryId && isStringANonContextualKeyword(symbolName)) return false; - if (!isTypeOnlyLocation && !importStatementCompletion && !(targetFlags & SymbolFlags.Value)) return false; - if (isTypeOnlyLocation && !(targetFlags & (SymbolFlags.Module | SymbolFlags.Type))) return false; + if ( + !isTypeOnlyLocation && !importStatementCompletion && !(targetFlags & SymbolFlags.Value) + ) return false; + if (isTypeOnlyLocation && !(targetFlags & (SymbolFlags.Module | SymbolFlags.Type))) { + return false; + } // Do not try to auto-import something with a lowercase first letter for a JSX tag const firstChar = symbolName.charCodeAt(0); - if (isRightOfOpenTag && (firstChar < CharacterCodes.A || firstChar > CharacterCodes.Z)) return false; + if (isRightOfOpenTag && (firstChar < CharacterCodes.A || firstChar > CharacterCodes.Z)) { + return false; + } if (detailsEntryId) return true; return charactersFuzzyMatchInString(symbolName, lowerCaseTokenText); }, (info, symbolName, isFromAmbientModule, exportMapKey) => { - if (detailsEntryId && !some(info, i => detailsEntryId.source === stripQuotes(i.moduleSymbol.name))) { + if ( + detailsEntryId + && !some(info, i => detailsEntryId.source === stripQuotes(i.moduleSymbol.name)) + ) { return; } @@ -2810,14 +3350,17 @@ namespace ts.Completions { } const isDefaultExport = exportInfo.exportKind === ExportKind.Default; - const symbol = isDefaultExport && getLocalSymbolForExportDefault(exportInfo.symbol) || exportInfo.symbol; + const symbol = isDefaultExport && getLocalSymbolForExportDefault(exportInfo.symbol) + || exportInfo.symbol; pushAutoImportSymbol(symbol, { - kind: moduleSpecifier ? SymbolOriginInfoKind.ResolvedExport : SymbolOriginInfoKind.Export, + kind: moduleSpecifier ? SymbolOriginInfoKind.ResolvedExport + : SymbolOriginInfoKind.Export, moduleSpecifier, symbolName, exportMapKey, - exportName: exportInfo.exportKind === ExportKind.ExportEquals ? InternalSymbolName.ExportEquals : exportInfo.symbol.name, + exportName: exportInfo.exportKind === ExportKind.ExportEquals + ? InternalSymbolName.ExportEquals : exportInfo.symbol.name, fileName: exportInfo.moduleFileName, isDefaultExport, moduleSymbol: exportInfo.moduleSymbol, @@ -2828,7 +3371,8 @@ namespace ts.Completions { hasUnresolvedAutoImports = context.skippedAny(); flags |= context.resolvedAny() ? CompletionInfoFlags.ResolvedModuleSpecifiers : 0; - flags |= context.resolvedBeyondLimit() ? CompletionInfoFlags.ResolvedModuleSpecifiersBeyondLimit : 0; + flags |= context.resolvedBeyondLimit() ? CompletionInfoFlags.ResolvedModuleSpecifiersBeyondLimit + : 0; }, ); @@ -2836,11 +3380,17 @@ namespace ts.Completions { const moduleFile = tryCast(info.moduleSymbol.valueDeclaration, isSourceFile); if (!moduleFile) { const moduleName = stripQuotes(info.moduleSymbol.name); - if (JsTyping.nodeCoreModules.has(moduleName) && startsWith(moduleName, "node:") !== shouldUseUriStyleNodeCoreModules(sourceFile, program)) { + if ( + JsTyping.nodeCoreModules.has(moduleName) + && startsWith(moduleName, "node:") !== shouldUseUriStyleNodeCoreModules(sourceFile, program) + ) { return false; } return packageJsonFilter - ? packageJsonFilter.allowsImportingAmbientModule(info.moduleSymbol, getModuleSpecifierResolutionHost(info.isFromPackageJson)) + ? packageJsonFilter.allowsImportingAmbientModule( + info.moduleSymbol, + getModuleSpecifierResolutionHost(info.isFromPackageJson), + ) : true; } return isImportableFile( @@ -2862,12 +3412,16 @@ namespace ts.Completions { return; } symbolToOriginInfoMap[symbols.length] = origin; - symbolToSortTextMap[symbolId] = importStatementCompletion ? SortText.LocationPriority : SortText.AutoImportSuggestions; + symbolToSortTextMap[symbolId] = importStatementCompletion ? SortText.LocationPriority + : SortText.AutoImportSuggestions; symbols.push(symbol); } /* Mutates `symbols` and `symbolToOriginInfoMap`. */ - function collectObjectLiteralMethodSymbols(members: Symbol[], enclosingDeclaration: ObjectLiteralExpression): void { + function collectObjectLiteralMethodSymbols( + members: Symbol[], + enclosingDeclaration: ObjectLiteralExpression, + ): void { // TODO: support JS files. if (isInJSFile(location)) { return; @@ -2900,7 +3454,10 @@ namespace ts.Completions { if (!entryProps) { return; } - const origin: SymbolOriginInfoObjectLiteralMethod = { kind: SymbolOriginInfoKind.ObjectLiteralMethod, ...entryProps }; + const origin: SymbolOriginInfoObjectLiteralMethod = { + kind: SymbolOriginInfoKind.ObjectLiteralMethod, + ...entryProps, + }; flags |= CompletionInfoFlags.MayIncludeMethodSnippets; symbolToOriginInfoMap[symbols.length] = origin; symbols.push(member); @@ -2937,11 +3494,11 @@ namespace ts.Completions { function isCompletionListBlocker(contextToken: Node): boolean { const start = timestamp(); - const result = isInStringOrRegularExpressionOrTemplateLiteral(contextToken) || - isSolelyIdentifierDefinitionLocation(contextToken) || - isDotOfNumericLiteral(contextToken) || - isInJsxText(contextToken) || - isBigIntLiteral(contextToken); + const result = isInStringOrRegularExpressionOrTemplateLiteral(contextToken) + || isSolelyIdentifierDefinitionLocation(contextToken) + || isDotOfNumericLiteral(contextToken) + || isInJsxText(contextToken) + || isBigIntLiteral(contextToken); log("getCompletionsAtPosition: isCompletionListBlocker: " + (timestamp() - start)); return result; } @@ -2957,7 +3514,11 @@ namespace ts.Completions { // - contextToken: GreaterThanToken (before cursor) // - location: JsxSelfClosingElement or JsxOpeningElement // - contextToken.parent === location - if (location === contextToken.parent && (location.kind === SyntaxKind.JsxOpeningElement || location.kind === SyntaxKind.JsxSelfClosingElement)) { + if ( + location === contextToken.parent + && (location.kind === SyntaxKind.JsxOpeningElement + || location.kind === SyntaxKind.JsxSelfClosingElement) + ) { return false; } @@ -2969,7 +3530,10 @@ namespace ts.Completions { return location.parent.kind !== SyntaxKind.JsxOpeningElement; } - if (contextToken.parent.kind === SyntaxKind.JsxClosingElement || contextToken.parent.kind === SyntaxKind.JsxSelfClosingElement) { + if ( + contextToken.parent.kind === SyntaxKind.JsxClosingElement + || contextToken.parent.kind === SyntaxKind.JsxSelfClosingElement + ) { return !!contextToken.parent.parent && contextToken.parent.parent.kind === SyntaxKind.JsxElement; } } @@ -3047,8 +3611,9 @@ namespace ts.Completions { // 2. at the end position of an unterminated token. // 3. at the end of a regular expression (due to trailing flags like '/foo/g'). return (isRegularExpressionLiteral(contextToken) || isStringTextContainingNode(contextToken)) && ( - rangeContainsPositionExclusive(createTextRangeFromSpan(createTextSpanFromNode(contextToken)), position) || - position === contextToken.end && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken)) + rangeContainsPositionExclusive(createTextRangeFromSpan(createTextSpanFromNode(contextToken)), position) + || position === contextToken.end + && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken)) ); } @@ -3056,7 +3621,8 @@ namespace ts.Completions { const typeLiteralNode = tryGetTypeLiteralNode(contextToken); if (!typeLiteralNode) return GlobalsSearch.Continue; - const intersectionTypeNode = isIntersectionTypeNode(typeLiteralNode.parent) ? typeLiteralNode.parent : undefined; + const intersectionTypeNode = isIntersectionTypeNode(typeLiteralNode.parent) ? typeLiteralNode.parent + : undefined; const containerTypeNode = intersectionTypeNode || typeLiteralNode; const containerExpectedType = getConstraintOfTypeArgumentProperty(containerTypeNode, typeChecker); @@ -3110,7 +3676,12 @@ namespace ts.Completions { const hasStringIndexType = (completionsType || instantiatedType).getStringIndexType(); const hasNumberIndextype = (completionsType || instantiatedType).getNumberIndexType(); isNewIdentifierLocation = !!hasStringIndexType || !!hasNumberIndextype; - typeMembers = getPropertiesForObjectExpression(instantiatedType, completionsType, objectLikeContainer, typeChecker); + typeMembers = getPropertiesForObjectExpression( + instantiatedType, + completionsType, + objectLikeContainer, + typeChecker, + ); existingMembers = objectLikeContainer.properties; if (typeMembers.length === 0) { @@ -3134,20 +3705,31 @@ namespace ts.Completions { // through type declaration or inference. // Also proceed if rootDeclaration is a parameter and if its containing function expression/arrow function is contextually typed - // type of parameter will flow in from the contextual type of the function - let canGetType = hasInitializer(rootDeclaration) || !!getEffectiveTypeAnnotationNode(rootDeclaration) || rootDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement; + let canGetType = hasInitializer(rootDeclaration) || !!getEffectiveTypeAnnotationNode(rootDeclaration) + || rootDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement; if (!canGetType && rootDeclaration.kind === SyntaxKind.Parameter) { if (isExpression(rootDeclaration.parent)) { canGetType = !!typeChecker.getContextualType(rootDeclaration.parent as Expression); } - else if (rootDeclaration.parent.kind === SyntaxKind.MethodDeclaration || rootDeclaration.parent.kind === SyntaxKind.SetAccessor) { - canGetType = isExpression(rootDeclaration.parent.parent) && !!typeChecker.getContextualType(rootDeclaration.parent.parent as Expression); + else if ( + rootDeclaration.parent.kind === SyntaxKind.MethodDeclaration + || rootDeclaration.parent.kind === SyntaxKind.SetAccessor + ) { + canGetType = isExpression(rootDeclaration.parent.parent) + && !!typeChecker.getContextualType(rootDeclaration.parent.parent as Expression); } } if (canGetType) { const typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer); if (!typeForObject) return GlobalsSearch.Fail; typeMembers = typeChecker.getPropertiesOfType(typeForObject).filter(propertySymbol => { - return typeChecker.isPropertyAccessible(objectLikeContainer, /*isSuper*/ false, /*writing*/ false, typeForObject, propertySymbol); + return typeChecker.isPropertyAccessible( + objectLikeContainer, + /*isSuper*/ false, + /*writing*/ false, + typeForObject, + propertySymbol, + ); }); existingMembers = objectLikeContainer.elements; } @@ -3188,8 +3770,11 @@ namespace ts.Completions { if (!contextToken) return GlobalsSearch.Continue; // `import { |` or `import { a as 0, | }` or `import { type | }` - const namedImportsOrExports = contextToken.kind === SyntaxKind.OpenBraceToken || contextToken.kind === SyntaxKind.CommaToken ? tryCast(contextToken.parent, isNamedImportsOrExports) : - isTypeKeywordTokenOrIdentifier(contextToken) ? tryCast(contextToken.parent.parent, isNamedImportsOrExports) : undefined; + const namedImportsOrExports = + contextToken.kind === SyntaxKind.OpenBraceToken || contextToken.kind === SyntaxKind.CommaToken + ? tryCast(contextToken.parent, isNamedImportsOrExports) + : isTypeKeywordTokenOrIdentifier(contextToken) + ? tryCast(contextToken.parent.parent, isNamedImportsOrExports) : undefined; if (!namedImportsOrExports) return GlobalsSearch.Continue; @@ -3199,10 +3784,12 @@ namespace ts.Completions { } // try to show exported member for imported/re-exported module - const { moduleSpecifier } = namedImportsOrExports.kind === SyntaxKind.NamedImports ? namedImportsOrExports.parent.parent : namedImportsOrExports.parent; + const { moduleSpecifier } = namedImportsOrExports.kind === SyntaxKind.NamedImports + ? namedImportsOrExports.parent.parent : namedImportsOrExports.parent; if (!moduleSpecifier) { isNewIdentifierLocation = true; - return namedImportsOrExports.kind === SyntaxKind.NamedImports ? GlobalsSearch.Fail : GlobalsSearch.Continue; + return namedImportsOrExports.kind === SyntaxKind.NamedImports ? GlobalsSearch.Fail + : GlobalsSearch.Continue; } const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(moduleSpecifier); // TODO: GH#18217 if (!moduleSpecifierSymbol) { @@ -3213,8 +3800,14 @@ namespace ts.Completions { completionKind = CompletionKind.MemberLike; isNewIdentifierLocation = false; const exports = typeChecker.getExportsAndPropertiesOfModule(moduleSpecifierSymbol); - const existing = new Set((namedImportsOrExports.elements as NodeArray).filter(n => !isCurrentlyEditingNode(n)).map(n => (n.propertyName || n.name).escapedText)); - const uniques = exports.filter(e => e.escapedName !== InternalSymbolName.Default && !existing.has(e.escapedName)); + const existing = new Set( + (namedImportsOrExports.elements as NodeArray).filter(n => + !isCurrentlyEditingNode(n) + ).map(n => (n.propertyName || n.name).escapedText), + ); + const uniques = exports.filter(e => + e.escapedName !== InternalSymbolName.Default && !existing.has(e.escapedName) + ); symbols = concatenate(symbols, uniques); if (!uniques.length) { // If there's nothing else to import, don't offer `type` either @@ -3233,7 +3826,8 @@ namespace ts.Completions { * preventing this function from running. */ function tryGetLocalNamedExportCompletionSymbols(): GlobalsSearch { - const namedExports = contextToken && (contextToken.kind === SyntaxKind.OpenBraceToken || contextToken.kind === SyntaxKind.CommaToken) + const namedExports = contextToken + && (contextToken.kind === SyntaxKind.OpenBraceToken || contextToken.kind === SyntaxKind.CommaToken) ? tryCast(contextToken.parent, isNamedExports) : undefined; @@ -3265,14 +3859,17 @@ namespace ts.Completions { completionKind = CompletionKind.MemberLike; // Declaring new property/method/accessor isNewIdentifierLocation = true; - keywordFilters = contextToken.kind === SyntaxKind.AsteriskToken ? KeywordCompletionFilters.None : - isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords; + keywordFilters = contextToken.kind === SyntaxKind.AsteriskToken ? KeywordCompletionFilters.None + : isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords + : KeywordCompletionFilters.InterfaceElementKeywords; // If you're in an interface you don't want to repeat things from super-interface. So just stop here. if (!isClassLike(decl)) return GlobalsSearch.Success; - const classElement = contextToken.kind === SyntaxKind.SemicolonToken ? contextToken.parent.parent : contextToken.parent; - let classElementModifierFlags = isClassElement(classElement) ? getEffectiveModifierFlags(classElement) : ModifierFlags.None; + const classElement = contextToken.kind === SyntaxKind.SemicolonToken ? contextToken.parent.parent + : contextToken.parent; + let classElementModifierFlags = isClassElement(classElement) ? getEffectiveModifierFlags(classElement) + : ModifierFlags.None; // If this is context token is not something we are editing now, consider if this would lead to be modifier if (contextToken.kind === SyntaxKind.Identifier && !isCurrentlyEditingNode(contextToken)) { switch (contextToken.getText()) { @@ -3294,14 +3891,19 @@ namespace ts.Completions { // No member list for private methods if (!(classElementModifierFlags & ModifierFlags.Private)) { // List of property symbols of base type that are not private and already implemented - const baseTypeNodes = isClassLike(decl) && classElementModifierFlags & ModifierFlags.Override ? singleElementArray(getEffectiveBaseTypeNode(decl)) : getAllSuperTypeNodes(decl); + const baseTypeNodes = isClassLike(decl) && classElementModifierFlags & ModifierFlags.Override + ? singleElementArray(getEffectiveBaseTypeNode(decl)) : getAllSuperTypeNodes(decl); const baseSymbols = flatMap(baseTypeNodes, baseTypeNode => { const type = typeChecker.getTypeAtLocation(baseTypeNode); - return classElementModifierFlags & ModifierFlags.Static ? - type?.symbol && typeChecker.getPropertiesOfType(typeChecker.getTypeOfSymbolAtLocation(type.symbol, decl)) : - type && typeChecker.getPropertiesOfType(type); + return classElementModifierFlags & ModifierFlags.Static + ? type?.symbol + && typeChecker.getPropertiesOfType(typeChecker.getTypeOfSymbolAtLocation(type.symbol, decl)) + : type && typeChecker.getPropertiesOfType(type); }); - symbols = concatenate(symbols, filterClassMembersList(baseSymbols, decl.members, classElementModifierFlags)); + symbols = concatenate( + symbols, + filterClassMembersList(baseSymbols, decl.members, classElementModifierFlags), + ); } return GlobalsSearch.Success; @@ -3362,10 +3964,21 @@ namespace ts.Completions { case SyntaxKind.JsxAttributes: case SyntaxKind.JsxAttribute: case SyntaxKind.JsxSpreadAttribute: - if (parent && (parent.kind === SyntaxKind.JsxSelfClosingElement || parent.kind === SyntaxKind.JsxOpeningElement)) { + if ( + parent + && (parent.kind === SyntaxKind.JsxSelfClosingElement + || parent.kind === SyntaxKind.JsxOpeningElement) + ) { if (contextToken.kind === SyntaxKind.GreaterThanToken) { - const precedingToken = findPrecedingToken(contextToken.pos, sourceFile, /*startNode*/ undefined); - if (!(parent as JsxOpeningLikeElement).typeArguments || (precedingToken && precedingToken.kind === SyntaxKind.SlashToken)) break; + const precedingToken = findPrecedingToken( + contextToken.pos, + sourceFile, + /*startNode*/ undefined, + ); + if ( + !(parent as JsxOpeningLikeElement).typeArguments + || (precedingToken && precedingToken.kind === SyntaxKind.SlashToken) + ) break; } return parent as JsxOpeningLikeElement; } @@ -3382,7 +3995,11 @@ namespace ts.Completions { // its parent is a JsxExpression, whose parent is a JsxAttribute, // whose parent is a JsxOpeningLikeElement case SyntaxKind.StringLiteral: - if (parent && ((parent.kind === SyntaxKind.JsxAttribute) || (parent.kind === SyntaxKind.JsxSpreadAttribute))) { + if ( + parent + && ((parent.kind === SyntaxKind.JsxAttribute) + || (parent.kind === SyntaxKind.JsxSpreadAttribute)) + ) { // Currently we parse JsxOpeningLikeElement as: // JsxOpeningLikeElement // attributes: JsxAttributes @@ -3394,9 +4011,9 @@ namespace ts.Completions { case SyntaxKind.CloseBraceToken: if ( - parent && - parent.kind === SyntaxKind.JsxExpression && - parent.parent && parent.parent.kind === SyntaxKind.JsxAttribute + parent + && parent.kind === SyntaxKind.JsxExpression + && parent.parent && parent.parent.kind === SyntaxKind.JsxAttribute ) { // Currently we parse JsxOpeningLikeElement as: // JsxOpeningLikeElement @@ -3428,19 +4045,19 @@ namespace ts.Completions { const containingNodeKind = parent.kind; switch (contextToken.kind) { case SyntaxKind.CommaToken: - return containingNodeKind === SyntaxKind.VariableDeclaration || - isVariableDeclarationListButNotTypeArgument(contextToken) || - containingNodeKind === SyntaxKind.VariableStatement || - containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { foo, | - isFunctionLikeButNotConstructor(containingNodeKind) || - containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface A= contextToken.pos); + || (isClassLike(parent) + && !!parent.typeParameters + && parent.typeParameters.end >= contextToken.pos); case SyntaxKind.DotToken: return containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [.| @@ -3452,25 +4069,25 @@ namespace ts.Completions { return containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [x| case SyntaxKind.OpenParenToken: - return containingNodeKind === SyntaxKind.CatchClause || - isFunctionLikeButNotConstructor(containingNodeKind); + return containingNodeKind === SyntaxKind.CatchClause + || isFunctionLikeButNotConstructor(containingNodeKind); case SyntaxKind.OpenBraceToken: return containingNodeKind === SyntaxKind.EnumDeclaration; // enum a { | case SyntaxKind.LessThanToken: - return containingNodeKind === SyntaxKind.ClassDeclaration || // class A< | - containingNodeKind === SyntaxKind.ClassExpression || // var C = class D< | - containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface A< | - containingNodeKind === SyntaxKind.TypeAliasDeclaration || // type List< | - isFunctionLikeKind(containingNodeKind); + return containingNodeKind === SyntaxKind.ClassDeclaration // class A< | + || containingNodeKind === SyntaxKind.ClassExpression // var C = class D< | + || containingNodeKind === SyntaxKind.InterfaceDeclaration // interface A< | + || containingNodeKind === SyntaxKind.TypeAliasDeclaration // type List< | + || isFunctionLikeKind(containingNodeKind); case SyntaxKind.StaticKeyword: return containingNodeKind === SyntaxKind.PropertyDeclaration && !isClassLike(parent.parent); case SyntaxKind.DotDotDotToken: - return containingNodeKind === SyntaxKind.Parameter || - (!!parent.parent && parent.parent.kind === SyntaxKind.ArrayBindingPattern); // var [...z| + return containingNodeKind === SyntaxKind.Parameter + || (!!parent.parent && parent.parent.kind === SyntaxKind.ArrayBindingPattern); // var [...z| case SyntaxKind.PublicKeyword: case SyntaxKind.PrivateKeyword: @@ -3478,9 +4095,9 @@ namespace ts.Completions { return containingNodeKind === SyntaxKind.Parameter && !isConstructorDeclaration(parent.parent); case SyntaxKind.AsKeyword: - return containingNodeKind === SyntaxKind.ImportSpecifier || - containingNodeKind === SyntaxKind.ExportSpecifier || - containingNodeKind === SyntaxKind.NamespaceImport; + return containingNodeKind === SyntaxKind.ImportSpecifier + || containingNodeKind === SyntaxKind.ExportSpecifier + || containingNodeKind === SyntaxKind.NamespaceImport; case SyntaxKind.GetKeyword: case SyntaxKind.SetKeyword: @@ -3488,9 +4105,9 @@ namespace ts.Completions { case SyntaxKind.Identifier: if ( - containingNodeKind === SyntaxKind.ImportSpecifier && - contextToken === (parent as ImportSpecifier).name && - (contextToken as Identifier).text === "type" + containingNodeKind === SyntaxKind.ImportSpecifier + && contextToken === (parent as ImportSpecifier).name + && (contextToken as Identifier).text === "type" ) { // import { type | } return false; @@ -3518,7 +4135,10 @@ namespace ts.Completions { // If the previous token is keyword corresponding to class member completion keyword // there will be completion available here - if (isClassMemberCompletionKeyword(keywordForNode(contextToken)) && isFromObjectTypeDeclaration(contextToken)) { + if ( + isClassMemberCompletionKeyword(keywordForNode(contextToken)) + && isFromObjectTypeDeclaration(contextToken) + ) { return false; } @@ -3528,9 +4148,9 @@ namespace ts.Completions { // - its name of the parameter and not being edited // eg. constructor(a |<- this shouldnt show completion if ( - !isIdentifier(contextToken) || - isParameterPropertyModifier(keywordForNode(contextToken)) || - isCurrentlyEditingNode(contextToken) + !isIdentifier(contextToken) + || isParameterPropertyModifier(keywordForNode(contextToken)) + || isCurrentlyEditingNode(contextToken) ) { return false; } @@ -3559,7 +4179,10 @@ namespace ts.Completions { // If we are inside a class declaration, and `constructor` is totally not present, // but we request a completion manually at a whitespace... const ancestorClassLike = findAncestor(contextToken.parent, isClassLike); - if (ancestorClassLike && contextToken === previousToken && isPreviousPropertyDeclarationTerminated(contextToken, position)) { + if ( + ancestorClassLike && contextToken === previousToken + && isPreviousPropertyDeclarationTerminated(contextToken, position) + ) { return false; // Don't block completions. } @@ -3592,12 +4215,13 @@ namespace ts.Completions { && !isJsxAttribute(contextToken.parent) // Don't block completions if we're in `class C /**/`, because we're *past* the end of the identifier and might want to complete `extends`. // If `contextToken !== previousToken`, this is `class C ex/**/`. - && !(isClassLike(contextToken.parent) && (contextToken !== previousToken || position > previousToken.end)); + && !(isClassLike(contextToken.parent) + && (contextToken !== previousToken || position > previousToken.end)); } function isPreviousPropertyDeclarationTerminated(contextToken: Node, position: number) { - return contextToken.kind !== SyntaxKind.EqualsToken && - (contextToken.kind === SyntaxKind.SemicolonToken + return contextToken.kind !== SyntaxKind.EqualsToken + && (contextToken.kind === SyntaxKind.SemicolonToken || !positionsAreOnSameLine(contextToken.end, position, sourceFile)); } @@ -3625,7 +4249,10 @@ namespace ts.Completions { * @returns Symbols to be suggested in an object binding pattern or object literal expression, barring those whose declarations * do not occur at the current position and have not otherwise been typed. */ - function filterObjectMembersList(contextualMemberSymbols: Symbol[], existingMembers: readonly Declaration[]): Symbol[] { + function filterObjectMembersList( + contextualMemberSymbols: Symbol[], + existingMembers: readonly Declaration[], + ): Symbol[] { if (existingMembers.length === 0) { return contextualMemberSymbols; } @@ -3635,13 +4262,13 @@ namespace ts.Completions { for (const m of existingMembers) { // Ignore omitted expressions for missing members if ( - m.kind !== SyntaxKind.PropertyAssignment && - m.kind !== SyntaxKind.ShorthandPropertyAssignment && - m.kind !== SyntaxKind.BindingElement && - m.kind !== SyntaxKind.MethodDeclaration && - m.kind !== SyntaxKind.GetAccessor && - m.kind !== SyntaxKind.SetAccessor && - m.kind !== SyntaxKind.SpreadAssignment + m.kind !== SyntaxKind.PropertyAssignment + && m.kind !== SyntaxKind.ShorthandPropertyAssignment + && m.kind !== SyntaxKind.BindingElement + && m.kind !== SyntaxKind.MethodDeclaration + && m.kind !== SyntaxKind.GetAccessor + && m.kind !== SyntaxKind.SetAccessor + && m.kind !== SyntaxKind.SpreadAssignment ) { continue; } @@ -3667,7 +4294,8 @@ namespace ts.Completions { // NOTE: if one only performs this step when m.name is an identifier, // things like '__proto__' are not filtered out. const name = getNameOfDeclaration(m); - existingName = name && isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; + existingName = name && isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) + : undefined; } if (existingName !== undefined) { @@ -3681,7 +4309,10 @@ namespace ts.Completions { return filteredSymbols; } - function setMembersDeclaredBySpreadAssignment(declaration: SpreadAssignment | JsxSpreadAttribute, membersDeclaredBySpreadAssignment: Set) { + function setMembersDeclaredBySpreadAssignment( + declaration: SpreadAssignment | JsxSpreadAttribute, + membersDeclaredBySpreadAssignment: Set, + ) { const expression = declaration.expression; const symbol = typeChecker.getSymbolAtLocation(expression); const type = symbol && typeChecker.getTypeOfSymbolAtLocation(symbol, expression); @@ -3704,13 +4335,17 @@ namespace ts.Completions { } // Set SortText to MemberDeclaredBySpreadAssignment if it is fulfilled by spread assignment - function setSortTextToMemberDeclaredBySpreadAssignment(membersDeclaredBySpreadAssignment: Set, contextualMemberSymbols: Symbol[]): void { + function setSortTextToMemberDeclaredBySpreadAssignment( + membersDeclaredBySpreadAssignment: Set, + contextualMemberSymbols: Symbol[], + ): void { if (membersDeclaredBySpreadAssignment.size === 0) { return; } for (const contextualMemberSymbol of contextualMemberSymbols) { if (membersDeclaredBySpreadAssignment.has(contextualMemberSymbol.name)) { - symbolToSortTextMap[getSymbolId(contextualMemberSymbol)] = SortText.MemberDeclaredBySpreadAssignment; + symbolToSortTextMap[getSymbolId(contextualMemberSymbol)] = + SortText.MemberDeclaredBySpreadAssignment; } } } @@ -3741,15 +4376,19 @@ namespace ts.Completions { * * @returns Symbols to be suggested in an class element depending on existing memebers and symbol flags */ - function filterClassMembersList(baseSymbols: readonly Symbol[], existingMembers: readonly ClassElement[], currentClassElementModifierFlags: ModifierFlags): Symbol[] { + function filterClassMembersList( + baseSymbols: readonly Symbol[], + existingMembers: readonly ClassElement[], + currentClassElementModifierFlags: ModifierFlags, + ): Symbol[] { const existingMemberNames = new Set<__String>(); for (const m of existingMembers) { // Ignore omitted expressions for missing members if ( - m.kind !== SyntaxKind.PropertyDeclaration && - m.kind !== SyntaxKind.MethodDeclaration && - m.kind !== SyntaxKind.GetAccessor && - m.kind !== SyntaxKind.SetAccessor + m.kind !== SyntaxKind.PropertyDeclaration + && m.kind !== SyntaxKind.MethodDeclaration + && m.kind !== SyntaxKind.GetAccessor + && m.kind !== SyntaxKind.SetAccessor ) { continue; } @@ -3776,10 +4415,11 @@ namespace ts.Completions { } return baseSymbols.filter(propertySymbol => - !existingMemberNames.has(propertySymbol.escapedName) && - !!propertySymbol.declarations && - !(getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private) && - !(propertySymbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(propertySymbol.valueDeclaration)) + !existingMemberNames.has(propertySymbol.escapedName) + && !!propertySymbol.declarations + && !(getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private) + && !(propertySymbol.valueDeclaration + && isPrivateIdentifierClassElementDeclaration(propertySymbol.valueDeclaration)) ); } @@ -3789,7 +4429,10 @@ namespace ts.Completions { * @returns Symbols to be suggested in a JSX element, barring those whose attributes * do not occur at the current position and have not otherwise been typed. */ - function filterJsxAttributes(symbols: Symbol[], attributes: NodeArray): Symbol[] { + function filterJsxAttributes( + symbols: Symbol[], + attributes: NodeArray, + ): Symbol[] { const seenNames = new Set<__String>(); const membersDeclaredBySpreadAssignment = new Set(); for (const attr of attributes) { @@ -3821,7 +4464,9 @@ namespace ts.Completions { * Returns the immediate owning object literal or binding pattern of a context token, * on the condition that one exists and that the context implies completion should be given. */ - function tryGetObjectLikeCompletionContainer(contextToken: Node | undefined): ObjectLiteralExpression | ObjectBindingPattern | undefined { + function tryGetObjectLikeCompletionContainer( + contextToken: Node | undefined, + ): ObjectLiteralExpression | ObjectBindingPattern | undefined { if (contextToken) { const { parent } = contextToken; switch (contextToken.kind) { @@ -3834,7 +4479,8 @@ namespace ts.Completions { case SyntaxKind.AsteriskToken: return isMethodDeclaration(parent) ? tryCast(parent.parent, isObjectLiteralExpression) : undefined; case SyntaxKind.Identifier: - return (contextToken as Identifier).text === "async" && isShorthandPropertyAssignment(contextToken.parent) + return (contextToken as Identifier).text === "async" + && isShorthandPropertyAssignment(contextToken.parent) ? contextToken.parent.parent : undefined; } } @@ -3842,21 +4488,33 @@ namespace ts.Completions { return undefined; } - function getRelevantTokens(position: number, sourceFile: SourceFile): { contextToken: Node; previousToken: Node; } | { contextToken: undefined; previousToken: undefined; } { + function getRelevantTokens( + position: number, + sourceFile: SourceFile, + ): { contextToken: Node; previousToken: Node; } | { contextToken: undefined; previousToken: undefined; } { const previousToken = findPrecedingToken(position, sourceFile); - if (previousToken && position <= previousToken.end && (isMemberName(previousToken) || isKeyword(previousToken.kind))) { + if ( + previousToken && position <= previousToken.end + && (isMemberName(previousToken) || isKeyword(previousToken.kind)) + ) { const contextToken = findPrecedingToken(previousToken.getFullStart(), sourceFile, /*startNode*/ undefined)!; // TODO: GH#18217 return { contextToken, previousToken }; } return { contextToken: previousToken as Node, previousToken: previousToken as Node }; } - function getAutoImportSymbolFromCompletionEntryData(name: string, data: CompletionEntryData, program: Program, host: LanguageServiceHost): { symbol: Symbol; origin: SymbolOriginInfoExport | SymbolOriginInfoResolvedExport; } | undefined { + function getAutoImportSymbolFromCompletionEntryData( + name: string, + data: CompletionEntryData, + program: Program, + host: LanguageServiceHost, + ): { symbol: Symbol; origin: SymbolOriginInfoExport | SymbolOriginInfoResolvedExport; } | undefined { const containingProgram = data.isPackageJsonImport ? host.getPackageJsonAutoImportProvider!()! : program; const checker = containingProgram.getTypeChecker(); - const moduleSymbol = data.ambientModuleName ? checker.tryFindAmbientModule(data.ambientModuleName) : - data.fileName ? checker.getMergedSymbol(Debug.checkDefined(containingProgram.getSourceFile(data.fileName)).symbol) : - undefined; + const moduleSymbol = data.ambientModuleName ? checker.tryFindAmbientModule(data.ambientModuleName) + : data.fileName + ? checker.getMergedSymbol(Debug.checkDefined(containingProgram.getSourceFile(data.fileName)).symbol) + : undefined; if (!moduleSymbol) return undefined; let symbol = data.exportName === InternalSymbolName.ExportEquals @@ -3892,7 +4550,10 @@ namespace ts.Completions { } const validNameResult: CompletionEntryDisplayNameForSymbol = { name, needsConvertPropertyAccess: false }; - if (isIdentifierText(name, target, jsxIdentifierExpected ? LanguageVariant.JSX : LanguageVariant.Standard) || symbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(symbol.valueDeclaration)) { + if ( + isIdentifierText(name, target, jsxIdentifierExpected ? LanguageVariant.JSX : LanguageVariant.Standard) + || symbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(symbol.valueDeclaration) + ) { return validNameResult; } switch (kind) { @@ -3904,7 +4565,8 @@ namespace ts.Completions { case CompletionKind.PropertyAccess: case CompletionKind.Global: // For a 'this.' completion it will be in a global context, but may have a non-identifier name. // Don't add a completion for a name starting with a space. See https://github.com/Microsoft/TypeScript/pull/20547 - return name.charCodeAt(0) === CharacterCodes.space ? undefined : { name, needsConvertPropertyAccess: true }; + return name.charCodeAt(0) === CharacterCodes.space ? undefined + : { name, needsConvertPropertyAccess: true }; case CompletionKind.None: case CompletionKind.String: return validNameResult; @@ -3928,47 +4590,51 @@ namespace ts.Completions { return res; }); - function getKeywordCompletions(keywordFilter: KeywordCompletionFilters, filterOutTsOnlyKeywords: boolean): readonly CompletionEntry[] { + function getKeywordCompletions( + keywordFilter: KeywordCompletionFilters, + filterOutTsOnlyKeywords: boolean, + ): readonly CompletionEntry[] { if (!filterOutTsOnlyKeywords) return getTypescriptKeywordCompletions(keywordFilter); const index = keywordFilter + KeywordCompletionFilters.Last + 1; - return _keywordCompletions[index] || - (_keywordCompletions[index] = getTypescriptKeywordCompletions(keywordFilter) + return _keywordCompletions[index] + || (_keywordCompletions[index] = getTypescriptKeywordCompletions(keywordFilter) .filter(entry => !isTypeScriptOnlyKeyword(stringToToken(entry.name)!))); } function getTypescriptKeywordCompletions(keywordFilter: KeywordCompletionFilters): readonly CompletionEntry[] { - return _keywordCompletions[keywordFilter] || (_keywordCompletions[keywordFilter] = allKeywordsCompletions().filter(entry => { - const kind = stringToToken(entry.name)!; - switch (keywordFilter) { - case KeywordCompletionFilters.None: - return false; - case KeywordCompletionFilters.All: - return isFunctionLikeBodyKeyword(kind) - || kind === SyntaxKind.DeclareKeyword - || kind === SyntaxKind.ModuleKeyword - || kind === SyntaxKind.TypeKeyword - || kind === SyntaxKind.NamespaceKeyword - || kind === SyntaxKind.AbstractKeyword - || isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword; - case KeywordCompletionFilters.FunctionLikeBodyKeywords: - return isFunctionLikeBodyKeyword(kind); - case KeywordCompletionFilters.ClassElementKeywords: - return isClassMemberCompletionKeyword(kind); - case KeywordCompletionFilters.InterfaceElementKeywords: - return isInterfaceOrTypeLiteralCompletionKeyword(kind); - case KeywordCompletionFilters.ConstructorParameterKeywords: - return isParameterPropertyModifier(kind); - case KeywordCompletionFilters.TypeAssertionKeywords: - return isTypeKeyword(kind) || kind === SyntaxKind.ConstKeyword; - case KeywordCompletionFilters.TypeKeywords: - return isTypeKeyword(kind); - case KeywordCompletionFilters.TypeKeyword: - return kind === SyntaxKind.TypeKeyword; - default: - return Debug.assertNever(keywordFilter); - } - })); + return _keywordCompletions[keywordFilter] + || (_keywordCompletions[keywordFilter] = allKeywordsCompletions().filter(entry => { + const kind = stringToToken(entry.name)!; + switch (keywordFilter) { + case KeywordCompletionFilters.None: + return false; + case KeywordCompletionFilters.All: + return isFunctionLikeBodyKeyword(kind) + || kind === SyntaxKind.DeclareKeyword + || kind === SyntaxKind.ModuleKeyword + || kind === SyntaxKind.TypeKeyword + || kind === SyntaxKind.NamespaceKeyword + || kind === SyntaxKind.AbstractKeyword + || isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword; + case KeywordCompletionFilters.FunctionLikeBodyKeywords: + return isFunctionLikeBodyKeyword(kind); + case KeywordCompletionFilters.ClassElementKeywords: + return isClassMemberCompletionKeyword(kind); + case KeywordCompletionFilters.InterfaceElementKeywords: + return isInterfaceOrTypeLiteralCompletionKeyword(kind); + case KeywordCompletionFilters.ConstructorParameterKeywords: + return isParameterPropertyModifier(kind); + case KeywordCompletionFilters.TypeAssertionKeywords: + return isTypeKeyword(kind) || kind === SyntaxKind.ConstKeyword; + case KeywordCompletionFilters.TypeKeywords: + return isTypeKeyword(kind); + case KeywordCompletionFilters.TypeKeyword: + return kind === SyntaxKind.TypeKeyword; + default: + return Debug.assertNever(keywordFilter); + } + })); } function isTypeScriptOnlyKeyword(kind: SyntaxKind) { @@ -4076,19 +4742,24 @@ namespace ts.Completions { /** Get the corresponding JSDocTag node if the position is in a jsDoc comment */ function getJsDocTagAtPosition(node: Node, position: number): JSDocTag | undefined { return findAncestor(node, n => - isJSDocTag(n) && rangeContainsPosition(n, position) ? true : - isJSDoc(n) ? "quit" : false) as JSDocTag | undefined; + isJSDocTag(n) && rangeContainsPosition(n, position) ? true + : isJSDoc(n) ? "quit" : false) as JSDocTag | undefined; } - export function getPropertiesForObjectExpression(contextualType: Type, completionsType: Type | undefined, obj: ObjectLiteralExpression | JsxAttributes, checker: TypeChecker): Symbol[] { + export function getPropertiesForObjectExpression( + contextualType: Type, + completionsType: Type | undefined, + obj: ObjectLiteralExpression | JsxAttributes, + checker: TypeChecker, + ): Symbol[] { const hasCompletionsType = completionsType && completionsType !== contextualType; const type = hasCompletionsType && !(completionsType.flags & TypeFlags.AnyOrUnknown) ? checker.getUnionType([contextualType, completionsType]) : contextualType; const properties = getApparentProperties(type, obj, checker); - return type.isClass() && containsNonPublicProperties(properties) ? [] : - hasCompletionsType ? filter(properties, hasDeclarationOtherThanSelf) : properties; + return type.isClass() && containsNonPublicProperties(properties) ? [] + : hasCompletionsType ? filter(properties, hasDeclarationOtherThanSelf) : properties; // Filter out members whose only declaration is the object literal itself to avoid // self-fulfilling completions like: @@ -4103,16 +4774,21 @@ namespace ts.Completions { function getApparentProperties(type: Type, node: ObjectLiteralExpression | JsxAttributes, checker: TypeChecker) { if (!type.isUnion()) return type.getApparentProperties(); - return checker.getAllPossiblePropertiesOfTypes(filter(type.types, memberType => - !(memberType.flags & TypeFlags.Primitive - || checker.isArrayLikeType(memberType) - || checker.isTypeInvalidDueToUnionDiscriminant(memberType, node) - || typeHasCallOrConstructSignatures(memberType, checker) - || memberType.isClass() && containsNonPublicProperties(memberType.getApparentProperties())))); + return checker.getAllPossiblePropertiesOfTypes( + filter(type.types, memberType => + !(memberType.flags & TypeFlags.Primitive + || checker.isArrayLikeType(memberType) + || checker.isTypeInvalidDueToUnionDiscriminant(memberType, node) + || typeHasCallOrConstructSignatures(memberType, checker) + || memberType.isClass() && containsNonPublicProperties(memberType.getApparentProperties()))), + ); } function containsNonPublicProperties(props: Symbol[]) { - return some(props, p => !!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier)); + return some( + props, + p => !!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier), + ); } /** @@ -4121,7 +4797,10 @@ namespace ts.Completions { */ function getPropertiesForCompletion(type: Type, checker: TypeChecker): Symbol[] { return type.isUnion() - ? Debug.checkEachDefined(checker.getAllPossiblePropertiesOfTypes(type.types), "getAllPossiblePropertiesOfTypes() should all be defined") + ? Debug.checkEachDefined( + checker.getAllPossiblePropertiesOfTypes(type.types), + "getAllPossiblePropertiesOfTypes() should all be defined", + ) : Debug.checkEachDefined(type.getApparentProperties(), "getApparentProperties() should all be defined"); } @@ -4129,13 +4808,21 @@ namespace ts.Completions { * Returns the immediate owning class declaration of a context token, * on the condition that one exists and that the context implies completion should be given. */ - function tryGetObjectTypeDeclarationCompletionContainer(sourceFile: SourceFile, contextToken: Node | undefined, location: Node, position: number): ObjectTypeDeclaration | undefined { + function tryGetObjectTypeDeclarationCompletionContainer( + sourceFile: SourceFile, + contextToken: Node | undefined, + location: Node, + position: number, + ): ObjectTypeDeclaration | undefined { // class c { method() { } | method2() { } } switch (location.kind) { case SyntaxKind.SyntaxList: return tryCast(location.parent, isObjectTypeDeclaration); case SyntaxKind.EndOfFileToken: - const cls = tryCast(lastOrUndefined(cast(location.parent, isSourceFile).statements), isObjectTypeDeclaration); + const cls = tryCast( + lastOrUndefined(cast(location.parent, isSourceFile).statements), + isObjectTypeDeclaration, + ); if (cls && !findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile)) { return cls; } @@ -4174,7 +4861,8 @@ namespace ts.Completions { case SyntaxKind.SemicolonToken: // class c {getValue(): number; | } case SyntaxKind.CloseBraceToken: // class c { method() { } | } // class c { method() { } b| } - return isFromObjectTypeDeclaration(location) && (location.parent as ClassElement | TypeElement).name === location + return isFromObjectTypeDeclaration(location) + && (location.parent as ClassElement | TypeElement).name === location ? location.parent.parent as ObjectTypeDeclaration : tryCast(location, isObjectTypeDeclaration); case SyntaxKind.OpenBraceToken: // class c { | @@ -4183,13 +4871,19 @@ namespace ts.Completions { default: if (!isFromObjectTypeDeclaration(contextToken)) { // class c extends React.Component { a: () => 1\n| } - if (getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line !== getLineAndCharacterOfPosition(sourceFile, position).line && isObjectTypeDeclaration(location)) { + if ( + getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line + !== getLineAndCharacterOfPosition(sourceFile, position).line + && isObjectTypeDeclaration(location) + ) { return location; } return undefined; } - const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword : isInterfaceOrTypeLiteralCompletionKeyword; - return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217 + const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword + : isInterfaceOrTypeLiteralCompletionKeyword; + return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken + || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217 ? contextToken.parent.parent as ObjectTypeDeclaration : undefined; } } @@ -4242,7 +4936,12 @@ namespace ts.Completions { return node.parent && isClassOrTypeElement(node.parent) && isObjectTypeDeclaration(node.parent.parent); } - function isValidTrigger(sourceFile: SourceFile, triggerCharacter: CompletionsTriggerCharacter, contextToken: Node | undefined, position: number): boolean { + function isValidTrigger( + sourceFile: SourceFile, + triggerCharacter: CompletionsTriggerCharacter, + contextToken: Node | undefined, + position: number, + ): boolean { switch (triggerCharacter) { case ".": case "@": @@ -4251,18 +4950,21 @@ namespace ts.Completions { case "'": case "`": // Only automatically bring up completions if this is an opening quote. - return !!contextToken && isStringLiteralOrTemplate(contextToken) && position === contextToken.getStart(sourceFile) + 1; + return !!contextToken && isStringLiteralOrTemplate(contextToken) + && position === contextToken.getStart(sourceFile) + 1; case "#": return !!contextToken && isPrivateIdentifier(contextToken) && !!getContainingClass(contextToken); case "<": // Opening JSX tag - return !!contextToken && contextToken.kind === SyntaxKind.LessThanToken && (!isBinaryExpression(contextToken.parent) || binaryExpressionMayBeOpenTag(contextToken.parent)); + return !!contextToken && contextToken.kind === SyntaxKind.LessThanToken + && (!isBinaryExpression(contextToken.parent) || binaryExpressionMayBeOpenTag(contextToken.parent)); case "/": return !!contextToken && (isStringLiteralLike(contextToken) ? !!tryGetImportFromModuleSpecifier(contextToken) : contextToken.kind === SyntaxKind.SlashToken && isJsxClosingElement(contextToken.parent)); case " ": - return !!contextToken && isImportKeyword(contextToken) && contextToken.parent.kind === SyntaxKind.SourceFile; + return !!contextToken && isImportKeyword(contextToken) + && contextToken.parent.kind === SyntaxKind.SourceFile; default: return Debug.assertNever(triggerCharacter); } @@ -4276,15 +4978,30 @@ namespace ts.Completions { function isProbablyGlobalType(type: Type, sourceFile: SourceFile, checker: TypeChecker) { // The type of `self` and `window` is the same in lib.dom.d.ts, but `window` does not exist in // lib.webworker.d.ts, so checking against `self` is also a check against `window` when it exists. - const selfSymbol = checker.resolveName("self", /*location*/ undefined, SymbolFlags.Value, /*excludeGlobals*/ false); + const selfSymbol = checker.resolveName( + "self", + /*location*/ undefined, + SymbolFlags.Value, + /*excludeGlobals*/ false, + ); if (selfSymbol && checker.getTypeOfSymbolAtLocation(selfSymbol, sourceFile) === type) { return true; } - const globalSymbol = checker.resolveName("global", /*location*/ undefined, SymbolFlags.Value, /*excludeGlobals*/ false); + const globalSymbol = checker.resolveName( + "global", + /*location*/ undefined, + SymbolFlags.Value, + /*excludeGlobals*/ false, + ); if (globalSymbol && checker.getTypeOfSymbolAtLocation(globalSymbol, sourceFile) === type) { return true; } - const globalThisSymbol = checker.resolveName("globalThis", /*location*/ undefined, SymbolFlags.Value, /*excludeGlobals*/ false); + const globalThisSymbol = checker.resolveName( + "globalThis", + /*location*/ undefined, + SymbolFlags.Value, + /*excludeGlobals*/ false, + ); if (globalThisSymbol && checker.getTypeOfSymbolAtLocation(globalThisSymbol, sourceFile) === type) { return true; } @@ -4292,7 +5009,8 @@ namespace ts.Completions { } function isStaticProperty(symbol: Symbol) { - return !!(symbol.valueDeclaration && getEffectiveModifierFlags(symbol.valueDeclaration) & ModifierFlags.Static && isClassLike(symbol.valueDeclaration.parent)); + return !!(symbol.valueDeclaration && getEffectiveModifierFlags(symbol.valueDeclaration) & ModifierFlags.Static + && isClassLike(symbol.valueDeclaration.parent)); } function tryGetObjectLiteralContextualType(node: ObjectLiteralExpression, typeChecker: TypeChecker) { @@ -4301,7 +5019,9 @@ namespace ts.Completions { return type; } const parent = walkUpParenthesizedExpressions(node.parent); - if (isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken && node === parent.left) { + if ( + isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken && node === parent.left + ) { // Object literal is assignment pattern: ({ | } = x) return typeChecker.getTypeAtLocation(parent); } @@ -4329,7 +5049,8 @@ namespace ts.Completions { isKeywordOnlyCompletion, keywordCompletion, isNewIdentifierLocation: !!(candidate || keywordCompletion === SyntaxKind.TypeKeyword), - isTopLevelTypeOnly: !!tryCast(candidate, isImportDeclaration)?.importClause?.isTypeOnly || !!tryCast(candidate, isImportEqualsDeclaration)?.isTypeOnly, + isTopLevelTypeOnly: !!tryCast(candidate, isImportDeclaration)?.importClause?.isTypeOnly + || !!tryCast(candidate, isImportEqualsDeclaration)?.isTypeOnly, couldBeTypeOnlyImportSpecifier: !!candidate && couldBeTypeOnlyImportSpecifier(candidate, contextToken), replacementSpan: getSingleLineReplacementSpanForImportCompletionNode(candidate), }; @@ -4346,9 +5067,9 @@ namespace ts.Completions { if (isNamedImports(parent) || isNamespaceImport(parent)) { if ( !parent.parent.isTypeOnly && ( - contextToken.kind === SyntaxKind.OpenBraceToken || - contextToken.kind === SyntaxKind.ImportKeyword || - contextToken.kind === SyntaxKind.CommaToken + contextToken.kind === SyntaxKind.OpenBraceToken + || contextToken.kind === SyntaxKind.ImportKeyword + || contextToken.kind === SyntaxKind.CommaToken ) ) { keywordCompletion = SyntaxKind.TypeKeyword; @@ -4356,7 +5077,9 @@ namespace ts.Completions { if (canCompleteFromNamedBindings(parent)) { // At `import { ... } |` or `import * as Foo |`, the only possible completion is `from` - if (contextToken.kind === SyntaxKind.CloseBraceToken || contextToken.kind === SyntaxKind.Identifier) { + if ( + contextToken.kind === SyntaxKind.CloseBraceToken || contextToken.kind === SyntaxKind.Identifier + ) { isKeywordOnlyCompletion = true; keywordCompletion = SyntaxKind.FromKeyword; } @@ -4380,7 +5103,14 @@ namespace ts.Completions { } } - function getSingleLineReplacementSpanForImportCompletionNode(node: ImportDeclaration | ImportEqualsDeclaration | ImportSpecifier | Token | undefined) { + function getSingleLineReplacementSpanForImportCompletionNode( + node: + | ImportDeclaration + | ImportEqualsDeclaration + | ImportSpecifier + | Token + | undefined, + ) { if (!node) return undefined; const top = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration)) ?? node; const sourceFile = top.getSourceFile(); @@ -4421,19 +5151,26 @@ namespace ts.Completions { function getPotentiallyInvalidImportSpecifier(namedBindings: NamedImportBindings | undefined) { return find( tryCast(namedBindings, isNamedImports)?.elements, - e => !e.propertyName && - isStringANonContextualKeyword(e.name.text) && - findPrecedingToken(e.name.pos, namedBindings!.getSourceFile(), namedBindings)?.kind !== SyntaxKind.CommaToken, + e => !e.propertyName + && isStringANonContextualKeyword(e.name.text) + && findPrecedingToken(e.name.pos, namedBindings!.getSourceFile(), namedBindings)?.kind + !== SyntaxKind.CommaToken, ); } - function couldBeTypeOnlyImportSpecifier(importSpecifier: Node, contextToken: Node | undefined): importSpecifier is ImportSpecifier { + function couldBeTypeOnlyImportSpecifier( + importSpecifier: Node, + contextToken: Node | undefined, + ): importSpecifier is ImportSpecifier { return isImportSpecifier(importSpecifier) - && (importSpecifier.isTypeOnly || contextToken === importSpecifier.name && isTypeKeywordTokenOrIdentifier(contextToken)); + && (importSpecifier.isTypeOnly + || contextToken === importSpecifier.name && isTypeKeywordTokenOrIdentifier(contextToken)); } function canCompleteFromNamedBindings(namedBindings: NamedImportBindings) { - if (!isModuleSpecifierMissingOrEmpty(namedBindings.parent.parent.moduleSpecifier) || namedBindings.parent.name) { + if ( + !isModuleSpecifierMissingOrEmpty(namedBindings.parent.parent.moduleSpecifier) || namedBindings.parent.name + ) { return false; } if (isNamedImports(namedBindings)) { @@ -4441,7 +5178,8 @@ namespace ts.Completions { // but parser recovery sometimes puts later statements in the named imports list, so // we try to only consider the probably-valid ones. const invalidNamedImport = getPotentiallyInvalidImportSpecifier(namedBindings); - const validImports = invalidNamedImport ? namedBindings.elements.indexOf(invalidNamedImport) : namedBindings.elements.length; + const validImports = invalidNamedImport ? namedBindings.elements.indexOf(invalidNamedImport) + : namedBindings.elements.length; return validImports < 2; } return true; @@ -4449,14 +5187,18 @@ namespace ts.Completions { function isModuleSpecifierMissingOrEmpty(specifier: ModuleReference | Expression) { if (nodeIsMissing(specifier)) return true; - return !tryCast(isExternalModuleReference(specifier) ? specifier.expression : specifier, isStringLiteralLike)?.text; + return !tryCast(isExternalModuleReference(specifier) ? specifier.expression : specifier, isStringLiteralLike) + ?.text; } function getVariableDeclaration(property: Node): VariableDeclaration | undefined { - const variableDeclaration = findAncestor(property, node => - isFunctionBlock(node) || isArrowFunctionBody(node) || isBindingPattern(node) - ? "quit" - : isVariableDeclaration(node)); + const variableDeclaration = findAncestor( + property, + node => + isFunctionBlock(node) || isArrowFunctionBody(node) || isBindingPattern(node) + ? "quit" + : isVariableDeclaration(node), + ); return variableDeclaration as VariableDeclaration | undefined; } @@ -4466,15 +5208,22 @@ namespace ts.Completions { } /** True if symbol is a type or a module containing at least one type. */ - function symbolCanBeReferencedAtTypeLocation(symbol: Symbol, checker: TypeChecker, seenModules = new Map()): boolean { + function symbolCanBeReferencedAtTypeLocation( + symbol: Symbol, + checker: TypeChecker, + seenModules = new Map(), + ): boolean { // Since an alias can be merged with a local declaration, we need to test both the alias and its target. // This code used to just test the result of `skipAlias`, but that would ignore any locally introduced meanings. - return nonAliasCanBeReferencedAtTypeLocation(symbol) || nonAliasCanBeReferencedAtTypeLocation(skipAlias(symbol.exportSymbol || symbol, checker)); + return nonAliasCanBeReferencedAtTypeLocation(symbol) + || nonAliasCanBeReferencedAtTypeLocation(skipAlias(symbol.exportSymbol || symbol, checker)); function nonAliasCanBeReferencedAtTypeLocation(symbol: Symbol): boolean { - return !!(symbol.flags & SymbolFlags.Type) || checker.isUnknownSymbol(symbol) || - !!(symbol.flags & SymbolFlags.Module) && addToSeen(seenModules, getSymbolId(symbol)) && - checker.getExportsOfModule(symbol).some(e => symbolCanBeReferencedAtTypeLocation(e, checker, seenModules)); + return !!(symbol.flags & SymbolFlags.Type) || checker.isUnknownSymbol(symbol) + || !!(symbol.flags & SymbolFlags.Module) && addToSeen(seenModules, getSymbolId(symbol)) + && checker.getExportsOfModule(symbol).some(e => + symbolCanBeReferencedAtTypeLocation(e, checker, seenModules) + ); } } @@ -4512,9 +5261,10 @@ namespace ts.Completions { const strChar = identifierString.charCodeAt(strIndex); const testChar = lowercaseCharacters.charCodeAt(characterIndex); if (strChar === testChar || strChar === toUpperCharCode(testChar)) { - matchedFirstCharacter ||= prevChar === undefined || // Beginning of word - CharacterCodes.a <= prevChar && prevChar <= CharacterCodes.z && CharacterCodes.A <= strChar && strChar <= CharacterCodes.Z || // camelCase transition - prevChar === CharacterCodes._ && strChar !== CharacterCodes._; // snake_case transition + matchedFirstCharacter ||= prevChar === undefined // Beginning of word + || CharacterCodes.a <= prevChar && prevChar <= CharacterCodes.z && CharacterCodes.A <= strChar + && strChar <= CharacterCodes.Z // camelCase transition + || prevChar === CharacterCodes._ && strChar !== CharacterCodes._; // snake_case transition if (matchedFirstCharacter) { characterIndex++; } diff --git a/src/services/documentHighlights.ts b/src/services/documentHighlights.ts index 6de0ec185e846..772b6fc1f17b1 100644 --- a/src/services/documentHighlights.ts +++ b/src/services/documentHighlights.ts @@ -6,17 +6,30 @@ namespace ts { /* @internal */ export namespace DocumentHighlights { - export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: readonly SourceFile[]): DocumentHighlights[] | undefined { + export function getDocumentHighlights( + program: Program, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + position: number, + sourceFilesToSearch: readonly SourceFile[], + ): DocumentHighlights[] | undefined { const node = getTouchingPropertyName(sourceFile, position); - if (node.parent && (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent))) { + if ( + node.parent + && (isJsxOpeningElement(node.parent) && node.parent.tagName === node + || isJsxClosingElement(node.parent)) + ) { // For a JSX element, just highlight the matching tag, not all references. const { openingElement, closingElement } = node.parent.parent; - const highlightSpans = [openingElement, closingElement].map(({ tagName }) => getHighlightSpanForNode(tagName, sourceFile)); + const highlightSpans = [openingElement, closingElement].map(({ tagName }) => + getHighlightSpanForNode(tagName, sourceFile) + ); return [{ fileName: sourceFile.fileName, highlightSpans }]; } - return getSemanticDocumentHighlights(position, node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile); + return getSemanticDocumentHighlights(position, node, program, cancellationToken, sourceFilesToSearch) + || getSyntacticDocumentHighlights(node, sourceFile); } function getHighlightSpanForNode(node: Node, sourceFile: SourceFile): HighlightSpan { @@ -27,19 +40,44 @@ namespace ts { }; } - function getSemanticDocumentHighlights(position: number, node: Node, program: Program, cancellationToken: CancellationToken, sourceFilesToSearch: readonly SourceFile[]): DocumentHighlights[] | undefined { + function getSemanticDocumentHighlights( + position: number, + node: Node, + program: Program, + cancellationToken: CancellationToken, + sourceFilesToSearch: readonly SourceFile[], + ): DocumentHighlights[] | undefined { const sourceFilesSet = new Set(sourceFilesToSearch.map(f => f.fileName)); - const referenceEntries = FindAllReferences.getReferenceEntriesForNode(position, node, program, sourceFilesToSearch, cancellationToken, /*options*/ undefined, sourceFilesSet); + const referenceEntries = FindAllReferences.getReferenceEntriesForNode( + position, + node, + program, + sourceFilesToSearch, + cancellationToken, + /*options*/ undefined, + sourceFilesSet, + ); if (!referenceEntries) return undefined; - const map = arrayToMultiMap(referenceEntries.map(FindAllReferences.toHighlightSpan), e => e.fileName, e => e.span); + const map = arrayToMultiMap( + referenceEntries.map(FindAllReferences.toHighlightSpan), + e => e.fileName, + e => e.span, + ); const getCanonicalFileName = createGetCanonicalFileName(program.useCaseSensitiveFileNames()); return mapDefined(arrayFrom(map.entries()), ([fileName, highlightSpans]) => { if (!sourceFilesSet.has(fileName)) { - if (!program.redirectTargetsMap.has(toPath(fileName, program.getCurrentDirectory(), getCanonicalFileName))) { + if ( + !program.redirectTargetsMap.has( + toPath(fileName, program.getCurrentDirectory(), getCanonicalFileName), + ) + ) { return undefined; } const redirectTarget = program.getSourceFile(fileName); - const redirect = find(sourceFilesToSearch, f => !!f.redirectInfo && f.redirectInfo.redirectTarget === redirectTarget)!; + const redirect = find( + sourceFilesToSearch, + f => !!f.redirectInfo && f.redirectInfo.redirectTarget === redirectTarget, + )!; fileName = redirect.fileName; Debug.assert(sourceFilesSet.has(fileName)); } @@ -81,7 +119,11 @@ namespace ts { case SyntaxKind.ForKeyword: case SyntaxKind.WhileKeyword: case SyntaxKind.DoKeyword: - return useParent(node.parent, (n): n is IterationStatement => isIterationStatement(n, /*lookInLabeledStatements*/ true), getLoopBreakContinueOccurrences); + return useParent( + node.parent, + (n): n is IterationStatement => isIterationStatement(n, /*lookInLabeledStatements*/ true), + getLoopBreakContinueOccurrences, + ); case SyntaxKind.ConstructorKeyword: return getFromAllDeclarations(isConstructorDeclaration, [SyntaxKind.ConstructorKeyword]); case SyntaxKind.GetKeyword: @@ -101,11 +143,27 @@ namespace ts { : undefined; } - function getFromAllDeclarations(nodeTest: (node: Node) => node is T, keywords: readonly SyntaxKind[]): HighlightSpan[] | undefined { - return useParent(node.parent, nodeTest, decl => mapDefined(decl.symbol.declarations, d => nodeTest(d) ? find(d.getChildren(sourceFile), c => contains(keywords, c.kind)) : undefined)); + function getFromAllDeclarations( + nodeTest: (node: Node) => node is T, + keywords: readonly SyntaxKind[], + ): HighlightSpan[] | undefined { + return useParent( + node.parent, + nodeTest, + decl => + mapDefined( + decl.symbol.declarations, + d => nodeTest(d) ? find(d.getChildren(sourceFile), c => contains(keywords, c.kind)) + : undefined, + ), + ); } - function useParent(node: Node, nodeTest: (node: Node) => node is T, getNodes: (node: T, sourceFile: SourceFile) => readonly Node[] | undefined): HighlightSpan[] | undefined { + function useParent( + node: Node, + nodeTest: (node: Node) => node is T, + getNodes: (node: T, sourceFile: SourceFile) => readonly Node[] | undefined, + ): HighlightSpan[] | undefined { return nodeTest(node) ? highlightSpans(getNodes(node, sourceFile)) : undefined; } @@ -125,7 +183,8 @@ namespace ts { else if (isTryStatement(node)) { // Exceptions thrown within a try block lacking a catch clause are "owned" in the current context. return concatenate( - node.catchClause ? aggregateOwnedThrowStatements(node.catchClause) : node.tryBlock && aggregateOwnedThrowStatements(node.tryBlock), + node.catchClause ? aggregateOwnedThrowStatements(node.catchClause) + : node.tryBlock && aggregateOwnedThrowStatements(node.tryBlock), node.finallyBlock && aggregateOwnedThrowStatements(node.finallyBlock), ); } @@ -161,7 +220,8 @@ namespace ts { } function aggregateAllBreakAndContinueStatements(node: Node): readonly BreakOrContinueStatement[] | undefined { - return isBreakOrContinueStatement(node) ? [node] : isFunctionLike(node) ? undefined : flatMapChildren(node, aggregateAllBreakAndContinueStatements); + return isBreakOrContinueStatement(node) ? [node] + : isFunctionLike(node) ? undefined : flatMapChildren(node, aggregateAllBreakAndContinueStatements); } function flatMapChildren(node: Node, cb: (child: Node) => readonly T[] | T | undefined): readonly T[] { @@ -204,12 +264,28 @@ namespace ts { } function getModifierOccurrences(modifier: Modifier["kind"], declaration: Node): Node[] { - return mapDefined(getNodesToSearchForModifier(declaration, modifierToFlag(modifier)), node => findModifier(node, modifier)); + return mapDefined( + getNodesToSearchForModifier(declaration, modifierToFlag(modifier)), + node => findModifier(node, modifier), + ); } - function getNodesToSearchForModifier(declaration: Node, modifierFlag: ModifierFlags): readonly Node[] | undefined { + function getNodesToSearchForModifier( + declaration: Node, + modifierFlag: ModifierFlags, + ): readonly Node[] | undefined { // Types of node whose children might have modifiers. - const container = declaration.parent as ModuleBlock | SourceFile | Block | CaseClause | DefaultClause | ConstructorDeclaration | MethodDeclaration | FunctionDeclaration | ObjectTypeDeclaration | ObjectLiteralExpression; + const container = declaration.parent as + | ModuleBlock + | SourceFile + | Block + | CaseClause + | DefaultClause + | ConstructorDeclaration + | MethodDeclaration + | FunctionDeclaration + | ObjectTypeDeclaration + | ObjectLiteralExpression; switch (container.kind) { case SyntaxKind.ModuleBlock: case SyntaxKind.SourceFile: @@ -226,7 +302,10 @@ namespace ts { case SyntaxKind.Constructor: case SyntaxKind.MethodDeclaration: case SyntaxKind.FunctionDeclaration: - return [...container.parameters, ...(isClassLike(container.parent) ? container.parent.members : [])]; + return [ + ...container.parameters, + ...(isClassLike(container.parent) ? container.parent.members : []), + ]; case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: case SyntaxKind.InterfaceDeclaration: @@ -267,7 +346,15 @@ namespace ts { function getLoopBreakContinueOccurrences(loopNode: IterationStatement): Node[] { const keywords: Node[] = []; - if (pushKeywordIf(keywords, loopNode.getFirstToken(), SyntaxKind.ForKeyword, SyntaxKind.WhileKeyword, SyntaxKind.DoKeyword)) { + if ( + pushKeywordIf( + keywords, + loopNode.getFirstToken(), + SyntaxKind.ForKeyword, + SyntaxKind.WhileKeyword, + SyntaxKind.DoKeyword, + ) + ) { // If we succeeded and got a do-while loop, then start looking for a 'while' keyword. if (loopNode.kind === SyntaxKind.DoStatement) { const loopTokens = loopNode.getChildren(); @@ -282,14 +369,21 @@ namespace ts { forEach(aggregateAllBreakAndContinueStatements(loopNode.statement), statement => { if (ownsBreakOrContinueStatement(loopNode, statement)) { - pushKeywordIf(keywords, statement.getFirstToken(), SyntaxKind.BreakKeyword, SyntaxKind.ContinueKeyword); + pushKeywordIf( + keywords, + statement.getFirstToken(), + SyntaxKind.BreakKeyword, + SyntaxKind.ContinueKeyword, + ); } }); return keywords; } - function getBreakOrContinueStatementOccurrences(breakOrContinueStatement: BreakOrContinueStatement): Node[] | undefined { + function getBreakOrContinueStatementOccurrences( + breakOrContinueStatement: BreakOrContinueStatement, + ): Node[] | undefined { const owner = getBreakOrContinueOwner(breakOrContinueStatement); if (owner) { @@ -434,7 +528,10 @@ namespace ts { // Do not cross function/class/interface/module/type boundaries. function traverseWithoutCrossingFunction(node: Node, cb: (node: Node) => void) { cb(node); - if (!isFunctionLike(node) && !isClassLike(node) && !isInterfaceDeclaration(node) && !isModuleDeclaration(node) && !isTypeAliasDeclaration(node) && !isTypeNode(node)) { + if ( + !isFunctionLike(node) && !isClassLike(node) && !isInterfaceDeclaration(node) + && !isModuleDeclaration(node) && !isTypeAliasDeclaration(node) && !isTypeNode(node) + ) { forEachChild(node, child => traverseWithoutCrossingFunction(child, cb)); } } @@ -513,7 +610,10 @@ namespace ts { * Note: 'node' cannot be a SourceFile. */ function isLabeledBy(node: Node, labelName: __String): boolean { - return !!findAncestor(node.parent, owner => !isLabeledStatement(owner) ? "quit" : owner.label.escapedText === labelName); + return !!findAncestor( + node.parent, + owner => !isLabeledStatement(owner) ? "quit" : owner.label.escapedText === labelName, + ); } } } diff --git a/src/services/documentRegistry.ts b/src/services/documentRegistry.ts index a4a0b6f289802..2645f534d5c77 100644 --- a/src/services/documentRegistry.ts +++ b/src/services/documentRegistry.ts @@ -111,11 +111,21 @@ namespace ts { * @param scriptKind The script kind of the file to be released * @param impliedNodeFormat The implied source file format of the file to be released */ - releaseDocument(fileName: string, compilationSettings: CompilerOptions, scriptKind: ScriptKind, impliedNodeFormat: SourceFile["impliedNodeFormat"]): void; // eslint-disable-line @typescript-eslint/unified-signatures + releaseDocument( + fileName: string, + compilationSettings: CompilerOptions, + scriptKind: ScriptKind, + impliedNodeFormat: SourceFile["impliedNodeFormat"], + ): void; // eslint-disable-line @typescript-eslint/unified-signatures /** * @deprecated pass scriptKind for and impliedNodeFormat correctness */ releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey, scriptKind?: ScriptKind): void; - releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey, scriptKind: ScriptKind, impliedNodeFormat: SourceFile["impliedNodeFormat"]): void; // eslint-disable-line @typescript-eslint/unified-signatures + releaseDocumentWithKey( + path: Path, + key: DocumentRegistryBucketKey, + scriptKind: ScriptKind, + impliedNodeFormat: SourceFile["impliedNodeFormat"], + ): void; // eslint-disable-line @typescript-eslint/unified-signatures /*@internal*/ getLanguageServiceRefCounts(path: Path, scriptKind: ScriptKind): [string, number | undefined][]; @@ -145,41 +155,52 @@ namespace ts { return !!(entry as DocumentRegistryEntry).sourceFile; } - export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory?: string): DocumentRegistry { + export function createDocumentRegistry( + useCaseSensitiveFileNames?: boolean, + currentDirectory?: string, + ): DocumentRegistry { return createDocumentRegistryInternal(useCaseSensitiveFileNames, currentDirectory); } /*@internal*/ export type DocumentRegistryBucketKeyWithMode = string & { __documentRegistryBucketKeyWithMode: any; }; /*@internal*/ - export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boolean, currentDirectory = "", externalCache?: ExternalDocumentCache): DocumentRegistry { + export function createDocumentRegistryInternal( + useCaseSensitiveFileNames?: boolean, + currentDirectory = "", + externalCache?: ExternalDocumentCache, + ): DocumentRegistry { // Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have // for those settings. const buckets = new Map>(); const getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames); function reportStats() { - const bucketInfoArray = arrayFrom(buckets.keys()).filter(name => name && name.charAt(0) === "_").map(name => { - const entries = buckets.get(name)!; - const sourceFiles: { name: string; scriptKind: ScriptKind; refCount: number; }[] = []; - entries.forEach((entry, name) => { - if (isDocumentRegistryEntry(entry)) { - sourceFiles.push({ - name, - scriptKind: entry.sourceFile.scriptKind, - refCount: entry.languageServiceRefCount, - }); - } - else { - entry.forEach((value, scriptKind) => sourceFiles.push({ name, scriptKind, refCount: value.languageServiceRefCount })); - } - }); - sourceFiles.sort((x, y) => y.refCount - x.refCount); - return { - bucket: name, - sourceFiles, - }; - }); + const bucketInfoArray = arrayFrom(buckets.keys()).filter(name => name && name.charAt(0) === "_").map( + name => { + const entries = buckets.get(name)!; + const sourceFiles: { name: string; scriptKind: ScriptKind; refCount: number; }[] = []; + entries.forEach((entry, name) => { + if (isDocumentRegistryEntry(entry)) { + sourceFiles.push({ + name, + scriptKind: entry.sourceFile.scriptKind, + refCount: entry.languageServiceRefCount, + }); + } + else { + entry.forEach((value, scriptKind) => + sourceFiles.push({ name, scriptKind, refCount: value.languageServiceRefCount }) + ); + } + }); + sourceFiles.sort((x, y) => y.refCount - x.refCount); + return { + bucket: name, + sourceFiles, + }; + }, + ); return JSON.stringify(bucketInfoArray, undefined, 2); } @@ -190,29 +211,108 @@ namespace ts { return settingsOrHost as CompilerOptions; } - function acquireDocument(fileName: string, compilationSettings: CompilerOptions | MinimalResolutionCacheHost, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind, languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget): SourceFile { + function acquireDocument( + fileName: string, + compilationSettings: CompilerOptions | MinimalResolutionCacheHost, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind, + languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget, + ): SourceFile { const path = toPath(fileName, currentDirectory, getCanonicalFileName); const key = getKeyForCompilationSettings(getCompilationSettings(compilationSettings)); - return acquireDocumentWithKey(fileName, path, compilationSettings, key, scriptSnapshot, version, scriptKind, languageVersionOrOptions); + return acquireDocumentWithKey( + fileName, + path, + compilationSettings, + key, + scriptSnapshot, + version, + scriptKind, + languageVersionOrOptions, + ); } - function acquireDocumentWithKey(fileName: string, path: Path, compilationSettings: CompilerOptions | MinimalResolutionCacheHost, key: DocumentRegistryBucketKey, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind, languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget): SourceFile { - return acquireOrUpdateDocument(fileName, path, compilationSettings, key, scriptSnapshot, version, /*acquiring*/ true, scriptKind, languageVersionOrOptions); + function acquireDocumentWithKey( + fileName: string, + path: Path, + compilationSettings: CompilerOptions | MinimalResolutionCacheHost, + key: DocumentRegistryBucketKey, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind, + languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget, + ): SourceFile { + return acquireOrUpdateDocument( + fileName, + path, + compilationSettings, + key, + scriptSnapshot, + version, + /*acquiring*/ true, + scriptKind, + languageVersionOrOptions, + ); } - function updateDocument(fileName: string, compilationSettings: CompilerOptions | MinimalResolutionCacheHost, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind, languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget): SourceFile { + function updateDocument( + fileName: string, + compilationSettings: CompilerOptions | MinimalResolutionCacheHost, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind, + languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget, + ): SourceFile { const path = toPath(fileName, currentDirectory, getCanonicalFileName); const key = getKeyForCompilationSettings(getCompilationSettings(compilationSettings)); - return updateDocumentWithKey(fileName, path, compilationSettings, key, scriptSnapshot, version, scriptKind, languageVersionOrOptions); + return updateDocumentWithKey( + fileName, + path, + compilationSettings, + key, + scriptSnapshot, + version, + scriptKind, + languageVersionOrOptions, + ); } - function updateDocumentWithKey(fileName: string, path: Path, compilationSettings: CompilerOptions | MinimalResolutionCacheHost, key: DocumentRegistryBucketKey, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind, languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget): SourceFile { - return acquireOrUpdateDocument(fileName, path, getCompilationSettings(compilationSettings), key, scriptSnapshot, version, /*acquiring*/ false, scriptKind, languageVersionOrOptions); + function updateDocumentWithKey( + fileName: string, + path: Path, + compilationSettings: CompilerOptions | MinimalResolutionCacheHost, + key: DocumentRegistryBucketKey, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind, + languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget, + ): SourceFile { + return acquireOrUpdateDocument( + fileName, + path, + getCompilationSettings(compilationSettings), + key, + scriptSnapshot, + version, + /*acquiring*/ false, + scriptKind, + languageVersionOrOptions, + ); } function getDocumentRegistryEntry(bucketEntry: BucketEntry, scriptKind: ScriptKind | undefined) { - const entry = isDocumentRegistryEntry(bucketEntry) ? bucketEntry : bucketEntry.get(Debug.checkDefined(scriptKind, "If there are more than one scriptKind's for same document the scriptKind should be provided")); - Debug.assert(scriptKind === undefined || !entry || entry.sourceFile.scriptKind === scriptKind, `Script kind should match provided ScriptKind:${scriptKind} and sourceFile.scriptKind: ${entry?.sourceFile.scriptKind}, !entry: ${!entry}`); + const entry = isDocumentRegistryEntry(bucketEntry) ? bucketEntry + : bucketEntry.get( + Debug.checkDefined( + scriptKind, + "If there are more than one scriptKind's for same document the scriptKind should be provided", + ), + ); + Debug.assert( + scriptKind === undefined || !entry || entry.sourceFile.scriptKind === scriptKind, + `Script kind should match provided ScriptKind:${scriptKind} and sourceFile.scriptKind: ${entry?.sourceFile.scriptKind}, !entry: ${!entry}`, + ); return entry; } @@ -229,13 +329,21 @@ namespace ts { ): SourceFile { scriptKind = ensureScriptKind(fileName, scriptKind); const compilationSettings = getCompilationSettings(compilationSettingsOrHost); - const host: MinimalResolutionCacheHost | undefined = compilationSettingsOrHost === compilationSettings ? undefined : compilationSettingsOrHost as MinimalResolutionCacheHost; - const scriptTarget = scriptKind === ScriptKind.JSON ? ScriptTarget.JSON : getEmitScriptTarget(compilationSettings); - const sourceFileOptions: CreateSourceFileOptions = typeof languageVersionOrOptions === "object" ? - languageVersionOrOptions : - { + const host: MinimalResolutionCacheHost | undefined = compilationSettingsOrHost === compilationSettings + ? undefined : compilationSettingsOrHost as MinimalResolutionCacheHost; + const scriptTarget = scriptKind === ScriptKind.JSON ? ScriptTarget.JSON + : getEmitScriptTarget(compilationSettings); + const sourceFileOptions: CreateSourceFileOptions = typeof languageVersionOrOptions === "object" + ? languageVersionOrOptions + : { languageVersion: scriptTarget, - impliedNodeFormat: host && getImpliedNodeFormatForFile(path, host.getCompilerHost?.()?.getModuleResolutionCache?.()?.getPackageJsonInfoCache(), host, compilationSettings), + impliedNodeFormat: host + && getImpliedNodeFormatForFile( + path, + host.getCompilerHost?.()?.getModuleResolutionCache?.()?.getPackageJsonInfoCache(), + host, + compilationSettings, + ), setExternalModuleIndicator: getSetExternalModuleIndicator(compilationSettings), }; sourceFileOptions.languageVersion = scriptTarget; @@ -247,16 +355,26 @@ namespace ts { // It is interesting, but not definitively problematic if a build requires multiple document registry buckets - // perhaps they are for two projects that don't have any overlap. // Bonus: these events can help us interpret the more interesting event below. - tracing.instant(tracing.Phase.Session, "createdDocumentRegistryBucket", { configFilePath: compilationSettings.configFilePath, key: keyWithMode }); + tracing.instant(tracing.Phase.Session, "createdDocumentRegistryBucket", { + configFilePath: compilationSettings.configFilePath, + key: keyWithMode, + }); } // It is fairly suspicious to have one path in two buckets - you'd expect dependencies to have similar configurations. // If this occurs unexpectedly, the fix is likely to synchronize the project settings. // Skip .d.ts files to reduce noise (should also cover most of node_modules). - const otherBucketKey = !isDeclarationFileName(path) && - forEachEntry(buckets, (bucket, bucketKey) => bucketKey !== keyWithMode && bucket.has(path) && bucketKey); + const otherBucketKey = !isDeclarationFileName(path) + && forEachEntry( + buckets, + (bucket, bucketKey) => bucketKey !== keyWithMode && bucket.has(path) && bucketKey, + ); if (otherBucketKey) { - tracing.instant(tracing.Phase.Session, "documentRegistryBucketOverlap", { path, key1: otherBucketKey, key2: keyWithMode }); + tracing.instant(tracing.Phase.Session, "documentRegistryBucketOverlap", { + path, + key1: otherBucketKey, + key2: keyWithMode, + }); } } @@ -276,7 +394,14 @@ namespace ts { if (!entry) { // Have never seen this file with these settings. Create a new source file for it. - const sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, sourceFileOptions, version, /*setNodeParents*/ false, scriptKind); + const sourceFile = createLanguageServiceSourceFile( + fileName, + scriptSnapshot, + sourceFileOptions, + version, + /*setNodeParents*/ false, + scriptKind, + ); if (externalCache) { externalCache.setDocument(keyWithMode, path, sourceFile); } @@ -291,7 +416,12 @@ namespace ts { // the script snapshot. If so, update it appropriately. Otherwise, we can just // return it as is. if (entry.sourceFile.version !== version) { - entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, scriptSnapshot.getChangeRange(entry.sourceFile.scriptSnapshot!)); // TODO: GH#18217 + entry.sourceFile = updateLanguageServiceSourceFile( + entry.sourceFile, + scriptSnapshot, + version, + scriptSnapshot.getChangeRange(entry.sourceFile.scriptSnapshot!), + ); // TODO: GH#18217 if (externalCache) { externalCache.setDocument(keyWithMode, path, entry.sourceFile); } @@ -326,14 +456,26 @@ namespace ts { } } - function releaseDocument(fileName: string, compilationSettings: CompilerOptions, scriptKind?: ScriptKind, impliedNodeFormat?: SourceFile["impliedNodeFormat"]): void { + function releaseDocument( + fileName: string, + compilationSettings: CompilerOptions, + scriptKind?: ScriptKind, + impliedNodeFormat?: SourceFile["impliedNodeFormat"], + ): void { const path = toPath(fileName, currentDirectory, getCanonicalFileName); const key = getKeyForCompilationSettings(compilationSettings); return releaseDocumentWithKey(path, key, scriptKind, impliedNodeFormat); } - function releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey, scriptKind?: ScriptKind, impliedNodeFormat?: SourceFile["impliedNodeFormat"]): void { - const bucket = Debug.checkDefined(buckets.get(getDocumentRegistryBucketKeyWithMode(key, impliedNodeFormat))); + function releaseDocumentWithKey( + path: Path, + key: DocumentRegistryBucketKey, + scriptKind?: ScriptKind, + impliedNodeFormat?: SourceFile["impliedNodeFormat"], + ): void { + const bucket = Debug.checkDefined( + buckets.get(getDocumentRegistryBucketKeyWithMode(key, impliedNodeFormat)), + ); const bucketEntry = bucket.get(path)!; const entry = getDocumentRegistryEntry(bucketEntry, scriptKind)!; entry.languageServiceRefCount--; @@ -390,10 +532,15 @@ namespace ts { } function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey { - return sourceFileAffectingCompilerOptions.map(option => compilerOptionValueToString(getCompilerOptionValue(settings, option))).join("|") + (settings.pathsBasePath ? `|${settings.pathsBasePath}` : undefined) as DocumentRegistryBucketKey; + return sourceFileAffectingCompilerOptions.map(option => + compilerOptionValueToString(getCompilerOptionValue(settings, option)) + ).join("|") + (settings.pathsBasePath ? `|${settings.pathsBasePath}` : undefined) as DocumentRegistryBucketKey; } - function getDocumentRegistryBucketKeyWithMode(key: DocumentRegistryBucketKey, mode: ModuleKind.ESNext | ModuleKind.CommonJS | undefined) { + function getDocumentRegistryBucketKeyWithMode( + key: DocumentRegistryBucketKey, + mode: ModuleKind.ESNext | ModuleKind.CommonJS | undefined, + ) { return (mode ? `${key}|${mode}` : key) as DocumentRegistryBucketKeyWithMode; } } diff --git a/src/services/exportInfoMap.ts b/src/services/exportInfoMap.ts index 03a3f2e4e5242..752f2b08e17ef 100644 --- a/src/services/exportInfoMap.ts +++ b/src/services/exportInfoMap.ts @@ -47,9 +47,28 @@ namespace ts { export interface ExportInfoMap { isUsableByFile(importingFile: Path): boolean; clear(): void; - add(importingFile: Path, symbol: Symbol, key: __String, moduleSymbol: Symbol, moduleFile: SourceFile | undefined, exportKind: ExportKind, isFromPackageJson: boolean, checker: TypeChecker): void; + add( + importingFile: Path, + symbol: Symbol, + key: __String, + moduleSymbol: Symbol, + moduleFile: SourceFile | undefined, + exportKind: ExportKind, + isFromPackageJson: boolean, + checker: TypeChecker, + ): void; get(importingFile: Path, key: string): readonly SymbolExportInfo[] | undefined; - search(importingFile: Path, preferCapitalized: boolean, matches: (name: string, targetFlags: SymbolFlags) => boolean, action: (info: readonly SymbolExportInfo[], symbolName: string, isFromAmbientModule: boolean, key: string) => T | undefined): T | undefined; + search( + importingFile: Path, + preferCapitalized: boolean, + matches: (name: string, targetFlags: SymbolFlags) => boolean, + action: ( + info: readonly SymbolExportInfo[], + symbolName: string, + isFromAmbientModule: boolean, + key: string, + ) => T | undefined, + ): T | undefined; releaseSymbols(): void; isEmpty(): boolean; /** @returns Whether the change resulted in the cache being cleared */ @@ -86,7 +105,16 @@ namespace ts { symbols.clear(); usableByFileName = undefined; }, - add: (importingFile, symbol, symbolTableKey, moduleSymbol, moduleFile, exportKind, isFromPackageJson, checker) => { + add: ( + importingFile, + symbol, + symbolTableKey, + moduleSymbol, + moduleFile, + exportKind, + isFromPackageJson, + checker, + ) => { if (importingFile !== usableByFileName) { cache.clear(); usableByFileName = importingFile; @@ -96,13 +124,20 @@ namespace ts { if (moduleFile) { const nodeModulesPathParts = getNodeModulePathParts(moduleFile.fileName); if (nodeModulesPathParts) { - const { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex } = nodeModulesPathParts; - packageName = unmangleScopedPackageName(getPackageNameFromTypesPackageName(moduleFile.fileName.substring(topLevelPackageNameIndex + 1, packageRootIndex))); + const { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex } = + nodeModulesPathParts; + packageName = unmangleScopedPackageName( + getPackageNameFromTypesPackageName( + moduleFile.fileName.substring(topLevelPackageNameIndex + 1, packageRootIndex), + ), + ); if (startsWith(importingFile, moduleFile.path.substring(0, topLevelNodeModulesIndex))) { const prevDeepestNodeModulesPath = packages.get(packageName); const nodeModulesPath = moduleFile.fileName.substring(0, topLevelPackageNameIndex + 1); if (prevDeepestNodeModulesPath) { - const prevDeepestNodeModulesIndex = prevDeepestNodeModulesPath.indexOf(nodeModulesPathPart); + const prevDeepestNodeModulesIndex = prevDeepestNodeModulesPath.indexOf( + nodeModulesPathPart, + ); if (topLevelNodeModulesIndex > prevDeepestNodeModulesIndex) { packages.set(packageName, nodeModulesPath); } @@ -137,21 +172,24 @@ namespace ts { const storedModuleSymbol = moduleSymbol.flags & SymbolFlags.Transient ? undefined : moduleSymbol; if (!storedSymbol || !storedModuleSymbol) symbols.set(id, [symbol, moduleSymbol]); - exportInfo.add(key(symbolName, symbol, isExternalModuleNameRelative(moduleName) ? undefined : moduleName, checker), { - id, - symbolTableKey, - symbolName, - capitalizedSymbolName, - moduleName, - moduleFile, - moduleFileName: moduleFile?.fileName, - packageName, - exportKind, - targetFlags: target.flags, - isFromPackageJson, - symbol: storedSymbol, - moduleSymbol: storedModuleSymbol, - }); + exportInfo.add( + key(symbolName, symbol, isExternalModuleNameRelative(moduleName) ? undefined : moduleName, checker), + { + id, + symbolTableKey, + symbolName, + capitalizedSymbolName, + moduleName, + moduleFile, + moduleFileName: moduleFile?.fileName, + packageName, + exportKind, + targetFlags: target.flags, + isFromPackageJson, + symbol: storedSymbol, + moduleSymbol: storedModuleSymbol, + }, + ); }, get: (importingFile, key) => { if (importingFile !== usableByFileName) return; @@ -165,7 +203,9 @@ namespace ts { const name = preferCapitalized && info[0].capitalizedSymbolName || symbolName; if (matches(name, info[0].targetFlags)) { const rehydrated = info.map(rehydrateCachedInfo); - const filtered = rehydrated.filter((r, i) => isNotShadowedByDeeperNodeModulesPackage(r, info[i].packageName)); + const filtered = rehydrated.filter((r, i) => + isNotShadowedByDeeperNodeModulesPackage(r, info[i].packageName) + ); if (filtered.length) { const res = action(filtered, name, !!ambientModuleName, key); if (res !== undefined) return res; @@ -182,15 +222,16 @@ namespace ts { return false; } if ( - usableByFileName && usableByFileName !== newSourceFile.path || + usableByFileName && usableByFileName !== newSourceFile.path // If ATA is enabled, auto-imports uses existing imports to guess whether you want auto-imports from node. // Adding or removing imports from node could change the outcome of that guess, so could change the suggestions list. - typeAcquisitionEnabled && consumesNodeCoreModules(oldSourceFile) !== consumesNodeCoreModules(newSourceFile) || + || typeAcquisitionEnabled + && consumesNodeCoreModules(oldSourceFile) !== consumesNodeCoreModules(newSourceFile) // Module agumentation and ambient module changes can add or remove exports available to be auto-imported. // Changes elsewhere in the file can change the *type* of an export in a module augmentation, // but type info is gathered in getCompletionEntryDetails, which doesn’t use the cache. - !arrayIsEqualTo(oldSourceFile.moduleAugmentations, newSourceFile.moduleAugmentations) || - !ambientModuleDeclarationsAreEqual(oldSourceFile, newSourceFile) + || !arrayIsEqualTo(oldSourceFile.moduleAugmentations, newSourceFile.moduleAugmentations) + || !ambientModuleDeclarationsAreEqual(oldSourceFile, newSourceFile) ) { cache.clear(); return true; @@ -229,7 +270,10 @@ namespace ts { const symbol = info.symbol || cachedSymbol || Debug.checkDefined( exportKind === ExportKind.ExportEquals ? checker.resolveExternalModuleSymbol(moduleSymbol) - : checker.tryGetMemberInModuleExportsAndProperties(unescapeLeadingUnderscores(info.symbolTableKey), moduleSymbol), + : checker.tryGetMemberInModuleExportsAndProperties( + unescapeLeadingUnderscores(info.symbolTableKey), + moduleSymbol, + ), `Could not find symbol '${info.symbolName}' by key '${info.symbolTableKey}' in module ${moduleSymbol.name}`, ); symbols.set(id, [symbol, moduleSymbol]); @@ -243,7 +287,12 @@ namespace ts { }; } - function key(importedName: string, symbol: Symbol, ambientModuleName: string | undefined, checker: TypeChecker): string { + function key( + importedName: string, + symbol: Symbol, + ambientModuleName: string | undefined, + checker: TypeChecker, + ): string { const moduleKey = ambientModuleName || ""; return `${importedName}|${getSymbolId(skipAlias(symbol, checker))}|${moduleKey}`; } @@ -256,7 +305,8 @@ namespace ts { } function fileIsGlobalOnly(file: SourceFile) { - return !file.commonJsModuleIndicator && !file.externalModuleIndicator && !file.moduleAugmentations && !file.ambientModuleNames; + return !file.commonJsModuleIndicator && !file.externalModuleIndicator && !file.moduleAugmentations + && !file.ambientModuleNames; } function ambientModuleDeclarationsAreEqual(oldSourceFile: SourceFile, newSourceFile: SourceFile) { @@ -266,10 +316,21 @@ namespace ts { let oldFileStatementIndex = -1; let newFileStatementIndex = -1; for (const ambientModuleName of newSourceFile.ambientModuleNames) { - const isMatchingModuleDeclaration = (node: Statement) => isNonGlobalAmbientModule(node) && node.name.text === ambientModuleName; - oldFileStatementIndex = findIndex(oldSourceFile.statements, isMatchingModuleDeclaration, oldFileStatementIndex + 1); - newFileStatementIndex = findIndex(newSourceFile.statements, isMatchingModuleDeclaration, newFileStatementIndex + 1); - if (oldSourceFile.statements[oldFileStatementIndex] !== newSourceFile.statements[newFileStatementIndex]) { + const isMatchingModuleDeclaration = (node: Statement) => + isNonGlobalAmbientModule(node) && node.name.text === ambientModuleName; + oldFileStatementIndex = findIndex( + oldSourceFile.statements, + isMatchingModuleDeclaration, + oldFileStatementIndex + 1, + ); + newFileStatementIndex = findIndex( + newSourceFile.statements, + isMatchingModuleDeclaration, + newFileStatementIndex + 1, + ); + if ( + oldSourceFile.statements[oldFileStatementIndex] !== newSourceFile.statements[newFileStatementIndex] + ) { return false; } } @@ -311,14 +372,21 @@ namespace ts { const toFile = program.getSourceFile(toPath); // Determine to import using toPath only if toPath is what we were looking at // or there doesnt exist the file in the program by the symlink - return (toFile === to || !toFile) && - isImportablePath(from.fileName, toPath, getCanonicalFileName, globalTypingsCache); + return (toFile === to || !toFile) + && isImportablePath(from.fileName, toPath, getCanonicalFileName, globalTypingsCache); }, ); if (packageJsonFilter) { - const isAutoImportable = hasImportablePath && packageJsonFilter.allowsImportingSourceFile(to, moduleSpecifierResolutionHost); - moduleSpecifierCache?.setBlockedByPackageJsonDependencies(from.path, to.path, preferences, {}, !isAutoImportable); + const isAutoImportable = hasImportablePath + && packageJsonFilter.allowsImportingSourceFile(to, moduleSpecifierResolutionHost); + moduleSpecifierCache?.setBlockedByPackageJsonDependencies( + from.path, + to.path, + preferences, + {}, + !isAutoImportable, + ); return isAutoImportable; } @@ -329,9 +397,17 @@ namespace ts { * Don't include something from a `node_modules` that isn't actually reachable by a global import. * A relative import to node_modules is usually a bad idea. */ - function isImportablePath(fromPath: string, toPath: string, getCanonicalFileName: GetCanonicalFileName, globalCachePath?: string): boolean { + function isImportablePath( + fromPath: string, + toPath: string, + getCanonicalFileName: GetCanonicalFileName, + globalCachePath?: string, + ): boolean { // If it's in a `node_modules` but is not reachable from here via a global import, don't bother. - const toNodeModules = forEachAncestorDirectory(toPath, ancestor => getBaseFileName(ancestor) === "node_modules" ? ancestor : undefined); + const toNodeModules = forEachAncestorDirectory( + toPath, + ancestor => getBaseFileName(ancestor) === "node_modules" ? ancestor : undefined, + ); const toNodeModulesParent = toNodeModules && getDirectoryPath(getCanonicalFileName(toNodeModules)); return toNodeModulesParent === undefined || startsWith(getCanonicalFileName(fromPath), toNodeModulesParent) @@ -346,26 +422,45 @@ namespace ts { cb: (module: Symbol, moduleFile: SourceFile | undefined, program: Program, isFromPackageJson: boolean) => void, ) { const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host); - const excludePatterns = preferences.autoImportFileExcludePatterns && mapDefined(preferences.autoImportFileExcludePatterns, spec => { - // The client is expected to send rooted path specs since we don't know - // what directory a relative path is relative to. - const pattern = getPatternFromSpec(spec, "", "exclude"); - return pattern ? getRegexFromPattern(pattern, useCaseSensitiveFileNames) : undefined; - }); + const excludePatterns = preferences.autoImportFileExcludePatterns + && mapDefined(preferences.autoImportFileExcludePatterns, spec => { + // The client is expected to send rooted path specs since we don't know + // what directory a relative path is relative to. + const pattern = getPatternFromSpec(spec, "", "exclude"); + return pattern ? getRegexFromPattern(pattern, useCaseSensitiveFileNames) : undefined; + }); - forEachExternalModule(program.getTypeChecker(), program.getSourceFiles(), excludePatterns, (module, file) => cb(module, file, program, /*isFromPackageJson*/ false)); + forEachExternalModule( + program.getTypeChecker(), + program.getSourceFiles(), + excludePatterns, + (module, file) => cb(module, file, program, /*isFromPackageJson*/ false), + ); const autoImportProvider = useAutoImportProvider && host.getPackageJsonAutoImportProvider?.(); if (autoImportProvider) { const start = timestamp(); - forEachExternalModule(autoImportProvider.getTypeChecker(), autoImportProvider.getSourceFiles(), excludePatterns, (module, file) => cb(module, file, autoImportProvider, /*isFromPackageJson*/ true)); + forEachExternalModule( + autoImportProvider.getTypeChecker(), + autoImportProvider.getSourceFiles(), + excludePatterns, + (module, file) => cb(module, file, autoImportProvider, /*isFromPackageJson*/ true), + ); host.log?.(`forEachExternalModuleToImportFrom autoImportProvider: ${timestamp() - start}`); } } - function forEachExternalModule(checker: TypeChecker, allSourceFiles: readonly SourceFile[], excludePatterns: readonly RegExp[] | undefined, cb: (module: Symbol, sourceFile: SourceFile | undefined) => void) { + function forEachExternalModule( + checker: TypeChecker, + allSourceFiles: readonly SourceFile[], + excludePatterns: readonly RegExp[] | undefined, + cb: (module: Symbol, sourceFile: SourceFile | undefined) => void, + ) { const isExcluded = (fileName: string) => excludePatterns?.some(p => p.test(fileName)); for (const ambient of checker.getAmbientModules()) { - if (!stringContains(ambient.name, "*") && !(excludePatterns && ambient.declarations?.every(d => isExcluded(d.getSourceFile().fileName)))) { + if ( + !stringContains(ambient.name, "*") + && !(excludePatterns && ambient.declarations?.every(d => isExcluded(d.getSourceFile().fileName))) + ) { cb(ambient, /*sourceFile*/ undefined); } } @@ -376,7 +471,13 @@ namespace ts { } } - export function getExportInfoMap(importingFile: SourceFile, host: LanguageServiceHost, program: Program, preferences: UserPreferences, cancellationToken: CancellationToken | undefined): ExportInfoMap { + export function getExportInfoMap( + importingFile: SourceFile, + host: LanguageServiceHost, + program: Program, + preferences: UserPreferences, + cancellationToken: CancellationToken | undefined, + ): ExportInfoMap { const start = timestamp(); // Pulling the AutoImportProvider project will trigger its updateGraph if pending, // which will invalidate the export map cache if things change, so pull it before @@ -397,40 +498,50 @@ namespace ts { const compilerOptions = program.getCompilerOptions(); let moduleCount = 0; try { - forEachExternalModuleToImportFrom(program, host, preferences, /*useAutoImportProvider*/ true, (moduleSymbol, moduleFile, program, isFromPackageJson) => { - if (++moduleCount % 100 === 0) cancellationToken?.throwIfCancellationRequested(); - const seenExports = new Map<__String, true>(); - const checker = program.getTypeChecker(); - const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); - // Note: I think we shouldn't actually see resolved module symbols here, but weird merges - // can cause it to happen: see 'completionsImport_mergedReExport.ts' - if (defaultInfo && isImportableSymbol(defaultInfo.symbol, checker)) { - cache.add( - importingFile.path, - defaultInfo.symbol, - defaultInfo.exportKind === ExportKind.Default ? InternalSymbolName.Default : InternalSymbolName.ExportEquals, - moduleSymbol, - moduleFile, - defaultInfo.exportKind, - isFromPackageJson, - checker, - ); - } - checker.forEachExportAndPropertyOfModule(moduleSymbol, (exported, key) => { - if (exported !== defaultInfo?.symbol && isImportableSymbol(exported, checker) && addToSeen(seenExports, key)) { + forEachExternalModuleToImportFrom( + program, + host, + preferences, + /*useAutoImportProvider*/ true, + (moduleSymbol, moduleFile, program, isFromPackageJson) => { + if (++moduleCount % 100 === 0) cancellationToken?.throwIfCancellationRequested(); + const seenExports = new Map<__String, true>(); + const checker = program.getTypeChecker(); + const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); + // Note: I think we shouldn't actually see resolved module symbols here, but weird merges + // can cause it to happen: see 'completionsImport_mergedReExport.ts' + if (defaultInfo && isImportableSymbol(defaultInfo.symbol, checker)) { cache.add( importingFile.path, - exported, - key, + defaultInfo.symbol, + defaultInfo.exportKind === ExportKind.Default ? InternalSymbolName.Default + : InternalSymbolName.ExportEquals, moduleSymbol, moduleFile, - ExportKind.Named, + defaultInfo.exportKind, isFromPackageJson, checker, ); } - }); - }); + checker.forEachExportAndPropertyOfModule(moduleSymbol, (exported, key) => { + if ( + exported !== defaultInfo?.symbol && isImportableSymbol(exported, checker) + && addToSeen(seenExports, key) + ) { + cache.add( + importingFile.path, + exported, + key, + moduleSymbol, + moduleFile, + ExportKind.Named, + isFromPackageJson, + checker, + ); + } + }); + }, + ); } catch (err) { // Ensure cache is reset if operation is cancelled @@ -442,7 +553,11 @@ namespace ts { return cache; } - export function getDefaultLikeExportInfo(moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions) { + export function getDefaultLikeExportInfo( + moduleSymbol: Symbol, + checker: TypeChecker, + compilerOptions: CompilerOptions, + ) { const exported = getDefaultLikeExportWorker(moduleSymbol, checker); if (!exported) return undefined; const { symbol, exportKind } = exported; @@ -451,17 +566,25 @@ namespace ts { } function isImportableSymbol(symbol: Symbol, checker: TypeChecker) { - return !checker.isUndefinedSymbol(symbol) && !checker.isUnknownSymbol(symbol) && !isKnownSymbol(symbol) && !isPrivateIdentifierSymbol(symbol); + return !checker.isUndefinedSymbol(symbol) && !checker.isUnknownSymbol(symbol) && !isKnownSymbol(symbol) + && !isPrivateIdentifierSymbol(symbol); } - function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol; readonly exportKind: ExportKind; } | undefined { + function getDefaultLikeExportWorker( + moduleSymbol: Symbol, + checker: TypeChecker, + ): { readonly symbol: Symbol; readonly exportKind: ExportKind; } | undefined { const exportEquals = checker.resolveExternalModuleSymbol(moduleSymbol); if (exportEquals !== moduleSymbol) return { symbol: exportEquals, exportKind: ExportKind.ExportEquals }; const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol); if (defaultExport) return { symbol: defaultExport, exportKind: ExportKind.Default }; } - function getDefaultExportInfoWorker(defaultExport: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol; readonly name: string; } | undefined { + function getDefaultExportInfoWorker( + defaultExport: Symbol, + checker: TypeChecker, + compilerOptions: CompilerOptions, + ): { readonly symbolForMeaning: Symbol; readonly name: string; } | undefined { const localSymbol = getLocalSymbolForExportDefault(defaultExport); if (localSymbol) return { symbolForMeaning: localSymbol, name: localSymbol.name }; @@ -480,12 +603,15 @@ namespace ts { } if ( - defaultExport.escapedName !== InternalSymbolName.Default && - defaultExport.escapedName !== InternalSymbolName.ExportEquals + defaultExport.escapedName !== InternalSymbolName.Default + && defaultExport.escapedName !== InternalSymbolName.ExportEquals ) { return { symbolForMeaning: defaultExport, name: defaultExport.getName() }; } - return { symbolForMeaning: defaultExport, name: getNameForExportedSymbol(defaultExport, compilerOptions.target) }; + return { + symbolForMeaning: defaultExport, + name: getNameForExportedSymbol(defaultExport, compilerOptions.target), + }; } function getNameForExportDefault(symbol: Symbol): string | undefined { @@ -494,7 +620,10 @@ namespace ts { return tryCast(skipOuterExpressions(declaration.expression), isIdentifier)?.text; } else if (isExportSpecifier(declaration)) { - Debug.assert(declaration.name.text === InternalSymbolName.Default, "Expected the specifier to be a default export"); + Debug.assert( + declaration.name.text === InternalSymbolName.Default, + "Expected the specifier to be a default export", + ); return declaration.propertyName && declaration.propertyName.text; } }); diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index f0d30b9e3bd14..931d1c689cb4c 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -19,7 +19,11 @@ namespace ts.FindAllReferences { | { readonly type: DefinitionKind.Keyword; readonly node: Node; } | { readonly type: DefinitionKind.This; readonly node: Node; } | { readonly type: DefinitionKind.String; readonly node: StringLiteralLike; } - | { readonly type: DefinitionKind.TripleSlashReference; readonly reference: FileReference; readonly file: SourceFile; }; + | { + readonly type: DefinitionKind.TripleSlashReference; + readonly reference: FileReference; + readonly file: SourceFile; + }; export const enum EntryKind { Span, @@ -28,7 +32,11 @@ namespace ts.FindAllReferences { SearchedLocalFoundProperty, SearchedPropertyFoundLocal, } - export type NodeEntryKind = EntryKind.Node | EntryKind.StringLiteral | EntryKind.SearchedLocalFoundProperty | EntryKind.SearchedPropertyFoundLocal; + export type NodeEntryKind = + | EntryKind.Node + | EntryKind.StringLiteral + | EntryKind.SearchedLocalFoundProperty + | EntryKind.SearchedPropertyFoundLocal; export type Entry = NodeEntry | SpanEntry; export interface ContextWithStartAndEndNode { start: Node; @@ -67,14 +75,17 @@ namespace ts.FindAllReferences { if (!isDeclaration(node.parent) && !isExportAssignment(node.parent)) { // Special property assignment in javascript if (isInJSFile(node)) { - const binaryExpression = isBinaryExpression(node.parent) ? - node.parent : - isAccessExpression(node.parent) && - isBinaryExpression(node.parent.parent) && - node.parent.parent.left === node.parent ? - node.parent.parent : - undefined; - if (binaryExpression && getAssignmentDeclarationKind(binaryExpression) !== AssignmentDeclarationKind.None) { + const binaryExpression = isBinaryExpression(node.parent) + ? node.parent + : isAccessExpression(node.parent) + && isBinaryExpression(node.parent.parent) + && node.parent.parent.left === node.parent + ? node.parent.parent + : undefined; + if ( + binaryExpression + && getAssignmentDeclarationKind(binaryExpression) !== AssignmentDeclarationKind.None + ) { return getContextNode(binaryExpression); } } @@ -84,9 +95,9 @@ namespace ts.FindAllReferences { return node.parent.parent; } else if ( - isJsxSelfClosingElement(node.parent) || - isLabeledStatement(node.parent) || - isBreakOrContinueStatement(node.parent) + isJsxSelfClosingElement(node.parent) + || isLabeledStatement(node.parent) + || isBreakOrContinueStatement(node.parent) ) { return node.parent; } @@ -94,31 +105,32 @@ namespace ts.FindAllReferences { const validImport = tryGetImportFromModuleSpecifier(node); if (validImport) { const declOrStatement = findAncestor(validImport, node => - isDeclaration(node) || - isStatement(node) || - isJSDocTag(node))! as NamedDeclaration | Statement | JSDocTag; - return isDeclaration(declOrStatement) ? - getContextNode(declOrStatement) : - declOrStatement; + isDeclaration(node) + || isStatement(node) + || isJSDocTag(node))! as NamedDeclaration | Statement | JSDocTag; + return isDeclaration(declOrStatement) + ? getContextNode(declOrStatement) + : declOrStatement; } } // Handle computed property name const propertyName = findAncestor(node, isComputedPropertyName); - return propertyName ? - getContextNode(propertyName.parent) : - undefined; + return propertyName + ? getContextNode(propertyName.parent) + : undefined; } if ( - node.parent.name === node || // node is name of declaration, use parent - isConstructorDeclaration(node.parent) || - isExportAssignment(node.parent) || + node.parent.name === node // node is name of declaration, use parent + || isConstructorDeclaration(node.parent) + || isExportAssignment(node.parent) // Property name of the import export specifier or binding pattern, use parent - ((isImportOrExportSpecifier(node.parent) || isBindingElement(node.parent)) - && node.parent.propertyName === node) || + || ((isImportOrExportSpecifier(node.parent) || isBindingElement(node.parent)) + && node.parent.propertyName === node) // Is default export - (node.kind === SyntaxKind.DefaultKeyword && hasSyntacticModifier(node.parent, ModifierFlags.ExportDefault)) + || (node.kind === SyntaxKind.DefaultKeyword + && hasSyntacticModifier(node.parent, ModifierFlags.ExportDefault)) ) { return getContextNode(node.parent); } @@ -126,17 +138,19 @@ namespace ts.FindAllReferences { return undefined; } - export function getContextNode(node: NamedDeclaration | BinaryExpression | ForInOrOfStatement | undefined): ContextNode | undefined { + export function getContextNode( + node: NamedDeclaration | BinaryExpression | ForInOrOfStatement | undefined, + ): ContextNode | undefined { if (!node) return undefined; switch (node.kind) { case SyntaxKind.VariableDeclaration: - return !isVariableDeclarationList(node.parent) || node.parent.declarations.length !== 1 ? - node : - isVariableStatement(node.parent.parent) ? - node.parent.parent : - isForInOrOfStatement(node.parent.parent) ? - getContextNode(node.parent.parent) : - node.parent; + return !isVariableDeclarationList(node.parent) || node.parent.declarations.length !== 1 + ? node + : isVariableStatement(node.parent.parent) + ? node.parent.parent + : isForInOrOfStatement(node.parent.parent) + ? getContextNode(node.parent.parent) + : node.parent; case SyntaxKind.BindingElement: return getContextNode(node.parent.parent as NamedDeclaration); @@ -153,9 +167,9 @@ namespace ts.FindAllReferences { return node.parent; case SyntaxKind.BinaryExpression: - return isExpressionStatement(node.parent) ? - node.parent : - node; + return isExpressionStatement(node.parent) + ? node.parent + : node; case SyntaxKind.ForOfStatement: case SyntaxKind.ForInStatement: @@ -166,25 +180,31 @@ namespace ts.FindAllReferences { case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - return isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent) ? - getContextNode( - findAncestor(node.parent, node => isBinaryExpression(node) || isForInOrOfStatement(node)) as BinaryExpression | ForInOrOfStatement, - ) : - node; + return isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent) + ? getContextNode( + findAncestor(node.parent, node => isBinaryExpression(node) || isForInOrOfStatement(node)) as + | BinaryExpression + | ForInOrOfStatement, + ) + : node; default: return node; } } - export function toContextSpan(textSpan: TextSpan, sourceFile: SourceFile, context?: ContextNode): { contextSpan: TextSpan; } | undefined { + export function toContextSpan( + textSpan: TextSpan, + sourceFile: SourceFile, + context?: ContextNode, + ): { contextSpan: TextSpan; } | undefined { if (!context) return undefined; - const contextSpan = isContextWithStartAndEndNode(context) ? - getTextSpan(context.start, sourceFile, context.end) : - getTextSpan(context, sourceFile); - return contextSpan.start !== textSpan.start || contextSpan.length !== textSpan.length ? - { contextSpan } : - undefined; + const contextSpan = isContextWithStartAndEndNode(context) + ? getTextSpan(context.start, sourceFile, context.end) + : getTextSpan(context, sourceFile); + return contextSpan.start !== textSpan.start || contextSpan.length !== textSpan.length + ? { contextSpan } + : undefined; } export const enum FindReferencesUse { @@ -218,20 +238,37 @@ namespace ts.FindAllReferences { readonly providePrefixAndSuffixTextForRename?: boolean; } - export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined { + export function findReferencedSymbols( + program: Program, + cancellationToken: CancellationToken, + sourceFiles: readonly SourceFile[], + sourceFile: SourceFile, + position: number, + ): ReferencedSymbol[] | undefined { const node = getTouchingPropertyName(sourceFile, position); const options = { use: FindReferencesUse.References }; - const referencedSymbols = Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options); + const referencedSymbols = Core.getReferencedSymbolsForNode( + position, + node, + program, + sourceFiles, + cancellationToken, + options, + ); const checker = program.getTypeChecker(); // Unless the starting node is a declaration (vs e.g. JSDoc), don't attempt to compute isDefinition const adjustedNode = Core.getAdjustedNode(node, options); const symbol = isDefinitionForReference(adjustedNode) ? checker.getSymbolAtLocation(adjustedNode) : undefined; - return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined(referencedSymbols, ({ definition, references }) => - // Only include referenced symbols that have a valid definition. - definition && { - definition: checker.runWithCancellationToken(cancellationToken, checker => definitionToReferencedSymbolDefinitionInfo(definition, checker, node)), - references: references.map(r => toReferencedSymbolEntry(r, symbol)), - }); + return !referencedSymbols || !referencedSymbols.length ? undefined + : mapDefined(referencedSymbols, ({ definition, references }) => + // Only include referenced symbols that have a valid definition. + definition && { + definition: checker.runWithCancellationToken(cancellationToken, checker => + definitionToReferencedSymbolDefinitionInfo(definition, checker, node)), + references: references.map(r => + toReferencedSymbolEntry(r, symbol) + ), + }); } function isDefinitionForReference(node: Node): boolean { @@ -241,7 +278,13 @@ namespace ts.FindAllReferences { || (node.kind === SyntaxKind.ConstructorKeyword && isConstructorDeclaration(node.parent)); } - export function getImplementationsAtPosition(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], sourceFile: SourceFile, position: number): ImplementationLocation[] | undefined { + export function getImplementationsAtPosition( + program: Program, + cancellationToken: CancellationToken, + sourceFiles: readonly SourceFile[], + sourceFile: SourceFile, + position: number, + ): ImplementationLocation[] | undefined { const node = getTouchingPropertyName(sourceFile, position); let referenceEntries: Entry[] | undefined; const entries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, node, position); @@ -263,7 +306,13 @@ namespace ts.FindAllReferences { continue; } referenceEntries = append(referenceEntries, entry); - const entries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, entry.node, entry.node.pos); + const entries = getImplementationReferenceEntries( + program, + cancellationToken, + sourceFiles, + entry.node, + entry.node.pos, + ); if (entries) { queue.enqueue(...entries); } @@ -273,7 +322,13 @@ namespace ts.FindAllReferences { return map(referenceEntries, entry => toImplementationLocation(entry, checker)); } - function getImplementationReferenceEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], node: Node, position: number): readonly Entry[] | undefined { + function getImplementationReferenceEntries( + program: Program, + cancellationToken: CancellationToken, + sourceFiles: readonly SourceFile[], + node: Node, + position: number, + ): readonly Entry[] | undefined { if (node.kind === SyntaxKind.SourceFile) { return undefined; } @@ -294,7 +349,10 @@ namespace ts.FindAllReferences { } else { // Perform "Find all References" and retrieve only those that are implementations - return getReferenceEntriesForNode(position, node, program, sourceFiles, cancellationToken, { implementations: true, use: FindReferencesUse.References }); + return getReferenceEntriesForNode(position, node, program, sourceFiles, cancellationToken, { + implementations: true, + use: FindReferencesUse.References, + }); } } @@ -307,7 +365,12 @@ namespace ts.FindAllReferences { options: Options | undefined, convertEntry: ToReferenceOrRenameEntry, ): T[] | undefined { - return map(flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options)), entry => convertEntry(entry, node, program.getTypeChecker())); + return map( + flattenEntries( + Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options), + ), + entry => convertEntry(entry, node, program.getTypeChecker()), + ); } export type ToReferenceOrRenameEntry = (entry: Entry, originalNode: Node, checker: TypeChecker) => T; @@ -321,15 +384,36 @@ namespace ts.FindAllReferences { options: Options = {}, sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName)), ): readonly Entry[] | undefined { - return flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options, sourceFilesSet)); + return flattenEntries( + Core.getReferencedSymbolsForNode( + position, + node, + program, + sourceFiles, + cancellationToken, + options, + sourceFilesSet, + ), + ); } function flattenEntries(referenceSymbols: readonly SymbolAndEntries[] | undefined): readonly Entry[] | undefined { return referenceSymbols && flatMap(referenceSymbols, r => r.references); } - function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: TypeChecker, originalNode: Node): ReferencedSymbolDefinitionInfo { - const info = ((): { sourceFile: SourceFile; textSpan: TextSpan; name: string; kind: ScriptElementKind; displayParts: SymbolDisplayPart[]; context?: Node | ContextWithStartAndEndNode; } => { + function definitionToReferencedSymbolDefinitionInfo( + def: Definition, + checker: TypeChecker, + originalNode: Node, + ): ReferencedSymbolDefinitionInfo { + const info = ((): { + sourceFile: SourceFile; + textSpan: TextSpan; + name: string; + kind: ScriptElementKind; + displayParts: SymbolDisplayPart[]; + context?: Node | ContextWithStartAndEndNode; + } => { switch (def.type) { case DefinitionKind.Symbol: { const { symbol } = def; @@ -347,12 +431,22 @@ namespace ts.FindAllReferences { } case DefinitionKind.Label: { const { node } = def; - return { ...getFileAndTextSpanFromNode(node), name: node.text, kind: ScriptElementKind.label, displayParts: [displayPart(node.text, SymbolDisplayPartKind.text)] }; + return { + ...getFileAndTextSpanFromNode(node), + name: node.text, + kind: ScriptElementKind.label, + displayParts: [displayPart(node.text, SymbolDisplayPartKind.text)], + }; } case DefinitionKind.Keyword: { const { node } = def; const name = tokenToString(node.kind)!; - return { ...getFileAndTextSpanFromNode(node), name, kind: ScriptElementKind.keyword, displayParts: [{ text: name, kind: ScriptElementKind.keyword }] }; + return { + ...getFileAndTextSpanFromNode(node), + name, + kind: ScriptElementKind.keyword, + displayParts: [{ text: name, kind: ScriptElementKind.keyword }], + }; } case DefinitionKind.This: { const { node } = def; @@ -364,7 +458,12 @@ namespace ts.FindAllReferences { getContainerNode(node), node, ).displayParts || [textPart("this")]; - return { ...getFileAndTextSpanFromNode(node), name: "this", kind: ScriptElementKind.variableElement, displayParts }; + return { + ...getFileAndTextSpanFromNode(node), + name: "this", + kind: ScriptElementKind.variableElement, + displayParts, + }; } case DefinitionKind.String: { const { node } = def; @@ -381,7 +480,9 @@ namespace ts.FindAllReferences { sourceFile: def.file, name: def.reference.fileName, kind: ScriptElementKind.string, - displayParts: [displayPart(`"${def.reference.fileName}"`, SymbolDisplayPartKind.stringLiteral)], + displayParts: [ + displayPart(`"${def.reference.fileName}"`, SymbolDisplayPartKind.stringLiteral), + ], }; } default: @@ -410,15 +511,34 @@ namespace ts.FindAllReferences { }; } - function getDefinitionKindAndDisplayParts(symbol: Symbol, checker: TypeChecker, node: Node): { displayParts: SymbolDisplayPart[]; kind: ScriptElementKind; } { + function getDefinitionKindAndDisplayParts( + symbol: Symbol, + checker: TypeChecker, + node: Node, + ): { displayParts: SymbolDisplayPart[]; kind: ScriptElementKind; } { const meaning = Core.getIntersectingMeaningFromDeclarations(node, symbol); const enclosingDeclaration = symbol.declarations && firstOrUndefined(symbol.declarations) || node; - const { displayParts, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, enclosingDeclaration.getSourceFile(), enclosingDeclaration, enclosingDeclaration, meaning); + const { displayParts, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind( + checker, + symbol, + enclosingDeclaration.getSourceFile(), + enclosingDeclaration, + enclosingDeclaration, + meaning, + ); return { displayParts, kind: symbolKind }; } - export function toRenameLocation(entry: Entry, originalNode: Node, checker: TypeChecker, providePrefixAndSuffixText: boolean): RenameLocation { - return { ...entryToDocumentSpan(entry), ...(providePrefixAndSuffixText && getPrefixAndSuffixText(entry, originalNode, checker)) }; + export function toRenameLocation( + entry: Entry, + originalNode: Node, + checker: TypeChecker, + providePrefixAndSuffixText: boolean, + ): RenameLocation { + return { + ...entryToDocumentSpan(entry), + ...(providePrefixAndSuffixText && getPrefixAndSuffixText(entry, originalNode, checker)), + }; } function toReferencedSymbolEntry(entry: Entry, symbol: Symbol | undefined): ReferencedSymbolEntry { @@ -468,7 +588,11 @@ namespace ts.FindAllReferences { const parent = node.parent; const name = originalNode.text; const isShorthandAssignment = isShorthandPropertyAssignment(parent); - if (isShorthandAssignment || (isObjectBindingElementWithoutPropertyName(parent) && parent.name === node && parent.dotDotDotToken === undefined)) { + if ( + isShorthandAssignment + || (isObjectBindingElementWithoutPropertyName(parent) && parent.name === node + && parent.dotDotDotToken === undefined) + ) { const prefixColon: PrefixAndSuffix = { prefixText: name + ": " }; const suffixColon: PrefixAndSuffix = { suffixText: ": " + name }; if (kind === EntryKind.SearchedLocalFoundProperty) { @@ -483,9 +607,9 @@ namespace ts.FindAllReferences { if (isShorthandAssignment) { const grandParent = parent.parent; if ( - isObjectLiteralExpression(grandParent) && - isBinaryExpression(grandParent.parent) && - isModuleExportsAccessExpression(grandParent.parent.left) + isObjectLiteralExpression(grandParent) + && isBinaryExpression(grandParent.parent) + && isModuleExportsAccessExpression(grandParent.parent.left) ) { return prefixColon; } @@ -497,14 +621,17 @@ namespace ts.FindAllReferences { } else if (isImportSpecifier(parent) && !parent.propertyName) { // If the original symbol was using this alias, just rename the alias. - const originalSymbol = isExportSpecifier(originalNode.parent) ? checker.getExportSpecifierLocalTargetSymbol(originalNode.parent) : checker.getSymbolAtLocation(originalNode); + const originalSymbol = isExportSpecifier(originalNode.parent) + ? checker.getExportSpecifierLocalTargetSymbol(originalNode.parent) + : checker.getSymbolAtLocation(originalNode); return contains(originalSymbol!.declarations, parent) ? { prefixText: name + " as " } : emptyOptions; } else if (isExportSpecifier(parent) && !parent.propertyName) { // If the symbol for the node is same as declared node symbol use prefix text - return originalNode === entry.node || checker.getSymbolAtLocation(originalNode) === checker.getSymbolAtLocation(entry.node) ? - { prefixText: name + " as " } : - { suffixText: " as " + name }; + return originalNode === entry.node + || checker.getSymbolAtLocation(originalNode) === checker.getSymbolAtLocation(entry.node) + ? { prefixText: name + " as " } + : { suffixText: " as " + name }; } } @@ -525,7 +652,10 @@ namespace ts.FindAllReferences { } } - function implementationKindDisplayParts(node: Node, checker: TypeChecker): { kind: ScriptElementKind; displayParts: SymbolDisplayPart[]; } { + function implementationKindDisplayParts( + node: Node, + checker: TypeChecker, + ): { kind: ScriptElementKind; displayParts: SymbolDisplayPart[]; } { const symbol = checker.getSymbolAtLocation(isDeclaration(node) && node.name ? node.name : node); if (symbol) { return getDefinitionKindAndDisplayParts(symbol, checker, node); @@ -533,13 +663,21 @@ namespace ts.FindAllReferences { else if (node.kind === SyntaxKind.ObjectLiteralExpression) { return { kind: ScriptElementKind.interfaceElement, - displayParts: [punctuationPart(SyntaxKind.OpenParenToken), textPart("object literal"), punctuationPart(SyntaxKind.CloseParenToken)], + displayParts: [ + punctuationPart(SyntaxKind.OpenParenToken), + textPart("object literal"), + punctuationPart(SyntaxKind.CloseParenToken), + ], }; } else if (node.kind === SyntaxKind.ClassExpression) { return { kind: ScriptElementKind.localClassElement, - displayParts: [punctuationPart(SyntaxKind.OpenParenToken), textPart("anonymous local class"), punctuationPart(SyntaxKind.CloseParenToken)], + displayParts: [ + punctuationPart(SyntaxKind.OpenParenToken), + textPart("anonymous local class"), + punctuationPart(SyntaxKind.CloseParenToken), + ], }; } else { @@ -581,23 +719,25 @@ namespace ts.FindAllReferences { } export function getTextSpanOfEntry(entry: Entry) { - return entry.kind === EntryKind.Span ? entry.textSpan : - getTextSpan(entry.node, entry.node.getSourceFile()); + return entry.kind === EntryKind.Span ? entry.textSpan + : getTextSpan(entry.node, entry.node.getSourceFile()); } /** A node is considered a writeAccess iff it is a name of a declaration or a target of an assignment */ function isWriteAccessForReference(node: Node): boolean { const decl = getDeclarationFromName(node); - return !!decl && declarationIsWriteAccess(decl) || node.kind === SyntaxKind.DefaultKeyword || isWriteAccess(node); + return !!decl && declarationIsWriteAccess(decl) || node.kind === SyntaxKind.DefaultKeyword + || isWriteAccess(node); } /** Whether a reference, `node`, is a definition of the `target` symbol */ export function isDeclarationOfSymbol(node: Node, target: Symbol | undefined): boolean { if (!target) return false; - const source = getDeclarationFromName(node) || - (node.kind === SyntaxKind.DefaultKeyword ? node.parent + const source = getDeclarationFromName(node) + || (node.kind === SyntaxKind.DefaultKeyword ? node.parent : isLiteralComputedPropertyDeclarationName(node) ? node.parent.parent - : node.kind === SyntaxKind.ConstructorKeyword && isConstructorDeclaration(node.parent) ? node.parent.parent + : node.kind === SyntaxKind.ConstructorKeyword && isConstructorDeclaration(node.parent) + ? node.parent.parent : undefined); const commonjsSource = source && isBinaryExpression(source) ? source.left as unknown as Declaration : undefined; return !!(source && target.declarations?.some(d => d === source || d === commonjsSource)); @@ -647,7 +787,13 @@ namespace ts.FindAllReferences { case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return !!(decl as FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration).body; + return !!(decl as + | FunctionDeclaration + | FunctionExpression + | ConstructorDeclaration + | MethodDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration).body; case SyntaxKind.VariableDeclaration: case SyntaxKind.PropertyDeclaration: @@ -667,7 +813,15 @@ namespace ts.FindAllReferences { /** Encapsulates the core find-all-references algorithm. */ export namespace Core { /** Core find-all-references algorithm. Handles special cases before delegating to `getReferencedSymbolsForSymbol`. */ - export function getReferencedSymbolsForNode(position: number, node: Node, program: Program, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName))): readonly SymbolAndEntries[] | undefined { + export function getReferencedSymbolsForNode( + position: number, + node: Node, + program: Program, + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + options: Options = {}, + sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName)), + ): readonly SymbolAndEntries[] | undefined { node = getAdjustedNode(node, options); if (isSourceFile(node)) { const resolvedRef = GoToDefinition.getReferenceAtPosition(node, position, program); @@ -676,14 +830,24 @@ namespace ts.FindAllReferences { } const moduleSymbol = program.getTypeChecker().getMergedSymbol(resolvedRef.file.symbol); if (moduleSymbol) { - return getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet); + return getReferencedSymbolsForModule( + program, + moduleSymbol, + /*excludeImportTypeOfExportEquals*/ false, + sourceFiles, + sourceFilesSet, + ); } const fileIncludeReasons = program.getFileIncludeReasons(); if (!fileIncludeReasons) { return undefined; } return [{ - definition: { type: DefinitionKind.TripleSlashReference, reference: resolvedRef.reference, file: node }, + definition: { + type: DefinitionKind.TripleSlashReference, + reference: resolvedRef.reference, + file: node, + }, references: getReferencesForNonModule(resolvedRef.file, fileIncludeReasons, program) || emptyArray, }]; } @@ -705,10 +869,18 @@ namespace ts.FindAllReferences { if (!options.implementations && isStringLiteralLike(node)) { if (isModuleSpecifierLike(node)) { const fileIncludeReasons = program.getFileIncludeReasons(); - const referencedFileName = node.getSourceFile().resolvedModules?.get(node.text, getModeForUsageLocation(node.getSourceFile(), node))?.resolvedFileName; - const referencedFile = referencedFileName ? program.getSourceFile(referencedFileName) : undefined; + const referencedFileName = node.getSourceFile().resolvedModules?.get( + node.text, + getModeForUsageLocation(node.getSourceFile(), node), + )?.resolvedFileName; + const referencedFile = referencedFileName ? program.getSourceFile(referencedFileName) + : undefined; if (referencedFile) { - return [{ definition: { type: DefinitionKind.String, node }, references: getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray }]; + return [{ + definition: { type: DefinitionKind.String, node }, + references: getReferencesForNonModule(referencedFile, fileIncludeReasons, program) + || emptyArray, + }]; } // Fall through to string literal references. This is not very likely to return // anything useful, but I guess it's better than nothing, and there's an existing @@ -720,19 +892,47 @@ namespace ts.FindAllReferences { } if (symbol.escapedName === InternalSymbolName.ExportEquals) { - return getReferencedSymbolsForModule(program, symbol.parent!, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet); + return getReferencedSymbolsForModule( + program, + symbol.parent!, + /*excludeImportTypeOfExportEquals*/ false, + sourceFiles, + sourceFilesSet, + ); } - const moduleReferences = getReferencedSymbolsForModuleIfDeclaredBySourceFile(symbol, program, sourceFiles, cancellationToken, options, sourceFilesSet); + const moduleReferences = getReferencedSymbolsForModuleIfDeclaredBySourceFile( + symbol, + program, + sourceFiles, + cancellationToken, + options, + sourceFilesSet, + ); if (moduleReferences && !(symbol.flags & SymbolFlags.Transient)) { return moduleReferences; } const aliasedSymbol = getMergedAliasedSymbolOfNamespaceExportDeclaration(node, symbol, checker); - const moduleReferencesOfExportTarget = aliasedSymbol && - getReferencedSymbolsForModuleIfDeclaredBySourceFile(aliasedSymbol, program, sourceFiles, cancellationToken, options, sourceFilesSet); + const moduleReferencesOfExportTarget = aliasedSymbol + && getReferencedSymbolsForModuleIfDeclaredBySourceFile( + aliasedSymbol, + program, + sourceFiles, + cancellationToken, + options, + sourceFilesSet, + ); - const references = getReferencedSymbolsForSymbol(symbol, node, sourceFiles, sourceFilesSet, checker, cancellationToken, options); + const references = getReferencedSymbolsForSymbol( + symbol, + node, + sourceFiles, + sourceFilesSet, + checker, + cancellationToken, + options, + ); return mergeReferences(program, moduleReferences, references, moduleReferencesOfExportTarget); } @@ -746,17 +946,33 @@ namespace ts.FindAllReferences { return node; } - export function getReferencesForFileName(fileName: string, program: Program, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName))): readonly Entry[] { + export function getReferencesForFileName( + fileName: string, + program: Program, + sourceFiles: readonly SourceFile[], + sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName)), + ): readonly Entry[] { const moduleSymbol = program.getSourceFile(fileName)?.symbol; if (moduleSymbol) { - return getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet)[0]?.references || emptyArray; + return getReferencedSymbolsForModule( + program, + moduleSymbol, + /*excludeImportTypeOfExportEquals*/ false, + sourceFiles, + sourceFilesSet, + )[0]?.references || emptyArray; } const fileIncludeReasons = program.getFileIncludeReasons(); const referencedFile = program.getSourceFile(fileName); - return referencedFile && fileIncludeReasons && getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray; + return referencedFile && fileIncludeReasons + && getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray; } - function getReferencesForNonModule(referencedFile: SourceFile, refFileMap: MultiMap, program: Program): readonly SpanEntry[] | undefined { + function getReferencesForNonModule( + referencedFile: SourceFile, + refFileMap: MultiMap, + program: Program, + ): readonly SpanEntry[] | undefined { let entries: SpanEntry[] | undefined; const references = refFileMap.get(referencedFile.path) || emptyArray; for (const ref of references) { @@ -786,23 +1002,52 @@ namespace ts.FindAllReferences { return undefined; } - function getReferencedSymbolsForModuleIfDeclaredBySourceFile(symbol: Symbol, program: Program, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken, options: Options, sourceFilesSet: ReadonlySet) { - const moduleSourceFile = (symbol.flags & SymbolFlags.Module) && symbol.declarations && find(symbol.declarations, isSourceFile); + function getReferencedSymbolsForModuleIfDeclaredBySourceFile( + symbol: Symbol, + program: Program, + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + options: Options, + sourceFilesSet: ReadonlySet, + ) { + const moduleSourceFile = (symbol.flags & SymbolFlags.Module) && symbol.declarations + && find(symbol.declarations, isSourceFile); if (!moduleSourceFile) return undefined; const exportEquals = symbol.exports!.get(InternalSymbolName.ExportEquals); // If !!exportEquals, we're about to add references to `import("mod")` anyway, so don't double-count them. - const moduleReferences = getReferencedSymbolsForModule(program, symbol, !!exportEquals, sourceFiles, sourceFilesSet); + const moduleReferences = getReferencedSymbolsForModule( + program, + symbol, + !!exportEquals, + sourceFiles, + sourceFilesSet, + ); if (!exportEquals || !sourceFilesSet.has(moduleSourceFile.fileName)) return moduleReferences; // Continue to get references to 'export ='. const checker = program.getTypeChecker(); symbol = skipAlias(exportEquals, checker); - return mergeReferences(program, moduleReferences, getReferencedSymbolsForSymbol(symbol, /*node*/ undefined, sourceFiles, sourceFilesSet, checker, cancellationToken, options)); + return mergeReferences( + program, + moduleReferences, + getReferencedSymbolsForSymbol( + symbol, + /*node*/ undefined, + sourceFiles, + sourceFilesSet, + checker, + cancellationToken, + options, + ), + ); } /** * Merges the references by sorting them (by file index in sourceFiles and their location in it) that point to same definition symbol */ - function mergeReferences(program: Program, ...referencesToMerge: (SymbolAndEntries[] | undefined)[]): SymbolAndEntries[] | undefined { + function mergeReferences( + program: Program, + ...referencesToMerge: (SymbolAndEntries[] | undefined)[] + ): SymbolAndEntries[] | undefined { let result: SymbolAndEntries[] | undefined; for (const references of referencesToMerge) { if (!references || !references.length) continue; @@ -817,9 +1062,9 @@ namespace ts.FindAllReferences { } const symbol = entry.definition.symbol; const refIndex = findIndex(result, ref => - !!ref.definition && - ref.definition.type === DefinitionKind.Symbol && - ref.definition.symbol === symbol); + !!ref.definition + && ref.definition.type === DefinitionKind.Symbol + && ref.definition.symbol === symbol); if (refIndex === -1) { result.push(entry); continue; @@ -837,9 +1082,9 @@ namespace ts.FindAllReferences { const entry1Span = getTextSpanOfEntry(entry1); const entry2Span = getTextSpanOfEntry(entry2); - return entry1Span.start !== entry2Span.start ? - compareValues(entry1Span.start, entry2Span.start) : - compareValues(entry1Span.length, entry2Span.length); + return entry1Span.start !== entry2Span.start + ? compareValues(entry1Span.start, entry2Span.start) + : compareValues(entry1Span.length, entry2Span.length); }), }; } @@ -848,35 +1093,44 @@ namespace ts.FindAllReferences { } function getSourceFileIndexOfEntry(program: Program, entry: Entry) { - const sourceFile = entry.kind === EntryKind.Span ? - program.getSourceFile(entry.fileName)! : - entry.node.getSourceFile(); + const sourceFile = entry.kind === EntryKind.Span + ? program.getSourceFile(entry.fileName)! + : entry.node.getSourceFile(); return program.getSourceFiles().indexOf(sourceFile); } - function getReferencedSymbolsForModule(program: Program, symbol: Symbol, excludeImportTypeOfExportEquals: boolean, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet): SymbolAndEntries[] { + function getReferencedSymbolsForModule( + program: Program, + symbol: Symbol, + excludeImportTypeOfExportEquals: boolean, + sourceFiles: readonly SourceFile[], + sourceFilesSet: ReadonlySet, + ): SymbolAndEntries[] { Debug.assert(!!symbol.valueDeclaration); - const references = mapDefined(findModuleReferences(program, sourceFiles, symbol), reference => { - if (reference.kind === "import") { - const parent = reference.literal.parent; - if (isLiteralTypeNode(parent)) { - const importType = cast(parent.parent, isImportTypeNode); - if (excludeImportTypeOfExportEquals && !importType.qualifier) { - return undefined; + const references = mapDefined( + findModuleReferences(program, sourceFiles, symbol), + reference => { + if (reference.kind === "import") { + const parent = reference.literal.parent; + if (isLiteralTypeNode(parent)) { + const importType = cast(parent.parent, isImportTypeNode); + if (excludeImportTypeOfExportEquals && !importType.qualifier) { + return undefined; + } } + // import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway. + return nodeEntry(reference.literal); } - // import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway. - return nodeEntry(reference.literal); - } - else { - return { - kind: EntryKind.Span, - fileName: reference.referencingFile.fileName, - textSpan: createTextSpanFromRange(reference.ref), - }; - } - }); + else { + return { + kind: EntryKind.Span, + fileName: reference.referencingFile.fileName, + textSpan: createTextSpanFromRange(reference.ref), + }; + } + }, + ); if (symbol.declarations) { for (const decl of symbol.declarations) { @@ -891,7 +1145,10 @@ namespace ts.FindAllReferences { break; default: // This may be merged with something. - Debug.assert(!!(symbol.flags & SymbolFlags.Transient), "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration."); + Debug.assert( + !!(symbol.flags & SymbolFlags.Transient), + "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration.", + ); } } } @@ -902,15 +1159,18 @@ namespace ts.FindAllReferences { const sourceFile = decl.getSourceFile(); if (sourceFilesSet.has(sourceFile.fileName)) { // At `module.exports = ...`, reference node is `module` - const node = isBinaryExpression(decl) && isPropertyAccessExpression(decl.left) ? decl.left.expression : - isExportAssignment(decl) ? Debug.checkDefined(findChildOfKind(decl, SyntaxKind.ExportKeyword, sourceFile)) : - getNameOfDeclaration(decl) || decl; + const node = isBinaryExpression(decl) && isPropertyAccessExpression(decl.left) + ? decl.left.expression + : isExportAssignment(decl) + ? Debug.checkDefined(findChildOfKind(decl, SyntaxKind.ExportKeyword, sourceFile)) + : getNameOfDeclaration(decl) || decl; references.push(nodeEntry(node)); } } } - return references.length ? [{ definition: { type: DefinitionKind.Symbol, symbol }, references }] : emptyArray; + return references.length ? [{ definition: { type: DefinitionKind.Symbol, symbol }, references }] + : emptyArray; } /** As in a `readonly prop: any` or `constructor(readonly prop: any)`, not a `readonly any[]`. */ @@ -921,7 +1181,11 @@ namespace ts.FindAllReferences { } /** getReferencedSymbols for special node kinds. */ - function getReferencedSymbolsSpecial(node: Node, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined { + function getReferencedSymbolsSpecial( + node: Node, + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + ): SymbolAndEntries[] | undefined { if (isTypeKeyword(node.kind)) { // A void expression (i.e., `void foo()`) is not special, but the `void` type is. if (node.kind === SyntaxKind.VoidKeyword && isVoidExpression(node.parent)) { @@ -975,25 +1239,73 @@ namespace ts.FindAllReferences { } /** Core find-all-references algorithm for a normal symbol. */ - function getReferencedSymbolsForSymbol(originalSymbol: Symbol, node: Node | undefined, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet, checker: TypeChecker, cancellationToken: CancellationToken, options: Options): SymbolAndEntries[] { - const symbol = node && skipPastExportOrImportSpecifierOrUnion(originalSymbol, node, checker, /*useLocalSymbolForExportSpecifier*/ !isForRenameWithPrefixAndSuffixText(options)) || originalSymbol; + function getReferencedSymbolsForSymbol( + originalSymbol: Symbol, + node: Node | undefined, + sourceFiles: readonly SourceFile[], + sourceFilesSet: ReadonlySet, + checker: TypeChecker, + cancellationToken: CancellationToken, + options: Options, + ): SymbolAndEntries[] { + const symbol = node + && skipPastExportOrImportSpecifierOrUnion( + originalSymbol, + node, + checker, + /*useLocalSymbolForExportSpecifier*/ !isForRenameWithPrefixAndSuffixText(options), + ) || originalSymbol; // Compute the meaning from the location and the symbol it references const searchMeaning = node ? getIntersectingMeaningFromDeclarations(node, symbol) : SemanticMeaning.All; const result: SymbolAndEntries[] = []; - const state = new State(sourceFiles, sourceFilesSet, node ? getSpecialSearchKind(node) : SpecialSearchKind.None, checker, cancellationToken, searchMeaning, options, result); + const state = new State( + sourceFiles, + sourceFilesSet, + node ? getSpecialSearchKind(node) : SpecialSearchKind.None, + checker, + cancellationToken, + searchMeaning, + options, + result, + ); - const exportSpecifier = !isForRenameWithPrefixAndSuffixText(options) || !symbol.declarations ? undefined : find(symbol.declarations, isExportSpecifier); + const exportSpecifier = !isForRenameWithPrefixAndSuffixText(options) || !symbol.declarations ? undefined + : find(symbol.declarations, isExportSpecifier); if (exportSpecifier) { // When renaming at an export specifier, rename the export and not the thing being exported. - getReferencesAtExportSpecifier(exportSpecifier.name, symbol, exportSpecifier, state.createSearch(node, originalSymbol, /*comingFrom*/ undefined), state, /*addReferencesHere*/ true, /*alwaysGetReferences*/ true); + getReferencesAtExportSpecifier( + exportSpecifier.name, + symbol, + exportSpecifier, + state.createSearch(node, originalSymbol, /*comingFrom*/ undefined), + state, + /*addReferencesHere*/ true, + /*alwaysGetReferences*/ true, + ); } - else if (node && node.kind === SyntaxKind.DefaultKeyword && symbol.escapedName === InternalSymbolName.Default && symbol.parent) { + else if ( + node && node.kind === SyntaxKind.DefaultKeyword && symbol.escapedName === InternalSymbolName.Default + && symbol.parent + ) { addReference(node, symbol, state); - searchForImportsOfExport(node, symbol, { exportingModuleSymbol: symbol.parent, exportKind: ExportKind.Default }, state); + searchForImportsOfExport(node, symbol, { + exportingModuleSymbol: symbol.parent, + exportKind: ExportKind.Default, + }, state); } else { - const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, options.use === FindReferencesUse.Rename, !!options.providePrefixAndSuffixTextForRename, !!options.implementations) : [symbol] }); + const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { + allSearchSymbols: node + ? populateSearchSymbolSet( + symbol, + node, + checker, + options.use === FindReferencesUse.Rename, + !!options.providePrefixAndSuffixTextForRename, + !!options.implementations, + ) : [symbol], + }); getReferencesInContainerOrFiles(symbol, state, search); } @@ -1005,7 +1317,13 @@ namespace ts.FindAllReferences { // otherwise we'll need to search globally (i.e. include each file). const scope = getSymbolScope(symbol); if (scope) { - getReferencesInContainer(scope, scope.getSourceFile(), search, state, /*addReferencesHere*/ !(isSourceFile(scope) && !contains(state.sourceFiles, scope))); + getReferencesInContainer( + scope, + scope.getSourceFile(), + search, + state, + /*addReferencesHere*/ !(isSourceFile(scope) && !contains(state.sourceFiles, scope)), + ); } else { // Global search @@ -1033,7 +1351,12 @@ namespace ts.FindAllReferences { } /** Handle a few special cases relating to export/import specifiers. */ - function skipPastExportOrImportSpecifierOrUnion(symbol: Symbol, node: Node, checker: TypeChecker, useLocalSymbolForExportSpecifier: boolean): Symbol | undefined { + function skipPastExportOrImportSpecifierOrUnion( + symbol: Symbol, + node: Node, + checker: TypeChecker, + useLocalSymbolForExportSpecifier: boolean, + ): Symbol | undefined { const { parent } = node; if (isExportSpecifier(parent) && useLocalSymbolForExportSpecifier) { return getLocalSymbolForExportSpecifier(node as Identifier, symbol, parent, checker); @@ -1044,7 +1367,9 @@ namespace ts.FindAllReferences { // Ignore UMD module and global merge if (symbol.flags & SymbolFlags.Transient) return undefined; // Assertions for GH#21814. We should be handling SourceFile symbols in `getReferencedSymbolsForModule` instead of getting here. - Debug.fail(`Unexpected symbol at ${Debug.formatSyntaxKind(node.kind)}: ${Debug.formatSymbol(symbol)}`); + Debug.fail( + `Unexpected symbol at ${Debug.formatSyntaxKind(node.kind)}: ${Debug.formatSymbol(symbol)}`, + ); } return isTypeLiteralNode(decl.parent) && isUnionTypeNode(decl.parent.parent) ? checker.getPropertyOfType(checker.getTypeFromTypeNode(decl.parent.parent), symbol.name) @@ -1082,7 +1407,8 @@ namespace ts.FindAllReferences { function getNonModuleSymbolOfMergedModuleSymbol(symbol: Symbol) { if (!(symbol.flags & (SymbolFlags.Module | SymbolFlags.Transient))) return undefined; - const decl = symbol.declarations && find(symbol.declarations, d => !isSourceFile(d) && !isModuleDeclaration(d)); + const decl = symbol.declarations + && find(symbol.declarations, d => !isSourceFile(d) && !isModuleDeclaration(d)); return decl && decl.symbol; } @@ -1135,23 +1461,49 @@ namespace ts.FindAllReferences { private importTracker: ImportTracker | undefined; /** Gets every place to look for references of an exported symbols. See `ImportsResult` in `importTracker.ts` for more documentation. */ getImportSearches(exportSymbol: Symbol, exportInfo: ExportInfo): ImportsResult { - if (!this.importTracker) this.importTracker = createImportTracker(this.sourceFiles, this.sourceFilesSet, this.checker, this.cancellationToken); + if (!this.importTracker) { + this.importTracker = createImportTracker( + this.sourceFiles, + this.sourceFilesSet, + this.checker, + this.cancellationToken, + ); + } return this.importTracker(exportSymbol, exportInfo, this.options.use === FindReferencesUse.Rename); } /** @param allSearchSymbols set of additional symbols for use by `includes`. */ - createSearch(location: Node | undefined, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions: { text?: string; allSearchSymbols?: Symbol[]; } = {}): Search { + createSearch( + location: Node | undefined, + symbol: Symbol, + comingFrom: ImportExport | undefined, + searchOptions: { text?: string; allSearchSymbols?: Symbol[]; } = {}, + ): Search { // Note: if this is an external module symbol, the name doesn't include quotes. // Note: getLocalSymbolForExportDefault handles `export default class C {}`, but not `export default C` or `export { C as default }`. // The other two forms seem to be handled downstream (e.g. in `skipPastExportOrImportSpecifier`), so special-casing the first form // here appears to be intentional). const { - text = stripQuotes(symbolName(getLocalSymbolForExportDefault(symbol) || getNonModuleSymbolOfMergedModuleSymbol(symbol) || symbol)), + text = stripQuotes( + symbolName( + getLocalSymbolForExportDefault(symbol) || getNonModuleSymbolOfMergedModuleSymbol(symbol) + || symbol, + ), + ), allSearchSymbols = [symbol], } = searchOptions; const escapedText = escapeLeadingUnderscores(text); - const parents = this.options.implementations && location ? getParentSymbolsOfPropertyAccess(location, symbol, this.checker) : undefined; - return { symbol, comingFrom, text, escapedText, parents, allSearchSymbols, includes: sym => contains(allSearchSymbols, sym) }; + const parents = this.options.implementations && location + ? getParentSymbolsOfPropertyAccess(location, symbol, this.checker) : undefined; + return { + symbol, + comingFrom, + text, + escapedText, + parents, + allSearchSymbols, + includes: sym => contains(allSearchSymbols, sym), + }; } private readonly symbolIdToReferences: Entry[][] = []; @@ -1182,7 +1534,8 @@ namespace ts.FindAllReferences { /** Returns `true` the first time we search for a symbol in a file and `false` afterwards. */ markSearchedSymbols(sourceFile: SourceFile, symbols: readonly Symbol[]): boolean { const sourceId = getNodeId(sourceFile); - const seenSymbols = this.sourceFileToSeenSymbols[sourceId] || (this.sourceFileToSeenSymbols[sourceId] = new Set()); + const seenSymbols = this.sourceFileToSeenSymbols[sourceId] + || (this.sourceFileToSeenSymbols[sourceId] = new Set()); let anyNewSymbols = false; for (const sym of symbols) { @@ -1193,8 +1546,16 @@ namespace ts.FindAllReferences { } /** Search for all imports of a given exported symbol using `State.getImportSearches`. */ - function searchForImportsOfExport(exportLocation: Node, exportSymbol: Symbol, exportInfo: ExportInfo, state: State): void { - const { importSearches, singleReferences, indirectUsers } = state.getImportSearches(exportSymbol, exportInfo); + function searchForImportsOfExport( + exportLocation: Node, + exportSymbol: Symbol, + exportInfo: ExportInfo, + state: State, + ): void { + const { importSearches, singleReferences, indirectUsers } = state.getImportSearches( + exportSymbol, + exportInfo, + ); // For `import { foo as bar }` just add the reference to `foo`, and don't otherwise search in the file. if (singleReferences.length) { @@ -1206,7 +1567,11 @@ namespace ts.FindAllReferences { // For each import, find all references to that import in its source file. for (const [importLocation, importSymbol] of importSearches) { - getReferencesInSourceFile(importLocation.getSourceFile(), state.createSearch(importLocation, importSymbol, ImportExport.Export), state); + getReferencesInSourceFile( + importLocation.getSourceFile(), + state.createSearch(importLocation, importSymbol, ImportExport.Export), + state, + ); } if (indirectUsers.length) { @@ -1217,7 +1582,10 @@ namespace ts.FindAllReferences { break; case ExportKind.Default: // Search for a property access to '.default'. This can't be renamed. - indirectSearch = state.options.use === FindReferencesUse.Rename ? undefined : state.createSearch(exportLocation, exportSymbol, ImportExport.Export, { text: "default" }); + indirectSearch = state.options.use === FindReferencesUse.Rename ? undefined + : state.createSearch(exportLocation, exportSymbol, ImportExport.Export, { + text: "default", + }); break; case ExportKind.ExportEquals: break; @@ -1240,8 +1608,16 @@ namespace ts.FindAllReferences { isDefaultExport: boolean, cb: (ref: Identifier) => void, ): void { - const importTracker = createImportTracker(sourceFiles, new Set(sourceFiles.map(f => f.fileName)), checker, cancellationToken); - const { importSearches, indirectUsers, singleReferences } = importTracker(exportSymbol, { exportKind: isDefaultExport ? ExportKind.Default : ExportKind.Named, exportingModuleSymbol }, /*isForRename*/ false); + const importTracker = createImportTracker( + sourceFiles, + new Set(sourceFiles.map(f => f.fileName)), + checker, + cancellationToken, + ); + const { importSearches, indirectUsers, singleReferences } = importTracker(exportSymbol, { + exportKind: isDefaultExport ? ExportKind.Default : ExportKind.Named, + exportingModuleSymbol, + }, /*isForRename*/ false); for (const [importLocation] of importSearches) { cb(importLocation); } @@ -1251,11 +1627,22 @@ namespace ts.FindAllReferences { } } for (const indirectUser of indirectUsers) { - for (const node of getPossibleSymbolReferenceNodes(indirectUser, isDefaultExport ? "default" : exportName)) { + for ( + const node of getPossibleSymbolReferenceNodes( + indirectUser, + isDefaultExport ? "default" : exportName, + ) + ) { // Import specifiers should be handled by importSearches const symbol = checker.getSymbolAtLocation(node); - const hasExportAssignmentDeclaration = some(symbol?.declarations, d => tryCast(d, isExportAssignment) ? true : false); - if (isIdentifier(node) && !isImportOrExportSpecifier(node.parent) && (symbol === exportSymbol || hasExportAssignmentDeclaration)) { + const hasExportAssignmentDeclaration = some( + symbol?.declarations, + d => tryCast(d, isExportAssignment) ? true : false, + ); + if ( + isIdentifier(node) && !isImportOrExportSpecifier(node.parent) + && (symbol === exportSymbol || hasExportAssignmentDeclaration) + ) { cb(node); } } @@ -1268,7 +1655,8 @@ namespace ts.FindAllReferences { // Don't rename an import type `import("./module-name")` when renaming `name` in `export = name;` if (!isIdentifier(singleRef)) return false; // At `default` in `import { default as x }` or `export { default as x }`, do add a reference, but do not rename. - return !(isImportOrExportSpecifier(singleRef.parent) && singleRef.escapedText === InternalSymbolName.Default); + return !(isImportOrExportSpecifier(singleRef.parent) + && singleRef.escapedText === InternalSymbolName.Default); } // Go to the symbol we imported from and find references for it. @@ -1278,7 +1666,12 @@ namespace ts.FindAllReferences { for (const declaration of symbol.declarations) { const exportingFile = declaration.getSourceFile(); // Need to search in the file even if it's not in the search-file set, because it might export the symbol. - getReferencesInSourceFile(exportingFile, state.createSearch(declaration, symbol, ImportExport.Import), state, state.includesSourceFile(exportingFile)); + getReferencesInSourceFile( + exportingFile, + state.createSearch(declaration, symbol, ImportExport.Import), + state, + state.includesSourceFile(exportingFile), + ); } } @@ -1307,7 +1700,11 @@ namespace ts.FindAllReferences { // If this is the symbol of a named function expression or named class expression, // then named references are limited to its own scope. const { declarations, flags, parent, valueDeclaration } = symbol; - if (valueDeclaration && (valueDeclaration.kind === SyntaxKind.FunctionExpression || valueDeclaration.kind === SyntaxKind.ClassExpression)) { + if ( + valueDeclaration + && (valueDeclaration.kind === SyntaxKind.FunctionExpression + || valueDeclaration.kind === SyntaxKind.ClassExpression) + ) { return valueDeclaration; } @@ -1317,7 +1714,11 @@ namespace ts.FindAllReferences { // If this is private property or method, the scope is the containing class if (flags & (SymbolFlags.Property | SymbolFlags.Method)) { - const privateDeclaration = find(declarations, d => hasEffectiveModifier(d, ModifierFlags.Private) || isPrivateIdentifierClassElementDeclaration(d)); + const privateDeclaration = find( + declarations, + d => hasEffectiveModifier(d, ModifierFlags.Private) + || isPrivateIdentifierClassElementDeclaration(d), + ); if (privateDeclaration) { return getAncestor(privateDeclaration, SyntaxKind.ClassDeclaration); } @@ -1351,7 +1752,10 @@ namespace ts.FindAllReferences { return undefined; } - if (!container || container.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(container as SourceFile)) { + if ( + !container + || container.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(container as SourceFile) + ) { // This is a global variable and not an external module, any declaration defined // within this scope is visible outside the file return undefined; @@ -1375,22 +1779,36 @@ namespace ts.FindAllReferences { } /** Used as a quick check for whether a symbol is used at all in a file (besides its definition). */ - export function isSymbolReferencedInFile(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile, searchContainer: Node = sourceFile): boolean { + export function isSymbolReferencedInFile( + definition: Identifier, + checker: TypeChecker, + sourceFile: SourceFile, + searchContainer: Node = sourceFile, + ): boolean { return eachSymbolReferenceInFile(definition, checker, sourceFile, () => true, searchContainer) || false; } - export function eachSymbolReferenceInFile(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile, cb: (token: Identifier) => T, searchContainer: Node = sourceFile): T | undefined { + export function eachSymbolReferenceInFile( + definition: Identifier, + checker: TypeChecker, + sourceFile: SourceFile, + cb: (token: Identifier) => T, + searchContainer: Node = sourceFile, + ): T | undefined { const symbol = isParameterPropertyDeclaration(definition.parent, definition.parent.parent) ? first(checker.getSymbolsOfParameterPropertyDeclaration(definition.parent, definition.text)) : checker.getSymbolAtLocation(definition); if (!symbol) return undefined; for (const token of getPossibleSymbolReferenceNodes(sourceFile, symbol.name, searchContainer)) { - if (!isIdentifier(token) || token === definition || token.escapedText !== definition.escapedText) continue; + if (!isIdentifier(token) || token === definition || token.escapedText !== definition.escapedText) { + continue; + } const referenceSymbol = checker.getSymbolAtLocation(token)!; if ( referenceSymbol === symbol || checker.getShorthandAssignmentValueSymbol(token.parent) === symbol - || isExportSpecifier(token.parent) && getLocalSymbolForExportSpecifier(token, referenceSymbol, token.parent, checker) === symbol + || isExportSpecifier(token.parent) + && getLocalSymbolForExportSpecifier(token, referenceSymbol, token.parent, checker) === symbol ) { const res = cb(token); if (res) return res; @@ -1398,8 +1816,14 @@ namespace ts.FindAllReferences { } } - export function getTopMostDeclarationNamesInFile(declarationName: string, sourceFile: SourceFile): readonly Node[] { - const candidates = filter(getPossibleSymbolReferenceNodes(sourceFile, declarationName), name => !!getDeclarationFromName(name)); + export function getTopMostDeclarationNamesInFile( + declarationName: string, + sourceFile: SourceFile, + ): readonly Node[] { + const candidates = filter( + getPossibleSymbolReferenceNodes(sourceFile, declarationName), + name => !!getDeclarationFromName(name), + ); return candidates.reduce((topMost, decl) => { const depth = getDepth(decl); if (!some(topMost.declarationNames) || depth === topMost.depth) { @@ -1435,9 +1859,13 @@ namespace ts.FindAllReferences { for (const sourceFile of sourceFiles) { for (const name of getPossibleSymbolReferenceNodes(sourceFile, symbol.name)) { - if (!isIdentifier(name) || name === signature.name || name.escapedText !== signature.name.escapedText) continue; + if ( + !isIdentifier(name) || name === signature.name + || name.escapedText !== signature.name.escapedText + ) continue; const called = climbPastPropertyAccess(name); - const call = isCallExpression(called.parent) && called.parent.expression === called ? called.parent : undefined; + const call = isCallExpression(called.parent) && called.parent.expression === called ? called.parent + : undefined; const referenceSymbol = checker.getSymbolAtLocation(name); if (referenceSymbol && checker.getRootSymbols(referenceSymbol).some(s => s === symbol)) { if (cb(name, call)) { @@ -1449,11 +1877,21 @@ namespace ts.FindAllReferences { return false; } - function getPossibleSymbolReferenceNodes(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): readonly Node[] { - return getPossibleSymbolReferencePositions(sourceFile, symbolName, container).map(pos => getTouchingPropertyName(sourceFile, pos)); + function getPossibleSymbolReferenceNodes( + sourceFile: SourceFile, + symbolName: string, + container: Node = sourceFile, + ): readonly Node[] { + return getPossibleSymbolReferencePositions(sourceFile, symbolName, container).map(pos => + getTouchingPropertyName(sourceFile, pos) + ); } - function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): readonly number[] { + function getPossibleSymbolReferencePositions( + sourceFile: SourceFile, + symbolName: string, + container: Node = sourceFile, + ): readonly number[] { const positions: number[] = []; /// TODO: Cache symbol existence for files to save text search @@ -1478,8 +1916,9 @@ namespace ts.FindAllReferences { const endPosition = position + symbolNameLength; if ( - (position === 0 || !isIdentifierPart(text.charCodeAt(position - 1), ScriptTarget.Latest)) && - (endPosition === sourceLength || !isIdentifierPart(text.charCodeAt(endPosition), ScriptTarget.Latest)) + (position === 0 || !isIdentifierPart(text.charCodeAt(position - 1), ScriptTarget.Latest)) + && (endPosition === sourceLength + || !isIdentifierPart(text.charCodeAt(endPosition), ScriptTarget.Latest)) ) { // Found a real match. Keep searching. positions.push(position); @@ -1495,7 +1934,8 @@ namespace ts.FindAllReferences { const labelName = targetLabel.text; const references = mapDefined(getPossibleSymbolReferenceNodes(sourceFile, labelName, container), node => // Only pick labels that are either the target label, or have a target that is the target label - node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel) ? nodeEntry(node) : undefined); + node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel) + ? nodeEntry(node) : undefined); return [{ definition: { type: DefinitionKind.Label, node: targetLabel }, references }]; } @@ -1512,12 +1952,16 @@ namespace ts.FindAllReferences { case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.StringLiteral: { const str = node as StringLiteralLike; - return (isLiteralNameOfPropertyDeclarationOrIndexAccess(str) || isNameOfModuleDeclaration(node) || isExpressionOfExternalModuleImportEqualsDeclaration(node) || (isCallExpression(node.parent) && isBindableObjectDefinePropertyCall(node.parent) && node.parent.arguments[1] === node)) && - str.text.length === searchSymbolName.length; + return (isLiteralNameOfPropertyDeclarationOrIndexAccess(str) || isNameOfModuleDeclaration(node) + || isExpressionOfExternalModuleImportEqualsDeclaration(node) + || (isCallExpression(node.parent) && isBindableObjectDefinePropertyCall(node.parent) + && node.parent.arguments[1] === node)) + && str.text.length === searchSymbolName.length; } case SyntaxKind.NumericLiteral: - return isLiteralNameOfPropertyDeclarationOrIndexAccess(node as NumericLiteral) && (node as NumericLiteral).text.length === searchSymbolName.length; + return isLiteralNameOfPropertyDeclarationOrIndexAccess(node as NumericLiteral) + && (node as NumericLiteral).text.length === searchSymbolName.length; case SyntaxKind.DefaultKeyword: return "default".length === searchSymbolName.length; @@ -1527,7 +1971,10 @@ namespace ts.FindAllReferences { } } - function getAllReferencesForImportMeta(sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined { + function getAllReferencesForImportMeta( + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + ): SymbolAndEntries[] | undefined { const references = flatMap(sourceFiles, sourceFile => { cancellationToken.throwIfCancellationRequested(); return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, "meta", sourceFile), node => { @@ -1537,22 +1984,37 @@ namespace ts.FindAllReferences { } }); }); - return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined; + return references.length + ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined; } - function getAllReferencesForKeyword(sourceFiles: readonly SourceFile[], keywordKind: SyntaxKind, cancellationToken: CancellationToken, filter?: (node: Node) => boolean): SymbolAndEntries[] | undefined { + function getAllReferencesForKeyword( + sourceFiles: readonly SourceFile[], + keywordKind: SyntaxKind, + cancellationToken: CancellationToken, + filter?: (node: Node) => boolean, + ): SymbolAndEntries[] | undefined { const references = flatMap(sourceFiles, sourceFile => { cancellationToken.throwIfCancellationRequested(); - return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), referenceLocation => { - if (referenceLocation.kind === keywordKind && (!filter || filter(referenceLocation))) { - return nodeEntry(referenceLocation); - } - }); + return mapDefined( + getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), + referenceLocation => { + if (referenceLocation.kind === keywordKind && (!filter || filter(referenceLocation))) { + return nodeEntry(referenceLocation); + } + }, + ); }); - return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined; + return references.length + ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined; } - function getReferencesInSourceFile(sourceFile: SourceFile, search: Search, state: State, addReferencesHere = true): void { + function getReferencesInSourceFile( + sourceFile: SourceFile, + search: Search, + state: State, + addReferencesHere = true, + ): void { state.cancellationToken.throwIfCancellationRequested(); return getReferencesInContainer(sourceFile, sourceFile, search, state, addReferencesHere); } @@ -1562,7 +2024,13 @@ namespace ts.FindAllReferences { * tuple of(searchSymbol, searchText, searchLocation, and searchMeaning). * searchLocation: a node where the search value */ - function getReferencesInContainer(container: Node, sourceFile: SourceFile, search: Search, state: State, addReferencesHere: boolean): void { + function getReferencesInContainer( + container: Node, + sourceFile: SourceFile, + search: Search, + state: State, + addReferencesHere: boolean, + ): void { if (!state.markSearchedSymbols(sourceFile, search.allSearchSymbols)) { return; } @@ -1576,19 +2044,32 @@ namespace ts.FindAllReferences { return !!(getMeaningFromLocation(referenceLocation) & state.searchMeaning); } - function getReferencesAtLocation(sourceFile: SourceFile, position: number, search: Search, state: State, addReferencesHere: boolean): void { + function getReferencesAtLocation( + sourceFile: SourceFile, + position: number, + search: Search, + state: State, + addReferencesHere: boolean, + ): void { const referenceLocation = getTouchingPropertyName(sourceFile, position); if (!isValidReferencePosition(referenceLocation, search.text)) { // This wasn't the start of a token. Check to see if it might be a // match in a comment or string if that's what the caller is asking // for. - if (!state.options.implementations && (state.options.findInStrings && isInString(sourceFile, position) || state.options.findInComments && isInNonReferenceComment(sourceFile, position))) { + if ( + !state.options.implementations + && (state.options.findInStrings && isInString(sourceFile, position) + || state.options.findInComments && isInNonReferenceComment(sourceFile, position)) + ) { // In the case where we're looking inside comments/strings, we don't have // an actual definition. So just use 'undefined' here. Features like // 'Rename' won't care (as they ignore the definitions), and features like // 'FindReferences' will just filter out these results. - state.addStringOrCommentReference(sourceFile.fileName, createTextSpan(position, search.text.length)); + state.addStringOrCommentReference( + sourceFile.fileName, + createTextSpan(position, search.text.length), + ); } return; @@ -1609,7 +2090,14 @@ namespace ts.FindAllReferences { if (isExportSpecifier(parent)) { Debug.assert(referenceLocation.kind === SyntaxKind.Identifier); - getReferencesAtExportSpecifier(referenceLocation as Identifier, referenceSymbol, parent, search, state, addReferencesHere); + getReferencesAtExportSpecifier( + referenceLocation as Identifier, + referenceSymbol, + parent, + search, + state, + addReferencesHere, + ); return; } @@ -1657,18 +2145,29 @@ namespace ts.FindAllReferences { addReferencesHere: boolean, alwaysGetReferences?: boolean, ): void { - Debug.assert(!alwaysGetReferences || !!state.options.providePrefixAndSuffixTextForRename, "If alwaysGetReferences is true, then prefix/suffix text must be enabled"); + Debug.assert( + !alwaysGetReferences || !!state.options.providePrefixAndSuffixTextForRename, + "If alwaysGetReferences is true, then prefix/suffix text must be enabled", + ); const { parent, propertyName, name } = exportSpecifier; const exportDeclaration = parent.parent; - const localSymbol = getLocalSymbolForExportSpecifier(referenceLocation, referenceSymbol, exportSpecifier, state.checker); + const localSymbol = getLocalSymbolForExportSpecifier( + referenceLocation, + referenceSymbol, + exportSpecifier, + state.checker, + ); if (!alwaysGetReferences && !search.includes(localSymbol)) { return; } if (!propertyName) { // Don't rename at `export { default } from "m";`. (but do continue to search for imports of the re-export) - if (!(state.options.use === FindReferencesUse.Rename && (name.escapedText === InternalSymbolName.Default))) { + if ( + !(state.options.use === FindReferencesUse.Rename + && (name.escapedText === InternalSymbolName.Default)) + ) { addRef(); } } @@ -1679,7 +2178,10 @@ namespace ts.FindAllReferences { addRef(); } - if (addReferencesHere && state.options.use !== FindReferencesUse.Rename && state.markSeenReExportRHS(name)) { + if ( + addReferencesHere && state.options.use !== FindReferencesUse.Rename + && state.markSeenReExportRHS(name) + ) { addReference(name, Debug.checkDefined(exportSpecifier.symbol), state); } } @@ -1702,7 +2204,10 @@ namespace ts.FindAllReferences { } // At `export { x } from "foo"`, also search for the imported symbol `"foo".x`. - if (search.comingFrom !== ImportExport.Export && exportDeclaration.moduleSpecifier && !propertyName && !isForRenameWithPrefixAndSuffixText(state.options)) { + if ( + search.comingFrom !== ImportExport.Export && exportDeclaration.moduleSpecifier && !propertyName + && !isForRenameWithPrefixAndSuffixText(state.options) + ) { const imported = state.checker.getExportSpecifierLocalTargetSymbol(exportSpecifier); if (imported) searchForImportedSymbol(imported, state); } @@ -1712,8 +2217,14 @@ namespace ts.FindAllReferences { } } - function getLocalSymbolForExportSpecifier(referenceLocation: Identifier, referenceSymbol: Symbol, exportSpecifier: ExportSpecifier, checker: TypeChecker): Symbol { - return isExportSpecifierAlias(referenceLocation, exportSpecifier) && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier) || referenceSymbol; + function getLocalSymbolForExportSpecifier( + referenceLocation: Identifier, + referenceSymbol: Symbol, + exportSpecifier: ExportSpecifier, + checker: TypeChecker, + ): Symbol { + return isExportSpecifierAlias(referenceLocation, exportSpecifier) + && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier) || referenceSymbol; } function isExportSpecifierAlias(referenceLocation: Identifier, exportSpecifier: ExportSpecifier): boolean { @@ -1730,8 +2241,18 @@ namespace ts.FindAllReferences { } } - function getImportOrExportReferences(referenceLocation: Node, referenceSymbol: Symbol, search: Search, state: State): void { - const importOrExport = getImportOrExportSymbol(referenceLocation, referenceSymbol, state.checker, search.comingFrom === ImportExport.Export); + function getImportOrExportReferences( + referenceLocation: Node, + referenceSymbol: Symbol, + search: Search, + state: State, + ): void { + const importOrExport = getImportOrExportSymbol( + referenceLocation, + referenceSymbol, + state.checker, + search.comingFrom === ImportExport.Export, + ); if (!importOrExport) return; const { symbol } = importOrExport; @@ -1746,7 +2267,11 @@ namespace ts.FindAllReferences { } } - function getReferenceForShorthandProperty({ flags, valueDeclaration }: Symbol, search: Search, state: State): void { + function getReferenceForShorthandProperty( + { flags, valueDeclaration }: Symbol, + search: Search, + state: State, + ): void { const shorthandValueSymbol = state.checker.getShorthandAssignmentValueSymbol(valueDeclaration)!; const name = valueDeclaration && getNameOfDeclaration(valueDeclaration); /* @@ -1762,10 +2287,13 @@ namespace ts.FindAllReferences { } function addReference(referenceLocation: Node, relatedSymbol: Symbol | RelatedSymbol, state: State): void { - const { kind, symbol } = "kind" in relatedSymbol ? relatedSymbol : { kind: undefined, symbol: relatedSymbol }; // eslint-disable-line local/no-in-operator + const { kind, symbol } = "kind" in relatedSymbol ? relatedSymbol + : { kind: undefined, symbol: relatedSymbol }; // eslint-disable-line local/no-in-operator // if rename symbol from default export anonymous function, for example `export default function() {}`, we do not need to add reference - if (state.options.use === FindReferencesUse.Rename && referenceLocation.kind === SyntaxKind.DefaultKeyword) { + if ( + state.options.use === FindReferencesUse.Rename && referenceLocation.kind === SyntaxKind.DefaultKeyword + ) { return; } @@ -1779,7 +2307,12 @@ namespace ts.FindAllReferences { } /** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */ - function addConstructorReferences(referenceLocation: Node, sourceFile: SourceFile, search: Search, state: State): void { + function addConstructorReferences( + referenceLocation: Node, + sourceFile: SourceFile, + search: Search, + state: State, + ): void { if (isNewExpressionTarget(referenceLocation)) { addReference(referenceLocation, search.symbol, state); } @@ -1787,7 +2320,10 @@ namespace ts.FindAllReferences { const pusher = () => state.referenceAdder(search.symbol); if (isClassLike(referenceLocation.parent)) { - Debug.assert(referenceLocation.kind === SyntaxKind.DefaultKeyword || referenceLocation.parent.name === referenceLocation); + Debug.assert( + referenceLocation.kind === SyntaxKind.DefaultKeyword + || referenceLocation.parent.name === referenceLocation, + ); // This is the class declaration containing the constructor. findOwnConstructorReferences(search.symbol, sourceFile, pusher()); } @@ -1828,7 +2364,11 @@ namespace ts.FindAllReferences { * `classSymbol` is the class where the constructor was defined. * Reference the constructor and all calls to `new this()`. */ - function findOwnConstructorReferences(classSymbol: Symbol, sourceFile: SourceFile, addNode: (node: Node) => void): void { + function findOwnConstructorReferences( + classSymbol: Symbol, + sourceFile: SourceFile, + addNode: (node: Node) => void, + ): void { const constructorSymbol = getClassConstructorSymbol(classSymbol); if (constructorSymbol && constructorSymbol.declarations) { for (const decl of constructorSymbol.declarations) { @@ -1860,7 +2400,10 @@ namespace ts.FindAllReferences { } /** Find references to `super` in the constructor of an extending class. */ - function findSuperConstructorAccesses(classDeclaration: ClassLikeDeclaration, addNode: (node: Node) => void): void { + function findSuperConstructorAccesses( + classDeclaration: ClassLikeDeclaration, + addNode: (node: Node) => void, + ): void { const constructor = getClassConstructorSymbol(classDeclaration.symbol); if (!(constructor && constructor.declarations)) { return; @@ -1915,9 +2458,15 @@ namespace ts.FindAllReferences { // If we got a type reference, try and see if the reference applies to any expressions that can implement an interface // Find the first node whose parent isn't a type node -- i.e., the highest type node. - const typeNode = findAncestor(refNode, a => !isQualifiedName(a.parent) && !isTypeNode(a.parent) && !isTypeElement(a.parent))!; + const typeNode = findAncestor( + refNode, + a => !isQualifiedName(a.parent) && !isTypeNode(a.parent) && !isTypeElement(a.parent), + )!; const typeHavingNode = typeNode.parent; - if (hasType(typeHavingNode) && typeHavingNode.type === typeNode && state.markSeenContainingTypeReference(typeHavingNode)) { + if ( + hasType(typeHavingNode) && typeHavingNode.type === typeNode + && state.markSeenContainingTypeReference(typeHavingNode) + ) { if (hasInitializer(typeHavingNode)) { addIfImplementation(typeHavingNode.initializer!); } @@ -1942,8 +2491,11 @@ namespace ts.FindAllReferences { } } - function getContainingClassIfInHeritageClause(node: Node): ClassLikeDeclaration | InterfaceDeclaration | undefined { - return isIdentifier(node) || isPropertyAccessExpression(node) ? getContainingClassIfInHeritageClause(node.parent) + function getContainingClassIfInHeritageClause( + node: Node, + ): ClassLikeDeclaration | InterfaceDeclaration | undefined { + return isIdentifier(node) || isPropertyAccessExpression(node) + ? getContainingClassIfInHeritageClause(node.parent) : isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, isClassLike) : undefined; } @@ -1984,7 +2536,12 @@ namespace ts.FindAllReferences { * @param parent Another class or interface Symbol * @param cachedResults A map of symbol id pairs (i.e. "child,parent") to booleans indicating previous results */ - function explicitlyInheritsFrom(symbol: Symbol, parent: Symbol, cachedResults: ESMap, checker: TypeChecker): boolean { + function explicitlyInheritsFrom( + symbol: Symbol, + parent: Symbol, + cachedResults: ESMap, + checker: TypeChecker, + ): boolean { if (symbol === parent) { return true; } @@ -1998,12 +2555,14 @@ namespace ts.FindAllReferences { // Set the key so that we don't infinitely recurse cachedResults.set(key, false); - const inherits = !!symbol.declarations && symbol.declarations.some(declaration => - getAllSuperTypeNodes(declaration).some(typeReference => { - const type = checker.getTypeAtLocation(typeReference); - return !!type && !!type.symbol && explicitlyInheritsFrom(type.symbol, parent, cachedResults, checker); - }) - ); + const inherits = !!symbol.declarations + && symbol.declarations.some(declaration => + getAllSuperTypeNodes(declaration).some(typeReference => { + const type = checker.getTypeAtLocation(typeReference); + return !!type && !!type.symbol + && explicitlyInheritsFrom(type.symbol, parent, cachedResults, checker); + }) + ); cachedResults.set(key, inherits); return inherits; } @@ -2032,27 +2591,36 @@ namespace ts.FindAllReferences { } const sourceFile = searchSpaceNode.getSourceFile(); - const references = mapDefined(getPossibleSymbolReferenceNodes(sourceFile, "super", searchSpaceNode), node => { - if (node.kind !== SyntaxKind.SuperKeyword) { - return; - } + const references = mapDefined( + getPossibleSymbolReferenceNodes(sourceFile, "super", searchSpaceNode), + node => { + if (node.kind !== SyntaxKind.SuperKeyword) { + return; + } - const container = getSuperContainer(node, /*stopOnFunctions*/ false); + const container = getSuperContainer(node, /*stopOnFunctions*/ false); - // If we have a 'super' container, we must have an enclosing class. - // Now make sure the owning class is the same as the search-space - // and has the same static qualifier as the original 'super's owner. - return container && isStatic(container) === !!staticFlag && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined; - }); + // If we have a 'super' container, we must have an enclosing class. + // Now make sure the owning class is the same as the search-space + // and has the same static qualifier as the original 'super's owner. + return container && isStatic(container) === !!staticFlag + && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined; + }, + ); return [{ definition: { type: DefinitionKind.Symbol, symbol: searchSpaceNode.symbol }, references }]; } function isParameterName(node: Node) { - return node.kind === SyntaxKind.Identifier && node.parent.kind === SyntaxKind.Parameter && (node.parent as ParameterDeclaration).name === node; + return node.kind === SyntaxKind.Identifier && node.parent.kind === SyntaxKind.Parameter + && (node.parent as ParameterDeclaration).name === node; } - function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined { + function getReferencesForThisKeyword( + thisOrSuperKeyword: Node, + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + ): SymbolAndEntries[] | undefined { let searchSpaceNode = getThisContainer(thisOrSuperKeyword, /* includeArrowFunctions */ false); // Whether 'this' occurs in a static context within a class. @@ -2089,31 +2657,41 @@ namespace ts.FindAllReferences { return undefined; } - const references = flatMap(searchSpaceNode.kind === SyntaxKind.SourceFile ? sourceFiles : [searchSpaceNode.getSourceFile()], sourceFile => { - cancellationToken.throwIfCancellationRequested(); - return getPossibleSymbolReferenceNodes(sourceFile, "this", isSourceFile(searchSpaceNode) ? sourceFile : searchSpaceNode).filter(node => { - if (!isThis(node)) { - return false; - } - const container = getThisContainer(node, /* includeArrowFunctions */ false); - switch (searchSpaceNode.kind) { - case SyntaxKind.FunctionExpression: - case SyntaxKind.FunctionDeclaration: - return searchSpaceNode.symbol === container.symbol; - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - return isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol; - case SyntaxKind.ClassExpression: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ObjectLiteralExpression: - // Make sure the container belongs to the same class/object literals - // and has the appropriate static modifier from the original container. - return container.parent && searchSpaceNode.symbol === container.parent.symbol && isStatic(container) === !!staticFlag; - case SyntaxKind.SourceFile: - return container.kind === SyntaxKind.SourceFile && !isExternalModule(container as SourceFile) && !isParameterName(node); - } - }); - }).map(n => nodeEntry(n)); + const references = flatMap( + searchSpaceNode.kind === SyntaxKind.SourceFile ? sourceFiles : [searchSpaceNode.getSourceFile()], + sourceFile => { + cancellationToken.throwIfCancellationRequested(); + return getPossibleSymbolReferenceNodes( + sourceFile, + "this", + isSourceFile(searchSpaceNode) ? sourceFile : searchSpaceNode, + ).filter(node => { + if (!isThis(node)) { + return false; + } + const container = getThisContainer(node, /* includeArrowFunctions */ false); + switch (searchSpaceNode.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + return searchSpaceNode.symbol === container.symbol; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return isObjectLiteralMethod(searchSpaceNode) + && searchSpaceNode.symbol === container.symbol; + case SyntaxKind.ClassExpression: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ObjectLiteralExpression: + // Make sure the container belongs to the same class/object literals + // and has the appropriate static modifier from the original container. + return container.parent && searchSpaceNode.symbol === container.parent.symbol + && isStatic(container) === !!staticFlag; + case SyntaxKind.SourceFile: + return container.kind === SyntaxKind.SourceFile + && !isExternalModule(container as SourceFile) && !isParameterName(node); + } + }); + }, + ).map(n => nodeEntry(n)); const thisParameter = firstDefined(references, r => isParameter(r.node.parent) ? r.node : undefined); return [{ @@ -2122,7 +2700,12 @@ namespace ts.FindAllReferences { }]; } - function getReferencesForStringLiteral(node: StringLiteralLike, sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken): SymbolAndEntries[] { + function getReferencesForStringLiteral( + node: StringLiteralLike, + sourceFiles: readonly SourceFile[], + checker: TypeChecker, + cancellationToken: CancellationToken, + ): SymbolAndEntries[] { const type = getContextualTypeFromParentOrAncestorTypeNode(node, checker); const references = flatMap(sourceFiles, sourceFile => { cancellationToken.throwIfCancellationRequested(); @@ -2135,8 +2718,9 @@ namespace ts.FindAllReferences { } } else { - return isNoSubstitutionTemplateLiteral(ref) && !rangeIsOnSingleLine(ref, sourceFile) ? undefined : - nodeEntry(ref, EntryKind.StringLiteral); + return isNoSubstitutionTemplateLiteral(ref) && !rangeIsOnSingleLine(ref, sourceFile) + ? undefined + : nodeEntry(ref, EntryKind.StringLiteral); } } }); @@ -2150,7 +2734,14 @@ namespace ts.FindAllReferences { // For certain symbol kinds, we need to include other symbols in the search set. // This is not needed when searching for re-exports. - function populateSearchSymbolSet(symbol: Symbol, location: Node, checker: TypeChecker, isForRename: boolean, providePrefixAndSuffixText: boolean, implementations: boolean): Symbol[] { + function populateSearchSymbolSet( + symbol: Symbol, + location: Node, + checker: TypeChecker, + isForRename: boolean, + providePrefixAndSuffixText: boolean, + implementations: boolean, + ): Symbol[] { const result: Symbol[] = []; forEachRelatedSymbol( symbol, @@ -2203,7 +2794,12 @@ namespace ts.FindAllReferences { const shorthandValueSymbol = checker.getShorthandAssignmentValueSymbol(location.parent); // gets the local symbol if (shorthandValueSymbol && isForRenamePopulateSearchSymbolSet) { // When renaming 'x' in `const o = { x }`, just rename the local variable, not the property. - return cbSymbol(shorthandValueSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedLocalFoundProperty); + return cbSymbol( + shorthandValueSymbol, + /*rootSymbol*/ undefined, + /*baseSymbol*/ undefined, + EntryKind.SearchedLocalFoundProperty, + ); } // If the location is in a context sensitive location (i.e. in an object literal) try @@ -2211,7 +2807,12 @@ namespace ts.FindAllReferences { // type to the search set const contextualType = checker.getContextualType(containingObjectLiteralElement.parent); const res = contextualType && firstDefined( - getPropertySymbolsFromContextualType(containingObjectLiteralElement, checker, contextualType, /*unionSymbolOk*/ true), + getPropertySymbolsFromContextualType( + containingObjectLiteralElement, + checker, + contextualType, + /*unionSymbolOk*/ true, + ), sym => fromRoot(sym, EntryKind.SearchedPropertyFoundLocal), ); if (res) return res; @@ -2220,10 +2821,22 @@ namespace ts.FindAllReferences { // Search the property symbol // for ( { property: p2 } of elems) { } const propertySymbol = getPropertySymbolOfDestructuringAssignment(location, checker); - const res1 = propertySymbol && cbSymbol(propertySymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedPropertyFoundLocal); + const res1 = propertySymbol + && cbSymbol( + propertySymbol, + /*rootSymbol*/ undefined, + /*baseSymbol*/ undefined, + EntryKind.SearchedPropertyFoundLocal, + ); if (res1) return res1; - const res2 = shorthandValueSymbol && cbSymbol(shorthandValueSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedLocalFoundProperty); + const res2 = shorthandValueSymbol + && cbSymbol( + shorthandValueSymbol, + /*rootSymbol*/ undefined, + /*baseSymbol*/ undefined, + EntryKind.SearchedLocalFoundProperty, + ); if (res2) return res2; } @@ -2237,10 +2850,19 @@ namespace ts.FindAllReferences { const res = fromRoot(symbol); if (res) return res; - if (symbol.valueDeclaration && isParameterPropertyDeclaration(symbol.valueDeclaration, symbol.valueDeclaration.parent)) { + if ( + symbol.valueDeclaration + && isParameterPropertyDeclaration(symbol.valueDeclaration, symbol.valueDeclaration.parent) + ) { // For a parameter property, now try on the other symbol (property if this was a parameter, parameter if this was a property). - const paramProps = checker.getSymbolsOfParameterPropertyDeclaration(cast(symbol.valueDeclaration, isParameter), symbol.name); - Debug.assert(paramProps.length === 2 && !!(paramProps[0].flags & SymbolFlags.FunctionScopedVariable) && !!(paramProps[1].flags & SymbolFlags.Property)); // is [parameter, property] + const paramProps = checker.getSymbolsOfParameterPropertyDeclaration( + cast(symbol.valueDeclaration, isParameter), + symbol.name, + ); + Debug.assert( + paramProps.length === 2 && !!(paramProps[0].flags & SymbolFlags.FunctionScopedVariable) + && !!(paramProps[1].flags & SymbolFlags.Property), + ); // is [parameter, property] return fromRoot(symbol.flags & SymbolFlags.FunctionScopedVariable ? paramProps[1] : paramProps[0]); } @@ -2248,7 +2870,12 @@ namespace ts.FindAllReferences { if (!isForRenamePopulateSearchSymbolSet || exportSpecifier && !exportSpecifier.propertyName) { const localSymbol = exportSpecifier && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier); if (localSymbol) { - const res = cbSymbol(localSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.Node); + const res = cbSymbol( + localSymbol, + /*rootSymbol*/ undefined, + /*baseSymbol*/ undefined, + EntryKind.Node, + ); if (res) return res; } } @@ -2258,12 +2885,17 @@ namespace ts.FindAllReferences { if (!isForRenamePopulateSearchSymbolSet) { let bindingElementPropertySymbol: Symbol | undefined; if (onlyIncludeBindingElementAtReferenceLocation) { - bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName(location.parent) ? getPropertySymbolFromBindingElement(checker, location.parent) : undefined; + bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName(location.parent) + ? getPropertySymbolFromBindingElement(checker, location.parent) : undefined; } else { - bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker); + bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName( + symbol, + checker, + ); } - return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal); + return bindingElementPropertySymbol + && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal); } Debug.assert(isForRenamePopulateSearchSymbolSet); @@ -2272,8 +2904,12 @@ namespace ts.FindAllReferences { const includeOriginalSymbolOfBindingElement = onlyIncludeBindingElementAtReferenceLocation; if (includeOriginalSymbolOfBindingElement) { - const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker); - return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal); + const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName( + symbol, + checker, + ); + return bindingElementPropertySymbol + && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal); } function fromRoot(sym: Symbol, kind?: NodeEntryKind): T | undefined { @@ -2283,15 +2919,27 @@ namespace ts.FindAllReferences { // If the symbol is an instantiation from a another symbol (e.g. widened symbol): // - In populateSearchSymbolsSet, add the root the list // - In findRelatedSymbol, return the source symbol if that is in the search. (Do not return the instantiation symbol.) - return firstDefined(checker.getRootSymbols(sym), rootSymbol => - cbSymbol(sym, rootSymbol, /*baseSymbol*/ undefined, kind) - // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions - || (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface) && allowBaseTypes(rootSymbol) - ? getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker, base => cbSymbol(sym, rootSymbol, base, kind)) - : undefined)); + return firstDefined( + checker.getRootSymbols(sym), + rootSymbol => + cbSymbol(sym, rootSymbol, /*baseSymbol*/ undefined, kind) + // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions + || (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface) + && allowBaseTypes(rootSymbol) + ? getPropertySymbolsFromBaseTypes( + rootSymbol.parent, + rootSymbol.name, + checker, + base => cbSymbol(sym, rootSymbol, base, kind), + ) + : undefined), + ); } - function getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol: Symbol, checker: TypeChecker): Symbol | undefined { + function getPropertySymbolOfObjectBindingPatternWithoutPropertyName( + symbol: Symbol, + checker: TypeChecker, + ): Symbol | undefined { const bindingElement = getDeclarationOfKind(symbol, SyntaxKind.BindingElement); if (bindingElement && isObjectBindingElementWithoutPropertyName(bindingElement)) { return getPropertySymbolFromBindingElement(checker, bindingElement); @@ -2307,7 +2955,12 @@ namespace ts.FindAllReferences { * @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisiting of the same symbol. * The value of previousIterationSymbol is undefined when the function is first called. */ - function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, checker: TypeChecker, cb: (symbol: Symbol) => T | undefined): T | undefined { + function getPropertySymbolsFromBaseTypes( + symbol: Symbol, + propertyName: string, + checker: TypeChecker, + cb: (symbol: Symbol) => T | undefined, + ): T | undefined { const seen = new Map(); return recur(symbol); @@ -2316,15 +2969,22 @@ namespace ts.FindAllReferences { // interface C extends C { // /*findRef*/propName: string; // } - if (!(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !addToSeen(seen, getSymbolId(symbol))) return; - - return firstDefined(symbol.declarations, declaration => - firstDefined(getAllSuperTypeNodes(declaration), typeReference => { - const type = checker.getTypeAtLocation(typeReference); - const propertySymbol = type && type.symbol && checker.getPropertyOfType(type, propertyName); - // Visit the typeReference as well to see if it directly or indirectly uses that property - return type && propertySymbol && (firstDefined(checker.getRootSymbols(propertySymbol), cb) || recur(type.symbol)); - })); + if ( + !(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) + || !addToSeen(seen, getSymbolId(symbol)) + ) return; + + return firstDefined( + symbol.declarations, + declaration => + firstDefined(getAllSuperTypeNodes(declaration), typeReference => { + const type = checker.getTypeAtLocation(typeReference); + const propertySymbol = type && type.symbol && checker.getPropertyOfType(type, propertyName); + // Visit the typeReference as well to see if it directly or indirectly uses that property + return type && propertySymbol + && (firstDefined(checker.getRootSymbols(propertySymbol), cb) || recur(type.symbol)); + }), + ); } } @@ -2339,21 +2999,42 @@ namespace ts.FindAllReferences { return !!(modifierFlags & ModifierFlags.Static); } - function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): RelatedSymbol | undefined { + function getRelatedSymbol( + search: Search, + referenceSymbol: Symbol, + referenceLocation: Node, + state: State, + ): RelatedSymbol | undefined { const { checker } = state; - return forEachRelatedSymbol(referenceSymbol, referenceLocation, checker, /*isForRenamePopulateSearchSymbolSet*/ false, /*onlyIncludeBindingElementAtReferenceLocation*/ state.options.use !== FindReferencesUse.Rename || !!state.options.providePrefixAndSuffixTextForRename, (sym, rootSymbol, baseSymbol, kind): RelatedSymbol | undefined => { - // check whether the symbol used to search itself is just the searched one. - if (baseSymbol) { - // static method/property and instance method/property might have the same name. Only check static or only check instance. - if (isStaticSymbol(referenceSymbol) !== isStaticSymbol(baseSymbol)) { - baseSymbol = undefined; + return forEachRelatedSymbol( + referenceSymbol, + referenceLocation, + checker, + /*isForRenamePopulateSearchSymbolSet*/ false, + /*onlyIncludeBindingElementAtReferenceLocation*/ state.options.use !== FindReferencesUse.Rename + || !!state.options.providePrefixAndSuffixTextForRename, + (sym, rootSymbol, baseSymbol, kind): RelatedSymbol | undefined => { + // check whether the symbol used to search itself is just the searched one. + if (baseSymbol) { + // static method/property and instance method/property might have the same name. Only check static or only check instance. + if (isStaticSymbol(referenceSymbol) !== isStaticSymbol(baseSymbol)) { + baseSymbol = undefined; + } } - } - return search.includes(baseSymbol || rootSymbol || sym) - // For a base type, use the symbol for the derived type. For a synthetic (e.g. union) property, use the union symbol. - ? { symbol: rootSymbol && !(getCheckFlags(sym) & CheckFlags.Synthetic) ? rootSymbol : sym, kind } - : undefined; - }, /*allowBaseTypes*/ rootSymbol => !(search.parents && !search.parents.some(parent => explicitlyInheritsFrom(rootSymbol.parent!, parent, state.inheritsFromCache, checker)))); + return search.includes(baseSymbol || rootSymbol || sym) + // For a base type, use the symbol for the derived type. For a synthetic (e.g. union) property, use the union symbol. + ? { + symbol: rootSymbol && !(getCheckFlags(sym) & CheckFlags.Synthetic) ? rootSymbol : sym, + kind, + } + : undefined; + }, + /*allowBaseTypes*/ rootSymbol => + !(search.parents + && !search.parents.some(parent => + explicitlyInheritsFrom(rootSymbol.parent!, parent, state.inheritsFromCache, checker) + )), + ); } /** @@ -2392,13 +3073,17 @@ namespace ts.FindAllReferences { } function isImplementation(node: Node): boolean { - return !!(node.flags & NodeFlags.Ambient) ? !(isInterfaceDeclaration(node) || isTypeAliasDeclaration(node)) : - (isVariableLike(node) ? hasInitializer(node) : - isFunctionLikeDeclaration(node) ? !!node.body : - isClassLike(node) || isModuleOrEnumDeclaration(node)); + return !!(node.flags & NodeFlags.Ambient) ? !(isInterfaceDeclaration(node) || isTypeAliasDeclaration(node)) + : (isVariableLike(node) ? hasInitializer(node) + : isFunctionLikeDeclaration(node) ? !!node.body + : isClassLike(node) || isModuleOrEnumDeclaration(node)); } - export function getReferenceEntriesForShorthandPropertyAssignment(node: Node, checker: TypeChecker, addReference: (node: Node) => void): void { + export function getReferenceEntriesForShorthandPropertyAssignment( + node: Node, + checker: TypeChecker, + addReference: (node: Node) => void, + ): void { const refSymbol = checker.getSymbolAtLocation(node)!; const shorthandSymbol = checker.getShorthandAssignmentValueSymbol(refSymbol.valueDeclaration); @@ -2431,10 +3116,20 @@ namespace ts.FindAllReferences { * symbol may have a different parent symbol if the local type's symbol does not declare the property * being accessed (i.e. it is declared in some parent class or interface) */ - function getParentSymbolsOfPropertyAccess(location: Node, symbol: Symbol, checker: TypeChecker): readonly Symbol[] | undefined { - const propertyAccessExpression = isRightSideOfPropertyAccess(location) ? location.parent as PropertyAccessExpression : undefined; + function getParentSymbolsOfPropertyAccess( + location: Node, + symbol: Symbol, + checker: TypeChecker, + ): readonly Symbol[] | undefined { + const propertyAccessExpression = isRightSideOfPropertyAccess(location) + ? location.parent as PropertyAccessExpression : undefined; const lhsType = propertyAccessExpression && checker.getTypeAtLocation(propertyAccessExpression.expression); - const res = mapDefined(lhsType && (lhsType.isUnionOrIntersection() ? lhsType.types : lhsType.symbol === symbol.parent ? undefined : [lhsType]), t => t.symbol && t.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? t.symbol : undefined); + const res = mapDefined( + lhsType + && (lhsType.isUnionOrIntersection() ? lhsType.types + : lhsType.symbol === symbol.parent ? undefined : [lhsType]), + t => t.symbol && t.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? t.symbol : undefined, + ); return res.length === 0 ? undefined : res; } diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 8385c7ffd6ced..0613c8ab2ee99 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -18,7 +18,11 @@ namespace ts.formatting { trailingTrivia: TextRangeWithTriviaKind[] | undefined; } - export function createTextRangeWithKind(pos: number, end: number, kind: T): TextRangeWithKind { + export function createTextRangeWithKind( + pos: number, + end: number, + kind: T, + ): TextRangeWithKind { const textRangeWithKind: TextRangeWithKind = { pos, end, kind }; if (Debug.isDebugging) { Object.defineProperty(textRangeWithKind, "__debugKind", { @@ -43,7 +47,12 @@ namespace ts.formatting { * the first token in line so it should be indented */ interface DynamicIndentation { - getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind, container: Node, suppressDelta: boolean): number; + getIndentationForToken( + tokenLine: number, + tokenKind: SyntaxKind, + container: Node, + suppressDelta: boolean, + ): number; getIndentationForComment(owningToken: SyntaxKind, tokenIndentation: number, container: Node): number; /** * Indentation for open and close tokens of the node if it is block or another node that needs special indentation @@ -73,7 +82,11 @@ namespace ts.formatting { recomputeIndentation(lineAddedByFormatting: boolean, parent: Node): void; } - export function formatOnEnter(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { + export function formatOnEnter( + position: number, + sourceFile: SourceFile, + formatContext: FormatContext, + ): TextChange[] { const line = sourceFile.getLineAndCharacterOfPosition(position).line; if (line === 0) { return []; @@ -102,12 +115,25 @@ namespace ts.formatting { return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatOnEnter); } - export function formatOnSemicolon(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { + export function formatOnSemicolon( + position: number, + sourceFile: SourceFile, + formatContext: FormatContext, + ): TextChange[] { const semicolon = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.SemicolonToken, sourceFile); - return formatNodeLines(findOutermostNodeWithinListLevel(semicolon), sourceFile, formatContext, FormattingRequestKind.FormatOnSemicolon); + return formatNodeLines( + findOutermostNodeWithinListLevel(semicolon), + sourceFile, + formatContext, + FormattingRequestKind.FormatOnSemicolon, + ); } - export function formatOnOpeningCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { + export function formatOnOpeningCurly( + position: number, + sourceFile: SourceFile, + formatContext: FormatContext, + ): TextChange[] { const openingCurly = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.OpenBraceToken, sourceFile); if (!openingCurly) { return []; @@ -135,9 +161,18 @@ namespace ts.formatting { return formatSpan(textRange, sourceFile, formatContext, FormattingRequestKind.FormatOnOpeningCurlyBrace); } - export function formatOnClosingCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { + export function formatOnClosingCurly( + position: number, + sourceFile: SourceFile, + formatContext: FormatContext, + ): TextChange[] { const precedingToken = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.CloseBraceToken, sourceFile); - return formatNodeLines(findOutermostNodeWithinListLevel(precedingToken), sourceFile, formatContext, FormattingRequestKind.FormatOnClosingCurlyBrace); + return formatNodeLines( + findOutermostNodeWithinListLevel(precedingToken), + sourceFile, + formatContext, + FormattingRequestKind.FormatOnClosingCurlyBrace, + ); } export function formatDocument(sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { @@ -148,7 +183,12 @@ namespace ts.formatting { return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatDocument); } - export function formatSelection(start: number, end: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { + export function formatSelection( + start: number, + end: number, + sourceFile: SourceFile, + formatContext: FormatContext, + ): TextChange[] { // format from the beginning of the line const span = { pos: getLineStartPositionForPosition(start, sourceFile), @@ -161,12 +201,16 @@ namespace ts.formatting { * Validating `expectedTokenKind` ensures the token was typed in the context we expect (eg: not a comment). * @param expectedTokenKind The kind of the last token constituting the desired parent node. */ - function findImmediatelyPrecedingTokenOfKind(end: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node | undefined { + function findImmediatelyPrecedingTokenOfKind( + end: number, + expectedTokenKind: SyntaxKind, + sourceFile: SourceFile, + ): Node | undefined { const precedingToken = findPrecedingToken(end, sourceFile); - return precedingToken && precedingToken.kind === expectedTokenKind && end === precedingToken.getEnd() ? - precedingToken : - undefined; + return precedingToken && precedingToken.kind === expectedTokenKind && end === precedingToken.getEnd() + ? precedingToken + : undefined; } /** @@ -185,10 +229,10 @@ namespace ts.formatting { function findOutermostNodeWithinListLevel(node: Node | undefined) { let current = node; while ( - current && - current.parent && - current.parent.end === node!.end && - !isListElement(current.parent, current) + current + && current.parent + && current.parent.end === node!.end + && !isListElement(current.parent, current) ) { current = current.parent; } @@ -238,7 +282,10 @@ namespace ts.formatting { * This function will return a predicate that for a given text range will tell * if there are any parse errors that overlap with the range. */ - function prepareRangeContainsErrorFunction(errors: readonly Diagnostic[], originalRange: TextRange): (r: TextRange) => boolean { + function prepareRangeContainsErrorFunction( + errors: readonly Diagnostic[], + originalRange: TextRange, + ): (r: TextRange) => boolean { if (!errors.length) { return rangeHasNoErrors; } @@ -344,23 +391,41 @@ namespace ts.formatting { return 0; } - export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, formatContext: FormatContext): TextChange[] { + export function formatNodeGivenIndentation( + node: Node, + sourceFileLike: SourceFileLike, + languageVariant: LanguageVariant, + initialIndentation: number, + delta: number, + formatContext: FormatContext, + ): TextChange[] { const range = { pos: node.pos, end: node.end }; - return getFormattingScanner(sourceFileLike.text, languageVariant, range.pos, range.end, scanner => - formatSpanWorker( - range, - node, - initialIndentation, - delta, - scanner, - formatContext, - FormattingRequestKind.FormatSelection, - _ => false, // assume that node does not have any errors - sourceFileLike, - )); + return getFormattingScanner( + sourceFileLike.text, + languageVariant, + range.pos, + range.end, + scanner => + formatSpanWorker( + range, + node, + initialIndentation, + delta, + scanner, + formatContext, + FormattingRequestKind.FormatSelection, + _ => false, // assume that node does not have any errors + sourceFileLike, + ), + ); } - function formatNodeLines(node: Node | undefined, sourceFile: SourceFile, formatContext: FormatContext, requestKind: FormattingRequestKind): TextChange[] { + function formatNodeLines( + node: Node | undefined, + sourceFile: SourceFile, + formatContext: FormatContext, + requestKind: FormattingRequestKind, + ): TextChange[] { if (!node) { return []; } @@ -373,7 +438,12 @@ namespace ts.formatting { return formatSpan(span, sourceFile, formatContext, requestKind); } - function formatSpan(originalRange: TextRange, sourceFile: SourceFile, formatContext: FormatContext, requestKind: FormattingRequestKind): TextChange[] { + function formatSpan( + originalRange: TextRange, + sourceFile: SourceFile, + formatContext: FormatContext, + requestKind: FormattingRequestKind, + ): TextChange[] { // find the smallest node that fully wraps the range and compute the initial indentation for the node const enclosingNode = findEnclosingNode(originalRange, sourceFile); return getFormattingScanner( @@ -385,7 +455,12 @@ namespace ts.formatting { formatSpanWorker( originalRange, enclosingNode, - SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options), + SmartIndenter.getIndentationForNode( + enclosingNode, + originalRange, + sourceFile, + formatContext.options, + ), getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile), scanner, formatContext, @@ -425,19 +500,39 @@ namespace ts.formatting { const startLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile)).line; let undecoratedStartLine = startLine; if (hasDecorators(enclosingNode)) { - undecoratedStartLine = sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(enclosingNode, sourceFile)).line; + undecoratedStartLine = + sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(enclosingNode, sourceFile)) + .line; } processNode(enclosingNode, enclosingNode, startLine, undecoratedStartLine, initialIndentation, delta); } if (!formattingScanner.isOnToken()) { - const indentation = SmartIndenter.nodeWillIndentChild(options, enclosingNode, /*child*/ undefined, sourceFile, /*indentByDefault*/ false) + const indentation = SmartIndenter.nodeWillIndentChild( + options, + enclosingNode, + /*child*/ undefined, + sourceFile, + /*indentByDefault*/ false, + ) ? initialIndentation + options.indentSize! : initialIndentation; const leadingTrivia = formattingScanner.getCurrentLeadingTrivia(); if (leadingTrivia) { - indentTriviaItems(leadingTrivia, indentation, /*indentNextTokenOrTrivia*/ false, item => processRange(item, sourceFile.getLineAndCharacterOfPosition(item.pos), enclosingNode, enclosingNode, /*dynamicIndentation*/ undefined!)); + indentTriviaItems( + leadingTrivia, + indentation, + /*indentNextTokenOrTrivia*/ false, + item => + processRange( + item, + sourceFile.getLineAndCharacterOfPosition(item.pos), + enclosingNode, + enclosingNode, + /*dynamicIndentation*/ undefined!, + ), + ); if (options.trimTrailingWhitespace !== false) { trimTrailingWhitespacesForRemainingRange(leadingTrivia); } @@ -455,9 +550,9 @@ namespace ts.formatting { // inclusive. We would expect a format-selection would delete the space (if rules apply), // but in order to do that, we need to process the pair ["{", "}"], but we stopped processing // just before getting there. This block handles this trailing edit. - const tokenInfo = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : - formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token : - undefined; + const tokenInfo = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() + : formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token + : undefined; if (tokenInfo && tokenInfo.pos === previousRangeTriviaEnd!) { // We need to check that tokenInfo and previousRange are contiguous: the `originalRange` @@ -495,10 +590,16 @@ namespace ts.formatting { * If list element is in the range - its indentation will be equal * to inherited indentation from its predecessors. */ - function tryComputeIndentationForListItem(startPos: number, endPos: number, parentStartLine: number, range: TextRange, inheritedIndentation: number): number { + function tryComputeIndentationForListItem( + startPos: number, + endPos: number, + parentStartLine: number, + range: TextRange, + inheritedIndentation: number, + ): number { if ( - rangeOverlapsWithStartEnd(range, startPos, endPos) || - rangeContainsStartEnd(range, startPos, endPos) /* Not to miss zero-range nodes e.g. JsxText */ + rangeOverlapsWithStartEnd(range, startPos, endPos) + || rangeContainsStartEnd(range, startPos, endPos) /* Not to miss zero-range nodes e.g. JsxText */ ) { if (inheritedIndentation !== Constants.Unknown) { return inheritedIndentation; @@ -507,7 +608,12 @@ namespace ts.formatting { else { const startLine = sourceFile.getLineAndCharacterOfPosition(startPos).line; const startLinePosition = getLineStartPositionForPosition(startPos, sourceFile); - const column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options); + const column = SmartIndenter.findFirstNonWhitespaceColumn( + startLinePosition, + startPos, + sourceFile, + options, + ); if (startLine !== parentStartLine || startPos === column) { // Use the base indent size if it is greater than // the indentation of the inherited predecessor. @@ -534,7 +640,8 @@ namespace ts.formatting { // - inherit indentation from the parent // - push children if either parent of node itself has non-zero delta return { - indentation: startLine === lastIndentedLine ? indentationOnLastIndentedLine : parentDynamicIndentation.getIndentation(), + indentation: startLine === lastIndentedLine ? indentationOnLastIndentedLine + : parentDynamicIndentation.getIndentation(), delta: Math.min(options.indentSize!, parentDynamicIndentation.getDelta(node) + delta), }; } @@ -542,17 +649,24 @@ namespace ts.formatting { if (node.kind === SyntaxKind.OpenParenToken && startLine === lastIndentedLine) { // the is used for chaining methods formatting // - we need to get the indentation on last line and the delta of parent - return { indentation: indentationOnLastIndentedLine, delta: parentDynamicIndentation.getDelta(node) }; + return { + indentation: indentationOnLastIndentedLine, + delta: parentDynamicIndentation.getDelta(node), + }; } else if ( - SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile) || - SmartIndenter.childIsUnindentedBranchOfConditionalExpression(parent, node, startLine, sourceFile) || - SmartIndenter.argumentStartsOnSameLineAsPreviousArgument(parent, node, startLine, sourceFile) + SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile) + || SmartIndenter.childIsUnindentedBranchOfConditionalExpression(parent, node, startLine, sourceFile) + || SmartIndenter.argumentStartsOnSameLineAsPreviousArgument(parent, node, startLine, sourceFile) ) { return { indentation: parentDynamicIndentation.getIndentation(), delta }; } else { - return { indentation: parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta(node), delta }; + return { + indentation: parentDynamicIndentation.getIndentation() + + parentDynamicIndentation.getDelta(node), + delta, + }; } } else { @@ -594,7 +708,12 @@ namespace ts.formatting { } } - function getDynamicIndentation(node: Node, nodeStartLine: number, indentation: number, delta: number): DynamicIndentation { + function getDynamicIndentation( + node: Node, + nodeStartLine: number, + indentation: number, + delta: number, + ): DynamicIndentation { return { getIndentationForComment: (kind, tokenIndentation, container) => { switch (kind) { @@ -619,7 +738,9 @@ namespace ts.formatting { // vs // var a = xValue // > yValue; - getIndentationForToken: (line, kind, container, suppressDelta) => !suppressDelta && shouldAddDelta(line, kind, container) ? indentation + getDelta(container) : indentation, + getIndentationForToken: (line, kind, container, suppressDelta) => + !suppressDelta && shouldAddDelta(line, kind, container) ? indentation + getDelta(container) + : indentation, getIndentation: () => indentation, getDelta, recomputeIndentation: (lineAdded, parent) => { @@ -664,11 +785,19 @@ namespace ts.formatting { function getDelta(child: TextRangeWithKind) { // Delta value should be zero when the node explicitly prevents indentation of the child node - return SmartIndenter.nodeWillIndentChild(options, node, child, sourceFile, /*indentByDefault*/ true) ? delta : 0; + return SmartIndenter.nodeWillIndentChild(options, node, child, sourceFile, /*indentByDefault*/ true) + ? delta : 0; } } - function processNode(node: Node, contextNode: Node, nodeStartLine: number, undecoratedNodeStartLine: number, indentation: number, delta: number) { + function processNode( + node: Node, + contextNode: Node, + nodeStartLine: number, + undecoratedNodeStartLine: number, + indentation: number, + delta: number, + ) { if (!rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) { return; } @@ -694,7 +823,15 @@ namespace ts.formatting { forEachChild( node, child => { - processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, undecoratedNodeStartLine, /*isListItem*/ false); + processChildNode( + child, + /*inheritedIndentation*/ Constants.Unknown, + node, + nodeDynamicIndentation, + nodeStartLine, + undecoratedNodeStartLine, + /*isListItem*/ false, + ); }, nodes => { processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation); @@ -732,14 +869,21 @@ namespace ts.formatting { let undecoratedChildStartLine = childStartLine; if (hasDecorators(child)) { - undecoratedChildStartLine = sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(child, sourceFile)).line; + undecoratedChildStartLine = + sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(child, sourceFile)).line; } // if child is a list item - try to get its indentation, only if parent is within the original range. let childIndentationAmount = Constants.Unknown; if (isListItem && rangeContainsRange(originalRange, parent)) { - childIndentationAmount = tryComputeIndentationForListItem(childStartPos, child.end, parentStartLine, originalRange, inheritedIndentation); + childIndentationAmount = tryComputeIndentationForListItem( + childStartPos, + child.end, + parentStartLine, + originalRange, + inheritedIndentation, + ); if (childIndentationAmount !== Constants.Unknown) { inheritedIndentation = childIndentationAmount; } @@ -789,21 +933,44 @@ namespace ts.formatting { } } - const effectiveParentStartLine = child.kind === SyntaxKind.Decorator ? childStartLine : undecoratedParentStartLine; - const childIndentation = computeIndentation(child, childStartLine, childIndentationAmount, node, parentDynamicIndentation, effectiveParentStartLine); + const effectiveParentStartLine = child.kind === SyntaxKind.Decorator ? childStartLine + : undecoratedParentStartLine; + const childIndentation = computeIndentation( + child, + childStartLine, + childIndentationAmount, + node, + parentDynamicIndentation, + effectiveParentStartLine, + ); - processNode(child, childContextNode, childStartLine, undecoratedChildStartLine, childIndentation.indentation, childIndentation.delta); + processNode( + child, + childContextNode, + childStartLine, + undecoratedChildStartLine, + childIndentation.indentation, + childIndentation.delta, + ); childContextNode = node; - if (isFirstListItem && parent.kind === SyntaxKind.ArrayLiteralExpression && inheritedIndentation === Constants.Unknown) { + if ( + isFirstListItem && parent.kind === SyntaxKind.ArrayLiteralExpression + && inheritedIndentation === Constants.Unknown + ) { inheritedIndentation = childIndentation.indentation; } return inheritedIndentation; } - function processChildNodes(nodes: NodeArray, parent: Node, parentStartLine: number, parentDynamicIndentation: DynamicIndentation): void { + function processChildNodes( + nodes: NodeArray, + parent: Node, + parentStartLine: number, + parentDynamicIndentation: DynamicIndentation, + ): void { Debug.assert(isNodeArray(nodes)); Debug.assert(!nodeIsSynthesized(nodes)); @@ -842,11 +1009,24 @@ namespace ts.formatting { indentationOnListStartToken = indentationOnLastIndentedLine; } else { - const startLinePosition = getLineStartPositionForPosition(tokenInfo.token.pos, sourceFile); - indentationOnListStartToken = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, tokenInfo.token.pos, sourceFile, options); + const startLinePosition = getLineStartPositionForPosition( + tokenInfo.token.pos, + sourceFile, + ); + indentationOnListStartToken = SmartIndenter.findFirstNonWhitespaceColumn( + startLinePosition, + tokenInfo.token.pos, + sourceFile, + options, + ); } - listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentationOnListStartToken, options.indentSize!); // TODO: GH#18217 + listDynamicIndentation = getDynamicIndentation( + parent, + parentStartLine, + indentationOnListStartToken, + options.indentSize!, + ); // TODO: GH#18217 } else { // consume any tokens that precede the list as child elements of 'node' using its indentation scope @@ -858,11 +1038,23 @@ namespace ts.formatting { let inheritedIndentation = Constants.Unknown; for (let i = 0; i < nodes.length; i++) { const child = nodes[i]; - inheritedIndentation = processChildNode(child, inheritedIndentation, node, listDynamicIndentation, startLine, startLine, /*isListItem*/ true, /*isFirstListItem*/ i === 0); + inheritedIndentation = processChildNode( + child, + inheritedIndentation, + node, + listDynamicIndentation, + startLine, + startLine, + /*isListItem*/ true, + /*isFirstListItem*/ i === 0, + ); } const listEndToken = getCloseTokenForOpenToken(listStartToken); - if (listEndToken !== SyntaxKind.Unknown && formattingScanner.isOnToken() && formattingScanner.getStartPos() < originalRange.end) { + if ( + listEndToken !== SyntaxKind.Unknown && formattingScanner.isOnToken() + && formattingScanner.getStartPos() < originalRange.end + ) { let tokenInfo: TokenInfo | undefined = formattingScanner.readTokenInfo(parent); if (tokenInfo.token.kind === SyntaxKind.CommaToken) { // consume the comma @@ -874,14 +1066,29 @@ namespace ts.formatting { // there might be the case when current token matches end token but does not considered as one // function (x: function) <-- // without this check close paren will be interpreted as list end token for function expression which is wrong - if (tokenInfo && tokenInfo.token.kind === listEndToken && rangeContainsRange(parent, tokenInfo.token)) { + if ( + tokenInfo && tokenInfo.token.kind === listEndToken + && rangeContainsRange(parent, tokenInfo.token) + ) { // consume list end token - consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent, /*isListEndToken*/ true); + consumeTokenAndAdvanceScanner( + tokenInfo, + parent, + listDynamicIndentation, + parent, + /*isListEndToken*/ true, + ); } } } - function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container: Node, isListEndToken?: boolean): void { + function consumeTokenAndAdvanceScanner( + currentTokenInfo: TokenInfo, + parent: Node, + dynamicIndentation: DynamicIndentation, + container: Node, + isListEndToken?: boolean, + ): void { Debug.assert(rangeContainsRange(parent, currentTokenInfo.token)); const lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine(); @@ -899,12 +1106,19 @@ namespace ts.formatting { const rangeHasError = rangeContainsError(currentTokenInfo.token); // save previousRange since processRange will overwrite this value with current one const savePreviousRange = previousRange; - lineAction = processRange(currentTokenInfo.token, tokenStart, parent, childContextNode, dynamicIndentation); + lineAction = processRange( + currentTokenInfo.token, + tokenStart, + parent, + childContextNode, + dynamicIndentation, + ); // do not indent comments\token if token range overlaps with some error if (!rangeHasError) { if (lineAction === LineAction.None) { // indent token only if end line of previous range does not match start line of the token - const prevEndLine = savePreviousRange && sourceFile.getLineAndCharacterOfPosition(savePreviousRange.end).line; + const prevEndLine = savePreviousRange + && sourceFile.getLineAndCharacterOfPosition(savePreviousRange.end).line; indentToken = lastTriviaWasNewLine && tokenStart.line !== prevEndLine; } else { @@ -919,19 +1133,37 @@ namespace ts.formatting { } if (indentToken) { - const tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) ? - dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container, !!isListEndToken) : - Constants.Unknown; + const tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) + ? dynamicIndentation.getIndentationForToken( + tokenStart.line, + currentTokenInfo.token.kind, + container, + !!isListEndToken, + ) + : Constants.Unknown; let indentNextTokenOrTrivia = true; if (currentTokenInfo.leadingTrivia) { - const commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind, tokenIndentation, container); - indentNextTokenOrTrivia = indentTriviaItems(currentTokenInfo.leadingTrivia, commentIndentation, indentNextTokenOrTrivia, item => insertIndentation(item.pos, commentIndentation, /*lineAdded*/ false)); + const commentIndentation = dynamicIndentation.getIndentationForComment( + currentTokenInfo.token.kind, + tokenIndentation, + container, + ); + indentNextTokenOrTrivia = indentTriviaItems( + currentTokenInfo.leadingTrivia, + commentIndentation, + indentNextTokenOrTrivia, + item => insertIndentation(item.pos, commentIndentation, /*lineAdded*/ false), + ); } // indent token only if is it is in target range and does not overlap with any error ranges if (tokenIndentation !== Constants.Unknown && indentNextTokenOrTrivia) { - insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAction === LineAction.LineAdded); + insertIndentation( + currentTokenInfo.token.pos, + tokenIndentation, + lineAction === LineAction.LineAdded, + ); lastIndentedLine = tokenStart.line; indentationOnLastIndentedLine = tokenIndentation; @@ -955,7 +1187,11 @@ namespace ts.formatting { switch (triviaItem.kind) { case SyntaxKind.MultiLineCommentTrivia: if (triviaInRange) { - indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia); + indentMultilineComment( + triviaItem, + commentIndentation, + /*firstLineIsIndented*/ !indentNextTokenOrTrivia, + ); } indentNextTokenOrTrivia = false; break; @@ -973,7 +1209,12 @@ namespace ts.formatting { return indentNextTokenOrTrivia; } - function processTrivia(trivia: TextRangeWithKind[], parent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation): void { + function processTrivia( + trivia: TextRangeWithKind[], + parent: Node, + contextNode: Node, + dynamicIndentation: DynamicIndentation, + ): void { for (const triviaItem of trivia) { if (isComment(triviaItem.kind) && rangeContainsRange(originalRange, triviaItem)) { const triviaItemStart = sourceFile.getLineAndCharacterOfPosition(triviaItem.pos); @@ -982,7 +1223,13 @@ namespace ts.formatting { } } - function processRange(range: TextRangeWithKind, rangeStart: LineAndCharacter, parent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation): LineAction { + function processRange( + range: TextRangeWithKind, + rangeStart: LineAndCharacter, + parent: Node, + contextNode: Node, + dynamicIndentation: DynamicIndentation, + ): LineAction { const rangeHasError = rangeContainsError(range); let lineAction = LineAction.None; if (!rangeHasError) { @@ -992,7 +1239,16 @@ namespace ts.formatting { trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line); } else { - lineAction = processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation); + lineAction = processPair( + range, + rangeStart.line, + parent, + previousRange, + previousRangeStartLine, + previousParent, + contextNode, + dynamicIndentation, + ); } } @@ -1004,7 +1260,16 @@ namespace ts.formatting { return lineAction; } - function processPair(currentItem: TextRangeWithKind, currentStartLine: number, currentParent: Node, previousItem: TextRangeWithKind, previousStartLine: number, previousParent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation | undefined): LineAction { + function processPair( + currentItem: TextRangeWithKind, + currentStartLine: number, + currentParent: Node, + previousItem: TextRangeWithKind, + previousStartLine: number, + previousParent: Node, + contextNode: Node, + dynamicIndentation: DynamicIndentation | undefined, + ): LineAction { formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode); const rules = getRules(formattingContext); @@ -1022,7 +1287,10 @@ namespace ts.formatting { // Handle the case where the next line is moved to be the end of this line. // In this case we don't indent the next line in the next pass. if (currentParent.getStart(sourceFile) === currentItem.pos) { - dynamicIndentation.recomputeIndentation(/*lineAddedByFormatting*/ false, contextNode); + dynamicIndentation.recomputeIndentation( + /*lineAddedByFormatting*/ false, + contextNode, + ); } break; case LineAction.LineAdded: @@ -1030,7 +1298,10 @@ namespace ts.formatting { // In this case we indent token2 in the next pass but we set // sameLineIndent flag to notify the indenter that the indentation is within the line. if (currentParent.getStart(sourceFile) === currentItem.pos) { - dynamicIndentation.recomputeIndentation(/*lineAddedByFormatting*/ true, contextNode); + dynamicIndentation.recomputeIndentation( + /*lineAddedByFormatting*/ true, + contextNode, + ); } break; default: @@ -1039,7 +1310,8 @@ namespace ts.formatting { } // We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line - trimTrailingWhitespaces = trimTrailingWhitespaces && !(rule.action & RuleAction.DeleteSpace) && rule.flags !== RuleFlags.CanDeleteNewLines; + trimTrailingWhitespaces = trimTrailingWhitespaces && !(rule.action & RuleAction.DeleteSpace) + && rule.flags !== RuleFlags.CanDeleteNewLines; }); } else { @@ -1064,7 +1336,10 @@ namespace ts.formatting { else { const tokenStart = sourceFile.getLineAndCharacterOfPosition(pos); const startLinePosition = getStartPositionOfLine(tokenStart.line, sourceFile); - if (indentation !== characterToColumn(startLinePosition, tokenStart.character) || indentationIsDifferent(indentationString, startLinePosition)) { + if ( + indentation !== characterToColumn(startLinePosition, tokenStart.character) + || indentationIsDifferent(indentationString, startLinePosition) + ) { recordReplace(startLinePosition, tokenStart.character, indentationString); } } @@ -1087,7 +1362,12 @@ namespace ts.formatting { return indentationString !== sourceFile.text.substr(startLinePosition, indentationString.length); } - function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean, indentFinalLine = true) { + function indentMultilineComment( + commentRange: TextRange, + indentation: number, + firstLineIsIndented: boolean, + indentFinalLine = true, + ) { // split comment in lines let startLine = sourceFile.getLineAndCharacterOfPosition(commentRange.pos).line; const endLine = sourceFile.getLineAndCharacterOfPosition(commentRange.end).line; @@ -1115,7 +1395,12 @@ namespace ts.formatting { const startLinePos = getStartPositionOfLine(startLine, sourceFile); - const nonWhitespaceColumnInFirstPart = SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(startLinePos, parts[0].pos, sourceFile, options); + const nonWhitespaceColumnInFirstPart = SmartIndenter.findFirstNonWhitespaceCharacterAndColumn( + startLinePos, + parts[0].pos, + sourceFile, + options, + ); let startIndex = 0; if (firstLineIsIndented) { @@ -1129,7 +1414,12 @@ namespace ts.formatting { const startLinePos = getStartPositionOfLine(startLine, sourceFile); const nonWhitespaceCharacterAndColumn = i === 0 ? nonWhitespaceColumnInFirstPart - : SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(parts[i].pos, parts[i].end, sourceFile, options); + : SmartIndenter.findFirstNonWhitespaceCharacterAndColumn( + parts[i].pos, + parts[i].end, + sourceFile, + options, + ); const newIndentation = nonWhitespaceCharacterAndColumn.column + delta; if (newIndentation > 0) { const indentationString = getIndentationString(newIndentation, options); @@ -1147,13 +1437,19 @@ namespace ts.formatting { const lineEndPosition = getEndLinePosition(line, sourceFile); // do not trim whitespaces in comments or template expression - if (range && (isComment(range.kind) || isStringOrRegularExpressionOrTemplateLiteral(range.kind)) && range.pos <= lineEndPosition && range.end > lineEndPosition) { + if ( + range && (isComment(range.kind) || isStringOrRegularExpressionOrTemplateLiteral(range.kind)) + && range.pos <= lineEndPosition && range.end > lineEndPosition + ) { continue; } const whitespaceStart = getTrailingWhitespaceStartPosition(lineStartPosition, lineEndPosition); if (whitespaceStart !== -1) { - Debug.assert(whitespaceStart === lineStartPosition || !isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(whitespaceStart - 1))); + Debug.assert( + whitespaceStart === lineStartPosition + || !isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(whitespaceStart - 1)), + ); recordDelete(whitespaceStart, lineEndPosition + 1 - whitespaceStart); } } @@ -1195,7 +1491,11 @@ namespace ts.formatting { } } - function trimTrailingWitespacesForPositions(startPos: number, endPos: number, previousRange: TextRangeWithKind) { + function trimTrailingWitespacesForPositions( + startPos: number, + endPos: number, + previousRange: TextRangeWithKind, + ) { const startLine = sourceFile.getLineAndCharacterOfPosition(startPos).line; const endLine = sourceFile.getLineAndCharacterOfPosition(endPos).line; @@ -1220,7 +1520,13 @@ namespace ts.formatting { } } - function applyRuleEdits(rule: Rule, previousRange: TextRangeWithKind, previousStartLine: number, currentRange: TextRangeWithKind, currentStartLine: number): LineAction { + function applyRuleEdits( + rule: Rule, + previousRange: TextRangeWithKind, + previousStartLine: number, + currentRange: TextRangeWithKind, + currentStartLine: number, + ): LineAction { const onLaterLine = currentStartLine !== previousStartLine; switch (rule.action) { case RuleAction.StopProcessingSpaceActions: @@ -1247,7 +1553,11 @@ namespace ts.formatting { // edit should not be applied if we have one line feed between elements const lineDelta = currentStartLine - previousStartLine; if (lineDelta !== 1) { - recordReplace(previousRange.end, currentRange.pos - previousRange.end, getNewLineOrDefaultFromHost(host, options)); + recordReplace( + previousRange.end, + currentRange.pos - previousRange.end, + getNewLineOrDefaultFromHost(host, options), + ); return onLaterLine ? LineAction.None : LineAction.LineAdded; } break; @@ -1293,15 +1603,17 @@ namespace ts.formatting { } // eslint-disable-next-line no-null/no-null - precedingToken = precedingToken === null ? undefined : precedingToken === undefined ? findPrecedingToken(position, sourceFile) : precedingToken; + precedingToken = precedingToken === null ? undefined + : precedingToken === undefined ? findPrecedingToken(position, sourceFile) : precedingToken; // Between two consecutive tokens, all comments are either trailing on the former // or leading on the latter (and none are in both lists). - const trailingRangesOfPreviousToken = precedingToken && getTrailingCommentRanges(sourceFile.text, precedingToken.end); + const trailingRangesOfPreviousToken = precedingToken + && getTrailingCommentRanges(sourceFile.text, precedingToken.end); const leadingCommentRangesOfNextToken = getLeadingCommentRangesOfNode(tokenAtPosition, sourceFile); const commentRanges = concatenate(trailingRangesOfPreviousToken, leadingCommentRangesOfNextToken); return commentRanges && find(commentRanges, range => - rangeContainsPositionExclusive(range, position) || + rangeContainsPositionExclusive(range, position) // The end marker of a single-line comment does not include the newline character. // With caret at `^`, in the following case, we are inside a comment (^ denotes the cursor position): // @@ -1315,7 +1627,8 @@ namespace ts.formatting { // // Internally, we represent the end of the comment at the newline and closing '/', respectively. // - position === range.end && (range.kind === SyntaxKind.SingleLineCommentTrivia || position === sourceFile.getFullWidth())); + || position === range.end + && (range.kind === SyntaxKind.SingleLineCommentTrivia || position === sourceFile.getFullWidth())); } function getOpenTokenForList(node: Node, list: readonly Node[]) { @@ -1391,7 +1704,8 @@ namespace ts.formatting { export function getIndentationString(indentation: number, options: EditorSettings): string { // reset interned strings if FormatCodeOptions were changed - const resetInternedStrings = !internedSizes || (internedSizes.tabSize !== options.tabSize || internedSizes.indentSize !== options.indentSize); + const resetInternedStrings = !internedSizes + || (internedSizes.tabSize !== options.tabSize || internedSizes.indentSize !== options.indentSize); if (resetInternedStrings) { internedSizes = { tabSize: options.tabSize!, indentSize: options.indentSize! }; diff --git a/src/services/formatting/formattingContext.ts b/src/services/formatting/formattingContext.ts index 355f42acd5653..97e9b47498c4f 100644 --- a/src/services/formatting/formattingContext.ts +++ b/src/services/formatting/formattingContext.ts @@ -22,10 +22,20 @@ namespace ts.formatting { private contextNodeBlockIsOnOneLine: boolean | undefined; private nextNodeBlockIsOnOneLine: boolean | undefined; - constructor(public readonly sourceFile: SourceFileLike, public formattingRequestKind: FormattingRequestKind, public options: FormatCodeSettings) { + constructor( + public readonly sourceFile: SourceFileLike, + public formattingRequestKind: FormattingRequestKind, + public options: FormatCodeSettings, + ) { } - public updateContext(currentRange: TextRangeWithKind, currentTokenParent: Node, nextRange: TextRangeWithKind, nextTokenParent: Node, commonParent: Node) { + public updateContext( + currentRange: TextRangeWithKind, + currentTokenParent: Node, + nextRange: TextRangeWithKind, + nextTokenParent: Node, + commonParent: Node, + ) { this.currentTokenSpan = Debug.checkDefined(currentRange); this.currentTokenParent = Debug.checkDefined(currentTokenParent); this.nextTokenSpan = Debug.checkDefined(nextRange); @@ -93,7 +103,8 @@ namespace ts.formatting { const closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile); if (openBrace && closeBrace) { const startLine = this.sourceFile.getLineAndCharacterOfPosition(openBrace.getEnd()).line; - const endLine = this.sourceFile.getLineAndCharacterOfPosition(closeBrace.getStart(this.sourceFile)).line; + const endLine = + this.sourceFile.getLineAndCharacterOfPosition(closeBrace.getStart(this.sourceFile)).line; return startLine === endLine; } return false; diff --git a/src/services/formatting/formattingScanner.ts b/src/services/formatting/formattingScanner.ts index 506a80d5abe78..913f502d21368 100644 --- a/src/services/formatting/formattingScanner.ts +++ b/src/services/formatting/formattingScanner.ts @@ -26,7 +26,13 @@ namespace ts.formatting { RescanJsxAttributeValue, } - export function getFormattingScanner(text: string, languageVariant: LanguageVariant, startPos: number, endPos: number, cb: (scanner: FormattingScanner) => T): T { + export function getFormattingScanner( + text: string, + languageVariant: LanguageVariant, + startPos: number, + endPos: number, + cb: (scanner: FormattingScanner) => T, + ): T { const scanner = languageVariant === LanguageVariant.JSX ? jsxScanner : standardScanner; scanner.setText(text); @@ -134,8 +140,8 @@ namespace ts.formatting { } function shouldRescanTemplateToken(container: Node): boolean { - return container.kind === SyntaxKind.TemplateMiddle || - container.kind === SyntaxKind.TemplateTail; + return container.kind === SyntaxKind.TemplateMiddle + || container.kind === SyntaxKind.TemplateTail; } function shouldRescanJsxAttributeValue(node: Node): boolean { @@ -151,13 +157,13 @@ namespace ts.formatting { // normally scanner returns the smallest available token // check the kind of context node to determine if scanner should have more greedy behavior and consume more text. - const expectedScanAction = shouldRescanGreaterThanToken(n) ? ScanAction.RescanGreaterThanToken : - shouldRescanSlashToken(n) ? ScanAction.RescanSlashToken : - shouldRescanTemplateToken(n) ? ScanAction.RescanTemplateToken : - shouldRescanJsxIdentifier(n) ? ScanAction.RescanJsxIdentifier : - shouldRescanJsxText(n) ? ScanAction.RescanJsxText : - shouldRescanJsxAttributeValue(n) ? ScanAction.RescanJsxAttributeValue : - ScanAction.Scan; + const expectedScanAction = shouldRescanGreaterThanToken(n) ? ScanAction.RescanGreaterThanToken + : shouldRescanSlashToken(n) ? ScanAction.RescanSlashToken + : shouldRescanTemplateToken(n) ? ScanAction.RescanTemplateToken + : shouldRescanJsxIdentifier(n) ? ScanAction.RescanJsxIdentifier + : shouldRescanJsxText(n) ? ScanAction.RescanJsxText + : shouldRescanJsxAttributeValue(n) ? ScanAction.RescanJsxAttributeValue + : ScanAction.Scan; if (lastTokenInfo && expectedScanAction === lastScanAction) { // readTokenInfo was called before with the same expected scan action. diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index a448206802393..db1e6fa8220ba 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -22,8 +22,19 @@ namespace ts.formatting { const anyTokenIncludingEOF = tokenRangeFrom([...allTokens, SyntaxKind.EndOfFileToken]); const keywords = tokenRangeFromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword); const binaryOperators = tokenRangeFromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator); - const binaryKeywordOperators = [SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword, SyntaxKind.OfKeyword, SyntaxKind.AsKeyword, SyntaxKind.IsKeyword]; - const unaryPrefixOperators = [SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]; + const binaryKeywordOperators = [ + SyntaxKind.InKeyword, + SyntaxKind.InstanceOfKeyword, + SyntaxKind.OfKeyword, + SyntaxKind.AsKeyword, + SyntaxKind.IsKeyword, + ]; + const unaryPrefixOperators = [ + SyntaxKind.PlusPlusToken, + SyntaxKind.MinusMinusToken, + SyntaxKind.TildeToken, + SyntaxKind.ExclamationToken, + ]; const unaryPrefixExpressions = [ SyntaxKind.NumericLiteral, SyntaxKind.BigIntLiteral, @@ -34,10 +45,30 @@ namespace ts.formatting { SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword, ]; - const unaryPreincrementExpressions = [SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]; - const unaryPostincrementExpressions = [SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]; - const unaryPredecrementExpressions = [SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]; - const unaryPostdecrementExpressions = [SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]; + const unaryPreincrementExpressions = [ + SyntaxKind.Identifier, + SyntaxKind.OpenParenToken, + SyntaxKind.ThisKeyword, + SyntaxKind.NewKeyword, + ]; + const unaryPostincrementExpressions = [ + SyntaxKind.Identifier, + SyntaxKind.CloseParenToken, + SyntaxKind.CloseBracketToken, + SyntaxKind.NewKeyword, + ]; + const unaryPredecrementExpressions = [ + SyntaxKind.Identifier, + SyntaxKind.OpenParenToken, + SyntaxKind.ThisKeyword, + SyntaxKind.NewKeyword, + ]; + const unaryPostdecrementExpressions = [ + SyntaxKind.Identifier, + SyntaxKind.CloseParenToken, + SyntaxKind.CloseBracketToken, + SyntaxKind.NewKeyword, + ]; const comments = [SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]; const typeNames = [SyntaxKind.Identifier, ...typeKeywords]; @@ -46,111 +77,314 @@ namespace ts.formatting { const functionOpenBraceLeftTokenRange = anyTokenIncludingMultilineComments; // Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc) - const typeScriptOpenBraceLeftTokenRange = tokenRangeFrom([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.ClassKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ImportKeyword]); + const typeScriptOpenBraceLeftTokenRange = tokenRangeFrom([ + SyntaxKind.Identifier, + SyntaxKind.MultiLineCommentTrivia, + SyntaxKind.ClassKeyword, + SyntaxKind.ExportKeyword, + SyntaxKind.ImportKeyword, + ]); // Place a space before open brace in a control flow construct - const controlOpenBraceLeftTokenRange = tokenRangeFrom([SyntaxKind.CloseParenToken, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.DoKeyword, SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword, SyntaxKind.ElseKeyword]); + const controlOpenBraceLeftTokenRange = tokenRangeFrom([ + SyntaxKind.CloseParenToken, + SyntaxKind.MultiLineCommentTrivia, + SyntaxKind.DoKeyword, + SyntaxKind.TryKeyword, + SyntaxKind.FinallyKeyword, + SyntaxKind.ElseKeyword, + ]); // These rules are higher in priority than user-configurable const highPriorityCommonRules = [ // Leave comments alone rule("IgnoreBeforeComment", anyToken, comments, anyContext, RuleAction.StopProcessingSpaceActions), - rule("IgnoreAfterLineComment", SyntaxKind.SingleLineCommentTrivia, anyToken, anyContext, RuleAction.StopProcessingSpaceActions), + rule( + "IgnoreAfterLineComment", + SyntaxKind.SingleLineCommentTrivia, + anyToken, + anyContext, + RuleAction.StopProcessingSpaceActions, + ), - rule("NotSpaceBeforeColon", anyToken, SyntaxKind.ColonToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext, isNotTypeAnnotationContext], RuleAction.DeleteSpace), - rule("SpaceAfterColon", SyntaxKind.ColonToken, anyToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.InsertSpace), - rule("NoSpaceBeforeQuestionMark", anyToken, SyntaxKind.QuestionToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext, isNotTypeAnnotationContext], RuleAction.DeleteSpace), + rule("NotSpaceBeforeColon", anyToken, SyntaxKind.ColonToken, [ + isNonJsxSameLineTokenContext, + isNotBinaryOpContext, + isNotTypeAnnotationContext, + ], RuleAction.DeleteSpace), + rule("SpaceAfterColon", SyntaxKind.ColonToken, anyToken, [ + isNonJsxSameLineTokenContext, + isNotBinaryOpContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeQuestionMark", anyToken, SyntaxKind.QuestionToken, [ + isNonJsxSameLineTokenContext, + isNotBinaryOpContext, + isNotTypeAnnotationContext, + ], RuleAction.DeleteSpace), // insert space after '?' only when it is used in conditional operator - rule("SpaceAfterQuestionMarkInConditionalOperator", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext, isConditionalOperatorContext], RuleAction.InsertSpace), + rule("SpaceAfterQuestionMarkInConditionalOperator", SyntaxKind.QuestionToken, anyToken, [ + isNonJsxSameLineTokenContext, + isConditionalOperatorContext, + ], RuleAction.InsertSpace), // in other cases there should be no space between '?' and next token - rule("NoSpaceAfterQuestionMark", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceAfterQuestionMark", + SyntaxKind.QuestionToken, + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), - rule("NoSpaceBeforeDot", anyToken, [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], [isNonJsxSameLineTokenContext, isNotPropertyAccessOnIntegerLiteral], RuleAction.DeleteSpace), - rule("NoSpaceAfterDot", [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], anyToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("NoSpaceBeforeDot", anyToken, [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], [ + isNonJsxSameLineTokenContext, + isNotPropertyAccessOnIntegerLiteral, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterDot", [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], anyToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), - rule("NoSpaceBetweenImportParenInImportType", SyntaxKind.ImportKeyword, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isImportTypeContext], RuleAction.DeleteSpace), + rule("NoSpaceBetweenImportParenInImportType", SyntaxKind.ImportKeyword, SyntaxKind.OpenParenToken, [ + isNonJsxSameLineTokenContext, + isImportTypeContext, + ], RuleAction.DeleteSpace), // Special handling of unary operators. // Prefix operators generally shouldn't have a space between // them and their target unary expression. - rule("NoSpaceAfterUnaryPrefixOperator", unaryPrefixOperators, unaryPrefixExpressions, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterUnaryPreincrementOperator", SyntaxKind.PlusPlusToken, unaryPreincrementExpressions, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterUnaryPredecrementOperator", SyntaxKind.MinusMinusToken, unaryPredecrementExpressions, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeUnaryPostincrementOperator", unaryPostincrementExpressions, SyntaxKind.PlusPlusToken, [isNonJsxSameLineTokenContext, isNotStatementConditionContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeUnaryPostdecrementOperator", unaryPostdecrementExpressions, SyntaxKind.MinusMinusToken, [isNonJsxSameLineTokenContext, isNotStatementConditionContext], RuleAction.DeleteSpace), + rule("NoSpaceAfterUnaryPrefixOperator", unaryPrefixOperators, unaryPrefixExpressions, [ + isNonJsxSameLineTokenContext, + isNotBinaryOpContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterUnaryPreincrementOperator", SyntaxKind.PlusPlusToken, unaryPreincrementExpressions, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterUnaryPredecrementOperator", SyntaxKind.MinusMinusToken, unaryPredecrementExpressions, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeUnaryPostincrementOperator", unaryPostincrementExpressions, SyntaxKind.PlusPlusToken, [ + isNonJsxSameLineTokenContext, + isNotStatementConditionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeUnaryPostdecrementOperator", unaryPostdecrementExpressions, SyntaxKind.MinusMinusToken, [ + isNonJsxSameLineTokenContext, + isNotStatementConditionContext, + ], RuleAction.DeleteSpace), // More unary operator special-casing. // DevDiv 181814: Be careful when removing leading whitespace // around unary operators. Examples: // 1 - -2 --X--> 1--2 // a + ++b --X--> a+++b - rule("SpaceAfterPostincrementWhenFollowedByAdd", SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterAddWhenFollowedByUnaryPlus", SyntaxKind.PlusToken, SyntaxKind.PlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterAddWhenFollowedByPreincrement", SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterPostdecrementWhenFollowedBySubtract", SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterSubtractWhenFollowedByUnaryMinus", SyntaxKind.MinusToken, SyntaxKind.MinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterSubtractWhenFollowedByPredecrement", SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - - rule("NoSpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, [SyntaxKind.CommaToken, SyntaxKind.SemicolonToken], [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceAfterPostincrementWhenFollowedByAdd", SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterAddWhenFollowedByUnaryPlus", SyntaxKind.PlusToken, SyntaxKind.PlusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterAddWhenFollowedByPreincrement", SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterPostdecrementWhenFollowedBySubtract", SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterSubtractWhenFollowedByUnaryMinus", SyntaxKind.MinusToken, SyntaxKind.MinusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterSubtractWhenFollowedByPredecrement", SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + + rule( + "NoSpaceAfterCloseBrace", + SyntaxKind.CloseBraceToken, + [SyntaxKind.CommaToken, SyntaxKind.SemicolonToken], + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), // For functions and control block place } on a new line [multi-line rule] - rule("NewLineBeforeCloseBraceInBlockContext", anyTokenIncludingMultilineComments, SyntaxKind.CloseBraceToken, [isMultilineBlockContext], RuleAction.InsertNewLine), + rule( + "NewLineBeforeCloseBraceInBlockContext", + anyTokenIncludingMultilineComments, + SyntaxKind.CloseBraceToken, + [isMultilineBlockContext], + RuleAction.InsertNewLine, + ), // Space/new line after }. - rule("SpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, anyTokenExcept(SyntaxKind.CloseParenToken), [isNonJsxSameLineTokenContext, isAfterCodeBlockContext], RuleAction.InsertSpace), + rule("SpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, anyTokenExcept(SyntaxKind.CloseParenToken), [ + isNonJsxSameLineTokenContext, + isAfterCodeBlockContext, + ], RuleAction.InsertSpace), // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied // Also should not apply to }) - rule("SpaceBetweenCloseBraceAndElse", SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBetweenCloseBraceAndWhile", SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectContext], RuleAction.DeleteSpace), + rule("SpaceBetweenCloseBraceAndElse", SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBetweenCloseBraceAndWhile", SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isNonJsxSameLineTokenContext, + isObjectContext, + ], RuleAction.DeleteSpace), // Add a space after control dec context if the next character is an open bracket ex: 'if (false)[a, b] = [1, 2];' -> 'if (false) [a, b] = [1, 2];' - rule("SpaceAfterConditionalClosingParen", SyntaxKind.CloseParenToken, SyntaxKind.OpenBracketToken, [isControlDeclContext], RuleAction.InsertSpace), + rule("SpaceAfterConditionalClosingParen", SyntaxKind.CloseParenToken, SyntaxKind.OpenBracketToken, [ + isControlDeclContext, + ], RuleAction.InsertSpace), - rule("NoSpaceBetweenFunctionKeywordAndStar", SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken, [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.DeleteSpace), - rule("SpaceAfterStarInGeneratorDeclaration", SyntaxKind.AsteriskToken, SyntaxKind.Identifier, [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.InsertSpace), + rule("NoSpaceBetweenFunctionKeywordAndStar", SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken, [ + isFunctionDeclarationOrFunctionExpressionContext, + ], RuleAction.DeleteSpace), + rule("SpaceAfterStarInGeneratorDeclaration", SyntaxKind.AsteriskToken, SyntaxKind.Identifier, [ + isFunctionDeclarationOrFunctionExpressionContext, + ], RuleAction.InsertSpace), - rule("SpaceAfterFunctionInFuncDecl", SyntaxKind.FunctionKeyword, anyToken, [isFunctionDeclContext], RuleAction.InsertSpace), + rule( + "SpaceAfterFunctionInFuncDecl", + SyntaxKind.FunctionKeyword, + anyToken, + [isFunctionDeclContext], + RuleAction.InsertSpace, + ), // Insert new line after { and before } in multi-line contexts. - rule("NewLineAfterOpenBraceInBlockContext", SyntaxKind.OpenBraceToken, anyToken, [isMultilineBlockContext], RuleAction.InsertNewLine), + rule( + "NewLineAfterOpenBraceInBlockContext", + SyntaxKind.OpenBraceToken, + anyToken, + [isMultilineBlockContext], + RuleAction.InsertNewLine, + ), // For get/set members, we check for (identifier,identifier) since get/set don't have tokens and they are represented as just an identifier token. // Though, we do extra check on the context to make sure we are dealing with get/set node. Example: // get x() {} // set x(val) {} - rule("SpaceAfterGetSetInMember", [SyntaxKind.GetKeyword, SyntaxKind.SetKeyword], SyntaxKind.Identifier, [isFunctionDeclContext], RuleAction.InsertSpace), - - rule("NoSpaceBetweenYieldKeywordAndStar", SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken, [isNonJsxSameLineTokenContext, isYieldOrYieldStarWithOperand], RuleAction.DeleteSpace), - rule("SpaceBetweenYieldOrYieldStarAndOperand", [SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken], anyToken, [isNonJsxSameLineTokenContext, isYieldOrYieldStarWithOperand], RuleAction.InsertSpace), + rule("SpaceAfterGetSetInMember", [SyntaxKind.GetKeyword, SyntaxKind.SetKeyword], SyntaxKind.Identifier, [ + isFunctionDeclContext, + ], RuleAction.InsertSpace), + + rule("NoSpaceBetweenYieldKeywordAndStar", SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken, [ + isNonJsxSameLineTokenContext, + isYieldOrYieldStarWithOperand, + ], RuleAction.DeleteSpace), + rule( + "SpaceBetweenYieldOrYieldStarAndOperand", + [SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken], + anyToken, + [isNonJsxSameLineTokenContext, isYieldOrYieldStarWithOperand], + RuleAction.InsertSpace, + ), - rule("NoSpaceBetweenReturnAndSemicolon", SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("SpaceAfterCertainKeywords", [SyntaxKind.VarKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.NewKeyword, SyntaxKind.DeleteKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.TypeOfKeyword, SyntaxKind.AwaitKeyword], anyToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceAfterLetConstInVariableDeclaration", [SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword], anyToken, [isNonJsxSameLineTokenContext, isStartOfVariableDeclarationList], RuleAction.InsertSpace), - rule("NoSpaceBeforeOpenParenInFuncCall", anyToken, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isFunctionCallOrNewContext, isPreviousTokenNotComma], RuleAction.DeleteSpace), + rule("NoSpaceBetweenReturnAndSemicolon", SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule( + "SpaceAfterCertainKeywords", + [ + SyntaxKind.VarKeyword, + SyntaxKind.ThrowKeyword, + SyntaxKind.NewKeyword, + SyntaxKind.DeleteKeyword, + SyntaxKind.ReturnKeyword, + SyntaxKind.TypeOfKeyword, + SyntaxKind.AwaitKeyword, + ], + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), + rule( + "SpaceAfterLetConstInVariableDeclaration", + [SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword], + anyToken, + [isNonJsxSameLineTokenContext, isStartOfVariableDeclarationList], + RuleAction.InsertSpace, + ), + rule("NoSpaceBeforeOpenParenInFuncCall", anyToken, SyntaxKind.OpenParenToken, [ + isNonJsxSameLineTokenContext, + isFunctionCallOrNewContext, + isPreviousTokenNotComma, + ], RuleAction.DeleteSpace), // Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options. - rule("SpaceBeforeBinaryKeywordOperator", anyToken, binaryKeywordOperators, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterBinaryKeywordOperator", binaryKeywordOperators, anyToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - - rule("SpaceAfterVoidOperator", SyntaxKind.VoidKeyword, anyToken, [isNonJsxSameLineTokenContext, isVoidOpContext], RuleAction.InsertSpace), + rule("SpaceBeforeBinaryKeywordOperator", anyToken, binaryKeywordOperators, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterBinaryKeywordOperator", binaryKeywordOperators, anyToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + + rule("SpaceAfterVoidOperator", SyntaxKind.VoidKeyword, anyToken, [ + isNonJsxSameLineTokenContext, + isVoidOpContext, + ], RuleAction.InsertSpace), // Async-await - rule("SpaceBetweenAsyncAndOpenParen", SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken, [isArrowFunctionContext, isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBetweenAsyncAndFunctionKeyword", SyntaxKind.AsyncKeyword, [SyntaxKind.FunctionKeyword, SyntaxKind.Identifier], [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule("SpaceBetweenAsyncAndOpenParen", SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken, [ + isArrowFunctionContext, + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule( + "SpaceBetweenAsyncAndFunctionKeyword", + SyntaxKind.AsyncKeyword, + [SyntaxKind.FunctionKeyword, SyntaxKind.Identifier], + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), // Template string - rule("NoSpaceBetweenTagAndTemplateString", [SyntaxKind.Identifier, SyntaxKind.CloseParenToken], [SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead], [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceBetweenTagAndTemplateString", + [SyntaxKind.Identifier, SyntaxKind.CloseParenToken], + [SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead], + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), // JSX opening elements - rule("SpaceBeforeJsxAttribute", anyToken, SyntaxKind.Identifier, [isNextTokenParentJsxAttribute, isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBeforeSlashInJsxOpeningElement", anyToken, SyntaxKind.SlashToken, [isJsxSelfClosingElementContext, isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceBeforeGreaterThanTokenInJsxOpeningElement", SyntaxKind.SlashToken, SyntaxKind.GreaterThanToken, [isJsxSelfClosingElementContext, isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeEqualInJsxAttribute", anyToken, SyntaxKind.EqualsToken, [isJsxAttributeContext, isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterEqualInJsxAttribute", SyntaxKind.EqualsToken, anyToken, [isJsxAttributeContext, isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceBeforeJsxAttribute", anyToken, SyntaxKind.Identifier, [ + isNextTokenParentJsxAttribute, + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeSlashInJsxOpeningElement", anyToken, SyntaxKind.SlashToken, [ + isJsxSelfClosingElementContext, + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule( + "NoSpaceBeforeGreaterThanTokenInJsxOpeningElement", + SyntaxKind.SlashToken, + SyntaxKind.GreaterThanToken, + [isJsxSelfClosingElementContext, isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), + rule("NoSpaceBeforeEqualInJsxAttribute", anyToken, SyntaxKind.EqualsToken, [ + isJsxAttributeContext, + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterEqualInJsxAttribute", SyntaxKind.EqualsToken, anyToken, [ + isJsxAttributeContext, + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // TypeScript-specific rules // Use of module as a function call. e.g.: import m2 = module("m2"); - rule("NoSpaceAfterModuleImport", [SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword], SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceAfterModuleImport", + [SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword], + SyntaxKind.OpenParenToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), // Add a space around certain TypeScript keywords rule( "SpaceAfterCertainTypeScriptKeywords", @@ -192,29 +426,87 @@ namespace ts.formatting { RuleAction.InsertSpace, ), // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { - rule("SpaceAfterModuleName", SyntaxKind.StringLiteral, SyntaxKind.OpenBraceToken, [isModuleDeclContext], RuleAction.InsertSpace), + rule( + "SpaceAfterModuleName", + SyntaxKind.StringLiteral, + SyntaxKind.OpenBraceToken, + [isModuleDeclContext], + RuleAction.InsertSpace, + ), // Lambda expressions - rule("SpaceBeforeArrow", anyToken, SyntaxKind.EqualsGreaterThanToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceAfterArrow", SyntaxKind.EqualsGreaterThanToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule( + "SpaceBeforeArrow", + anyToken, + SyntaxKind.EqualsGreaterThanToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), + rule( + "SpaceAfterArrow", + SyntaxKind.EqualsGreaterThanToken, + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), // Optional parameters and let args - rule("NoSpaceAfterEllipsis", SyntaxKind.DotDotDotToken, SyntaxKind.Identifier, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOptionalParameters", SyntaxKind.QuestionToken, [SyntaxKind.CloseParenToken, SyntaxKind.CommaToken], [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.DeleteSpace), + rule("NoSpaceAfterEllipsis", SyntaxKind.DotDotDotToken, SyntaxKind.Identifier, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule( + "NoSpaceAfterOptionalParameters", + SyntaxKind.QuestionToken, + [SyntaxKind.CloseParenToken, SyntaxKind.CommaToken], + [isNonJsxSameLineTokenContext, isNotBinaryOpContext], + RuleAction.DeleteSpace, + ), // Remove spaces in empty interface literals. e.g.: x: {} - rule("NoSpaceBetweenEmptyInterfaceBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectTypeContext], RuleAction.DeleteSpace), + rule("NoSpaceBetweenEmptyInterfaceBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isNonJsxSameLineTokenContext, + isObjectTypeContext, + ], RuleAction.DeleteSpace), // generics and type assertions - rule("NoSpaceBeforeOpenAngularBracket", typeNames, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceBetweenCloseParenAndAngularBracket", SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOpenAngularBracket", SyntaxKind.LessThanToken, anyToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseAngularBracket", anyToken, SyntaxKind.GreaterThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterCloseAngularBracket", SyntaxKind.GreaterThanToken, [SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.GreaterThanToken, SyntaxKind.CommaToken], [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext, isNotFunctionDeclContext /*To prevent an interference with the SpaceBeforeOpenParenInFuncDecl rule*/], RuleAction.DeleteSpace), + rule("NoSpaceBeforeOpenAngularBracket", typeNames, SyntaxKind.LessThanToken, [ + isNonJsxSameLineTokenContext, + isTypeArgumentOrParameterOrAssertionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBetweenCloseParenAndAngularBracket", SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken, [ + isNonJsxSameLineTokenContext, + isTypeArgumentOrParameterOrAssertionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterOpenAngularBracket", SyntaxKind.LessThanToken, anyToken, [ + isNonJsxSameLineTokenContext, + isTypeArgumentOrParameterOrAssertionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseAngularBracket", anyToken, SyntaxKind.GreaterThanToken, [ + isNonJsxSameLineTokenContext, + isTypeArgumentOrParameterOrAssertionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterCloseAngularBracket", SyntaxKind.GreaterThanToken, [ + SyntaxKind.OpenParenToken, + SyntaxKind.OpenBracketToken, + SyntaxKind.GreaterThanToken, + SyntaxKind.CommaToken, + ], [ + isNonJsxSameLineTokenContext, + isTypeArgumentOrParameterOrAssertionContext, + isNotFunctionDeclContext, /*To prevent an interference with the SpaceBeforeOpenParenInFuncDecl rule*/ + ], RuleAction.DeleteSpace), // decorators - rule("SpaceBeforeAt", [SyntaxKind.CloseParenToken, SyntaxKind.Identifier], SyntaxKind.AtToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceAfterAt", SyntaxKind.AtToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceBeforeAt", [SyntaxKind.CloseParenToken, SyntaxKind.Identifier], SyntaxKind.AtToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule( + "NoSpaceAfterAt", + SyntaxKind.AtToken, + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), // Insert space after @ in decorator rule( "SpaceAfterDecorator", @@ -238,116 +530,404 @@ namespace ts.formatting { RuleAction.InsertSpace, ), - rule("NoSpaceBeforeNonNullAssertionOperator", anyToken, SyntaxKind.ExclamationToken, [isNonJsxSameLineTokenContext, isNonNullAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterNewKeywordOnConstructorSignature", SyntaxKind.NewKeyword, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isConstructorSignatureContext], RuleAction.DeleteSpace), - rule("SpaceLessThanAndNonJSXTypeAnnotation", SyntaxKind.LessThanToken, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule("NoSpaceBeforeNonNullAssertionOperator", anyToken, SyntaxKind.ExclamationToken, [ + isNonJsxSameLineTokenContext, + isNonNullAssertionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterNewKeywordOnConstructorSignature", SyntaxKind.NewKeyword, SyntaxKind.OpenParenToken, [ + isNonJsxSameLineTokenContext, + isConstructorSignatureContext, + ], RuleAction.DeleteSpace), + rule("SpaceLessThanAndNonJSXTypeAnnotation", SyntaxKind.LessThanToken, SyntaxKind.LessThanToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), ]; // These rules are applied after high priority const userConfigurableRules = [ // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses - rule("SpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterConstructor"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterConstructor"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - - rule("SpaceAfterComma", SyntaxKind.CommaToken, anyToken, [isOptionEnabled("insertSpaceAfterCommaDelimiter"), isNonJsxSameLineTokenContext, isNonJsxElementOrFragmentContext, isNextTokenNotCloseBracket, isNextTokenNotCloseParen], RuleAction.InsertSpace), - rule("NoSpaceAfterComma", SyntaxKind.CommaToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterCommaDelimiter"), isNonJsxSameLineTokenContext, isNonJsxElementOrFragmentContext], RuleAction.DeleteSpace), + rule("SpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [ + isOptionEnabled("insertSpaceAfterConstructor"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterConstructor"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + + rule("SpaceAfterComma", SyntaxKind.CommaToken, anyToken, [ + isOptionEnabled("insertSpaceAfterCommaDelimiter"), + isNonJsxSameLineTokenContext, + isNonJsxElementOrFragmentContext, + isNextTokenNotCloseBracket, + isNextTokenNotCloseParen, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterComma", SyntaxKind.CommaToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterCommaDelimiter"), + isNonJsxSameLineTokenContext, + isNonJsxElementOrFragmentContext, + ], RuleAction.DeleteSpace), // Insert space after function keyword for anonymous functions - rule("SpaceAfterAnonymousFunctionKeyword", [SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken], SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], RuleAction.InsertSpace), - rule("NoSpaceAfterAnonymousFunctionKeyword", [SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken], SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], RuleAction.DeleteSpace), + rule( + "SpaceAfterAnonymousFunctionKeyword", + [SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken], + SyntaxKind.OpenParenToken, + [isOptionEnabled("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], + RuleAction.InsertSpace, + ), + rule( + "NoSpaceAfterAnonymousFunctionKeyword", + [SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken], + SyntaxKind.OpenParenToken, + [ + isOptionDisabledOrUndefined("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), + isFunctionDeclContext, + ], + RuleAction.DeleteSpace, + ), // Insert space after keywords in control flow statements - rule("SpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterKeywordsInControlFlowStatements"), isControlDeclContext], RuleAction.InsertSpace), - rule("NoSpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterKeywordsInControlFlowStatements"), isControlDeclContext], RuleAction.DeleteSpace), + rule("SpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [ + isOptionEnabled("insertSpaceAfterKeywordsInControlFlowStatements"), + isControlDeclContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterKeywordsInControlFlowStatements"), + isControlDeclContext, + ], RuleAction.DeleteSpace), // Insert space after opening and before closing nonempty parenthesis - rule("SpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBetweenOpenParens", SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceBetweenParens", SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBetweenOpenParens", SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenParens", SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // Insert space after opening and before closing nonempty brackets - rule("SpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceBetweenBrackets", SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenBrackets", SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}. - rule("SpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isBraceWrappedContext], RuleAction.InsertSpace), - rule("SpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isBraceWrappedContext], RuleAction.InsertSpace), - rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [ + isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), + isBraceWrappedContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [ + isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), + isBraceWrappedContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isNonJsxSameLineTokenContext, + isObjectContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [ + isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [ + isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // Insert a space after opening and before closing empty brace brackets - rule("SpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingEmptyBraces")], RuleAction.InsertSpace), - rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingEmptyBraces"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingEmptyBraces"), + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingEmptyBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // Insert space after opening and before closing template string braces - rule("SpaceAfterTemplateHeadAndMiddle", [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxTextContext], RuleAction.InsertSpace, RuleFlags.CanDeleteNewLines), - rule("SpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceAfterTemplateHeadAndMiddle", [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxTextContext], RuleAction.DeleteSpace, RuleFlags.CanDeleteNewLines), - rule("NoSpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "SpaceAfterTemplateHeadAndMiddle", + [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], + anyToken, + [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxTextContext], + RuleAction.InsertSpace, + RuleFlags.CanDeleteNewLines, + ), + rule("SpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule( + "NoSpaceAfterTemplateHeadAndMiddle", + [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], + anyToken, + [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), + isNonJsxTextContext, + ], + RuleAction.DeleteSpace, + RuleFlags.CanDeleteNewLines, + ), + rule("NoSpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // No space after { and before } in JSX expression - rule("SpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.InsertSpace), - rule("SpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.InsertSpace), - rule("NoSpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.DeleteSpace), + rule("SpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), + isNonJsxSameLineTokenContext, + isJsxExpressionContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), + isNonJsxSameLineTokenContext, + isJsxExpressionContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), + isNonJsxSameLineTokenContext, + isJsxExpressionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), + isNonJsxSameLineTokenContext, + isJsxExpressionContext, + ], RuleAction.DeleteSpace), // Insert space after semicolon in for statement - rule("SpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [isOptionEnabled("insertSpaceAfterSemicolonInForStatements"), isNonJsxSameLineTokenContext, isForContext], RuleAction.InsertSpace), - rule("NoSpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterSemicolonInForStatements"), isNonJsxSameLineTokenContext, isForContext], RuleAction.DeleteSpace), + rule("SpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [ + isOptionEnabled("insertSpaceAfterSemicolonInForStatements"), + isNonJsxSameLineTokenContext, + isForContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterSemicolonInForStatements"), + isNonJsxSameLineTokenContext, + isForContext, + ], RuleAction.DeleteSpace), // Insert space before and after binary operators - rule("SpaceBeforeBinaryOperator", anyToken, binaryOperators, [isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterBinaryOperator", binaryOperators, anyToken, [isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("NoSpaceBeforeBinaryOperator", anyToken, binaryOperators, [isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterBinaryOperator", binaryOperators, anyToken, [isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.DeleteSpace), - - rule("SpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceBeforeFunctionParenthesis"), isNonJsxSameLineTokenContext, isFunctionDeclContext], RuleAction.InsertSpace), - rule("NoSpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceBeforeFunctionParenthesis"), isNonJsxSameLineTokenContext, isFunctionDeclContext], RuleAction.DeleteSpace), + rule("SpaceBeforeBinaryOperator", anyToken, binaryOperators, [ + isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterBinaryOperator", binaryOperators, anyToken, [ + isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeBinaryOperator", anyToken, binaryOperators, [ + isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterBinaryOperator", binaryOperators, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.DeleteSpace), + + rule("SpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [ + isOptionEnabled("insertSpaceBeforeFunctionParenthesis"), + isNonJsxSameLineTokenContext, + isFunctionDeclContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [ + isOptionDisabledOrUndefined("insertSpaceBeforeFunctionParenthesis"), + isNonJsxSameLineTokenContext, + isFunctionDeclContext, + ], RuleAction.DeleteSpace), // Open Brace braces after control block - rule("NewLineBeforeOpenBraceInControl", controlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForControlBlocks"), isControlDeclContext, isBeforeMultilineBlockContext], RuleAction.InsertNewLine, RuleFlags.CanDeleteNewLines), + rule( + "NewLineBeforeOpenBraceInControl", + controlOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionEnabled("placeOpenBraceOnNewLineForControlBlocks"), + isControlDeclContext, + isBeforeMultilineBlockContext, + ], + RuleAction.InsertNewLine, + RuleFlags.CanDeleteNewLines, + ), // Open Brace braces after function // TypeScript: Function can have return types, which can be made of tons of different token kinds - rule("NewLineBeforeOpenBraceInFunction", functionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), isFunctionDeclContext, isBeforeMultilineBlockContext], RuleAction.InsertNewLine, RuleFlags.CanDeleteNewLines), + rule( + "NewLineBeforeOpenBraceInFunction", + functionOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), + isFunctionDeclContext, + isBeforeMultilineBlockContext, + ], + RuleAction.InsertNewLine, + RuleFlags.CanDeleteNewLines, + ), // Open Brace braces after TypeScript module/class/interface - rule("NewLineBeforeOpenBraceInTypeScriptDeclWithBlock", typeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), isTypeScriptDeclWithBlockContext, isBeforeMultilineBlockContext], RuleAction.InsertNewLine, RuleFlags.CanDeleteNewLines), - - rule("SpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [isOptionEnabled("insertSpaceAfterTypeAssertion"), isNonJsxSameLineTokenContext, isTypeAssertionContext], RuleAction.InsertSpace), - rule("NoSpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterTypeAssertion"), isNonJsxSameLineTokenContext, isTypeAssertionContext], RuleAction.DeleteSpace), - - rule("SpaceBeforeTypeAnnotation", anyToken, [SyntaxKind.QuestionToken, SyntaxKind.ColonToken], [isOptionEnabled("insertSpaceBeforeTypeAnnotation"), isNonJsxSameLineTokenContext, isTypeAnnotationContext], RuleAction.InsertSpace), - rule("NoSpaceBeforeTypeAnnotation", anyToken, [SyntaxKind.QuestionToken, SyntaxKind.ColonToken], [isOptionDisabledOrUndefined("insertSpaceBeforeTypeAnnotation"), isNonJsxSameLineTokenContext, isTypeAnnotationContext], RuleAction.DeleteSpace), + rule( + "NewLineBeforeOpenBraceInTypeScriptDeclWithBlock", + typeScriptOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), + isTypeScriptDeclWithBlockContext, + isBeforeMultilineBlockContext, + ], + RuleAction.InsertNewLine, + RuleFlags.CanDeleteNewLines, + ), - rule("NoOptionalSemicolon", SyntaxKind.SemicolonToken, anyTokenIncludingEOF, [optionEquals("semicolons", SemicolonPreference.Remove), isSemicolonDeletionContext], RuleAction.DeleteToken), - rule("OptionalSemicolon", anyToken, anyTokenIncludingEOF, [optionEquals("semicolons", SemicolonPreference.Insert), isSemicolonInsertionContext], RuleAction.InsertTrailingSemicolon), + rule("SpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [ + isOptionEnabled("insertSpaceAfterTypeAssertion"), + isNonJsxSameLineTokenContext, + isTypeAssertionContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterTypeAssertion"), + isNonJsxSameLineTokenContext, + isTypeAssertionContext, + ], RuleAction.DeleteSpace), + + rule("SpaceBeforeTypeAnnotation", anyToken, [SyntaxKind.QuestionToken, SyntaxKind.ColonToken], [ + isOptionEnabled("insertSpaceBeforeTypeAnnotation"), + isNonJsxSameLineTokenContext, + isTypeAnnotationContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeTypeAnnotation", anyToken, [SyntaxKind.QuestionToken, SyntaxKind.ColonToken], [ + isOptionDisabledOrUndefined("insertSpaceBeforeTypeAnnotation"), + isNonJsxSameLineTokenContext, + isTypeAnnotationContext, + ], RuleAction.DeleteSpace), + + rule("NoOptionalSemicolon", SyntaxKind.SemicolonToken, anyTokenIncludingEOF, [ + optionEquals("semicolons", SemicolonPreference.Remove), + isSemicolonDeletionContext, + ], RuleAction.DeleteToken), + rule("OptionalSemicolon", anyToken, anyTokenIncludingEOF, [ + optionEquals("semicolons", SemicolonPreference.Insert), + isSemicolonInsertionContext, + ], RuleAction.InsertTrailingSemicolon), ]; // These rules are lower in priority than user-configurable. Rules earlier in this list have priority over rules later in the list. const lowPriorityCommonRules = [ // Space after keyword but not before ; or : or ? - rule("NoSpaceBeforeSemicolon", anyToken, SyntaxKind.SemicolonToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceBeforeSemicolon", + anyToken, + SyntaxKind.SemicolonToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), - rule("SpaceBeforeOpenBraceInControl", controlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForControlBlocks"), isControlDeclContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.InsertSpace, RuleFlags.CanDeleteNewLines), - rule("SpaceBeforeOpenBraceInFunction", functionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), isFunctionDeclContext, isBeforeBlockContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.InsertSpace, RuleFlags.CanDeleteNewLines), - rule("SpaceBeforeOpenBraceInTypeScriptDeclWithBlock", typeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), isTypeScriptDeclWithBlockContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.InsertSpace, RuleFlags.CanDeleteNewLines), + rule( + "SpaceBeforeOpenBraceInControl", + controlOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForControlBlocks"), + isControlDeclContext, + isNotFormatOnEnter, + isSameLineTokenOrBeforeBlockContext, + ], + RuleAction.InsertSpace, + RuleFlags.CanDeleteNewLines, + ), + rule( + "SpaceBeforeOpenBraceInFunction", + functionOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), + isFunctionDeclContext, + isBeforeBlockContext, + isNotFormatOnEnter, + isSameLineTokenOrBeforeBlockContext, + ], + RuleAction.InsertSpace, + RuleFlags.CanDeleteNewLines, + ), + rule( + "SpaceBeforeOpenBraceInTypeScriptDeclWithBlock", + typeScriptOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), + isTypeScriptDeclWithBlockContext, + isNotFormatOnEnter, + isSameLineTokenOrBeforeBlockContext, + ], + RuleAction.InsertSpace, + RuleFlags.CanDeleteNewLines, + ), - rule("NoSpaceBeforeComma", anyToken, SyntaxKind.CommaToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceBeforeComma", + anyToken, + SyntaxKind.CommaToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), // No space before and after indexer `x[]` - rule("NoSpaceBeforeOpenBracket", anyTokenExcept(SyntaxKind.AsyncKeyword, SyntaxKind.CaseKeyword), SyntaxKind.OpenBracketToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterCloseBracket", SyntaxKind.CloseBracketToken, anyToken, [isNonJsxSameLineTokenContext, isNotBeforeBlockInFunctionDeclarationContext], RuleAction.DeleteSpace), - rule("SpaceAfterSemicolon", SyntaxKind.SemicolonToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule( + "NoSpaceBeforeOpenBracket", + anyTokenExcept(SyntaxKind.AsyncKeyword, SyntaxKind.CaseKeyword), + SyntaxKind.OpenBracketToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), + rule("NoSpaceAfterCloseBracket", SyntaxKind.CloseBracketToken, anyToken, [ + isNonJsxSameLineTokenContext, + isNotBeforeBlockInFunctionDeclarationContext, + ], RuleAction.DeleteSpace), + rule( + "SpaceAfterSemicolon", + SyntaxKind.SemicolonToken, + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), // Remove extra space between for and await - rule("SpaceBetweenForAndAwaitKeyword", SyntaxKind.ForKeyword, SyntaxKind.AwaitKeyword, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule("SpaceBetweenForAndAwaitKeyword", SyntaxKind.ForKeyword, SyntaxKind.AwaitKeyword, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), // Add a space between statements. All keywords except (do,else,case) has open/close parens after them. // So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any] @@ -359,7 +939,13 @@ namespace ts.formatting { RuleAction.InsertSpace, ), // This low-pri rule takes care of "try {", "catch {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter. - rule("SpaceAfterTryCatchFinally", [SyntaxKind.TryKeyword, SyntaxKind.CatchKeyword, SyntaxKind.FinallyKeyword], SyntaxKind.OpenBraceToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule( + "SpaceAfterTryCatchFinally", + [SyntaxKind.TryKeyword, SyntaxKind.CatchKeyword, SyntaxKind.FinallyKeyword], + SyntaxKind.OpenBraceToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), ]; return [ @@ -389,7 +975,11 @@ namespace ts.formatting { action: RuleAction, flags: RuleFlags = RuleFlags.None, ): RuleSpec { - return { leftTokenRange: toTokenRange(left), rightTokenRange: toTokenRange(right), rule: { debugName, context, action, flags } }; + return { + leftTokenRange: toTokenRange(left), + rightTokenRange: toTokenRange(right), + rule: { debugName, context, action, flags }, + }; } function tokenRangeFrom(tokens: readonly SyntaxKind[]): TokenRange { @@ -414,7 +1004,10 @@ namespace ts.formatting { /// Contexts /// - function optionEquals(optionName: K, optionValue: FormatCodeSettings[K]): (context: FormattingContext) => boolean { + function optionEquals( + optionName: K, + optionValue: FormatCodeSettings[K], + ): (context: FormattingContext) => boolean { return context => context.options && context.options[optionName] === optionValue; } @@ -426,16 +1019,23 @@ namespace ts.formatting { return context => context.options && hasProperty(context.options, optionName) && !context.options[optionName]; } - function isOptionDisabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { + function isOptionDisabledOrUndefined( + optionName: keyof FormatCodeSettings, + ): (context: FormattingContext) => boolean { return context => !context.options || !hasProperty(context.options, optionName) || !context.options[optionName]; } - function isOptionDisabledOrUndefinedOrTokensOnSameLine(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return context => !context.options || !hasProperty(context.options, optionName) || !context.options[optionName] || context.TokensAreOnSameLine(); + function isOptionDisabledOrUndefinedOrTokensOnSameLine( + optionName: keyof FormatCodeSettings, + ): (context: FormattingContext) => boolean { + return context => + !context.options || !hasProperty(context.options, optionName) || !context.options[optionName] + || context.TokensAreOnSameLine(); } function isOptionEnabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return context => !context.options || !hasProperty(context.options, optionName) || !!context.options[optionName]; + return context => + !context.options || !hasProperty(context.options, optionName) || !!context.options[optionName]; } function isForContext(context: FormattingContext): boolean { @@ -481,16 +1081,21 @@ namespace ts.formatting { case SyntaxKind.EnumMember: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; + return context.currentTokenSpan.kind === SyntaxKind.EqualsToken + || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; // "in" keyword in for (let x in []) { } case SyntaxKind.ForInStatement: // "in" keyword in [P in keyof T]: T[P] // falls through case SyntaxKind.TypeParameter: - return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword || context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; + return context.currentTokenSpan.kind === SyntaxKind.InKeyword + || context.nextTokenSpan.kind === SyntaxKind.InKeyword + || context.currentTokenSpan.kind === SyntaxKind.EqualsToken + || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; // Technically, "of" is not a binary operator, but format it the same way as "in" case SyntaxKind.ForOfStatement: - return context.currentTokenSpan.kind === SyntaxKind.OfKeyword || context.nextTokenSpan.kind === SyntaxKind.OfKeyword; + return context.currentTokenSpan.kind === SyntaxKind.OfKeyword + || context.nextTokenSpan.kind === SyntaxKind.OfKeyword; } return false; } @@ -505,16 +1110,16 @@ namespace ts.formatting { function isTypeAnnotationContext(context: FormattingContext): boolean { const contextKind = context.contextNode.kind; - return contextKind === SyntaxKind.PropertyDeclaration || - contextKind === SyntaxKind.PropertySignature || - contextKind === SyntaxKind.Parameter || - contextKind === SyntaxKind.VariableDeclaration || - isFunctionLikeKind(contextKind); + return contextKind === SyntaxKind.PropertyDeclaration + || contextKind === SyntaxKind.PropertySignature + || contextKind === SyntaxKind.Parameter + || contextKind === SyntaxKind.VariableDeclaration + || isFunctionLikeKind(contextKind); } function isConditionalOperatorContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ConditionalExpression || - context.contextNode.kind === SyntaxKind.ConditionalType; + return context.contextNode.kind === SyntaxKind.ConditionalExpression + || context.contextNode.kind === SyntaxKind.ConditionalType; } function isSameLineTokenOrBeforeBlockContext(context: FormattingContext): boolean { @@ -522,18 +1127,20 @@ namespace ts.formatting { } function isBraceWrappedContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ObjectBindingPattern || - context.contextNode.kind === SyntaxKind.MappedType || - isSingleLineBlockContext(context); + return context.contextNode.kind === SyntaxKind.ObjectBindingPattern + || context.contextNode.kind === SyntaxKind.MappedType + || isSingleLineBlockContext(context); } // This check is done before an open brace in a control construct, a function, or a typescript block declaration function isBeforeMultilineBlockContext(context: FormattingContext): boolean { - return isBeforeBlockContext(context) && !(context.NextNodeAllOnSameLine() || context.NextNodeBlockIsOnOneLine()); + return isBeforeBlockContext(context) + && !(context.NextNodeAllOnSameLine() || context.NextNodeBlockIsOnOneLine()); } function isMultilineBlockContext(context: FormattingContext): boolean { - return isBlockContext(context) && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); + return isBlockContext(context) + && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); } function isSingleLineBlockContext(context: FormattingContext): boolean { @@ -597,7 +1204,8 @@ namespace ts.formatting { } function isFunctionDeclarationOrFunctionExpressionContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.FunctionDeclaration || context.contextNode.kind === SyntaxKind.FunctionExpression; + return context.contextNode.kind === SyntaxKind.FunctionDeclaration + || context.contextNode.kind === SyntaxKind.FunctionExpression; } function isTypeScriptDeclWithBlockContext(context: FormattingContext): boolean { @@ -634,7 +1242,11 @@ namespace ts.formatting { case SyntaxKind.Block: { const blockParent = context.currentTokenParent.parent; // In a codefix scenario, we can't rely on parents being set. So just always return true. - if (!blockParent || blockParent.kind !== SyntaxKind.ArrowFunction && blockParent.kind !== SyntaxKind.FunctionExpression) { + if ( + !blockParent + || blockParent.kind !== SyntaxKind.ArrowFunction + && blockParent.kind !== SyntaxKind.FunctionExpression + ) { return true; } } @@ -709,11 +1321,13 @@ namespace ts.formatting { } function isNonJsxElementOrFragmentContext(context: FormattingContext): boolean { - return context.contextNode.kind !== SyntaxKind.JsxElement && context.contextNode.kind !== SyntaxKind.JsxFragment; + return context.contextNode.kind !== SyntaxKind.JsxElement + && context.contextNode.kind !== SyntaxKind.JsxFragment; } function isJsxExpressionContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.JsxExpression || context.contextNode.kind === SyntaxKind.JsxSpreadAttribute; + return context.contextNode.kind === SyntaxKind.JsxExpression + || context.contextNode.kind === SyntaxKind.JsxSpreadAttribute; } function isNextTokenParentJsxAttribute(context: FormattingContext): boolean { @@ -733,10 +1347,10 @@ namespace ts.formatting { } function isEndOfDecoratorContextOnSameLine(context: FormattingContext): boolean { - return context.TokensAreOnSameLine() && - hasDecorators(context.contextNode) && - nodeIsInDecoratorContext(context.currentTokenParent) && - !nodeIsInDecoratorContext(context.nextTokenParent); + return context.TokensAreOnSameLine() + && hasDecorators(context.contextNode) + && nodeIsInDecoratorContext(context.currentTokenParent) + && !nodeIsInDecoratorContext(context.nextTokenParent); } function nodeIsInDecoratorContext(node: Node): boolean { @@ -747,8 +1361,8 @@ namespace ts.formatting { } function isStartOfVariableDeclarationList(context: FormattingContext): boolean { - return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList && - context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos; + return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList + && context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos; } function isNotFormatOnEnter(context: FormattingContext): boolean { @@ -795,8 +1409,8 @@ namespace ts.formatting { } function isTypeArgumentOrParameterOrAssertionContext(context: FormattingContext): boolean { - return isTypeArgumentOrParameterOrAssertion(context.currentTokenSpan, context.currentTokenParent) || - isTypeArgumentOrParameterOrAssertion(context.nextTokenSpan, context.nextTokenParent); + return isTypeArgumentOrParameterOrAssertion(context.currentTokenSpan, context.currentTokenParent) + || isTypeArgumentOrParameterOrAssertion(context.nextTokenSpan, context.nextTokenParent); } function isTypeAssertionContext(context: FormattingContext): boolean { @@ -804,11 +1418,13 @@ namespace ts.formatting { } function isVoidOpContext(context: FormattingContext): boolean { - return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.VoidExpression; + return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword + && context.currentTokenParent.kind === SyntaxKind.VoidExpression; } function isYieldOrYieldStarWithOperand(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.YieldExpression && (context.contextNode as YieldExpression).expression !== undefined; + return context.contextNode.kind === SyntaxKind.YieldExpression + && (context.contextNode as YieldExpression).expression !== undefined; } function isNonNullAssertionContext(context: FormattingContext): boolean { @@ -860,15 +1476,15 @@ namespace ts.formatting { } if ( - nextTokenKind === SyntaxKind.SemicolonClassElement || - nextTokenKind === SyntaxKind.SemicolonToken + nextTokenKind === SyntaxKind.SemicolonClassElement + || nextTokenKind === SyntaxKind.SemicolonToken ) { return false; } if ( - context.contextNode.kind === SyntaxKind.InterfaceDeclaration || - context.contextNode.kind === SyntaxKind.TypeAliasDeclaration + context.contextNode.kind === SyntaxKind.InterfaceDeclaration + || context.contextNode.kind === SyntaxKind.TypeAliasDeclaration ) { // Can’t remove semicolon after `foo`; it would parse as a method declaration: // diff --git a/src/services/formatting/rulesMap.ts b/src/services/formatting/rulesMap.ts index 96299835f07b9..61f022107ffbd 100644 --- a/src/services/formatting/rulesMap.ts +++ b/src/services/formatting/rulesMap.ts @@ -79,7 +79,10 @@ namespace ts.formatting { } function getRuleBucketIndex(row: number, column: number): number { - Debug.assert(row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, "Must compute formatting context from tokens"); + Debug.assert( + row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, + "Must compute formatting context from tokens", + ); return (row * mapRowLength) + column; } @@ -111,12 +114,18 @@ namespace ts.formatting { // Example: // In order to insert a rule to the end of sub-bucket (3), we get the index by adding // the values in the bitmap segments 3rd, 2nd, and 1st. - function addRule(rules: Rule[], rule: Rule, specificTokens: boolean, constructionState: number[], rulesBucketIndex: number): void { - const position = rule.action & RuleAction.StopAction ? - specificTokens ? RulesPosition.StopRulesSpecific : RulesPosition.StopRulesAny : - rule.context !== anyContext ? - specificTokens ? RulesPosition.ContextRulesSpecific : RulesPosition.ContextRulesAny : - specificTokens ? RulesPosition.NoContextRulesSpecific : RulesPosition.NoContextRulesAny; + function addRule( + rules: Rule[], + rule: Rule, + specificTokens: boolean, + constructionState: number[], + rulesBucketIndex: number, + ): void { + const position = rule.action & RuleAction.StopAction + ? specificTokens ? RulesPosition.StopRulesSpecific : RulesPosition.StopRulesAny + : rule.context !== anyContext + ? specificTokens ? RulesPosition.ContextRulesSpecific : RulesPosition.ContextRulesAny + : specificTokens ? RulesPosition.NoContextRulesSpecific : RulesPosition.NoContextRulesAny; const state = constructionState[rulesBucketIndex] || 0; rules.splice(getInsertionIndex(state, position), 0, rule); @@ -134,7 +143,10 @@ namespace ts.formatting { function increaseInsertionIndex(indexBitmap: number, maskPosition: RulesPosition): number { const value = ((indexBitmap >> maskPosition) & mask) + 1; - Debug.assert((value & mask) === value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules."); + Debug.assert( + (value & mask) === value, + "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules.", + ); return (indexBitmap & ~(mask << maskPosition)) | (value << maskPosition); } } diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index 270080e95f63e..7a388f0dd35f8 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -20,7 +20,12 @@ namespace ts.formatting { * When inserting some text after an open brace, we would like to get indentation as if a newline was already there. * By default indentation at `position` will be 0 so 'assumeNewLineBeforeCloseBrace' overrides this behavior. */ - export function getIndentation(position: number, sourceFile: SourceFile, options: EditorSettings, assumeNewLineBeforeCloseBrace = false): number { + export function getIndentation( + position: number, + sourceFile: SourceFile, + options: EditorSettings, + assumeNewLineBeforeCloseBrace = false, + ): number { if (position > sourceFile.text.length) { return getBaseIndentation(options); // past EOF } @@ -31,7 +36,12 @@ namespace ts.formatting { return 0; } - const precedingToken = findPrecedingToken(position, sourceFile, /*startNode*/ undefined, /*excludeJsdoc*/ true); + const precedingToken = findPrecedingToken( + position, + sourceFile, + /*startNode*/ undefined, + /*excludeJsdoc*/ true, + ); // eslint-disable-next-line no-null/no-null const enclosingCommentRange = getRangeOfEnclosingComment(sourceFile, position, precedingToken || null); @@ -45,7 +55,10 @@ namespace ts.formatting { // no indentation in string \regex\template literals const precedingTokenIsLiteral = isStringOrRegularExpressionOrTemplateLiteral(precedingToken.kind); - if (precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && position < precedingToken.end) { + if ( + precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position + && position < precedingToken.end + ) { return 0; } @@ -75,14 +88,22 @@ namespace ts.formatting { // y: undefined, // } // ``` - const isObjectLiteral = currentToken.kind === SyntaxKind.OpenBraceToken && currentToken.parent.kind === SyntaxKind.ObjectLiteralExpression; + const isObjectLiteral = currentToken.kind === SyntaxKind.OpenBraceToken + && currentToken.parent.kind === SyntaxKind.ObjectLiteralExpression; if (options.indentStyle === IndentStyle.Block || isObjectLiteral) { return getBlockIndent(sourceFile, position, options); } - if (precedingToken.kind === SyntaxKind.CommaToken && precedingToken.parent.kind !== SyntaxKind.BinaryExpression) { + if ( + precedingToken.kind === SyntaxKind.CommaToken + && precedingToken.parent.kind !== SyntaxKind.BinaryExpression + ) { // previous token is comma that separates items in list - find the previous item and try to derive indentation from it - const actualIndentation = getActualIndentationForListItemBeforeComma(precedingToken, sourceFile, options); + const actualIndentation = getActualIndentationForListItemBeforeComma( + precedingToken, + sourceFile, + options, + ); if (actualIndentation !== Value.Unknown) { return actualIndentation; } @@ -91,26 +112,49 @@ namespace ts.formatting { const containerList = getListByPosition(position, precedingToken.parent, sourceFile); // use list position if the preceding token is before any list items if (containerList && !rangeContainsRange(containerList, precedingToken)) { - const useTheSameBaseIndentation = [SyntaxKind.FunctionExpression, SyntaxKind.ArrowFunction].indexOf(currentToken.parent.kind) !== -1; + const useTheSameBaseIndentation = + [SyntaxKind.FunctionExpression, SyntaxKind.ArrowFunction].indexOf(currentToken.parent.kind) !== -1; const indentSize = useTheSameBaseIndentation ? 0 : options.indentSize!; return getActualIndentationForListStartLine(containerList, sourceFile, options) + indentSize; // TODO: GH#18217 } - return getSmartIndent(sourceFile, position, precedingToken, lineAtPosition, assumeNewLineBeforeCloseBrace, options); + return getSmartIndent( + sourceFile, + position, + precedingToken, + lineAtPosition, + assumeNewLineBeforeCloseBrace, + options, + ); } - function getCommentIndent(sourceFile: SourceFile, position: number, options: EditorSettings, enclosingCommentRange: CommentRange): number { + function getCommentIndent( + sourceFile: SourceFile, + position: number, + options: EditorSettings, + enclosingCommentRange: CommentRange, + ): number { const previousLine = getLineAndCharacterOfPosition(sourceFile, position).line - 1; const commentStartLine = getLineAndCharacterOfPosition(sourceFile, enclosingCommentRange.pos).line; Debug.assert(commentStartLine >= 0); if (previousLine <= commentStartLine) { - return findFirstNonWhitespaceColumn(getStartPositionOfLine(commentStartLine, sourceFile), position, sourceFile, options); + return findFirstNonWhitespaceColumn( + getStartPositionOfLine(commentStartLine, sourceFile), + position, + sourceFile, + options, + ); } const startPositionOfLine = getStartPositionOfLine(previousLine, sourceFile); - const { column, character } = findFirstNonWhitespaceCharacterAndColumn(startPositionOfLine, position, sourceFile, options); + const { column, character } = findFirstNonWhitespaceCharacterAndColumn( + startPositionOfLine, + position, + sourceFile, + options, + ); if (column === 0) { return column; @@ -136,28 +180,57 @@ namespace ts.formatting { return findFirstNonWhitespaceColumn(lineStart, current, sourceFile, options); } - function getSmartIndent(sourceFile: SourceFile, position: number, precedingToken: Node, lineAtPosition: number, assumeNewLineBeforeCloseBrace: boolean, options: EditorSettings): number { + function getSmartIndent( + sourceFile: SourceFile, + position: number, + precedingToken: Node, + lineAtPosition: number, + assumeNewLineBeforeCloseBrace: boolean, + options: EditorSettings, + ): number { // try to find node that can contribute to indentation and includes 'position' starting from 'precedingToken' // if such node is found - compute initial indentation for 'position' inside this node let previous: Node | undefined; let current = precedingToken; while (current) { - if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(options, current, previous, sourceFile, /*isNextChild*/ true)) { + if ( + positionBelongsToNode(current, position, sourceFile) + && shouldIndentChildNode(options, current, previous, sourceFile, /*isNextChild*/ true) + ) { const currentStart = getStartLineAndCharacterForNode(current, sourceFile); - const nextTokenKind = nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile); + const nextTokenKind = nextTokenIsCurlyBraceOnSameLineAsCursor( + precedingToken, + current, + lineAtPosition, + sourceFile, + ); const indentationDelta = nextTokenKind !== NextTokenKind.Unknown // handle cases when codefix is about to be inserted before the close brace - ? assumeNewLineBeforeCloseBrace && nextTokenKind === NextTokenKind.CloseBrace ? options.indentSize : 0 + ? assumeNewLineBeforeCloseBrace && nextTokenKind === NextTokenKind.CloseBrace + ? options.indentSize : 0 : lineAtPosition !== currentStart.line ? options.indentSize : 0; - return getIndentationForNodeWorker(current, currentStart, /*ignoreActualIndentationRange*/ undefined, indentationDelta!, sourceFile, /*isNextChild*/ true, options); // TODO: GH#18217 + return getIndentationForNodeWorker( + current, + currentStart, + /*ignoreActualIndentationRange*/ undefined, + indentationDelta!, + sourceFile, + /*isNextChild*/ true, + options, + ); // TODO: GH#18217 } // check if current node is a list item - if yes, take indentation from it // do not consider parent-child line sharing yet: // function foo(a // | preceding node 'a' does share line with its parent but indentation is expected - const actualIndentation = getActualIndentationForListItem(current, sourceFile, options, /*listIndentsChild*/ true); + const actualIndentation = getActualIndentationForListItem( + current, + sourceFile, + options, + /*listIndentsChild*/ true, + ); if (actualIndentation !== Value.Unknown) { return actualIndentation; } @@ -169,9 +242,22 @@ namespace ts.formatting { return getBaseIndentation(options); } - export function getIndentationForNode(n: Node, ignoreActualIndentationRange: TextRange, sourceFile: SourceFile, options: EditorSettings): number { + export function getIndentationForNode( + n: Node, + ignoreActualIndentationRange: TextRange, + sourceFile: SourceFile, + options: EditorSettings, + ): number { const start = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)); - return getIndentationForNodeWorker(n, start, ignoreActualIndentationRange, /*indentationDelta*/ 0, sourceFile, /*isNextChild*/ false, options); + return getIndentationForNodeWorker( + n, + start, + ignoreActualIndentationRange, + /*indentationDelta*/ 0, + sourceFile, + /*isNextChild*/ false, + options, + ); } export function getBaseIndentation(options: EditorSettings) { @@ -196,12 +282,13 @@ namespace ts.formatting { let useActualIndentation = true; if (ignoreActualIndentationRange) { const start = current.getStart(sourceFile); - useActualIndentation = start < ignoreActualIndentationRange.pos || start > ignoreActualIndentationRange.end; + useActualIndentation = start < ignoreActualIndentationRange.pos + || start > ignoreActualIndentationRange.end; } const containingListOrParentStart = getContainingListOrParentStart(parent, current, sourceFile); - const parentAndChildShareLine = containingListOrParentStart.line === currentStart.line || - childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile); + const parentAndChildShareLine = containingListOrParentStart.line === currentStart.line + || childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile); if (useActualIndentation) { // check if current node is a list item - if yes, take indentation from it @@ -222,21 +309,37 @@ namespace ts.formatting { // }, { itself contributes nothing. // prop: 1 L3 - The indentation of the second object literal is best understood by // }) looking at the relationship between the list and *first* list item. - const listIndentsChild = !!firstListChild && getStartLineAndCharacterForNode(firstListChild, sourceFile).line > containingListOrParentStart.line; - let actualIndentation = getActualIndentationForListItem(current, sourceFile, options, listIndentsChild); + const listIndentsChild = !!firstListChild + && getStartLineAndCharacterForNode(firstListChild, sourceFile).line + > containingListOrParentStart.line; + let actualIndentation = getActualIndentationForListItem( + current, + sourceFile, + options, + listIndentsChild, + ); if (actualIndentation !== Value.Unknown) { return actualIndentation + indentationDelta; } // try to fetch actual indentation for current node from source text - actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options); + actualIndentation = getActualIndentationForNode( + current, + parent, + currentStart, + parentAndChildShareLine, + sourceFile, + options, + ); if (actualIndentation !== Value.Unknown) { return actualIndentation + indentationDelta; } } // increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line - if (shouldIndentChildNode(options, parent, current, sourceFile, isNextChild) && !parentAndChildShareLine) { + if ( + shouldIndentChildNode(options, parent, current, sourceFile, isNextChild) && !parentAndChildShareLine + ) { indentationDelta += options.indentSize!; } @@ -249,11 +352,17 @@ namespace ts.formatting { // Instead, when at an argument, we unspoof the starting position of the enclosing call expression // *after* applying indentation for the argument. - const useTrueStart = isArgumentAndStartLineOverlapsExpressionBeingCalled(parent, current, currentStart.line, sourceFile); + const useTrueStart = isArgumentAndStartLineOverlapsExpressionBeingCalled( + parent, + current, + currentStart.line, + sourceFile, + ); current = parent; parent = current.parent; - currentStart = useTrueStart ? sourceFile.getLineAndCharacterOfPosition(current.getStart(sourceFile)) : containingListOrParentStart; + currentStart = useTrueStart ? sourceFile.getLineAndCharacterOfPosition(current.getStart(sourceFile)) + : containingListOrParentStart; } return indentationDelta + getBaseIndentation(options); @@ -268,11 +377,20 @@ namespace ts.formatting { /* * Function returns Value.Unknown if indentation cannot be determined */ - function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: EditorSettings): number { + function getActualIndentationForListItemBeforeComma( + commaToken: Node, + sourceFile: SourceFile, + options: EditorSettings, + ): number { // previous token is comma that separates items in list - find the previous item and try to derive indentation from it const commaItemInfo = findListItemInfo(commaToken); if (commaItemInfo && commaItemInfo.listItemIndex > 0) { - return deriveActualIndentationFromList(commaItemInfo.list.getChildren(), commaItemInfo.listItemIndex - 1, sourceFile, options); + return deriveActualIndentationFromList( + commaItemInfo.list.getChildren(), + commaItemInfo.listItemIndex - 1, + sourceFile, + options, + ); } else { // handle broken code gracefully @@ -283,12 +401,19 @@ namespace ts.formatting { /* * Function returns Value.Unknown if actual indentation for node should not be used (i.e because node is nested expression) */ - function getActualIndentationForNode(current: Node, parent: Node, currentLineAndChar: LineAndCharacter, parentAndChildShareLine: boolean, sourceFile: SourceFile, options: EditorSettings): number { + function getActualIndentationForNode( + current: Node, + parent: Node, + currentLineAndChar: LineAndCharacter, + parentAndChildShareLine: boolean, + sourceFile: SourceFile, + options: EditorSettings, + ): number { // actual indentation is used for statements\declarations if one of cases below is true: // - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually // - parent and child are not on the same line - const useActualIndentation = (isDeclaration(current) || isStatementButNotDeclaration(current)) && - (parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine); + const useActualIndentation = (isDeclaration(current) || isStatementButNotDeclaration(current)) + && (parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine); if (!useActualIndentation) { return Value.Unknown; @@ -303,7 +428,12 @@ namespace ts.formatting { CloseBrace, } - function nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken: Node, current: Node, lineAtPosition: number, sourceFile: SourceFile): NextTokenKind { + function nextTokenIsCurlyBraceOnSameLineAsCursor( + precedingToken: Node, + current: Node, + lineAtPosition: number, + sourceFile: SourceFile, + ): NextTokenKind { const nextToken = findNextToken(precedingToken, current, sourceFile); if (!nextToken) { return NextTokenKind.Unknown; @@ -334,17 +464,28 @@ namespace ts.formatting { return sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)); } - export function isArgumentAndStartLineOverlapsExpressionBeingCalled(parent: Node, child: Node, childStartLine: number, sourceFile: SourceFileLike): boolean { + export function isArgumentAndStartLineOverlapsExpressionBeingCalled( + parent: Node, + child: Node, + childStartLine: number, + sourceFile: SourceFileLike, + ): boolean { if (!(isCallExpression(parent) && contains(parent.arguments, child))) { return false; } const expressionOfCallExpressionEnd = parent.expression.getEnd(); - const expressionOfCallExpressionEndLine = getLineAndCharacterOfPosition(sourceFile, expressionOfCallExpressionEnd).line; + const expressionOfCallExpressionEndLine = + getLineAndCharacterOfPosition(sourceFile, expressionOfCallExpressionEnd).line; return expressionOfCallExpressionEndLine === childStartLine; } - export function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFileLike): boolean { + export function childStartsOnTheSameLineWithElseInIfStatement( + parent: Node, + child: TextRangeWithKind, + childStartLine: number, + sourceFile: SourceFileLike, + ): boolean { if (parent.kind === SyntaxKind.IfStatement && (parent as IfStatement).elseStatement === child) { const elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile)!; Debug.assert(elseKeyword !== undefined); @@ -377,7 +518,12 @@ namespace ts.formatting { // whenTrue and whenFalse children to avoid double-indenting their contents. To identify this scenario, // we check for the whenTrue branch beginning on the line that the condition ends, and the whenFalse // branch beginning on the line that the whenTrue branch ends. - export function childIsUnindentedBranchOfConditionalExpression(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFileLike): boolean { + export function childIsUnindentedBranchOfConditionalExpression( + parent: Node, + child: TextRangeWithKind, + childStartLine: number, + sourceFile: SourceFileLike, + ): boolean { if (isConditionalExpression(parent) && (child === parent.whenTrue || child === parent.whenFalse)) { const conditionEndLine = getLineAndCharacterOfPosition(sourceFile, parent.condition.end).line; if (child === parent.whenTrue) { @@ -399,7 +545,12 @@ namespace ts.formatting { return false; } - export function argumentStartsOnSameLineAsPreviousArgument(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFileLike): boolean { + export function argumentStartsOnSameLineAsPreviousArgument( + parent: Node, + child: TextRangeWithKind, + childStartLine: number, + sourceFile: SourceFileLike, + ): boolean { if (isCallOrNewExpression(parent)) { if (!parent.arguments) return false; const currentNode = find(parent.arguments, arg => arg.pos === child.pos); @@ -427,7 +578,12 @@ namespace ts.formatting { return node && getListByRange(pos, pos, node, sourceFile); } - function getListByRange(start: number, end: number, node: Node, sourceFile: SourceFile): NodeArray | undefined { + function getListByRange( + start: number, + end: number, + node: Node, + sourceFile: SourceFile, + ): NodeArray | undefined { switch (node.kind) { case SyntaxKind.TypeReference: return getList((node as TypeReferenceNode).typeArguments); @@ -446,7 +602,8 @@ namespace ts.formatting { case SyntaxKind.Constructor: case SyntaxKind.ConstructorType: case SyntaxKind.ConstructSignature: - return getList((node as SignatureDeclaration).typeParameters) || getList((node as SignatureDeclaration).parameters); + return getList((node as SignatureDeclaration).typeParameters) + || getList((node as SignatureDeclaration).parameters); case SyntaxKind.GetAccessor: return getList((node as GetAccessorDeclaration).parameters); case SyntaxKind.ClassDeclaration: @@ -454,10 +611,18 @@ namespace ts.formatting { case SyntaxKind.InterfaceDeclaration: case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.JSDocTemplateTag: - return getList((node as ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag).typeParameters); + return getList( + (node as + | ClassDeclaration + | ClassExpression + | InterfaceDeclaration + | TypeAliasDeclaration + | JSDocTemplateTag).typeParameters, + ); case SyntaxKind.NewExpression: case SyntaxKind.CallExpression: - return getList((node as CallExpression).typeArguments) || getList((node as CallExpression).arguments); + return getList((node as CallExpression).typeArguments) + || getList((node as CallExpression).arguments); case SyntaxKind.VariableDeclarationList: return getList((node as VariableDeclarationList).declarations); case SyntaxKind.NamedImports: @@ -469,7 +634,8 @@ namespace ts.formatting { } function getList(list: NodeArray | undefined): NodeArray | undefined { - return list && rangeContainsStartEnd(getVisualListRange(node, list, sourceFile), start, end) ? list : undefined; + return list && rangeContainsStartEnd(getVisualListRange(node, list, sourceFile), start, end) ? list + : undefined; } } @@ -483,14 +649,27 @@ namespace ts.formatting { return list; } - function getActualIndentationForListStartLine(list: NodeArray, sourceFile: SourceFile, options: EditorSettings): number { + function getActualIndentationForListStartLine( + list: NodeArray, + sourceFile: SourceFile, + options: EditorSettings, + ): number { if (!list) { return Value.Unknown; } - return findColumnForFirstNonWhitespaceCharacterInLine(sourceFile.getLineAndCharacterOfPosition(list.pos), sourceFile, options); + return findColumnForFirstNonWhitespaceCharacterInLine( + sourceFile.getLineAndCharacterOfPosition(list.pos), + sourceFile, + options, + ); } - function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorSettings, listIndentsChild: boolean): number { + function getActualIndentationForListItem( + node: Node, + sourceFile: SourceFile, + options: EditorSettings, + listIndentsChild: boolean, + ): number { if (node.parent && node.parent.kind === SyntaxKind.VariableDeclarationList) { // VariableDeclarationList has no wrapping tokens return Value.Unknown; @@ -504,12 +683,18 @@ namespace ts.formatting { return result; } } - return getActualIndentationForListStartLine(containingList, sourceFile, options) + (listIndentsChild ? options.indentSize! : 0); // TODO: GH#18217 + return getActualIndentationForListStartLine(containingList, sourceFile, options) + + (listIndentsChild ? options.indentSize! : 0); // TODO: GH#18217 } return Value.Unknown; } - function deriveActualIndentationFromList(list: readonly Node[], index: number, sourceFile: SourceFile, options: EditorSettings): number { + function deriveActualIndentationFromList( + list: readonly Node[], + index: number, + sourceFile: SourceFile, + options: EditorSettings, + ): number { Debug.assert(index >= 0 && index < list.length); const node = list[index]; @@ -531,7 +716,11 @@ namespace ts.formatting { return Value.Unknown; } - function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: EditorSettings): number { + function findColumnForFirstNonWhitespaceCharacterInLine( + lineAndCharacter: LineAndCharacter, + sourceFile: SourceFile, + options: EditorSettings, + ): number { const lineStart = sourceFile.getPositionOfLineAndCharacter(lineAndCharacter.line, 0); return findFirstNonWhitespaceColumn(lineStart, lineStart + lineAndCharacter.character, sourceFile, options); } @@ -543,7 +732,12 @@ namespace ts.formatting { * value of 'character' for '$' is 3 * value of 'column' for '$' is 6 (assuming that tab size is 4) */ - export function findFirstNonWhitespaceCharacterAndColumn(startPos: number, endPos: number, sourceFile: SourceFileLike, options: EditorSettings) { + export function findFirstNonWhitespaceCharacterAndColumn( + startPos: number, + endPos: number, + sourceFile: SourceFileLike, + options: EditorSettings, + ) { let character = 0; let column = 0; for (let pos = startPos; pos < endPos; pos++) { @@ -564,11 +758,22 @@ namespace ts.formatting { return { column, character }; } - export function findFirstNonWhitespaceColumn(startPos: number, endPos: number, sourceFile: SourceFileLike, options: EditorSettings): number { + export function findFirstNonWhitespaceColumn( + startPos: number, + endPos: number, + sourceFile: SourceFileLike, + options: EditorSettings, + ): number { return findFirstNonWhitespaceCharacterAndColumn(startPos, endPos, sourceFile, options).column; } - export function nodeWillIndentChild(settings: FormatCodeSettings, parent: TextRangeWithKind, child: TextRangeWithKind | undefined, sourceFile: SourceFileLike | undefined, indentByDefault: boolean): boolean { + export function nodeWillIndentChild( + settings: FormatCodeSettings, + parent: TextRangeWithKind, + child: TextRangeWithKind | undefined, + sourceFile: SourceFileLike | undefined, + indentByDefault: boolean, + ): boolean { const childKind = child ? child.kind : SyntaxKind.Unknown; switch (parent.kind) { @@ -620,12 +825,20 @@ namespace ts.formatting { case SyntaxKind.VariableDeclaration: case SyntaxKind.PropertyAssignment: case SyntaxKind.BinaryExpression: - if (!settings.indentMultiLineObjectLiteralBeginningOnBlankLine && sourceFile && childKind === SyntaxKind.ObjectLiteralExpression) { // TODO: GH#18217 + if ( + !settings.indentMultiLineObjectLiteralBeginningOnBlankLine && sourceFile + && childKind === SyntaxKind.ObjectLiteralExpression + ) { // TODO: GH#18217 return rangeIsOnOneLine(sourceFile, child!); } - if (parent.kind === SyntaxKind.BinaryExpression && sourceFile && child && childKind === SyntaxKind.JsxElement) { - const parentStartLine = sourceFile.getLineAndCharacterOfPosition(skipTrivia(sourceFile.text, parent.pos)).line; - const childStartLine = sourceFile.getLineAndCharacterOfPosition(skipTrivia(sourceFile.text, child.pos)).line; + if ( + parent.kind === SyntaxKind.BinaryExpression && sourceFile && child + && childKind === SyntaxKind.JsxElement + ) { + const parentStartLine = + sourceFile.getLineAndCharacterOfPosition(skipTrivia(sourceFile.text, parent.pos)).line; + const childStartLine = + sourceFile.getLineAndCharacterOfPosition(skipTrivia(sourceFile.text, child.pos)).line; return parentStartLine !== childStartLine; } if (parent.kind !== SyntaxKind.BinaryExpression) { @@ -653,8 +866,9 @@ namespace ts.formatting { case SyntaxKind.ExportDeclaration: return childKind !== SyntaxKind.NamedExports; case SyntaxKind.ImportDeclaration: - return childKind !== SyntaxKind.ImportClause || - (!!(child as ImportClause).namedBindings && (child as ImportClause).namedBindings!.kind !== SyntaxKind.NamedImports); + return childKind !== SyntaxKind.ImportClause + || (!!(child as ImportClause).namedBindings + && (child as ImportClause).namedBindings!.kind !== SyntaxKind.NamedImports); case SyntaxKind.JsxElement: return childKind !== SyntaxKind.JsxClosingElement; case SyntaxKind.JsxFragment: @@ -686,7 +900,13 @@ namespace ts.formatting { * True when the parent node should indent the given child by an explicit rule. * @param isNextChild If true, we are judging indent of a hypothetical child *after* this one, not the current child. */ - export function shouldIndentChildNode(settings: FormatCodeSettings, parent: TextRangeWithKind, child?: Node, sourceFile?: SourceFileLike, isNextChild = false): boolean { + export function shouldIndentChildNode( + settings: FormatCodeSettings, + parent: TextRangeWithKind, + child?: Node, + sourceFile?: SourceFileLike, + isNextChild = false, + ): boolean { return nodeWillIndentChild(settings, parent, child, sourceFile, /*indentByDefault*/ false) && !(isNextChild && child && isControlFlowEndingStatement(child.kind, parent)); } diff --git a/src/services/getEditsForFileRename.ts b/src/services/getEditsForFileRename.ts index c47ac38c6cdb1..60290239f49fa 100644 --- a/src/services/getEditsForFileRename.ts +++ b/src/services/getEditsForFileRename.ts @@ -14,7 +14,15 @@ namespace ts { const oldToNew = getPathUpdater(oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName, sourceMapper); const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper); return textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => { - updateTsconfigFiles(program, changeTracker, oldToNew, oldFileOrDirPath, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames); + updateTsconfigFiles( + program, + changeTracker, + oldToNew, + oldFileOrDirPath, + newFileOrDirPath, + host.getCurrentDirectory(), + useCaseSensitiveFileNames, + ); updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName); }); } @@ -22,13 +30,19 @@ namespace ts { /** If 'path' refers to an old directory, returns path in the new directory. */ type PathUpdater = (path: string) => string | undefined; // exported for tests - export function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName, sourceMapper: SourceMapper | undefined): PathUpdater { + export function getPathUpdater( + oldFileOrDirPath: string, + newFileOrDirPath: string, + getCanonicalFileName: GetCanonicalFileName, + sourceMapper: SourceMapper | undefined, + ): PathUpdater { const canonicalOldPath = getCanonicalFileName(oldFileOrDirPath); return path => { const originalPath = sourceMapper && sourceMapper.tryGetSourcePosition({ fileName: path, pos: 0 }); const updatedPath = getUpdatedPath(originalPath ? originalPath.fileName : path); return originalPath - ? updatedPath === undefined ? undefined : makeCorrespondingRelativeChange(originalPath.fileName, updatedPath, path, getCanonicalFileName) + ? updatedPath === undefined ? undefined + : makeCorrespondingRelativeChange(originalPath.fileName, updatedPath, path, getCanonicalFileName) : updatedPath; }; @@ -40,12 +54,25 @@ namespace ts { } // Relative path from a0 to b0 should be same as relative path from a1 to b1. Returns b1. - function makeCorrespondingRelativeChange(a0: string, b0: string, a1: string, getCanonicalFileName: GetCanonicalFileName): string { + function makeCorrespondingRelativeChange( + a0: string, + b0: string, + a1: string, + getCanonicalFileName: GetCanonicalFileName, + ): string { const rel = getRelativePathFromFile(a0, b0, getCanonicalFileName); return combinePathsSafe(getDirectoryPath(a1), rel); } - function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldToNew: PathUpdater, oldFileOrDirPath: string, newFileOrDirPath: string, currentDirectory: string, useCaseSensitiveFileNames: boolean): void { + function updateTsconfigFiles( + program: Program, + changeTracker: textChanges.ChangeTracker, + oldToNew: PathUpdater, + oldFileOrDirPath: string, + newFileOrDirPath: string, + currentDirectory: string, + useCaseSensitiveFileNames: boolean, + ): void { const { configFile } = program.getCompilerOptions(); if (!configFile) return; const configDir = getDirectoryPath(configFile.fileName); @@ -59,16 +86,35 @@ namespace ts { case "include": case "exclude": { const foundExactMatch = updatePaths(property); - if (foundExactMatch || propertyName !== "include" || !isArrayLiteralExpression(property.initializer)) return; - const includes = mapDefined(property.initializer.elements, e => isStringLiteral(e) ? e.text : undefined); + if ( + foundExactMatch || propertyName !== "include" || !isArrayLiteralExpression(property.initializer) + ) return; + const includes = mapDefined( + property.initializer.elements, + e => isStringLiteral(e) ? e.text : undefined, + ); if (includes.length === 0) return; - const matchers = getFileMatcherPatterns(configDir, /*excludes*/ [], includes, useCaseSensitiveFileNames, currentDirectory); + const matchers = getFileMatcherPatterns( + configDir, + /*excludes*/ [], + includes, + useCaseSensitiveFileNames, + currentDirectory, + ); // If there isn't some include for this, add a new one. if ( - getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(oldFileOrDirPath) && - !getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(newFileOrDirPath) + getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames) + .test(oldFileOrDirPath) + && !getRegexFromPattern( + Debug.checkDefined(matchers.includeFilePattern), + useCaseSensitiveFileNames, + ).test(newFileOrDirPath) ) { - changeTracker.insertNodeAfter(configFile, last(property.initializer.elements), factory.createStringLiteral(relativePath(newFileOrDirPath))); + changeTracker.insertNodeAfter( + configFile, + last(property.initializer.elements), + factory.createStringLiteral(relativePath(newFileOrDirPath)), + ); } return; } @@ -92,7 +138,8 @@ namespace ts { }); function updatePaths(property: PropertyAssignment): boolean { - const elements = isArrayLiteralExpression(property.initializer) ? property.initializer.elements : [property.initializer]; + const elements = isArrayLiteralExpression(property.initializer) ? property.initializer.elements + : [property.initializer]; let foundExactMatch = false; for (const element of elements) { foundExactMatch = tryUpdateString(element) || foundExactMatch; @@ -106,7 +153,11 @@ namespace ts { const updated = oldToNew(elementFileName); if (updated !== undefined) { - changeTracker.replaceRangeWithText(configFile!, createStringRange(element, configFile!), relativePath(updated)); + changeTracker.replaceRangeWithText( + configFile!, + createStringRange(element, configFile!), + relativePath(updated), + ); return true; } return false; @@ -141,21 +192,45 @@ namespace ts { if (!pathIsRelative(referenceText)) return undefined; const oldAbsolute = combinePathsSafe(oldImportFromDirectory, referenceText); const newAbsolute = oldToNew(oldAbsolute); - return newAbsolute === undefined ? undefined : ensurePathIsNonModuleName(getRelativePathFromDirectory(newImportFromDirectory, newAbsolute, getCanonicalFileName)); + return newAbsolute === undefined ? undefined + : ensurePathIsNonModuleName( + getRelativePathFromDirectory(newImportFromDirectory, newAbsolute, getCanonicalFileName), + ); }, importLiteral => { const importedModuleSymbol = program.getTypeChecker().getSymbolAtLocation(importLiteral); // No need to update if it's an ambient module^M - if (importedModuleSymbol?.declarations && importedModuleSymbol.declarations.some(d => isAmbientModule(d))) return undefined; + if ( + importedModuleSymbol?.declarations + && importedModuleSymbol.declarations.some(d => isAmbientModule(d)) + ) return undefined; const toImport = oldFromNew !== undefined // If we're at the new location (file was already renamed), need to redo module resolution starting from the old location. // TODO:GH#18217 - ? getSourceFileToImportFromResolved(importLiteral, resolveModuleName(importLiteral.text, oldImportFromPath, program.getCompilerOptions(), host as ModuleResolutionHost), oldToNew, allFiles) + ? getSourceFileToImportFromResolved( + importLiteral, + resolveModuleName( + importLiteral.text, + oldImportFromPath, + program.getCompilerOptions(), + host as ModuleResolutionHost, + ), + oldToNew, + allFiles, + ) : getSourceFileToImport(importedModuleSymbol, importLiteral, sourceFile, program, host, oldToNew); // Need an update if the imported file moved, or the importing file moved and was using a relative path. - return toImport !== undefined && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text))) - ? moduleSpecifiers.updateModuleSpecifier(program.getCompilerOptions(), sourceFile, getCanonicalFileName(newImportFromPath) as Path, toImport.newFileName, createModuleSpecifierResolutionHost(program, host), importLiteral.text) + return toImport !== undefined + && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text))) + ? moduleSpecifiers.updateModuleSpecifier( + program.getCompilerOptions(), + sourceFile, + getCanonicalFileName(newImportFromPath) as Path, + toImport.newFileName, + createModuleSpecifierResolutionHost(program, host), + importLiteral.text, + ) : undefined; }); } @@ -185,18 +260,33 @@ namespace ts { // `find` should succeed because we checked for ambient modules before calling this function. const oldFileName = find(importedModuleSymbol.declarations, isSourceFile)!.fileName; const newFileName = oldToNew(oldFileName); - return newFileName === undefined ? { newFileName: oldFileName, updated: false } : { newFileName, updated: true }; + return newFileName === undefined ? { newFileName: oldFileName, updated: false } + : { newFileName, updated: true }; } else { const mode = getModeForUsageLocation(importingSourceFile, importLiteral); const resolved = host.resolveModuleNames - ? host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importLiteral.text, importingSourceFile.fileName, mode) - : program.getResolvedModuleWithFailedLookupLocationsFromCache(importLiteral.text, importingSourceFile.fileName, mode); + ? host.getResolvedModuleWithFailedLookupLocationsFromCache + && host.getResolvedModuleWithFailedLookupLocationsFromCache( + importLiteral.text, + importingSourceFile.fileName, + mode, + ) + : program.getResolvedModuleWithFailedLookupLocationsFromCache( + importLiteral.text, + importingSourceFile.fileName, + mode, + ); return getSourceFileToImportFromResolved(importLiteral, resolved, oldToNew, program.getSourceFiles()); } } - function getSourceFileToImportFromResolved(importLiteral: StringLiteralLike, resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, sourceFiles: readonly SourceFile[]): ToImport | undefined { + function getSourceFileToImportFromResolved( + importLiteral: StringLiteralLike, + resolved: ResolvedModuleWithFailedLookupLocations | undefined, + oldToNew: PathUpdater, + sourceFiles: readonly SourceFile[], + ): ToImport | undefined { // Search through all locations looking for a moved file, and only then test already existing files. // This is because if `a.ts` is compiled to `a.js` and `a.ts` is moved, we don't want to resolve anything to `a.js`, but to `a.ts`'s new location. if (!resolved) return undefined; @@ -211,7 +301,8 @@ namespace ts { const result = forEach(resolved.failedLookupLocations, tryChangeWithIgnoringPackageJsonExisting) // Then failed lookups except package.json since we dont want to touch them (only included ts/js files). // At this point, the confidence level of this fix being correct is too low to change bare specifiers or absolute paths. - || pathIsRelative(importLiteral.text) && forEach(resolved.failedLookupLocations, tryChangeWithIgnoringPackageJson); + || pathIsRelative(importLiteral.text) + && forEach(resolved.failedLookupLocations, tryChangeWithIgnoringPackageJson); if (result) return result; // If nothing changed, then result is resolved module file thats not updated @@ -233,15 +324,28 @@ namespace ts { } } - function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined) { + function updateImportsWorker( + sourceFile: SourceFile, + changeTracker: textChanges.ChangeTracker, + updateRef: (refText: string) => string | undefined, + updateImport: (importLiteral: StringLiteralLike) => string | undefined, + ) { for (const ref of sourceFile.referencedFiles || emptyArray) { // TODO: GH#26162 const updated = updateRef(ref.fileName); - if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) changeTracker.replaceRangeWithText(sourceFile, ref, updated); + if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) { + changeTracker.replaceRangeWithText(sourceFile, ref, updated); + } } for (const importStringLiteral of sourceFile.imports) { const updated = updateImport(importStringLiteral); - if (updated !== undefined && updated !== importStringLiteral.text) changeTracker.replaceRangeWithText(sourceFile, createStringRange(importStringLiteral, sourceFile), updated); + if (updated !== undefined && updated !== importStringLiteral.text) { + changeTracker.replaceRangeWithText( + sourceFile, + createStringRange(importStringLiteral, sourceFile), + updated, + ); + } } } @@ -249,7 +353,10 @@ namespace ts { return createRange(node.getStart(sourceFile) + 1, node.end - 1); } - function forEachProperty(objectLiteral: Expression, cb: (property: PropertyAssignment, propertyName: string) => void) { + function forEachProperty( + objectLiteral: Expression, + cb: (property: PropertyAssignment, propertyName: string) => void, + ) { if (!isObjectLiteralExpression(objectLiteral)) return; for (const property of objectLiteral.properties) { if (isPropertyAssignment(property) && isStringLiteral(property.name)) { diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index 0fbe92205a5d2..f0f798974493a 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -1,8 +1,19 @@ /* @internal */ namespace ts.GoToDefinition { - export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number, searchOtherFilesOnly?: boolean, stopAtAlias?: boolean): readonly DefinitionInfo[] | undefined { + export function getDefinitionAtPosition( + program: Program, + sourceFile: SourceFile, + position: number, + searchOtherFilesOnly?: boolean, + stopAtAlias?: boolean, + ): readonly DefinitionInfo[] | undefined { const resolvedRef = getReferenceAtPosition(sourceFile, position, program); - const fileReferenceDefinition = resolvedRef && [getDefinitionInfoForFileReference(resolvedRef.reference.fileName, resolvedRef.fileName, resolvedRef.unverified)] || emptyArray; + const fileReferenceDefinition = resolvedRef + && [getDefinitionInfoForFileReference( + resolvedRef.reference.fileName, + resolvedRef.fileName, + resolvedRef.unverified, + )] || emptyArray; if (resolvedRef?.file) { // If `file` is missing, do a symbol-based lookup as well return fileReferenceDefinition; @@ -16,14 +27,24 @@ namespace ts.GoToDefinition { const { parent } = node; const typeChecker = program.getTypeChecker(); - if (node.kind === SyntaxKind.OverrideKeyword || (isIdentifier(node) && isJSDocOverrideTag(parent) && parent.tagName === node)) { + if ( + node.kind === SyntaxKind.OverrideKeyword + || (isIdentifier(node) && isJSDocOverrideTag(parent) && parent.tagName === node) + ) { return getDefinitionFromOverriddenMember(typeChecker, node) || emptyArray; } // Labels if (isJumpStatementTarget(node)) { const label = getTargetLabel(node.parent, node.text); - return label ? [createDefinitionInfoFromName(typeChecker, label, ScriptElementKind.label, node.text, /*containerName*/ undefined!)] : undefined; // TODO: GH#18217 + return label + ? [createDefinitionInfoFromName( + typeChecker, + label, + ScriptElementKind.label, + node.text, + /*containerName*/ undefined!, + )] : undefined; // TODO: GH#18217 } if (isStaticModifier(node) && isClassStaticBlockDeclaration(node.parent)) { @@ -36,7 +57,16 @@ namespace ts.GoToDefinition { return map(staticBlocks, staticBlock => { let { pos } = moveRangePastModifiers(staticBlock); pos = skipTrivia(sourceFile.text, pos); - return createDefinitionInfoFromName(typeChecker, staticBlock, ScriptElementKind.constructorImplementationElement, "static {}", containerName, /*unverified*/ false, failedAliasResolution, { start: pos, length: "static".length }); + return createDefinitionInfoFromName( + typeChecker, + staticBlock, + ScriptElementKind.constructorImplementationElement, + "static {}", + containerName, + /*unverified*/ false, + failedAliasResolution, + { start: pos, length: "static".length }, + ); }); } @@ -45,7 +75,10 @@ namespace ts.GoToDefinition { if (searchOtherFilesOnly && failedAliasResolution) { // We couldn't resolve the specific import, try on the module specifier. - const importDeclaration = forEach([node, ...symbol?.declarations || emptyArray], n => findAncestor(n, isAnyImportOrBareOrAccessedRequire)); + const importDeclaration = forEach( + [node, ...symbol?.declarations || emptyArray], + n => findAncestor(n, isAnyImportOrBareOrAccessedRequire), + ); const moduleSpecifier = importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration); if (moduleSpecifier) { ({ symbol, failedAliasResolution } = getSymbol(moduleSpecifier, typeChecker, stopAtAlias)); @@ -56,7 +89,10 @@ namespace ts.GoToDefinition { if (!symbol && isModuleSpecifierLike(fallbackNode)) { // We couldn't resolve the module specifier as an external module, but it could // be that module resolution succeeded but the target was not a module. - const ref = sourceFile.resolvedModules?.get(fallbackNode.text, getModeForUsageLocation(sourceFile, fallbackNode)); + const ref = sourceFile.resolvedModules?.get( + fallbackNode.text, + getModeForUsageLocation(sourceFile, fallbackNode), + ); if (ref) { return [{ name: fallbackNode.text, @@ -78,19 +114,27 @@ namespace ts.GoToDefinition { return concatenate(fileReferenceDefinition, getDefinitionInfoForIndexSignatures(node, typeChecker)); } - if (searchOtherFilesOnly && every(symbol.declarations, d => d.getSourceFile().fileName === sourceFile.fileName)) return undefined; + if ( + searchOtherFilesOnly && every(symbol.declarations, d => d.getSourceFile().fileName === sourceFile.fileName) + ) return undefined; const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node); // Don't go to the component constructor definition for a JSX element, just go to the component definition. if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorLike(calledDeclaration))) { - const sigInfo = createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration, failedAliasResolution); + const sigInfo = createDefinitionFromSignatureDeclaration( + typeChecker, + calledDeclaration, + failedAliasResolution, + ); // For a function, if this is the original function definition, return just sigInfo. // If this is the original constructor definition, parent is the class. if (typeChecker.getRootSymbols(symbol).some(s => symbolMatchesSignature(s, calledDeclaration))) { return [sigInfo]; } else { - const defs = getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution, calledDeclaration) || emptyArray; + const defs = + getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution, calledDeclaration) + || emptyArray; // For a 'super()' call, put the signature first, else put the variable first. return node.kind === SyntaxKind.SuperKeyword ? [sigInfo, ...defs] : [...defs, sigInfo]; } @@ -103,7 +147,16 @@ namespace ts.GoToDefinition { // assignment. This case and others are handled by the following code. if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { const shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); - const definitions = shorthandSymbol?.declarations ? shorthandSymbol.declarations.map(decl => createDefinitionInfo(decl, typeChecker, shorthandSymbol, node, /*unverified*/ false, failedAliasResolution)) : emptyArray; + const definitions = shorthandSymbol?.declarations ? shorthandSymbol.declarations.map(decl => + createDefinitionInfo( + decl, + typeChecker, + shorthandSymbol, + node, + /*unverified*/ false, + failedAliasResolution, + ) + ) : emptyArray; return concatenate(definitions, getDefinitionFromObjectLiteralElement(typeChecker, node) || emptyArray); } @@ -119,8 +172,8 @@ namespace ts.GoToDefinition { // } // bar(({pr/*goto*/op1})=>{}); if ( - isPropertyName(node) && isBindingElement(parent) && isObjectBindingPattern(parent.parent) && - (node === (parent.propertyName || parent.name)) + isPropertyName(node) && isBindingElement(parent) && isObjectBindingPattern(parent.parent) + && (node === (parent.propertyName || parent.name)) ) { const name = getNameFromPropertyName(node); const type = typeChecker.getTypeAtLocation(parent.parent); @@ -130,7 +183,11 @@ namespace ts.GoToDefinition { }); } - return concatenate(fileReferenceDefinition, getDefinitionFromObjectLiteralElement(typeChecker, node) || getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution)); + return concatenate( + fileReferenceDefinition, + getDefinitionFromObjectLiteralElement(typeChecker, node) + || getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution), + ); } /** @@ -159,7 +216,10 @@ namespace ts.GoToDefinition { if (element) { const contextualType = element && typeChecker.getContextualType(element.parent); if (contextualType) { - return flatMap(getPropertySymbolsFromContextualType(element, typeChecker, contextualType, /*unionSymbolOk*/ false), propertySymbol => getDefinitionFromSymbol(typeChecker, propertySymbol, node)); + return flatMap( + getPropertySymbolsFromContextualType(element, typeChecker, contextualType, /*unionSymbolOk*/ false), + propertySymbol => getDefinitionFromSymbol(typeChecker, propertySymbol, node), + ); } } } @@ -186,7 +246,11 @@ namespace ts.GoToDefinition { return getDefinitionFromSymbol(typeChecker, symbol, node); } - export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { reference: FileReference; fileName: string; unverified: boolean; file?: SourceFile; } | undefined { + export function getReferenceAtPosition( + sourceFile: SourceFile, + position: number, + program: Program, + ): { reference: FileReference; fileName: string; unverified: boolean; file?: SourceFile; } | undefined { const referencePath = findReferenceInPosition(sourceFile.referencedFiles, position); if (referencePath) { const file = program.getSourceFileFromReference(sourceFile, referencePath); @@ -195,7 +259,10 @@ namespace ts.GoToDefinition { const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position); if (typeReferenceDirective) { - const reference = program.getResolvedTypeReferenceDirectives().get(typeReferenceDirective.fileName, typeReferenceDirective.resolutionMode || sourceFile.impliedNodeFormat); + const reference = program.getResolvedTypeReferenceDirectives().get( + typeReferenceDirective.fileName, + typeReferenceDirective.resolutionMode || sourceFile.impliedNodeFormat, + ); const file = reference && program.getSourceFile(reference.resolvedFileName!); // TODO:GH#18217 return file && { reference: typeReferenceDirective, fileName: file.fileName, file, unverified: false }; } @@ -208,8 +275,14 @@ namespace ts.GoToDefinition { if (sourceFile.resolvedModules?.size()) { const node = getTouchingToken(sourceFile, position); - if (isModuleSpecifierLike(node) && isExternalModuleNameRelative(node.text) && sourceFile.resolvedModules.has(node.text, getModeForUsageLocation(sourceFile, node))) { - const verifiedFileName = sourceFile.resolvedModules.get(node.text, getModeForUsageLocation(sourceFile, node))?.resolvedFileName; + if ( + isModuleSpecifierLike(node) && isExternalModuleNameRelative(node.text) + && sourceFile.resolvedModules.has(node.text, getModeForUsageLocation(sourceFile, node)) + ) { + const verifiedFileName = sourceFile.resolvedModules.get( + node.text, + getModeForUsageLocation(sourceFile, node), + )?.resolvedFileName; const fileName = verifiedFileName || resolvePath(getDirectoryPath(sourceFile.fileName), node.text); return { file: program.getSourceFile(fileName), @@ -228,14 +301,23 @@ namespace ts.GoToDefinition { } /// Goto type - export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile: SourceFile, position: number): readonly DefinitionInfo[] | undefined { + export function getTypeDefinitionAtPosition( + typeChecker: TypeChecker, + sourceFile: SourceFile, + position: number, + ): readonly DefinitionInfo[] | undefined { const node = getTouchingPropertyName(sourceFile, position); if (node === sourceFile) { return undefined; } if (isImportMeta(node.parent) && node.parent.name === node) { - return definitionFromType(typeChecker.getTypeAtLocation(node.parent), typeChecker, node.parent, /*failedAliasResolution*/ false); + return definitionFromType( + typeChecker.getTypeAtLocation(node.parent), + typeChecker, + node.parent, + /*failedAliasResolution*/ false, + ); } const { symbol, failedAliasResolution } = getSymbol(node, typeChecker, /*stopAtAlias*/ false); @@ -245,23 +327,34 @@ namespace ts.GoToDefinition { const returnType = tryGetReturnTypeOfFunction(symbol, typeAtLocation, typeChecker); const fromReturnType = returnType && definitionFromType(returnType, typeChecker, node, failedAliasResolution); // If a function returns 'void' or some other type with no definition, just return the function definition. - const typeDefinitions = fromReturnType && fromReturnType.length !== 0 ? fromReturnType : definitionFromType(typeAtLocation, typeChecker, node, failedAliasResolution); + const typeDefinitions = fromReturnType && fromReturnType.length !== 0 ? fromReturnType + : definitionFromType(typeAtLocation, typeChecker, node, failedAliasResolution); return typeDefinitions.length ? typeDefinitions - : !(symbol.flags & SymbolFlags.Value) && symbol.flags & SymbolFlags.Type ? getDefinitionFromSymbol(typeChecker, skipAlias(symbol, typeChecker), node, failedAliasResolution) + : !(symbol.flags & SymbolFlags.Value) && symbol.flags & SymbolFlags.Type + ? getDefinitionFromSymbol(typeChecker, skipAlias(symbol, typeChecker), node, failedAliasResolution) : undefined; } - function definitionFromType(type: Type, checker: TypeChecker, node: Node, failedAliasResolution: boolean | undefined): readonly DefinitionInfo[] { - return flatMap(type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], t => t.symbol && getDefinitionFromSymbol(checker, t.symbol, node, failedAliasResolution)); + function definitionFromType( + type: Type, + checker: TypeChecker, + node: Node, + failedAliasResolution: boolean | undefined, + ): readonly DefinitionInfo[] { + return flatMap( + type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], + t => t.symbol && getDefinitionFromSymbol(checker, t.symbol, node, failedAliasResolution), + ); } function tryGetReturnTypeOfFunction(symbol: Symbol, type: Type, checker: TypeChecker): Type | undefined { // If the type is just a function's inferred type, // go-to-type should go to the return type instead, since go-to-definition takes you to the function anyway. if ( - type.symbol === symbol || + type.symbol === symbol // At `const f = () => {}`, the symbol is `f` and the type symbol is at `() => {}` - symbol.valueDeclaration && type.symbol && isVariableDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.initializer === type.symbol.valueDeclaration as Node + || symbol.valueDeclaration && type.symbol && isVariableDeclaration(symbol.valueDeclaration) + && symbol.valueDeclaration.initializer === type.symbol.valueDeclaration as Node ) { const sigs = type.getCallSignatures(); if (sigs.length === 1) return checker.getReturnTypeOfSignature(first(sigs)); @@ -269,7 +362,11 @@ namespace ts.GoToDefinition { return undefined; } - export function getDefinitionAndBoundSpan(program: Program, sourceFile: SourceFile, position: number): DefinitionInfoAndBoundSpan | undefined { + export function getDefinitionAndBoundSpan( + program: Program, + sourceFile: SourceFile, + position: number, + ): DefinitionInfoAndBoundSpan | undefined { const definitions = getDefinitionAtPosition(program, sourceFile, position); if (!definitions || definitions.length === 0) { @@ -277,9 +374,9 @@ namespace ts.GoToDefinition { } // Check if position is on triple slash reference. - const comment = findReferenceInPosition(sourceFile.referencedFiles, position) || - findReferenceInPosition(sourceFile.typeReferenceDirectives, position) || - findReferenceInPosition(sourceFile.libReferenceDirectives, position); + const comment = findReferenceInPosition(sourceFile.referencedFiles, position) + || findReferenceInPosition(sourceFile.typeReferenceDirectives, position) + || findReferenceInPosition(sourceFile.libReferenceDirectives, position); if (comment) { return { definitions, textSpan: createTextSpanFromRange(comment) }; @@ -293,7 +390,10 @@ namespace ts.GoToDefinition { // At 'x.foo', see if the type of 'x' has an index signature, and if so find its declarations. function getDefinitionInfoForIndexSignatures(node: Node, checker: TypeChecker): DefinitionInfo[] | undefined { - return mapDefined(checker.getIndexInfosAtLocation(node), info => info.declaration && createDefinitionFromSignatureDeclaration(checker, info.declaration)); + return mapDefined( + checker.getIndexInfosAtLocation(node), + info => info.declaration && createDefinitionFromSignatureDeclaration(checker, info.declaration), + ); } function getSymbol(node: Node, checker: TypeChecker, stopAtAlias: boolean | undefined) { @@ -303,7 +403,10 @@ namespace ts.GoToDefinition { // import {A, B} from "mod"; // to jump to the implementation directly. let failedAliasResolution = false; - if (symbol?.declarations && symbol.flags & SymbolFlags.Alias && !stopAtAlias && shouldSkipAlias(node, symbol.declarations[0])) { + if ( + symbol?.declarations && symbol.flags & SymbolFlags.Alias && !stopAtAlias + && shouldSkipAlias(node, symbol.declarations[0]) + ) { const aliased = checker.getAliasedSymbol(symbol); if (aliased.declarations) { return { symbol: aliased }; @@ -357,20 +460,43 @@ namespace ts.GoToDefinition { if (!isAssignmentDeclaration(p as Declaration)) return "quit"; return false; }) as AssignmentExpression | undefined; - return !!containingAssignment && getAssignmentDeclarationKind(containingAssignment) === AssignmentDeclarationKind.Property; + return !!containingAssignment + && getAssignmentDeclarationKind(containingAssignment) === AssignmentDeclarationKind.Property; } - function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node, failedAliasResolution?: boolean, excludeDeclaration?: Node): DefinitionInfo[] | undefined { + function getDefinitionFromSymbol( + typeChecker: TypeChecker, + symbol: Symbol, + node: Node, + failedAliasResolution?: boolean, + excludeDeclaration?: Node, + ): DefinitionInfo[] | undefined { const filteredDeclarations = filter(symbol.declarations, d => d !== excludeDeclaration); const withoutExpandos = filter(filteredDeclarations, d => !isExpandoDeclaration(d)); const results = some(withoutExpandos) ? withoutExpandos : filteredDeclarations; - return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(results, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node, /*unverified*/ false, failedAliasResolution)); + return getConstructSignatureDefinition() || getCallSignatureDefinition() + || map( + results, + declaration => + createDefinitionInfo( + declaration, + typeChecker, + symbol, + node, + /*unverified*/ false, + failedAliasResolution, + ), + ); function getConstructSignatureDefinition(): DefinitionInfo[] | undefined { // Applicable only if we are in a new expression, or we are on a constructor declaration // and in either case the symbol has a construct signature definition, i.e. class - if (symbol.flags & SymbolFlags.Class && !(symbol.flags & (SymbolFlags.Function | SymbolFlags.Variable)) && (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword)) { - const cls = find(filteredDeclarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration"); + if ( + symbol.flags & SymbolFlags.Class && !(symbol.flags & (SymbolFlags.Function | SymbolFlags.Variable)) + && (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword) + ) { + const cls = find(filteredDeclarations, isClassLike) + || Debug.fail("Expected declaration to have at least one class-like declaration"); return getSignatureDefinition(cls.members, /*selectConstructors*/ true); } } @@ -381,32 +507,68 @@ namespace ts.GoToDefinition { : undefined; } - function getSignatureDefinition(signatureDeclarations: readonly Declaration[] | undefined, selectConstructors: boolean): DefinitionInfo[] | undefined { + function getSignatureDefinition( + signatureDeclarations: readonly Declaration[] | undefined, + selectConstructors: boolean, + ): DefinitionInfo[] | undefined { if (!signatureDeclarations) { return undefined; } - const declarations = signatureDeclarations.filter(selectConstructors ? isConstructorDeclaration : isFunctionLike); + const declarations = signatureDeclarations.filter( + selectConstructors ? isConstructorDeclaration : isFunctionLike, + ); const declarationsWithBody = declarations.filter(d => !!(d as FunctionLikeDeclaration).body); // declarations defined on the global scope can be defined on multiple files. Get all of them. return declarations.length ? declarationsWithBody.length !== 0 ? declarationsWithBody.map(x => createDefinitionInfo(x, typeChecker, symbol, node)) - : [createDefinitionInfo(last(declarations), typeChecker, symbol, node, /*unverified*/ false, failedAliasResolution)] + : [createDefinitionInfo( + last(declarations), + typeChecker, + symbol, + node, + /*unverified*/ false, + failedAliasResolution, + )] : undefined; } } /** Creates a DefinitionInfo from a Declaration, using the declaration's name if possible. */ - export function createDefinitionInfo(declaration: Declaration, checker: TypeChecker, symbol: Symbol, node: Node, unverified?: boolean, failedAliasResolution?: boolean): DefinitionInfo { + export function createDefinitionInfo( + declaration: Declaration, + checker: TypeChecker, + symbol: Symbol, + node: Node, + unverified?: boolean, + failedAliasResolution?: boolean, + ): DefinitionInfo { const symbolName = checker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol const symbolKind = SymbolDisplay.getSymbolKind(checker, symbol, node); const containerName = symbol.parent ? checker.symbolToString(symbol.parent, node) : ""; - return createDefinitionInfoFromName(checker, declaration, symbolKind, symbolName, containerName, unverified, failedAliasResolution); + return createDefinitionInfoFromName( + checker, + declaration, + symbolKind, + symbolName, + containerName, + unverified, + failedAliasResolution, + ); } /** Creates a DefinitionInfo directly from the name of a declaration. */ - function createDefinitionInfoFromName(checker: TypeChecker, declaration: Declaration, symbolKind: ScriptElementKind, symbolName: string, containerName: string, unverified?: boolean, failedAliasResolution?: boolean, textSpan?: TextSpan): DefinitionInfo { + function createDefinitionInfoFromName( + checker: TypeChecker, + declaration: Declaration, + symbolKind: ScriptElementKind, + symbolName: string, + containerName: string, + unverified?: boolean, + failedAliasResolution?: boolean, + textSpan?: TextSpan, + ): DefinitionInfo { const sourceFile = declaration.getSourceFile(); if (!textSpan) { const name = getNameOfDeclaration(declaration) || declaration; @@ -436,7 +598,9 @@ namespace ts.GoToDefinition { if (!declaration.parent) return false; // Variable initializers are visible if variable is visible - if (hasInitializer(declaration.parent) && declaration.parent.initializer === declaration) return isDefinitionVisible(checker, declaration.parent as Declaration); + if (hasInitializer(declaration.parent) && declaration.parent.initializer === declaration) { + return isDefinitionVisible(checker, declaration.parent as Declaration); + } // Handle some exceptions here like arrow function, members of class and object literal expression which are technically not visible but we want the definition to be determined by its parent switch (declaration.kind) { @@ -462,7 +626,11 @@ namespace ts.GoToDefinition { } } - function createDefinitionFromSignatureDeclaration(typeChecker: TypeChecker, decl: SignatureDeclaration, failedAliasResolution?: boolean): DefinitionInfo { + function createDefinitionFromSignatureDeclaration( + typeChecker: TypeChecker, + decl: SignatureDeclaration, + failedAliasResolution?: boolean, + ): DefinitionInfo { return createDefinitionInfo(decl, typeChecker, decl.symbol, decl, /*unverified*/ false, failedAliasResolution); } @@ -470,7 +638,11 @@ namespace ts.GoToDefinition { return find(refs, ref => textRangeContainsPositionInclusive(ref, pos)); } - function getDefinitionInfoForFileReference(name: string, targetFileName: string, unverified: boolean): DefinitionInfo { + function getDefinitionInfoForFileReference( + name: string, + targetFileName: string, + unverified: boolean, + ): DefinitionInfo { return { fileName: targetFileName, textSpan: createTextSpanFromBounds(0, 0), @@ -486,14 +658,18 @@ namespace ts.GoToDefinition { function getAncestorCallLikeExpression(node: Node): CallLikeExpression | undefined { const target = findAncestor(node, n => !isRightSideOfPropertyAccess(n)); const callLike = target?.parent; - return callLike && isCallLikeExpression(callLike) && getInvokedExpression(callLike) === target ? callLike : undefined; + return callLike && isCallLikeExpression(callLike) && getInvokedExpression(callLike) === target ? callLike + : undefined; } function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined { const callLike = getAncestorCallLikeExpression(node); const signature = callLike && typeChecker.getResolvedSignature(callLike); // Don't go to a function type, go to the value having that type. - return tryCast(signature && signature.declaration, (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d)); + return tryCast( + signature && signature.declaration, + (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d), + ); } function isConstructorLike(node: Node): boolean { diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index 091589a41202e..fef8cb3b8bee3 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -12,11 +12,32 @@ namespace ts.FindAllReferences { export type ImportTracker = (exportSymbol: Symbol, exportInfo: ExportInfo, isForRename: boolean) => ImportsResult; /** Creates the imports map and returns an ImportTracker that uses it. Call this lazily to avoid calling `getDirectImportsMap` unnecessarily. */ - export function createImportTracker(sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet, checker: TypeChecker, cancellationToken: CancellationToken | undefined): ImportTracker { + export function createImportTracker( + sourceFiles: readonly SourceFile[], + sourceFilesSet: ReadonlySet, + checker: TypeChecker, + cancellationToken: CancellationToken | undefined, + ): ImportTracker { const allDirectImports = getDirectImportsMap(sourceFiles, checker, cancellationToken); return (exportSymbol, exportInfo, isForRename) => { - const { directImports, indirectUsers } = getImportersForExport(sourceFiles, sourceFilesSet, allDirectImports, exportInfo, checker, cancellationToken); - return { indirectUsers, ...getSearchesFromDirectImports(directImports, exportSymbol, exportInfo.exportKind, checker, isForRename) }; + const { directImports, indirectUsers } = getImportersForExport( + sourceFiles, + sourceFilesSet, + allDirectImports, + exportInfo, + checker, + cancellationToken, + ); + return { + indirectUsers, + ...getSearchesFromDirectImports( + directImports, + exportSymbol, + exportInfo.exportKind, + checker, + isForRename, + ), + }; }; } @@ -101,7 +122,10 @@ namespace ts.FindAllReferences { } if (!isAvailableThroughGlobal) { const parent = direct.parent; - if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) { + if ( + exportKind === ExportKind.ExportEquals + && parent.kind === SyntaxKind.VariableDeclaration + ) { const { name } = parent as VariableDeclaration; if (name.kind === SyntaxKind.Identifier) { directImports.push(name); @@ -115,14 +139,24 @@ namespace ts.FindAllReferences { break; // TODO: GH#23879 case SyntaxKind.ImportEqualsDeclaration: - handleNamespaceImport(direct, direct.name, hasSyntacticModifier(direct, ModifierFlags.Export), /*alreadyAddedDirect*/ false); + handleNamespaceImport( + direct, + direct.name, + hasSyntacticModifier(direct, ModifierFlags.Export), + /*alreadyAddedDirect*/ false, + ); break; case SyntaxKind.ImportDeclaration: directImports.push(direct); const namedBindings = direct.importClause && direct.importClause.namedBindings; if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) { - handleNamespaceImport(direct, namedBindings.name, /*isReExport*/ false, /*alreadyAddedDirect*/ true); + handleNamespaceImport( + direct, + namedBindings.name, + /*isReExport*/ false, + /*alreadyAddedDirect*/ true, + ); } else if (!isAvailableThroughGlobal && isDefaultImport(direct)) { addIndirectUser(getSourceFileLikeForImportDeclaration(direct)); // Add a check for indirect uses to handle synthetic default imports @@ -136,7 +170,10 @@ namespace ts.FindAllReferences { } else if (direct.exportClause.kind === SyntaxKind.NamespaceExport) { // `export * as foo from "foo"` add to indirect uses - addIndirectUser(getSourceFileLikeForImportDeclaration(direct), /** addTransitiveDependencies */ true); + addIndirectUser( + getSourceFileLikeForImportDeclaration(direct), + /** addTransitiveDependencies */ true, + ); } else { // This is `export { foo } from "foo"` and creates an alias symbol, so recursive search will get handle re-exports. @@ -146,7 +183,9 @@ namespace ts.FindAllReferences { case SyntaxKind.ImportType: // Only check for typeof import('xyz') - if (!isAvailableThroughGlobal && direct.isTypeOf && !direct.qualifier && isExported(direct)) { + if ( + !isAvailableThroughGlobal && direct.isTypeOf && !direct.qualifier && isExported(direct) + ) { addIndirectUser(direct.getSourceFile(), /** addTransitiveDependencies */ true); } directImports.push(direct); @@ -161,7 +200,10 @@ namespace ts.FindAllReferences { function handleImportCall(importCall: ImportCall) { const top = findAncestor(importCall, isAmbientModuleDeclaration) || importCall.getSourceFile(); - addIndirectUser(top, /** addTransitiveDependencies */ !!isExported(importCall, /** stopAtAmbientModule */ true)); + addIndirectUser( + top, + /** addTransitiveDependencies */ !!isExported(importCall, /** stopAtAmbientModule */ true), + ); } function isExported(node: Node, stopAtAmbientModule = false) { @@ -171,14 +213,22 @@ namespace ts.FindAllReferences { }); } - function handleNamespaceImport(importDeclaration: ImportEqualsDeclaration | ImportDeclaration, name: Identifier, isReExport: boolean, alreadyAddedDirect: boolean): void { + function handleNamespaceImport( + importDeclaration: ImportEqualsDeclaration | ImportDeclaration, + name: Identifier, + isReExport: boolean, + alreadyAddedDirect: boolean, + ): void { if (exportKind === ExportKind.ExportEquals) { // This is a direct import, not import-as-namespace. if (!alreadyAddedDirect) directImports.push(importDeclaration); } else if (!isAvailableThroughGlobal) { const sourceFileLike = getSourceFileLikeForImportDeclaration(importDeclaration); - Debug.assert(sourceFileLike.kind === SyntaxKind.SourceFile || sourceFileLike.kind === SyntaxKind.ModuleDeclaration); + Debug.assert( + sourceFileLike.kind === SyntaxKind.SourceFile + || sourceFileLike.kind === SyntaxKind.ModuleDeclaration, + ); if (isReExport || findNamespaceReExports(sourceFileLike, name, checker)) { addIndirectUser(sourceFileLike, /** addTransitiveDependencies */ true); } @@ -203,7 +253,10 @@ namespace ts.FindAllReferences { if (directImports) { for (const directImport of directImports) { if (!isImportTypeNode(directImport)) { - addIndirectUser(getSourceFileLikeForImportDeclaration(directImport), /** addTransitiveDependencies */ true); + addIndirectUser( + getSourceFileLikeForImportDeclaration(directImport), + /** addTransitiveDependencies */ true, + ); } } } @@ -219,7 +272,13 @@ namespace ts.FindAllReferences { * The returned `importSearches` will result in the entire source file being searched. * But re-exports will be placed in 'singleReferences' since they cannot be locally referenced. */ - function getSearchesFromDirectImports(directImports: Importer[], exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker, isForRename: boolean): Pick { + function getSearchesFromDirectImports( + directImports: Importer[], + exportSymbol: Symbol, + exportKind: ExportKind, + checker: TypeChecker, + isForRename: boolean, + ): Pick { const importSearches: [Identifier, Symbol][] = []; const singleReferences: (Identifier | StringLiteral)[] = []; function addSearch(location: Identifier, symbol: Symbol): void { @@ -293,7 +352,10 @@ namespace ts.FindAllReferences { // `export =` might be imported by a default import if `--allowSyntheticDefaultImports` is on, so this handles both ExportKind.Default and ExportKind.ExportEquals. // If a default import has the same name as the default export, allow to rename it. // Given `import f` and `export default function f`, we will rename both, but for `import g` we will rename just that. - if (name && (exportKind === ExportKind.Default || exportKind === ExportKind.ExportEquals) && (!isForRename || name.escapedText === symbolEscapedNameNoDefault(exportSymbol))) { + if ( + name && (exportKind === ExportKind.Default || exportKind === ExportKind.ExportEquals) + && (!isForRename || name.escapedText === symbolEscapedNameNoDefault(exportSymbol)) + ) { const defaultImportAlias = checker.getSymbolAtLocation(name)!; addSearch(name, defaultImportAlias); } @@ -343,7 +405,8 @@ namespace ts.FindAllReferences { function isNameMatch(name: __String): boolean { // Use name of "default" even in `export =` case because we may have allowSyntheticDefaultImports - return name === exportSymbol.escapedName || exportKind !== ExportKind.Named && name === InternalSymbolName.Default; + return name === exportSymbol.escapedName + || exportKind !== ExportKind.Named && name === InternalSymbolName.Default; } } @@ -354,8 +417,10 @@ namespace ts.FindAllReferences { return !!forEachPossibleImportOrExportStatement(sourceFileLike, statement => { if (!isExportDeclaration(statement)) return; const { exportClause, moduleSpecifier } = statement; - return !moduleSpecifier && exportClause && isNamedExports(exportClause) && - exportClause.elements.some(element => checker.getExportSpecifierLocalTargetSymbol(element) === namespaceImportSymbol); + return !moduleSpecifier && exportClause && isNamedExports(exportClause) + && exportClause.elements.some(element => + checker.getExportSpecifierLocalTargetSymbol(element) === namespaceImportSymbol + ); }); } @@ -364,7 +429,11 @@ namespace ts.FindAllReferences { | { kind: "import"; literal: StringLiteralLike; } /** or */ | { kind: "reference"; referencingFile: SourceFile; ref: FileReference; }; - export function findModuleReferences(program: Program, sourceFiles: readonly SourceFile[], searchModuleSymbol: Symbol): ModuleReference[] { + export function findModuleReferences( + program: Program, + sourceFiles: readonly SourceFile[], + searchModuleSymbol: Symbol, + ): ModuleReference[] { const refs: ModuleReference[] = []; const checker = program.getTypeChecker(); for (const referencingFile of sourceFiles) { @@ -376,8 +445,14 @@ namespace ts.FindAllReferences { } } for (const ref of referencingFile.typeReferenceDirectives) { - const referenced = program.getResolvedTypeReferenceDirectives().get(ref.fileName, ref.resolutionMode || referencingFile.impliedNodeFormat); - if (referenced !== undefined && referenced.resolvedFileName === (searchSourceFile as SourceFile).fileName) { + const referenced = program.getResolvedTypeReferenceDirectives().get( + ref.fileName, + ref.resolutionMode || referencingFile.impliedNodeFormat, + ); + if ( + referenced !== undefined + && referenced.resolvedFileName === (searchSourceFile as SourceFile).fileName + ) { refs.push({ kind: "reference", referencingFile, ref }); } } @@ -394,7 +469,11 @@ namespace ts.FindAllReferences { } /** Returns a map from a module symbol Id to all import statements that directly reference the module. */ - function getDirectImportsMap(sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken | undefined): ESMap { + function getDirectImportsMap( + sourceFiles: readonly SourceFile[], + checker: TypeChecker, + cancellationToken: CancellationToken | undefined, + ): ESMap { const map = new Map(); for (const sourceFile of sourceFiles) { @@ -416,14 +495,25 @@ namespace ts.FindAllReferences { } /** Iterates over all statements at the top level or in module declarations. Returns the first truthy result. */ - function forEachPossibleImportOrExportStatement(sourceFileLike: SourceFileLike, action: (statement: Statement) => T) { - return forEach(sourceFileLike.kind === SyntaxKind.SourceFile ? sourceFileLike.statements : sourceFileLike.body!.statements, statement => - // TODO: GH#18217 - action(statement) || (isAmbientModuleDeclaration(statement) && forEach(statement.body && statement.body.statements, action))); + function forEachPossibleImportOrExportStatement( + sourceFileLike: SourceFileLike, + action: (statement: Statement) => T, + ) { + return forEach( + sourceFileLike.kind === SyntaxKind.SourceFile ? sourceFileLike.statements : sourceFileLike.body!.statements, + statement => + // TODO: GH#18217 + action(statement) + || (isAmbientModuleDeclaration(statement) + && forEach(statement.body && statement.body.statements, action)), + ); } /** Calls `action` for each import, re-export, or require() in a file. */ - function forEachImport(sourceFile: SourceFile, action: (importStatement: ImporterOrCallExpression, imported: StringLiteralLike) => void): void { + function forEachImport( + sourceFile: SourceFile, + action: (importStatement: ImporterOrCallExpression, imported: StringLiteralLike) => void, + ): void { if (sourceFile.externalModuleIndicator || sourceFile.imports !== undefined) { for (const i of sourceFile.imports) { action(importFromModuleSpecifier(i), i); @@ -470,7 +560,12 @@ namespace ts.FindAllReferences { * This doesn't handle export specifiers; that is done in `getReferencesAtExportSpecifier`. * @param comingFromExport If we are doing a search for all exports, don't bother looking backwards for the imported symbol, since that's the reason we're here. */ - export function getImportOrExportSymbol(node: Node, symbol: Symbol, checker: TypeChecker, comingFromExport: boolean): ImportedSymbol | ExportedSymbol | undefined { + export function getImportOrExportSymbol( + node: Node, + symbol: Symbol, + checker: TypeChecker, + comingFromExport: boolean, + ): ImportedSymbol | ExportedSymbol | undefined { return comingFromExport ? getExport() : getExport() || getImport(); function getExport(): ExportedSymbol | ImportedSymbol | undefined { @@ -531,10 +626,17 @@ namespace ts.FindAllReferences { // Get the symbol for the `export =` node; its parent is the module it's the export of. if (!ex.symbol.parent) return undefined; const exportKind = ex.isExportEquals ? ExportKind.ExportEquals : ExportKind.Default; - return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol: ex.symbol.parent, exportKind } }; + return { + kind: ImportExport.Export, + symbol, + exportInfo: { exportingModuleSymbol: ex.symbol.parent, exportKind }, + }; } - function getSpecialPropertyExport(node: BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined { + function getSpecialPropertyExport( + node: BinaryExpression, + useLhsSymbol: boolean, + ): ExportedSymbol | undefined { let kind: ExportKind; switch (getAssignmentDeclarationKind(node)) { case AssignmentDeclarationKind.ExportsProperty: @@ -547,7 +649,9 @@ namespace ts.FindAllReferences { return undefined; } - const sym = useLhsSymbol ? checker.getSymbolAtLocation(getNameOfAccessExpression(cast(node.left, isAccessExpression))) : symbol; + const sym = useLhsSymbol + ? checker.getSymbolAtLocation(getNameOfAccessExpression(cast(node.left, isAccessExpression))) + : symbol; return sym && exportInfo(sym, kind); } } @@ -572,7 +676,10 @@ namespace ts.FindAllReferences { // If `importedName` is undefined, do continue searching as the export is anonymous. // (All imports returned from this function will be ignored anyway if we are in rename and this is a not a named export.) const importedName = symbolEscapedNameNoDefault(importedSymbol); - if (importedName === undefined || importedName === InternalSymbolName.Default || importedName === symbol.escapedName) { + if ( + importedName === undefined || importedName === InternalSymbolName.Default + || importedName === symbol.escapedName + ) { return { kind: ImportExport.Import, symbol: importedSymbol }; } } @@ -609,10 +716,12 @@ namespace ts.FindAllReferences { // If a reference is a class expression, the exported node would be its parent. // If a reference is a variable declaration, the exported node would be the variable statement. function getExportNode(parent: Node, node: Node): Node | undefined { - const declaration = isVariableDeclaration(parent) ? parent : isBindingElement(parent) ? walkUpBindingElementsAndPatterns(parent) : undefined; + const declaration = isVariableDeclaration(parent) ? parent + : isBindingElement(parent) ? walkUpBindingElementsAndPatterns(parent) : undefined; if (declaration) { - return (parent as VariableDeclaration | BindingElement).name !== node ? undefined : - isCatchClause(declaration.parent) ? undefined : isVariableStatement(declaration.parent.parent) ? declaration.parent.parent : undefined; + return (parent as VariableDeclaration | BindingElement).name !== node ? undefined + : isCatchClause(declaration.parent) ? undefined + : isVariableStatement(declaration.parent.parent) ? declaration.parent.parent : undefined; } else { return parent; @@ -623,7 +732,8 @@ namespace ts.FindAllReferences { const { parent } = node; switch (parent.kind) { case SyntaxKind.ImportEqualsDeclaration: - return (parent as ImportEqualsDeclaration).name === node && isExternalModuleImportEquals(parent as ImportEqualsDeclaration); + return (parent as ImportEqualsDeclaration).name === node + && isExternalModuleImportEquals(parent as ImportEqualsDeclaration); case SyntaxKind.ImportSpecifier: // For a rename import `{ foo as bar }`, don't search for the imported symbol. Just find local uses of `bar`. return !(parent as ImportSpecifier).propertyName; @@ -632,13 +742,18 @@ namespace ts.FindAllReferences { Debug.assert((parent as ImportClause | NamespaceImport).name === node); return true; case SyntaxKind.BindingElement: - return isInJSFile(node) && isVariableDeclarationInitializedToBareOrAccessedRequire(parent.parent.parent); + return isInJSFile(node) + && isVariableDeclarationInitializedToBareOrAccessedRequire(parent.parent.parent); default: return false; } } - export function getExportInfo(exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker): ExportInfo | undefined { + export function getExportInfo( + exportSymbol: Symbol, + exportKind: ExportKind, + checker: TypeChecker, + ): ExportInfo | undefined { const moduleSymbol = exportSymbol.parent; if (!moduleSymbol) return undefined; // This can happen if an `export` is not at the top-level (which is a compile error). const exportingModuleSymbol = checker.getMergedSymbol(moduleSymbol); // Need to get merged symbol in case there's an augmentation. @@ -651,17 +766,24 @@ namespace ts.FindAllReferences { // For `export { foo } from './bar", there's nothing to skip, because it does not create a new alias. But `export { foo } does. if (symbol.declarations) { for (const declaration of symbol.declarations) { - if (isExportSpecifier(declaration) && !declaration.propertyName && !declaration.parent.parent.moduleSpecifier) { + if ( + isExportSpecifier(declaration) && !declaration.propertyName + && !declaration.parent.parent.moduleSpecifier + ) { return checker.getExportSpecifierLocalTargetSymbol(declaration)!; } - else if (isPropertyAccessExpression(declaration) && isModuleExportsAccessExpression(declaration.expression) && !isPrivateIdentifier(declaration.name)) { + else if ( + isPropertyAccessExpression(declaration) && isModuleExportsAccessExpression(declaration.expression) + && !isPrivateIdentifier(declaration.name) + ) { // Export of form 'module.exports.propName = expr'; return checker.getSymbolAtLocation(declaration)!; } else if ( isShorthandPropertyAssignment(declaration) && isBinaryExpression(declaration.parent.parent) - && getAssignmentDeclarationKind(declaration.parent.parent) === AssignmentDeclarationKind.ModuleExports + && getAssignmentDeclarationKind(declaration.parent.parent) + === AssignmentDeclarationKind.ModuleExports ) { return checker.getExportSpecifierLocalTargetSymbol(declaration.name)!; } @@ -688,10 +810,14 @@ namespace ts.FindAllReferences { } function isAmbientModuleDeclaration(node: Node): node is AmbientModuleDeclaration { - return node.kind === SyntaxKind.ModuleDeclaration && (node as ModuleDeclaration).name.kind === SyntaxKind.StringLiteral; + return node.kind === SyntaxKind.ModuleDeclaration + && (node as ModuleDeclaration).name.kind === SyntaxKind.StringLiteral; } - function isExternalModuleImportEquals(eq: ImportEqualsDeclaration): eq is ImportEqualsDeclaration & { moduleReference: { expression: StringLiteral; }; } { - return eq.moduleReference.kind === SyntaxKind.ExternalModuleReference && eq.moduleReference.expression.kind === SyntaxKind.StringLiteral; + function isExternalModuleImportEquals( + eq: ImportEqualsDeclaration, + ): eq is ImportEqualsDeclaration & { moduleReference: { expression: StringLiteral; }; } { + return eq.moduleReference.kind === SyntaxKind.ExternalModuleReference + && eq.moduleReference.expression.kind === SyntaxKind.StringLiteral; } } diff --git a/src/services/inlayHints.ts b/src/services/inlayHints.ts index d7663c7f328b1..c542e2a67ba01 100644 --- a/src/services/inlayHints.ts +++ b/src/services/inlayHints.ts @@ -7,7 +7,8 @@ namespace ts.InlayHints { }; function shouldShowParameterNameHints(preferences: UserPreferences) { - return preferences.includeInlayParameterNameHints === "literals" || preferences.includeInlayParameterNameHints === "all"; + return preferences.includeInlayParameterNameHints === "literals" + || preferences.includeInlayParameterNameHints === "all"; } function shouldShowLiteralParameterNameHintsOnly(preferences: UserPreferences) { @@ -63,18 +64,32 @@ namespace ts.InlayHints { visitCallOrNewExpression(node); } else { - if (preferences.includeInlayFunctionParameterTypeHints && isFunctionLikeDeclaration(node) && hasContextSensitiveParameters(node)) { + if ( + preferences.includeInlayFunctionParameterTypeHints && isFunctionLikeDeclaration(node) + && hasContextSensitiveParameters(node) + ) { visitFunctionLikeForParameterType(node); } - if (preferences.includeInlayFunctionLikeReturnTypeHints && isSignatureSupportingReturnAnnotation(node)) { + if ( + preferences.includeInlayFunctionLikeReturnTypeHints && isSignatureSupportingReturnAnnotation(node) + ) { visitFunctionDeclarationLikeForReturnType(node); } } return forEachChild(node, visitor); } - function isSignatureSupportingReturnAnnotation(node: Node): node is FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration { - return isArrowFunction(node) || isFunctionExpression(node) || isFunctionDeclaration(node) || isMethodDeclaration(node) || isGetAccessorDeclaration(node); + function isSignatureSupportingReturnAnnotation( + node: Node, + ): node is + | FunctionDeclaration + | ArrowFunction + | FunctionExpression + | MethodDeclaration + | GetAccessorDeclaration + { + return isArrowFunction(node) || isFunctionExpression(node) || isFunctionDeclaration(node) + || isMethodDeclaration(node) || isGetAccessorDeclaration(node); } function addParameterHints(text: string, position: number, isFirstVariadicArgument: boolean) { @@ -120,7 +135,10 @@ namespace ts.InlayHints { } function visitVariableLikeDeclaration(decl: VariableDeclaration | PropertyDeclaration) { - if (!decl.initializer || isBindingPattern(decl.name) || isVariableDeclaration(decl) && !isHintableDeclaration(decl)) { + if ( + !decl.initializer || isBindingPattern(decl.name) + || isVariableDeclaration(decl) && !isHintableDeclaration(decl) + ) { return; } @@ -136,7 +154,8 @@ namespace ts.InlayHints { const typeDisplayString = printTypeInSingleLine(declarationType); if (typeDisplayString) { - const isVariableNameMatchesType = preferences.includeInlayVariableTypeHintsWhenTypeMatchesName === false && equateStringsCaseInsensitive(decl.name.getText(), typeDisplayString); + const isVariableNameMatchesType = preferences.includeInlayVariableTypeHintsWhenTypeMatchesName === false + && equateStringsCaseInsensitive(decl.name.getText(), typeDisplayString); if (isVariableNameMatchesType) { return; } @@ -166,7 +185,9 @@ namespace ts.InlayHints { const identifierNameInfo = checker.getParameterIdentifierNameAtPosition(signature, i); if (identifierNameInfo) { const [parameterName, isFirstVariadicArgument] = identifierNameInfo; - const isParameterNameNotSameAsArgument = preferences.includeInlayParameterNameHintsWhenArgumentMatchesName || !identifierOrAccessExpressionPostfixMatchesParameterName(arg, parameterName); + const isParameterNameNotSameAsArgument = + preferences.includeInlayParameterNameHintsWhenArgumentMatchesName + || !identifierOrAccessExpressionPostfixMatchesParameterName(arg, parameterName); if (!isParameterNameNotSameAsArgument && !isFirstVariadicArgument) { continue; } @@ -209,7 +230,8 @@ namespace ts.InlayHints { switch (node.kind) { case SyntaxKind.PrefixUnaryExpression: { const operand = (node as PrefixUnaryExpression).operand; - return isLiteralExpression(operand) || isIdentifier(operand) && isInfinityOrNaNString(operand.escapedText); + return isLiteralExpression(operand) + || isIdentifier(operand) && isInfinityOrNaNString(operand.escapedText); } case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: @@ -225,7 +247,9 @@ namespace ts.InlayHints { return isLiteralExpression(node); } - function visitFunctionDeclarationLikeForReturnType(decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration) { + function visitFunctionDeclarationLikeForReturnType( + decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration, + ) { if (isArrowFunction(decl)) { if (!findChildOfKind(decl, SyntaxKind.OpenParenToken, file)) { return; @@ -255,7 +279,9 @@ namespace ts.InlayHints { addTypeHints(typeDisplayString, getTypeAnnotationPosition(decl)); } - function getTypeAnnotationPosition(decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration) { + function getTypeAnnotationPosition( + decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration, + ) { const closeParenToken = findChildOfKind(decl, SyntaxKind.CloseParenToken, file); if (closeParenToken) { return closeParenToken.end; @@ -311,7 +337,8 @@ namespace ts.InlayHints { } function printTypeInSingleLine(type: Type) { - const flags = NodeBuilderFlags.IgnoreErrors | TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope; + const flags = NodeBuilderFlags.IgnoreErrors | TypeFormatFlags.AllowUniqueESSymbolType + | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope; const options: PrinterOptions = { removeComments: true }; const printer = createPrinter(options); @@ -329,7 +356,8 @@ namespace ts.InlayHints { function isHintableDeclaration(node: VariableDeclaration | ParameterDeclaration) { if ((isParameterDeclaration(node) || isVariableDeclaration(node) && isVarConst(node)) && node.initializer) { const initializer = skipParentheses(node.initializer); - return !(isHintableLiteral(initializer) || isNewExpression(initializer) || isObjectLiteralExpression(initializer) || isAssertionExpression(initializer)); + return !(isHintableLiteral(initializer) || isNewExpression(initializer) + || isObjectLiteralExpression(initializer) || isAssertionExpression(initializer)); } return true; } diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index dd06c8d341e4c..3be713e2b7766 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -83,7 +83,10 @@ namespace ts.JsDoc { let jsDocTagNameCompletionEntries: CompletionEntry[]; let jsDocTagCompletionEntries: CompletionEntry[]; - export function getJsDocCommentsFromDeclarations(declarations: readonly Declaration[], checker?: TypeChecker): SymbolDisplayPart[] { + export function getJsDocCommentsFromDeclarations( + declarations: readonly Declaration[], + checker?: TypeChecker, + ): SymbolDisplayPart[] { // Only collect doc comments from duplicate declarations once: // In case of a union property there might be same declaration multiple times // which only varies in type parameter @@ -93,7 +96,12 @@ namespace ts.JsDoc { const parts: SymbolDisplayPart[][] = []; forEachUnique(declarations, declaration => { for (const jsdoc of getCommentHavingNodes(declaration)) { - const inheritDoc = isJSDoc(jsdoc) && jsdoc.tags && find(jsdoc.tags, t => t.kind === SyntaxKind.JSDocTag && (t.tagName.escapedText === "inheritDoc" || t.tagName.escapedText === "inheritdoc")); + const inheritDoc = isJSDoc(jsdoc) && jsdoc.tags + && find( + jsdoc.tags, + t => t.kind === SyntaxKind.JSDocTag + && (t.tagName.escapedText === "inheritDoc" || t.tagName.escapedText === "inheritdoc"), + ); // skip comments containing @typedefs since they're not associated with particular declarations // Exceptions: // - @typedefs are themselves declarations with associated comments @@ -101,10 +109,15 @@ namespace ts.JsDoc { if ( jsdoc.comment === undefined && !inheritDoc || isJSDoc(jsdoc) - && declaration.kind !== SyntaxKind.JSDocTypedefTag && declaration.kind !== SyntaxKind.JSDocCallbackTag + && declaration.kind !== SyntaxKind.JSDocTypedefTag + && declaration.kind !== SyntaxKind.JSDocCallbackTag && jsdoc.tags - && jsdoc.tags.some(t => t.kind === SyntaxKind.JSDocTypedefTag || t.kind === SyntaxKind.JSDocCallbackTag) - && !jsdoc.tags.some(t => t.kind === SyntaxKind.JSDocParameterTag || t.kind === SyntaxKind.JSDocReturnTag) + && jsdoc.tags.some(t => + t.kind === SyntaxKind.JSDocTypedefTag || t.kind === SyntaxKind.JSDocCallbackTag + ) + && !jsdoc.tags.some(t => + t.kind === SyntaxKind.JSDocParameterTag || t.kind === SyntaxKind.JSDocReturnTag + ) ) { continue; } @@ -158,7 +171,10 @@ namespace ts.JsDoc { return infos; } - function getDisplayPartsFromComment(comment: string | readonly JSDocComment[], checker: TypeChecker | undefined): SymbolDisplayPart[] { + function getDisplayPartsFromComment( + comment: string | readonly JSDocComment[], + checker: TypeChecker | undefined, + ): SymbolDisplayPart[] { if (typeof comment === "string") { return [textPart(comment)]; } @@ -205,7 +221,12 @@ namespace ts.JsDoc { case SyntaxKind.JSDocPropertyTag: case SyntaxKind.JSDocParameterTag: case SyntaxKind.JSDocSeeTag: - const { name } = tag as JSDocTypedefTag | JSDocCallbackTag | JSDocPropertyTag | JSDocParameterTag | JSDocSeeTag; + const { name } = tag as + | JSDocTypedefTag + | JSDocCallbackTag + | JSDocPropertyTag + | JSDocParameterTag + | JSDocSeeTag; return name ? withNode(name) : comment === undefined ? undefined : getDisplayPartsFromComment(comment, checker); @@ -298,13 +319,20 @@ namespace ts.JsDoc { const name = param.name.text; if ( - jsdoc.tags!.some(t => t !== tag && isJSDocParameterTag(t) && isIdentifier(t.name) && t.name.escapedText === name) // TODO: GH#18217 + jsdoc.tags!.some(t => + t !== tag && isJSDocParameterTag(t) && isIdentifier(t.name) && t.name.escapedText === name + ) // TODO: GH#18217 || nameThusFar !== undefined && !startsWith(name, nameThusFar) ) { return undefined; } - return { name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText: Completions.SortText.LocationPriority }; + return { + name, + kind: ScriptElementKind.parameterElement, + kindModifiers: "", + sortText: Completions.SortText.LocationPriority, + }; }); } @@ -343,7 +371,12 @@ namespace ts.JsDoc { * @param position The (character-indexed) position in the file where the check should * be performed. */ - export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number, options?: DocCommentTemplateOptions): TextInsertion | undefined { + export function getDocCommentTemplateAtPosition( + newLine: string, + sourceFile: SourceFile, + position: number, + options?: DocCommentTemplateOptions, + ): TextInsertion | undefined { const tokenAtPos = getTokenAtPosition(sourceFile, position); const existingDocComment = findAncestor(tokenAtPos, isJSDoc); if (existingDocComment && (existingDocComment.comment !== undefined || length(existingDocComment.tags))) { @@ -376,8 +409,9 @@ namespace ts.JsDoc { const indentationStr = getIndentationStringAtPosition(sourceFile, position); const isJavaScriptFile = hasJSFileExtension(sourceFile.fileName); - const tags = (parameters ? parameterDocComments(parameters || [], isJavaScriptFile, indentationStr, newLine) : "") + - (hasReturn ? returnsDocComment(indentationStr, newLine) : ""); + const tags = + (parameters ? parameterDocComments(parameters || [], isJavaScriptFile, indentationStr, newLine) : "") + + (hasReturn ? returnsDocComment(indentationStr, newLine) : ""); // A doc comment consists of the following // * The opening comment line @@ -410,7 +444,12 @@ namespace ts.JsDoc { return text.slice(lineStart, pos); } - function parameterDocComments(parameters: readonly ParameterDeclaration[], isJavaScriptFile: boolean, indentationStr: string, newLine: string): string { + function parameterDocComments( + parameters: readonly ParameterDeclaration[], + isJavaScriptFile: boolean, + indentationStr: string, + newLine: string, + ): string { return parameters.map(({ name, dotDotDotToken }, i) => { const paramName = name.kind === SyntaxKind.Identifier ? name.text : "param" + i; const type = isJavaScriptFile ? (dotDotDotToken ? "{...any} " : "{any} ") : ""; @@ -427,10 +466,16 @@ namespace ts.JsDoc { readonly parameters?: readonly ParameterDeclaration[]; readonly hasReturn?: boolean; } - function getCommentOwnerInfo(tokenAtPos: Node, options: DocCommentTemplateOptions | undefined): CommentOwnerInfo | undefined { + function getCommentOwnerInfo( + tokenAtPos: Node, + options: DocCommentTemplateOptions | undefined, + ): CommentOwnerInfo | undefined { return forEachAncestor(tokenAtPos, n => getCommentOwnerInfoWorker(n, options)); } - function getCommentOwnerInfoWorker(commentOwner: Node, options: DocCommentTemplateOptions | undefined): CommentOwnerInfo | undefined | "quit" { + function getCommentOwnerInfoWorker( + commentOwner: Node, + options: DocCommentTemplateOptions | undefined, + ): CommentOwnerInfo | undefined | "quit" { switch (commentOwner.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: @@ -438,7 +483,12 @@ namespace ts.JsDoc { case SyntaxKind.Constructor: case SyntaxKind.MethodSignature: case SyntaxKind.ArrowFunction: - const host = commentOwner as ArrowFunction | FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature; + const host = commentOwner as + | ArrowFunction + | FunctionDeclaration + | MethodDeclaration + | ConstructorDeclaration + | MethodSignature; return { commentOwner, parameters: host.parameters, hasReturn: hasReturn(host, options) }; case SyntaxKind.PropertyAssignment: @@ -492,12 +542,15 @@ namespace ts.JsDoc { } function hasReturn(node: Node, options: DocCommentTemplateOptions | undefined) { - return !!options?.generateReturnInDocTemplate && - (isArrowFunction(node) && isExpression(node.body) - || isFunctionLikeDeclaration(node) && node.body && isBlock(node.body) && !!forEachReturnStatement(node.body, n => n)); + return !!options?.generateReturnInDocTemplate + && (isArrowFunction(node) && isExpression(node.body) + || isFunctionLikeDeclaration(node) && node.body && isBlock(node.body) + && !!forEachReturnStatement(node.body, n => n)); } - function getRightHandSideOfAssignment(rightHandSide: Expression): FunctionExpression | ArrowFunction | ConstructorDeclaration | undefined { + function getRightHandSideOfAssignment( + rightHandSide: Expression, + ): FunctionExpression | ArrowFunction | ConstructorDeclaration | undefined { while (rightHandSide.kind === SyntaxKind.ParenthesizedExpression) { rightHandSide = (rightHandSide as ParenthesizedExpression).expression; } diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index 462d4fd0ac3ef..06e3b5df3a177 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -8,7 +8,14 @@ namespace ts.NavigateTo { readonly declaration: Declaration; } - export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number | undefined, excludeDtsFiles: boolean): NavigateToItem[] { + export function getNavigateToItems( + sourceFiles: readonly SourceFile[], + checker: TypeChecker, + cancellationToken: CancellationToken, + searchValue: string, + maxResultCount: number | undefined, + excludeDtsFiles: boolean, + ): NavigateToItem[] { const patternMatcher = createPatternMatcher(searchValue); if (!patternMatcher) return emptyArray; const rawItems: RawNavigateToItem[] = []; @@ -22,7 +29,14 @@ namespace ts.NavigateTo { } sourceFile.getNamedDeclarations().forEach((declarations, name) => { - getItemsFromNamedDeclaration(patternMatcher, name, declarations, checker, sourceFile.fileName, rawItems); + getItemsFromNamedDeclaration( + patternMatcher, + name, + declarations, + checker, + sourceFile.fileName, + rawItems, + ); }); } @@ -30,7 +44,14 @@ namespace ts.NavigateTo { return (maxResultCount === undefined ? rawItems : rawItems.slice(0, maxResultCount)).map(createNavigateToItem); } - function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: string, declarations: readonly Declaration[], checker: TypeChecker, fileName: string, rawItems: Push): void { + function getItemsFromNamedDeclaration( + patternMatcher: PatternMatcher, + name: string, + declarations: readonly Declaration[], + checker: TypeChecker, + fileName: string, + rawItems: Push, + ): void { // First do a quick check to see if the name of the declaration matches the // last portion of the (possibly) dotted name they're searching for. const match = patternMatcher.getMatchForLastSegmentOfPattern(name); @@ -45,11 +66,23 @@ namespace ts.NavigateTo { // If the pattern has dots in it, then also see if the declaration container matches as well. const fullMatch = patternMatcher.getFullMatch(getContainers(declaration), name); if (fullMatch) { - rawItems.push({ name, fileName, matchKind: fullMatch.kind, isCaseSensitive: fullMatch.isCaseSensitive, declaration }); + rawItems.push({ + name, + fileName, + matchKind: fullMatch.kind, + isCaseSensitive: fullMatch.isCaseSensitive, + declaration, + }); } } else { - rawItems.push({ name, fileName, matchKind: match.kind, isCaseSensitive: match.isCaseSensitive, declaration }); + rawItems.push({ + name, + fileName, + matchKind: match.kind, + isCaseSensitive: match.isCaseSensitive, + declaration, + }); } } } @@ -59,7 +92,9 @@ namespace ts.NavigateTo { case SyntaxKind.ImportClause: case SyntaxKind.ImportSpecifier: case SyntaxKind.ImportEqualsDeclaration: - const importer = checker.getSymbolAtLocation((declaration as ImportClause | ImportSpecifier | ImportEqualsDeclaration).name!)!; // TODO: GH#18217 + const importer = checker.getSymbolAtLocation( + (declaration as ImportClause | ImportSpecifier | ImportEqualsDeclaration).name!, + )!; // TODO: GH#18217 const imported = checker.getAliasedSymbol(importer); return importer.escapedName !== imported.escapedName; default: @@ -69,7 +104,10 @@ namespace ts.NavigateTo { function tryAddSingleDeclarationName(declaration: Declaration, containers: Push): boolean { const name = getNameOfDeclaration(declaration); - return !!name && (pushLiteral(name, containers) || name.kind === SyntaxKind.ComputedPropertyName && tryAddComputedPropertyName(name.expression, containers)); + return !!name + && (pushLiteral(name, containers) + || name.kind === SyntaxKind.ComputedPropertyName + && tryAddComputedPropertyName(name.expression, containers)); } // Only added the names of computed properties if they're simple dotted expressions, like: @@ -77,7 +115,8 @@ namespace ts.NavigateTo { // [X.Y.Z]() { } function tryAddComputedPropertyName(expression: Expression, containers: Push): boolean { return pushLiteral(expression, containers) - || isPropertyAccessExpression(expression) && (containers.push(expression.name.text), true) && tryAddComputedPropertyName(expression.expression, containers); + || isPropertyAccessExpression(expression) && (containers.push(expression.name.text), true) + && tryAddComputedPropertyName(expression.expression, containers); } function pushLiteral(node: Node, containers: Push): boolean { @@ -90,7 +129,10 @@ namespace ts.NavigateTo { // First, if we started with a computed property name, then add all but the last // portion into the container array. const name = getNameOfDeclaration(declaration); - if (name && name.kind === SyntaxKind.ComputedPropertyName && !tryAddComputedPropertyName(name.expression, containers)) { + if ( + name && name.kind === SyntaxKind.ComputedPropertyName + && !tryAddComputedPropertyName(name.expression, containers) + ) { return emptyArray; } // Don't include the last portion. diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 8bb0ef2c5e036..d287d428250bf 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -52,7 +52,10 @@ namespace ts.NavigationBar { indent: number; // # of parents } - export function getNavigationBarItems(sourceFile: SourceFile, cancellationToken: CancellationToken): NavigationBarItem[] { + export function getNavigationBarItems( + sourceFile: SourceFile, + cancellationToken: CancellationToken, + ): NavigationBarItem[] { curCancellationToken = cancellationToken; curSourceFile = sourceFile; try { @@ -101,7 +104,14 @@ namespace ts.NavigationBar { function rootNavigationBarNode(sourceFile: SourceFile): NavigationBarNode { Debug.assert(!parentsStack.length); - const root: NavigationBarNode = { node: sourceFile, name: undefined, additionalNodes: undefined, parent: undefined, children: undefined, indent: 0 }; + const root: NavigationBarNode = { + node: sourceFile, + name: undefined, + additionalNodes: undefined, + parent: undefined, + children: undefined, + indent: 0, + }; parent = root; for (const statement of sourceFile.statements) { addChildrenRecursively(statement); @@ -183,7 +193,9 @@ namespace ts.NavigationBar { endNode(); } - function addNodeWithRecursiveInitializer(node: VariableDeclaration | PropertyAssignment | BindingElement | PropertyDeclaration): void { + function addNodeWithRecursiveInitializer( + node: VariableDeclaration | PropertyAssignment | BindingElement | PropertyDeclaration, + ): void { if (node.initializer && isFunctionOrClassExpression(node.initializer)) { startNode(node); forEachChild(node.initializer, addChildrenRecursively); @@ -200,12 +212,12 @@ namespace ts.NavigationBar { * symbols from other unique symbols, we do the below to retain those members in the nav tree. */ function hasNavigationBarName(node: Declaration) { - return !hasDynamicName(node) || - ( - node.kind !== SyntaxKind.BinaryExpression && - isPropertyAccessExpression(node.name.expression) && - isIdentifier(node.name.expression.expression) && - idText(node.name.expression.expression) === "Symbol" + return !hasDynamicName(node) + || ( + node.kind !== SyntaxKind.BinaryExpression + && isPropertyAccessExpression(node.name.expression) + && isIdentifier(node.name.expression.expression) + && idText(node.name.expression.expression) === "Symbol" ); } @@ -334,8 +346,8 @@ namespace ts.NavigationBar { case SyntaxKind.ExportAssignment: { const expression = (node as ExportAssignment).expression; - const child = isObjectLiteralExpression(expression) || isCallExpression(expression) ? expression : - isArrowFunction(expression) || isFunctionExpression(expression) ? expression.body : undefined; + const child = isObjectLiteralExpression(expression) || isCallExpression(expression) ? expression + : isArrowFunction(expression) || isFunctionExpression(expression) ? expression.body : undefined; if (child) { startNode(node); addChildrenRecursively(child); @@ -368,9 +380,9 @@ namespace ts.NavigationBar { const binaryExpression = (node as BinaryExpression); const assignmentTarget = binaryExpression.left as PropertyAccessExpression; - const prototypeAccess = special === AssignmentDeclarationKind.PrototypeProperty ? - assignmentTarget.expression as PropertyAccessExpression : - assignmentTarget; + const prototypeAccess = special === AssignmentDeclarationKind.PrototypeProperty + ? assignmentTarget.expression as PropertyAccessExpression + : assignmentTarget; let depth = 0; let className: PropertyNameLiteral; @@ -381,7 +393,10 @@ namespace ts.NavigationBar { className = prototypeAccess.expression; } else { - [depth, className] = startNestedNodes(binaryExpression, prototypeAccess.expression as EntityNameExpression); + [depth, className] = startNestedNodes( + binaryExpression, + prototypeAccess.expression as EntityNameExpression, + ); } if (special === AssignmentDeclarationKind.Prototype) { if (isObjectLiteralExpression(binaryExpression.right)) { @@ -392,7 +407,9 @@ namespace ts.NavigationBar { } } } - else if (isFunctionExpression(binaryExpression.right) || isArrowFunction(binaryExpression.right)) { + else if ( + isFunctionExpression(binaryExpression.right) || isArrowFunction(binaryExpression.right) + ) { addNodeWithRecursiveChild(node, binaryExpression.right, className); } else { @@ -406,9 +423,9 @@ namespace ts.NavigationBar { case AssignmentDeclarationKind.ObjectDefinePropertyValue: case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: { const defineCall = node as BindableObjectDefinePropertyCall; - const className = special === AssignmentDeclarationKind.ObjectDefinePropertyValue ? - defineCall.arguments[0] : - (defineCall.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression; + const className = special === AssignmentDeclarationKind.ObjectDefinePropertyValue + ? defineCall.arguments[0] + : (defineCall.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression; const memberName = defineCall.arguments[1]; const [depth, classNameIdentifier] = startNestedNodes(node, className); @@ -422,18 +439,27 @@ namespace ts.NavigationBar { } case AssignmentDeclarationKind.Property: { const binaryExpression = (node as BinaryExpression); - const assignmentTarget = binaryExpression.left as PropertyAccessExpression | BindableElementAccessExpression; + const assignmentTarget = binaryExpression.left as + | PropertyAccessExpression + | BindableElementAccessExpression; const targetFunction = assignmentTarget.expression; if ( - isIdentifier(targetFunction) && getElementOrPropertyAccessName(assignmentTarget) !== "prototype" && - trackedEs5Classes && trackedEs5Classes.has(targetFunction.text) + isIdentifier(targetFunction) + && getElementOrPropertyAccessName(assignmentTarget) !== "prototype" + && trackedEs5Classes && trackedEs5Classes.has(targetFunction.text) ) { - if (isFunctionExpression(binaryExpression.right) || isArrowFunction(binaryExpression.right)) { + if ( + isFunctionExpression(binaryExpression.right) || isArrowFunction(binaryExpression.right) + ) { addNodeWithRecursiveChild(node, binaryExpression.right, targetFunction); } else if (isBindableStaticAccessExpression(assignmentTarget)) { startNode(binaryExpression, targetFunction); - addNodeWithRecursiveChild(binaryExpression.left, binaryExpression.right, getNameOrArgument(assignmentTarget)); + addNodeWithRecursiveChild( + binaryExpression.left, + binaryExpression.right, + getNameOrArgument(assignmentTarget), + ); endNode(); } return; @@ -513,17 +539,22 @@ namespace ts.NavigationBar { [AssignmentDeclarationKind.Prototype]: true, [AssignmentDeclarationKind.ThisProperty]: false, }; - function tryMergeEs5Class(a: NavigationBarNode, b: NavigationBarNode, bIndex: number, parent: NavigationBarNode): boolean | undefined { + function tryMergeEs5Class( + a: NavigationBarNode, + b: NavigationBarNode, + bIndex: number, + parent: NavigationBarNode, + ): boolean | undefined { function isPossibleConstructor(node: Node) { return isFunctionExpression(node) || isFunctionDeclaration(node) || isVariableDeclaration(node); } - const bAssignmentDeclarationKind = isBinaryExpression(b.node) || isCallExpression(b.node) ? - getAssignmentDeclarationKind(b.node) : - AssignmentDeclarationKind.None; + const bAssignmentDeclarationKind = isBinaryExpression(b.node) || isCallExpression(b.node) + ? getAssignmentDeclarationKind(b.node) + : AssignmentDeclarationKind.None; - const aAssignmentDeclarationKind = isBinaryExpression(a.node) || isCallExpression(a.node) ? - getAssignmentDeclarationKind(a.node) : - AssignmentDeclarationKind.None; + const aAssignmentDeclarationKind = isBinaryExpression(a.node) || isCallExpression(a.node) + ? getAssignmentDeclarationKind(a.node) + : AssignmentDeclarationKind.None; // We treat this as an es5 class and merge the nodes in in one of several cases if ( @@ -541,9 +572,9 @@ namespace ts.NavigationBar { (!isClassDeclaration(a.node) && !isClassDeclaration(b.node)) // If neither outline node is a class || isPossibleConstructor(a.node) || isPossibleConstructor(b.node) // If either function is a constructor function ) { - const ctorFunction = isPossibleConstructor(a.node) ? a.node : - isPossibleConstructor(b.node) ? b.node : - undefined; + const ctorFunction = isPossibleConstructor(a.node) ? a.node + : isPossibleConstructor(b.node) ? b.node + : undefined; if (ctorFunction !== undefined) { const ctorNode = setTextRange( @@ -553,7 +584,8 @@ namespace ts.NavigationBar { const ctor = emptyNavigationBarNode(ctorNode); ctor.indent = a.indent + 1; ctor.children = a.node === ctorFunction ? a.children : b.children; - a.children = a.node === ctorFunction ? concatenate([ctor], b.children || [b]) : concatenate(a.children || [{ ...a }], [ctor]); + a.children = a.node === ctorFunction ? concatenate([ctor], b.children || [b]) + : concatenate(a.children || [{ ...a }], [ctor]); } else { if (a.children || b.children) { @@ -636,7 +668,8 @@ namespace ts.NavigationBar { return isStatic(a) === isStatic(b); case SyntaxKind.ModuleDeclaration: return areSameModule(a as ModuleDeclaration, b as ModuleDeclaration) - && getFullyQualifiedModuleName(a as ModuleDeclaration) === getFullyQualifiedModuleName(b as ModuleDeclaration); + && getFullyQualifiedModuleName(a as ModuleDeclaration) + === getFullyQualifiedModuleName(b as ModuleDeclaration); default: return true; } @@ -659,7 +692,9 @@ namespace ts.NavigationBar { if (!a.body || !b.body) { return a.body === b.body; } - return a.body.kind === b.body.kind && (a.body.kind !== SyntaxKind.ModuleDeclaration || areSameModule(a.body as ModuleDeclaration, b.body as ModuleDeclaration)); + return a.body.kind === b.body.kind + && (a.body.kind !== SyntaxKind.ModuleDeclaration + || areSameModule(a.body as ModuleDeclaration, b.body as ModuleDeclaration)); } /** Merge source into target. Source should be thrown away after this is called. */ @@ -733,7 +768,8 @@ namespace ts.NavigationBar { ? `"${escapeString(getBaseFileName(removeFileExtension(normalizePath(sourceFile.fileName))))}"` : ""; case SyntaxKind.ExportAssignment: - return isExportAssignment(node) && node.isExportEquals ? InternalSymbolName.ExportEquals : InternalSymbolName.Default; + return isExportAssignment(node) && node.isExportEquals ? InternalSymbolName.ExportEquals + : InternalSymbolName.Default; case SyntaxKind.ArrowFunction: case SyntaxKind.FunctionDeclaration: @@ -904,7 +940,8 @@ namespace ts.NavigationBar { } function getNodeSpan(node: Node): TextSpan { - return node.kind === SyntaxKind.SourceFile ? createTextSpanFromRange(node) : createTextSpanFromNode(node, curSourceFile); + return node.kind === SyntaxKind.SourceFile ? createTextSpanFromRange(node) + : createTextSpanFromNode(node, curSourceFile); } function getModifiers(node: Node): string { @@ -914,7 +951,9 @@ namespace ts.NavigationBar { return getNodeModifiers(node); } - function getFunctionOrClassName(node: FunctionExpression | FunctionDeclaration | ArrowFunction | ClassLikeDeclaration): string { + function getFunctionOrClassName( + node: FunctionExpression | FunctionDeclaration | ArrowFunction | ClassLikeDeclaration, + ): string { const { parent } = node; if (node.name && getFullWidth(node.name) > 0) { return cleanText(declarationNameToString(node.name)); @@ -947,7 +986,10 @@ namespace ts.NavigationBar { return `${name} callback`; } - const args = cleanText(mapDefined(parent.arguments, a => isStringLiteralLike(a) ? a.getText(curSourceFile) : undefined).join(", ")); + const args = cleanText( + mapDefined(parent.arguments, a => isStringLiteralLike(a) ? a.getText(curSourceFile) : undefined) + .join(", "), + ); return `${name}(${args}) callback`; } } diff --git a/src/services/organizeImports.ts b/src/services/organizeImports.ts index 0816a99afc752..d5abe7a6b2e6f 100644 --- a/src/services/organizeImports.ts +++ b/src/services/organizeImports.ts @@ -28,8 +28,13 @@ namespace ts.OrganizeImports { }; // All of the old ImportDeclarations in the file, in syntactic order. - const topLevelImportGroupDecls = groupImportsByNewlineContiguous(sourceFile, sourceFile.statements.filter(isImportDeclaration)); - topLevelImportGroupDecls.forEach(importGroupDecl => organizeImportsWorker(importGroupDecl, processImportsOfSameModuleSpecifier)); + const topLevelImportGroupDecls = groupImportsByNewlineContiguous( + sourceFile, + sourceFile.statements.filter(isImportDeclaration), + ); + topLevelImportGroupDecls.forEach(importGroupDecl => + organizeImportsWorker(importGroupDecl, processImportsOfSameModuleSpecifier) + ); // Exports are always used if (mode !== OrganizeImportsMode.RemoveUnused) { @@ -41,8 +46,13 @@ namespace ts.OrganizeImports { for (const ambientModule of sourceFile.statements.filter(isAmbientModule)) { if (!ambientModule.body) continue; - const ambientModuleImportGroupDecls = groupImportsByNewlineContiguous(sourceFile, ambientModule.body.statements.filter(isImportDeclaration)); - ambientModuleImportGroupDecls.forEach(importGroupDecl => organizeImportsWorker(importGroupDecl, processImportsOfSameModuleSpecifier)); + const ambientModuleImportGroupDecls = groupImportsByNewlineContiguous( + sourceFile, + ambientModule.body.statements.filter(isImportDeclaration), + ); + ambientModuleImportGroupDecls.forEach(importGroupDecl => + organizeImportsWorker(importGroupDecl, processImportsOfSameModuleSpecifier) + ); // Exports are always used if (mode !== OrganizeImportsMode.RemoveUnused) { @@ -72,12 +82,18 @@ namespace ts.OrganizeImports { ? group(oldImportDecls, importDecl => getExternalModuleName(importDecl.moduleSpecifier!)!) : [oldImportDecls]; const sortedImportGroups = shouldSort - ? stableSort(oldImportGroups, (group1, group2) => compareModuleSpecifiers(group1[0].moduleSpecifier, group2[0].moduleSpecifier)) + ? stableSort( + oldImportGroups, + (group1, group2) => compareModuleSpecifiers(group1[0].moduleSpecifier, group2[0].moduleSpecifier), + ) : oldImportGroups; - const newImportDecls = flatMap(sortedImportGroups, importGroup => - getExternalModuleName(importGroup[0].moduleSpecifier!) - ? coalesce(importGroup) - : importGroup); + const newImportDecls = flatMap( + sortedImportGroups, + importGroup => + getExternalModuleName(importGroup[0].moduleSpecifier!) + ? coalesce(importGroup) + : importGroup, + ); // Delete all nodes if there are no imports. if (newImportDecls.length === 0) { @@ -95,7 +111,11 @@ namespace ts.OrganizeImports { suffix: getNewLineOrDefaultFromHost(host, formatContext.options), }; changeTracker.replaceNodeWithNodes(sourceFile, oldImportDecls[0], newImportDecls, replaceOptions); - const hasTrailingComment = changeTracker.nodeHasTrailingComment(sourceFile, oldImportDecls[0], replaceOptions); + const hasTrailingComment = changeTracker.nodeHasTrailingComment( + sourceFile, + oldImportDecls[0], + replaceOptions, + ); changeTracker.deleteNodes(sourceFile, oldImportDecls.slice(1), { trailingTriviaOption: textChanges.TrailingTriviaOption.Include, }, hasTrailingComment); @@ -103,7 +123,10 @@ namespace ts.OrganizeImports { } } - function groupImportsByNewlineContiguous(sourceFile: SourceFile, importDecls: ImportDeclaration[]): ImportDeclaration[][] { + function groupImportsByNewlineContiguous( + sourceFile: SourceFile, + importDecls: ImportDeclaration[], + ): ImportDeclaration[][] { const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ false, sourceFile.languageVariant); const groupImports: ImportDeclaration[][] = []; let groupIndex = 0; @@ -215,16 +238,20 @@ namespace ts.OrganizeImports { function isDeclarationUsed(identifier: Identifier) { // The JSX factory symbol is always used if JSX elements are present - even if they are not allowed. - return jsxElementsPresent && (identifier.text === jsxNamespace || jsxFragmentFactory && identifier.text === jsxFragmentFactory) && jsxModeNeedsExplicitImport(compilerOptions.jsx) || - FindAllReferences.Core.isSymbolReferencedInFile(identifier, typeChecker, sourceFile); + return jsxElementsPresent + && (identifier.text === jsxNamespace + || jsxFragmentFactory && identifier.text === jsxFragmentFactory) + && jsxModeNeedsExplicitImport(compilerOptions.jsx) + || FindAllReferences.Core.isSymbolReferencedInFile(identifier, typeChecker, sourceFile); } } function hasModuleDeclarationMatchingSpecifier(sourceFile: SourceFile, moduleSpecifier: Expression) { const moduleSpecifierText = isStringLiteral(moduleSpecifier) && moduleSpecifier.text; - return isString(moduleSpecifierText) && some(sourceFile.moduleAugmentations, moduleName => - isStringLiteral(moduleName) - && moduleName.text === moduleSpecifierText); + return isString(moduleSpecifierText) + && some(sourceFile.moduleAugmentations, moduleName => + isStringLiteral(moduleName) + && moduleName.text === moduleSpecifierText); } function getExternalModuleName(specifier: Expression) { @@ -255,22 +282,39 @@ namespace ts.OrganizeImports { const { defaultImports, namespaceImports, namedImports } = group; // Normally, we don't combine default and namespace imports, but it would be silly to // produce two import declarations in this special case. - if (!isTypeOnly && defaultImports.length === 1 && namespaceImports.length === 1 && namedImports.length === 0) { + if ( + !isTypeOnly && defaultImports.length === 1 && namespaceImports.length === 1 && namedImports.length === 0 + ) { // Add the namespace import to the existing default ImportDeclaration. const defaultImport = defaultImports[0]; coalescedImports.push( - updateImportDeclarationAndClause(defaultImport, defaultImport.importClause!.name, namespaceImports[0].importClause!.namedBindings), + updateImportDeclarationAndClause( + defaultImport, + defaultImport.importClause!.name, + namespaceImports[0].importClause!.namedBindings, + ), ); // TODO: GH#18217 continue; } - const sortedNamespaceImports = stableSort(namespaceImports, (i1, i2) => compareIdentifiers((i1.importClause!.namedBindings as NamespaceImport).name, (i2.importClause!.namedBindings as NamespaceImport).name)); // TODO: GH#18217 + const sortedNamespaceImports = stableSort( + namespaceImports, + (i1, i2) => + compareIdentifiers( + (i1.importClause!.namedBindings as NamespaceImport).name, + (i2.importClause!.namedBindings as NamespaceImport).name, + ), + ); // TODO: GH#18217 for (const namespaceImport of sortedNamespaceImports) { // Drop the name, if any coalescedImports.push( - updateImportDeclarationAndClause(namespaceImport, /*name*/ undefined, namespaceImport.importClause!.namedBindings), + updateImportDeclarationAndClause( + namespaceImport, + /*name*/ undefined, + namespaceImport.importClause!.namedBindings, + ), ); // TODO: GH#18217 } @@ -286,7 +330,11 @@ namespace ts.OrganizeImports { else { for (const defaultImport of defaultImports) { newImportSpecifiers.push( - factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier("default"), defaultImport.importClause!.name!), + factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier("default"), + defaultImport.importClause!.name!, + ), ); // TODO: GH#18217 } } @@ -304,7 +352,10 @@ namespace ts.OrganizeImports { : factory.createNamedImports(emptyArray) : namedImports.length === 0 ? factory.createNamedImports(sortedImportSpecifiers) - : factory.updateNamedImports(namedImports[0].importClause!.namedBindings as NamedImports, sortedImportSpecifiers); // TODO: GH#18217 + : factory.updateNamedImports( + namedImports[0].importClause!.namedBindings as NamedImports, + sortedImportSpecifiers, + ); // TODO: GH#18217 // Type-only imports are not allowed to mix default, namespace, and named imports in any combination. // We could rewrite a default import as a named import (`import { default as name }`), but we currently @@ -314,7 +365,11 @@ namespace ts.OrganizeImports { updateImportDeclarationAndClause(importDecl, newDefaultImport, /*namedBindings*/ undefined), ); coalescedImports.push( - updateImportDeclarationAndClause(namedImports[0] ?? importDecl, /*name*/ undefined, newNamedImports), + updateImportDeclarationAndClause( + namedImports[0] ?? importDecl, + /*name*/ undefined, + newNamedImports, + ), ); } else { @@ -399,7 +454,12 @@ namespace ts.OrganizeImports { continue; } const newExportSpecifiers: ExportSpecifier[] = []; - newExportSpecifiers.push(...flatMap(exportGroup, i => i.exportClause && isNamedExports(i.exportClause) ? i.exportClause.elements : emptyArray)); + newExportSpecifiers.push( + ...flatMap( + exportGroup, + i => i.exportClause && isNamedExports(i.exportClause) ? i.exportClause.elements : emptyArray, + ), + ); const sortedExportSpecifiers = sortSpecifiers(newExportSpecifiers); @@ -410,9 +470,9 @@ namespace ts.OrganizeImports { exportDecl.modifiers, exportDecl.isTypeOnly, exportDecl.exportClause && ( - isNamedExports(exportDecl.exportClause) ? - factory.updateNamedExports(exportDecl.exportClause, sortedExportSpecifiers) : - factory.updateNamespaceExport(exportDecl.exportClause, exportDecl.exportClause.name) + isNamedExports(exportDecl.exportClause) + ? factory.updateNamedExports(exportDecl.exportClause, sortedExportSpecifiers) + : factory.updateNamespaceExport(exportDecl.exportClause, exportDecl.exportClause.name) ), exportDecl.moduleSpecifier, exportDecl.assertClause, @@ -462,7 +522,12 @@ namespace ts.OrganizeImports { return factory.updateImportDeclaration( importDeclaration, importDeclaration.modifiers, - factory.updateImportClause(importDeclaration.importClause!, importDeclaration.importClause!.isTypeOnly, name, namedBindings), // TODO: GH#18217 + factory.updateImportClause( + importDeclaration.importClause!, + importDeclaration.importClause!.isTypeOnly, + name, + namedBindings, + ), // TODO: GH#18217 importDeclaration.moduleSpecifier, importDeclaration.assertClause, ); @@ -483,9 +548,9 @@ namespace ts.OrganizeImports { export function compareModuleSpecifiers(m1: Expression | undefined, m2: Expression | undefined) { const name1 = m1 === undefined ? undefined : getExternalModuleName(m1); const name2 = m2 === undefined ? undefined : getExternalModuleName(m2); - return compareBooleans(name1 === undefined, name2 === undefined) || - compareBooleans(isExternalModuleNameRelative(name1!), isExternalModuleNameRelative(name2!)) || - compareStringsCaseInsensitive(name1!, name2!); + return compareBooleans(name1 === undefined, name2 === undefined) + || compareBooleans(isExternalModuleNameRelative(name1!), isExternalModuleNameRelative(name2!)) + || compareStringsCaseInsensitive(name1!, name2!); } function compareIdentifiers(s1: Identifier, s2: Identifier) { @@ -503,26 +568,40 @@ namespace ts.OrganizeImports { } } - export function importsAreSorted(imports: readonly AnyImportOrRequireStatement[]): imports is SortedReadonlyArray { + export function importsAreSorted( + imports: readonly AnyImportOrRequireStatement[], + ): imports is SortedReadonlyArray { return arrayIsSorted(imports, compareImportsOrRequireStatements); } - export function importSpecifiersAreSorted(imports: readonly ImportSpecifier[]): imports is SortedReadonlyArray { + export function importSpecifiersAreSorted( + imports: readonly ImportSpecifier[], + ): imports is SortedReadonlyArray { return arrayIsSorted(imports, compareImportOrExportSpecifiers); } - export function getImportDeclarationInsertionIndex(sortedImports: SortedReadonlyArray, newImport: AnyImportOrRequireStatement) { + export function getImportDeclarationInsertionIndex( + sortedImports: SortedReadonlyArray, + newImport: AnyImportOrRequireStatement, + ) { const index = binarySearch(sortedImports, newImport, identity, compareImportsOrRequireStatements); return index < 0 ? ~index : index; } - export function getImportSpecifierInsertionIndex(sortedImports: SortedReadonlyArray, newImport: ImportSpecifier) { + export function getImportSpecifierInsertionIndex( + sortedImports: SortedReadonlyArray, + newImport: ImportSpecifier, + ) { const index = binarySearch(sortedImports, newImport, identity, compareImportOrExportSpecifiers); return index < 0 ? ~index : index; } - export function compareImportsOrRequireStatements(s1: AnyImportOrRequireStatement, s2: AnyImportOrRequireStatement) { - return compareModuleSpecifiers(getModuleSpecifierExpression(s1), getModuleSpecifierExpression(s2)) || compareImportKind(s1, s2); + export function compareImportsOrRequireStatements( + s1: AnyImportOrRequireStatement, + s2: AnyImportOrRequireStatement, + ) { + return compareModuleSpecifiers(getModuleSpecifierExpression(s1), getModuleSpecifierExpression(s2)) + || compareImportKind(s1, s2); } function compareImportKind(s1: AnyImportOrRequireStatement, s2: AnyImportOrRequireStatement) { @@ -552,11 +631,23 @@ namespace ts.OrganizeImports { } function getNewImportSpecifiers(namedImports: ImportDeclaration[]) { - return flatMap(namedImports, namedImport => - map(tryGetNamedBindingElements(namedImport), importSpecifier => - importSpecifier.name && importSpecifier.propertyName && importSpecifier.name.escapedText === importSpecifier.propertyName.escapedText - ? factory.updateImportSpecifier(importSpecifier, importSpecifier.isTypeOnly, /*propertyName*/ undefined, importSpecifier.name) - : importSpecifier)); + return flatMap( + namedImports, + namedImport => + map( + tryGetNamedBindingElements(namedImport), + importSpecifier => + importSpecifier.name && importSpecifier.propertyName + && importSpecifier.name.escapedText === importSpecifier.propertyName.escapedText + ? factory.updateImportSpecifier( + importSpecifier, + importSpecifier.isTypeOnly, + /*propertyName*/ undefined, + importSpecifier.name, + ) + : importSpecifier, + ), + ); } function tryGetNamedBindingElements(namedImport: ImportDeclaration) { diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index ee06b0c3a6833..71bcb37da9c1e 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -7,7 +7,11 @@ namespace ts.OutliningElementsCollector { return res.sort((span1, span2) => span1.textSpan.start - span2.textSpan.start); } - function addNodeOutliningSpans(sourceFile: SourceFile, cancellationToken: CancellationToken, out: Push): void { + function addNodeOutliningSpans( + sourceFile: SourceFile, + cancellationToken: CancellationToken, + out: Push, + ): void { let depthRemaining = 40; let current = 0; // Includes the EOF Token so that comments which aren't attached to statements are included @@ -26,7 +30,15 @@ namespace ts.OutliningElementsCollector { } const lastImport = current - 1; if (lastImport !== firstImport) { - out.push(createOutliningSpanFromBounds(findChildOfKind(statements[firstImport], SyntaxKind.ImportKeyword, sourceFile)!.getStart(sourceFile), statements[lastImport].getEnd(), OutliningSpanKind.Imports)); + out.push( + createOutliningSpanFromBounds( + findChildOfKind(statements[firstImport], SyntaxKind.ImportKeyword, sourceFile)!.getStart( + sourceFile, + ), + statements[lastImport].getEnd(), + OutliningSpanKind.Imports, + ), + ); } } @@ -34,7 +46,10 @@ namespace ts.OutliningElementsCollector { if (depthRemaining === 0) return; cancellationToken.throwIfCancellationRequested(); - if (isDeclaration(n) || isVariableStatement(n) || isReturnStatement(n) || isCallOrNewExpression(n) || n.kind === SyntaxKind.EndOfFileToken) { + if ( + isDeclaration(n) || isVariableStatement(n) || isReturnStatement(n) || isCallOrNewExpression(n) + || n.kind === SyntaxKind.EndOfFileToken + ) { addOutliningForLeadingCommentsForNode(n, sourceFile, cancellationToken, out); } @@ -89,7 +104,15 @@ namespace ts.OutliningElementsCollector { if (!result[1]) { const span = createTextSpanFromBounds(sourceFile.text.indexOf("//", currentLineStart), lineEnd); - regions.push(createOutliningSpan(span, OutliningSpanKind.Region, span, /*autoCollapse*/ false, result[2] || "#region")); + regions.push( + createOutliningSpan( + span, + OutliningSpanKind.Region, + span, + /*autoCollapse*/ false, + result[2] || "#region", + ), + ); } else { const region = regions.pop(); @@ -114,7 +137,12 @@ namespace ts.OutliningElementsCollector { return regionDelimiterRegExp.exec(lineText); } - function addOutliningForLeadingCommentsForPos(pos: number, sourceFile: SourceFile, cancellationToken: CancellationToken, out: Push): void { + function addOutliningForLeadingCommentsForPos( + pos: number, + sourceFile: SourceFile, + cancellationToken: CancellationToken, + out: Push, + ): void { const comments = getLeadingCommentRanges(sourceFile.text, pos); if (!comments) return; @@ -156,12 +184,23 @@ namespace ts.OutliningElementsCollector { function combineAndAddMultipleSingleLineComments(): void { // Only outline spans of two or more consecutive single line comments if (singleLineCommentCount > 1) { - out.push(createOutliningSpanFromBounds(firstSingleLineCommentStart, lastSingleLineCommentEnd, OutliningSpanKind.Comment)); + out.push( + createOutliningSpanFromBounds( + firstSingleLineCommentStart, + lastSingleLineCommentEnd, + OutliningSpanKind.Comment, + ), + ); } } } - function addOutliningForLeadingCommentsForNode(n: Node, sourceFile: SourceFile, cancellationToken: CancellationToken, out: Push): void { + function addOutliningForLeadingCommentsForNode( + n: Node, + sourceFile: SourceFile, + cancellationToken: CancellationToken, + out: Push, + ): void { if (isJsxText(n)) return; addOutliningForLeadingCommentsForPos(n.pos, sourceFile, cancellationToken, out); } @@ -216,7 +255,12 @@ namespace ts.OutliningElementsCollector { case SyntaxKind.ObjectBindingPattern: return spanForNode(n); case SyntaxKind.TupleType: - return spanForNode(n, /*autoCollapse*/ false, /*useFullStart*/ !isTupleTypeNode(n.parent), SyntaxKind.OpenBracketToken); + return spanForNode( + n, + /*autoCollapse*/ false, + /*useFullStart*/ !isTupleTypeNode(n.parent), + SyntaxKind.OpenBracketToken, + ); case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: return spanForNodeArray((n as CaseClause | DefaultClause).statements); @@ -235,7 +279,12 @@ namespace ts.OutliningElementsCollector { case SyntaxKind.NoSubstitutionTemplateLiteral: return spanForTemplateLiteral(n as TemplateExpression | NoSubstitutionTemplateLiteral); case SyntaxKind.ArrayBindingPattern: - return spanForNode(n, /*autoCollapse*/ false, /*useFullStart*/ !isBindingElement(n.parent), SyntaxKind.OpenBracketToken); + return spanForNode( + n, + /*autoCollapse*/ false, + /*useFullStart*/ !isBindingElement(n.parent), + SyntaxKind.OpenBracketToken, + ); case SyntaxKind.ArrowFunction: return spanForArrowFunction(n as ArrowFunction); case SyntaxKind.CallExpression: @@ -254,11 +303,21 @@ namespace ts.OutliningElementsCollector { return undefined; } - return spanBetweenTokens(openToken, closeToken, node, sourceFile, /*autoCollapse*/ false, /*useFullStart*/ true); + return spanBetweenTokens( + openToken, + closeToken, + node, + sourceFile, + /*autoCollapse*/ false, + /*useFullStart*/ true, + ); } function spanForArrowFunction(node: ArrowFunction): OutliningSpan | undefined { - if (isBlock(node.body) || isParenthesizedExpression(node.body) || positionsAreOnSameLine(node.body.getFullStart(), node.body.getEnd(), sourceFile)) { + if ( + isBlock(node.body) || isParenthesizedExpression(node.body) + || positionsAreOnSameLine(node.body.getFullStart(), node.body.getEnd(), sourceFile) + ) { return undefined; } const textSpan = createTextSpanFromBounds(node.body.getFullStart(), node.body.getEnd()); @@ -266,14 +325,20 @@ namespace ts.OutliningElementsCollector { } function spanForJSXElement(node: JsxElement): OutliningSpan | undefined { - const textSpan = createTextSpanFromBounds(node.openingElement.getStart(sourceFile), node.closingElement.getEnd()); + const textSpan = createTextSpanFromBounds( + node.openingElement.getStart(sourceFile), + node.closingElement.getEnd(), + ); const tagName = node.openingElement.tagName.getText(sourceFile); const bannerText = "<" + tagName + ">..."; return createOutliningSpan(textSpan, OutliningSpanKind.Code, textSpan, /*autoCollapse*/ false, bannerText); } function spanForJSXFragment(node: JsxFragment): OutliningSpan | undefined { - const textSpan = createTextSpanFromBounds(node.openingFragment.getStart(sourceFile), node.closingFragment.getEnd()); + const textSpan = createTextSpanFromBounds( + node.openingFragment.getStart(sourceFile), + node.closingFragment.getEnd(), + ); const bannerText = "<>..."; return createOutliningSpan(textSpan, OutliningSpanKind.Code, textSpan, /*autoCollapse*/ false, bannerText); } @@ -293,21 +358,38 @@ namespace ts.OutliningElementsCollector { return createOutliningSpanFromBounds(node.getStart(sourceFile), node.getEnd(), OutliningSpanKind.Code); } - function spanForObjectOrArrayLiteral(node: Node, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken): OutliningSpan | undefined { + function spanForObjectOrArrayLiteral( + node: Node, + open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken, + ): OutliningSpan | undefined { // If the block has no leading keywords and is inside an array literal or call expression, // we only want to collapse the span of the block. // Otherwise, the collapsed section will include the end of the previous line. - return spanForNode(node, /*autoCollapse*/ false, /*useFullStart*/ !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent), open); + return spanForNode( + node, + /*autoCollapse*/ false, + /*useFullStart*/ !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent), + open, + ); } - function spanForNode(hintSpanNode: Node, autoCollapse = false, useFullStart = true, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken, close: SyntaxKind = open === SyntaxKind.OpenBraceToken ? SyntaxKind.CloseBraceToken : SyntaxKind.CloseBracketToken): OutliningSpan | undefined { + function spanForNode( + hintSpanNode: Node, + autoCollapse = false, + useFullStart = true, + open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken, + close: SyntaxKind = open === SyntaxKind.OpenBraceToken ? SyntaxKind.CloseBraceToken + : SyntaxKind.CloseBracketToken, + ): OutliningSpan | undefined { const openToken = findChildOfKind(n, open, sourceFile); const closeToken = findChildOfKind(n, close, sourceFile); - return openToken && closeToken && spanBetweenTokens(openToken, closeToken, hintSpanNode, sourceFile, autoCollapse, useFullStart); + return openToken && closeToken + && spanBetweenTokens(openToken, closeToken, hintSpanNode, sourceFile, autoCollapse, useFullStart); } function spanForNodeArray(nodeArray: NodeArray): OutliningSpan | undefined { - return nodeArray.length ? createOutliningSpan(createTextSpanFromRange(nodeArray), OutliningSpanKind.Code) : undefined; + return nodeArray.length ? createOutliningSpan(createTextSpanFromRange(nodeArray), OutliningSpanKind.Code) + : undefined; } function spanForParenthesizedExpression(node: ParenthesizedExpression): OutliningSpan | undefined { @@ -320,19 +402,51 @@ namespace ts.OutliningElementsCollector { function functionSpan(node: SignatureDeclaration, body: Block, sourceFile: SourceFile): OutliningSpan | undefined { const openToken = tryGetFunctionOpenToken(node, body, sourceFile); const closeToken = findChildOfKind(body, SyntaxKind.CloseBraceToken, sourceFile); - return openToken && closeToken && spanBetweenTokens(openToken, closeToken, node, sourceFile, /*autoCollapse*/ node.kind !== SyntaxKind.ArrowFunction); + return openToken && closeToken + && spanBetweenTokens( + openToken, + closeToken, + node, + sourceFile, + /*autoCollapse*/ node.kind !== SyntaxKind.ArrowFunction, + ); } - function spanBetweenTokens(openToken: Node, closeToken: Node, hintSpanNode: Node, sourceFile: SourceFile, autoCollapse = false, useFullStart = true): OutliningSpan { - const textSpan = createTextSpanFromBounds(useFullStart ? openToken.getFullStart() : openToken.getStart(sourceFile), closeToken.getEnd()); - return createOutliningSpan(textSpan, OutliningSpanKind.Code, createTextSpanFromNode(hintSpanNode, sourceFile), autoCollapse); + function spanBetweenTokens( + openToken: Node, + closeToken: Node, + hintSpanNode: Node, + sourceFile: SourceFile, + autoCollapse = false, + useFullStart = true, + ): OutliningSpan { + const textSpan = createTextSpanFromBounds( + useFullStart ? openToken.getFullStart() : openToken.getStart(sourceFile), + closeToken.getEnd(), + ); + return createOutliningSpan( + textSpan, + OutliningSpanKind.Code, + createTextSpanFromNode(hintSpanNode, sourceFile), + autoCollapse, + ); } - function createOutliningSpan(textSpan: TextSpan, kind: OutliningSpanKind, hintSpan: TextSpan = textSpan, autoCollapse = false, bannerText = "..."): OutliningSpan { + function createOutliningSpan( + textSpan: TextSpan, + kind: OutliningSpanKind, + hintSpan: TextSpan = textSpan, + autoCollapse = false, + bannerText = "...", + ): OutliningSpan { return { textSpan, kind, hintSpan, bannerText, autoCollapse }; } - function tryGetFunctionOpenToken(node: SignatureDeclaration, body: Block, sourceFile: SourceFile): Node | undefined { + function tryGetFunctionOpenToken( + node: SignatureDeclaration, + body: Block, + sourceFile: SourceFile, + ): Node | undefined { if (isNodeArrayMultiLine(node.parameters, sourceFile)) { const openParenToken = findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile); if (openParenToken) { diff --git a/src/services/patternMatcher.ts b/src/services/patternMatcher.ts index d22e287644fd8..d45a23f2d02cd 100644 --- a/src/services/patternMatcher.ts +++ b/src/services/patternMatcher.ts @@ -109,13 +109,20 @@ namespace ts { if (dotSeparatedSegments.some(segment => !segment.subWordTextChunks.length)) return undefined; return { - getFullMatch: (containers, candidate) => getFullMatch(containers, candidate, dotSeparatedSegments, stringToWordSpans), - getMatchForLastSegmentOfPattern: candidate => matchSegment(candidate, last(dotSeparatedSegments), stringToWordSpans), + getFullMatch: (containers, candidate) => + getFullMatch(containers, candidate, dotSeparatedSegments, stringToWordSpans), + getMatchForLastSegmentOfPattern: candidate => + matchSegment(candidate, last(dotSeparatedSegments), stringToWordSpans), patternContainsDots: dotSeparatedSegments.length > 1, }; } - function getFullMatch(candidateContainers: readonly string[], candidate: string, dotSeparatedSegments: readonly Segment[], stringToWordSpans: ESMap): PatternMatch | undefined { + function getFullMatch( + candidateContainers: readonly string[], + candidate: string, + dotSeparatedSegments: readonly Segment[], + stringToWordSpans: ESMap, + ): PatternMatch | undefined { // First, check that the last part of the dot separated pattern matches the name of the // candidate. If not, then there's no point in proceeding and doing the more // expensive work. @@ -134,7 +141,10 @@ namespace ts { let bestMatch: PatternMatch | undefined; for (let i = dotSeparatedSegments.length - 2, j = candidateContainers.length - 1; i >= 0; i -= 1, j -= 1) { - bestMatch = betterMatch(bestMatch, matchSegment(candidateContainers[j], dotSeparatedSegments[i], stringToWordSpans)); + bestMatch = betterMatch( + bestMatch, + matchSegment(candidateContainers[j], dotSeparatedSegments[i], stringToWordSpans), + ); } return bestMatch; } @@ -147,12 +157,19 @@ namespace ts { return spans; } - function matchTextChunk(candidate: string, chunk: TextChunk, stringToWordSpans: ESMap): PatternMatch | undefined { + function matchTextChunk( + candidate: string, + chunk: TextChunk, + stringToWordSpans: ESMap, + ): PatternMatch | undefined { const index = indexOfIgnoringCase(candidate, chunk.textLowerCase); if (index === 0) { // a) Check if the word is a prefix of the candidate, in a case insensitive or // sensitive manner. If it does, return that there was an exact match if the word and candidate are the same length, else a prefix match. - return createPatternMatch(chunk.text.length === candidate.length ? PatternMatchKind.exact : PatternMatchKind.prefix, /*isCaseSensitive:*/ startsWith(candidate, chunk.text)); + return createPatternMatch( + chunk.text.length === candidate.length ? PatternMatchKind.exact : PatternMatchKind.prefix, + /*isCaseSensitive:*/ startsWith(candidate, chunk.text), + ); } if (chunk.isLowerCase) { @@ -167,7 +184,10 @@ namespace ts { const wordSpans = getWordSpans(candidate, stringToWordSpans); for (const span of wordSpans) { if (partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ true)) { - return createPatternMatch(PatternMatchKind.substring, /*isCaseSensitive:*/ partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ false)); + return createPatternMatch( + PatternMatchKind.substring, + /*isCaseSensitive:*/ partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ false), + ); } } // c) Is the pattern a substring of the candidate starting on one of the candidate's word boundaries? @@ -190,7 +210,8 @@ namespace ts { // e) If the part was not entirely lowercase, then attempt a camel cased match as well. if (chunk.characterSpans.length > 0) { const candidateParts = getWordSpans(candidate, stringToWordSpans); - const isCaseSensitive = tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ false) ? true + const isCaseSensitive = tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ false) + ? true : tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ true) ? false : undefined; if (isCaseSensitive !== undefined) { return createPatternMatch(PatternMatchKind.camelCase, isCaseSensitive); @@ -199,7 +220,11 @@ namespace ts { } } - function matchSegment(candidate: string, segment: Segment, stringToWordSpans: ESMap): PatternMatch | undefined { + function matchSegment( + candidate: string, + segment: Segment, + stringToWordSpans: ESMap, + ): PatternMatch | undefined { // First check if the segment matches as is. This is also useful if the segment contains // characters we would normally strip when splitting into parts that we also may want to // match in the candidate. For example if the segment is "@int" and the candidate is @@ -264,16 +289,35 @@ namespace ts { : compareValues(a.kind, b.kind) || compareBooleans(!a.isCaseSensitive, !b.isCaseSensitive); } - function partStartsWith(candidate: string, candidateSpan: TextSpan, pattern: string, ignoreCase: boolean, patternSpan: TextSpan = { start: 0, length: pattern.length }): boolean { + function partStartsWith( + candidate: string, + candidateSpan: TextSpan, + pattern: string, + ignoreCase: boolean, + patternSpan: TextSpan = { start: 0, length: pattern.length }, + ): boolean { return patternSpan.length <= candidateSpan.length // If pattern part is longer than the candidate part there can never be a match. - && everyInRange(0, patternSpan.length, i => equalChars(pattern.charCodeAt(patternSpan.start + i), candidate.charCodeAt(candidateSpan.start + i), ignoreCase)); + && everyInRange( + 0, + patternSpan.length, + i => equalChars( + pattern.charCodeAt(patternSpan.start + i), + candidate.charCodeAt(candidateSpan.start + i), + ignoreCase, + ), + ); } function equalChars(ch1: number, ch2: number, ignoreCase: boolean): boolean { return ignoreCase ? toLowerCase(ch1) === toLowerCase(ch2) : ch1 === ch2; } - function tryCamelCaseMatch(candidate: string, candidateParts: TextSpan[], chunk: TextChunk, ignoreCase: boolean): boolean { + function tryCamelCaseMatch( + candidate: string, + candidateParts: TextSpan[], + chunk: TextChunk, + ignoreCase: boolean, + ): boolean { const chunkCharacterSpans = chunk.characterSpans; // Note: we may have more pattern parts than candidate parts. This is because multiple @@ -311,8 +355,8 @@ namespace ts { // only continue trying to consumer pattern parts if the last part and this // part are both upper case. if ( - !isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan - 1].start)) || - !isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan].start)) + !isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan - 1].start)) + || !isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan].start)) ) { break; } @@ -331,7 +375,10 @@ namespace ts { // obviously contiguous. contiguous = contiguous === undefined ? true : contiguous; - candidatePart = createTextSpan(candidatePart.start + chunkCharacterSpan.length, candidatePart.length - chunkCharacterSpan.length); + candidatePart = createTextSpan( + candidatePart.start + chunkCharacterSpan.length, + candidatePart.length - chunkCharacterSpan.length, + ); } // Check if we matched anything at all. If we didn't, then we need to unset the @@ -419,7 +466,8 @@ namespace ts { } function isWordChar(ch: number) { - return isUpperCaseLetter(ch) || isLowerCaseLetter(ch) || isDigit(ch) || ch === CharacterCodes._ || ch === CharacterCodes.$; + return isUpperCaseLetter(ch) || isLowerCaseLetter(ch) || isDigit(ch) || ch === CharacterCodes._ + || ch === CharacterCodes.$; } function breakPatternIntoTextChunks(pattern: string): TextChunk[] { @@ -480,11 +528,11 @@ namespace ts { const hasTransitionFromUpperToLower = word && transitionFromUpperToLower(identifier, i, wordStart); if ( - charIsPunctuation(identifier.charCodeAt(i - 1)) || - charIsPunctuation(identifier.charCodeAt(i)) || - lastIsDigit !== currentIsDigit || - hasTransitionFromLowerToUpper || - hasTransitionFromUpperToLower + charIsPunctuation(identifier.charCodeAt(i - 1)) + || charIsPunctuation(identifier.charCodeAt(i)) + || lastIsDigit !== currentIsDigit + || hasTransitionFromLowerToUpper + || hasTransitionFromUpperToLower ) { if (!isAllPunctuation(identifier, wordStart, i)) { result.push(createTextSpan(wordStart, i - wordStart)); diff --git a/src/services/preProcess.ts b/src/services/preProcess.ts index 37284bacfe881..c535908db7ba5 100644 --- a/src/services/preProcess.ts +++ b/src/services/preProcess.ts @@ -1,5 +1,9 @@ namespace ts { - export function preProcessFile(sourceText: string, readImportFiles = true, detectJavaScriptImports = false): PreProcessedFileInfo { + export function preProcessFile( + sourceText: string, + readImportFiles = true, + detectJavaScriptImports = false, + ): PreProcessedFileInfo { const pragmaContext: PragmaContext = { languageVersion: ScriptTarget.ES5, // controls whether the token scanner considers unicode identifiers or not - shouldn't matter, since we're only using it for trivia pragmas: undefined, @@ -105,10 +109,10 @@ namespace ts { const skipTypeKeyword = scanner.lookAhead(() => { const token = scanner.scan(); return token !== SyntaxKind.FromKeyword && ( - token === SyntaxKind.AsteriskToken || - token === SyntaxKind.OpenBraceToken || - token === SyntaxKind.Identifier || - isKeyword(token) + token === SyntaxKind.AsteriskToken + || token === SyntaxKind.OpenBraceToken + || token === SyntaxKind.Identifier + || isKeyword(token) ); }); if (skipTypeKeyword) { @@ -194,8 +198,8 @@ namespace ts { if (token === SyntaxKind.TypeKeyword) { const skipTypeKeyword = scanner.lookAhead(() => { const token = scanner.scan(); - return token === SyntaxKind.AsteriskToken || - token === SyntaxKind.OpenBraceToken; + return token === SyntaxKind.AsteriskToken + || token === SyntaxKind.OpenBraceToken; }); if (skipTypeKeyword) { token = nextToken(); @@ -236,8 +240,8 @@ namespace ts { if (token === SyntaxKind.TypeKeyword) { const skipTypeKeyword = scanner.lookAhead(() => { const token = scanner.scan(); - return token === SyntaxKind.Identifier || - isKeyword(token); + return token === SyntaxKind.Identifier + || isKeyword(token); }); if (skipTypeKeyword) { token = nextToken(); @@ -266,8 +270,8 @@ namespace ts { if (token === SyntaxKind.OpenParenToken) { token = nextToken(); if ( - token === SyntaxKind.StringLiteral || - allowTemplateLiterals && token === SyntaxKind.NoSubstitutionTemplateLiteral + token === SyntaxKind.StringLiteral + || allowTemplateLiterals && token === SyntaxKind.NoSubstitutionTemplateLiteral ) { // require("mod"); recordModuleName(); @@ -368,7 +372,10 @@ namespace ts { case SyntaxKind.CloseBraceToken: if (length(stack)) { if (lastOrUndefined(stack) === SyntaxKind.TemplateHead) { - if (scanner.reScanTemplateToken(/* isTaggedTemplate */ false) === SyntaxKind.TemplateTail) { + if ( + scanner.reScanTemplateToken(/* isTaggedTemplate */ false) + === SyntaxKind.TemplateTail + ) { stack.pop(); } } @@ -384,12 +391,12 @@ namespace ts { // check if at least one of alternative have moved scanner forward if ( - tryConsumeDeclare() || - tryConsumeImport() || - tryConsumeExport() || - (detectJavaScriptImports && ( - tryConsumeRequireCall(/*skipCurrentToken*/ false, /*allowTemplateLiterals*/ true) || - tryConsumeDefine() + tryConsumeDeclare() + || tryConsumeImport() + || tryConsumeExport() + || (detectJavaScriptImports && ( + tryConsumeRequireCall(/*skipCurrentToken*/ false, /*allowTemplateLiterals*/ true) + || tryConsumeDefine() )) ) { continue; @@ -415,7 +422,14 @@ namespace ts { importedFiles.push(decl.ref); } } - return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, libReferenceDirectives: pragmaContext.libReferenceDirectives, importedFiles, isLibFile: !!pragmaContext.hasNoDefaultLib, ambientExternalModules: undefined }; + return { + referencedFiles: pragmaContext.referencedFiles, + typeReferenceDirectives: pragmaContext.typeReferenceDirectives, + libReferenceDirectives: pragmaContext.libReferenceDirectives, + importedFiles, + isLibFile: !!pragmaContext.hasNoDefaultLib, + ambientExternalModules: undefined, + }; } else { // for global scripts ambient modules still can have augmentations - look for ambient modules with depth > 0 @@ -433,7 +447,14 @@ namespace ts { } } } - return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, libReferenceDirectives: pragmaContext.libReferenceDirectives, importedFiles, isLibFile: !!pragmaContext.hasNoDefaultLib, ambientExternalModules: ambientModuleNames }; + return { + referencedFiles: pragmaContext.referencedFiles, + typeReferenceDirectives: pragmaContext.typeReferenceDirectives, + libReferenceDirectives: pragmaContext.libReferenceDirectives, + importedFiles, + isLibFile: !!pragmaContext.hasNoDefaultLib, + ambientExternalModules: ambientModuleNames, + }; } } } diff --git a/src/services/refactorProvider.ts b/src/services/refactorProvider.ts index 47db755271311..1eabbbcf15576 100644 --- a/src/services/refactorProvider.ts +++ b/src/services/refactorProvider.ts @@ -10,13 +10,22 @@ namespace ts.refactor { } export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] { - return arrayFrom(flatMapIterator(refactors.values(), refactor => - context.cancellationToken && context.cancellationToken.isCancellationRequested() || - !refactor.kinds?.some(kind => refactorKindBeginsWith(kind, context.kind)) ? undefined : - refactor.getAvailableActions(context))); + return arrayFrom( + flatMapIterator( + refactors.values(), + refactor => + context.cancellationToken && context.cancellationToken.isCancellationRequested() + || !refactor.kinds?.some(kind => refactorKindBeginsWith(kind, context.kind)) ? undefined + : refactor.getAvailableActions(context), + ), + ); } - export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string): RefactorEditInfo | undefined { + export function getEditsForRefactor( + context: RefactorContext, + refactorName: string, + actionName: string, + ): RefactorEditInfo | undefined { const refactor = refactors.get(refactorName); return refactor && refactor.getEditsForAction(context, actionName); } diff --git a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts index 70b5665f8b260..5b8022ff5b177 100644 --- a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts +++ b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts @@ -55,7 +55,10 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { return emptyArray; } - function getRefactorEditsToRemoveFunctionBraces(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { + function getRefactorEditsToRemoveFunctionBraces( + context: RefactorContext, + actionName: string, + ): RefactorEditInfo | undefined { const { file, startPosition } = context; const info = getConvertibleArrowFunctionAtPosition(file, startPosition); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); @@ -67,14 +70,39 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { if (actionName === addBracesAction.name) { const returnStatement = factory.createReturnStatement(expression); body = factory.createBlock([returnStatement], /* multiLine */ true); - copyLeadingComments(expression!, returnStatement, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ true); + copyLeadingComments( + expression!, + returnStatement, + file, + SyntaxKind.MultiLineCommentTrivia, + /* hasTrailingNewLine */ true, + ); } else if (actionName === removeBracesAction.name && returnStatement) { const actualExpression = expression || factory.createVoidZero(); - body = needsParentheses(actualExpression) ? factory.createParenthesizedExpression(actualExpression) : actualExpression; - copyTrailingAsLeadingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); - copyLeadingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); - copyTrailingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); + body = needsParentheses(actualExpression) ? factory.createParenthesizedExpression(actualExpression) + : actualExpression; + copyTrailingAsLeadingComments( + returnStatement, + body, + file, + SyntaxKind.MultiLineCommentTrivia, + /* hasTrailingNewLine */ false, + ); + copyLeadingComments( + returnStatement, + body, + file, + SyntaxKind.MultiLineCommentTrivia, + /* hasTrailingNewLine */ false, + ); + copyTrailingComments( + returnStatement, + body, + file, + SyntaxKind.MultiLineCommentTrivia, + /* hasTrailingNewLine */ false, + ); } else { Debug.fail("invalid action"); @@ -87,7 +115,12 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { return { renameFilename: undefined, renameLocation: undefined, edits }; } - function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number, considerFunctionBodies = true, kind?: string): FunctionBracesInfo | RefactorErrorInfo | undefined { + function getConvertibleArrowFunctionAtPosition( + file: SourceFile, + startPosition: number, + considerFunctionBodies = true, + kind?: string, + ): FunctionBracesInfo | RefactorErrorInfo | undefined { const node = getTokenAtPosition(file, startPosition); const func = getContainingFunction(node); @@ -110,10 +143,18 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { if (refactorKindBeginsWith(addBracesAction.kind, kind) && isExpression(func.body)) { return { func, addBraces: true, expression: func.body }; } - else if (refactorKindBeginsWith(removeBracesAction.kind, kind) && isBlock(func.body) && func.body.statements.length === 1) { + else if ( + refactorKindBeginsWith(removeBracesAction.kind, kind) && isBlock(func.body) + && func.body.statements.length === 1 + ) { const firstStatement = first(func.body.statements); if (isReturnStatement(firstStatement)) { - return { func, addBraces: false, expression: firstStatement.expression, returnStatement: firstStatement }; + return { + func, + addBraces: false, + expression: firstStatement.expression, + returnStatement: firstStatement, + }; } } return undefined; diff --git a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts index de33ef410b4bd..5f109ea795e5d 100644 --- a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts +++ b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts @@ -40,7 +40,9 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { readonly name: Identifier; } - function getRefactorActionsToConvertFunctionExpressions(context: RefactorContext): readonly ApplicableRefactorInfo[] { + function getRefactorActionsToConvertFunctionExpressions( + context: RefactorContext, + ): readonly ApplicableRefactorInfo[] { const { file, startPosition, program, kind } = context; const info = getFunctionInfo(file, startPosition, program); @@ -49,8 +51,8 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { const possibleActions: RefactorActionInfo[] = []; const errors: RefactorActionInfo[] = []; if (refactorKindBeginsWith(toNamedFunctionAction.kind, kind)) { - const error = selectedVariableDeclaration || (isArrowFunction(func) && isVariableDeclaration(func.parent)) ? - undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_named_function); + const error = selectedVariableDeclaration || (isArrowFunction(func) && isVariableDeclaration(func.parent)) + ? undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_named_function); if (error) { errors.push({ ...toNamedFunctionAction, notApplicableReason: error }); } @@ -60,8 +62,8 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { } if (refactorKindBeginsWith(toAnonymousFunctionAction.kind, kind)) { - const error = !selectedVariableDeclaration && isArrowFunction(func) ? - undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_anonymous_function); + const error = !selectedVariableDeclaration && isArrowFunction(func) + ? undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_anonymous_function); if (error) { errors.push({ ...toAnonymousFunctionAction, notApplicableReason: error }); } @@ -71,7 +73,8 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { } if (refactorKindBeginsWith(toArrowFunctionAction.kind, kind)) { - const error = isFunctionExpression(func) ? undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_arrow_function); + const error = isFunctionExpression(func) ? undefined + : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_arrow_function); if (error) { errors.push({ ...toArrowFunctionAction, notApplicableReason: error }); } @@ -83,12 +86,15 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { return [{ name: refactorName, description: refactorDescription, - actions: possibleActions.length === 0 && context.preferences.provideRefactorNotApplicableReason ? - errors : possibleActions, + actions: possibleActions.length === 0 && context.preferences.provideRefactorNotApplicableReason + ? errors : possibleActions, }]; } - function getRefactorEditsToConvertFunctionExpressions(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { + function getRefactorEditsToConvertFunctionExpressions( + context: RefactorContext, + actionName: string, + ): RefactorEditInfo | undefined { const { file, startPosition, program } = context; const info = getFunctionInfo(file, startPosition, program); @@ -146,13 +152,15 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { const maybeFunc = getContainingFunction(token); if ( - maybeFunc && - (isFunctionExpression(maybeFunc) || isArrowFunction(maybeFunc)) && - !rangeContainsRange(maybeFunc.body, token) && - !containingThis(maybeFunc.body) && - !typeChecker.containsArgumentsReference(maybeFunc) + maybeFunc + && (isFunctionExpression(maybeFunc) || isArrowFunction(maybeFunc)) + && !rangeContainsRange(maybeFunc.body, token) + && !containingThis(maybeFunc.body) + && !typeChecker.containsArgumentsReference(maybeFunc) ) { - if (isFunctionExpression(maybeFunc) && isFunctionReferencedInFile(file, typeChecker, maybeFunc)) return undefined; + if (isFunctionExpression(maybeFunc) && isFunctionReferencedInFile(file, typeChecker, maybeFunc)) { + return undefined; + } return { selectedVariableDeclaration: false, func: maybeFunc }; } @@ -163,13 +171,22 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { return isVariableDeclaration(parent) || (isVariableDeclarationList(parent) && parent.declarations.length === 1); } - function tryGetFunctionFromVariableDeclaration(sourceFile: SourceFile, typeChecker: TypeChecker, parent: Node): ArrowFunction | FunctionExpression | undefined { + function tryGetFunctionFromVariableDeclaration( + sourceFile: SourceFile, + typeChecker: TypeChecker, + parent: Node, + ): ArrowFunction | FunctionExpression | undefined { if (!isSingleVariableDeclaration(parent)) { return undefined; } const variableDeclaration = isVariableDeclaration(parent) ? parent : first(parent.declarations); const initializer = variableDeclaration.initializer; - if (initializer && (isArrowFunction(initializer) || isFunctionExpression(initializer) && !isFunctionReferencedInFile(sourceFile, typeChecker, initializer))) { + if ( + initializer + && (isArrowFunction(initializer) + || isFunctionExpression(initializer) + && !isFunctionReferencedInFile(sourceFile, typeChecker, initializer)) + ) { return initializer; } return undefined; @@ -180,7 +197,13 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { const returnStatement = factory.createReturnStatement(body); const file = body.getSourceFile(); suppressLeadingAndTrailingTrivia(returnStatement); - copyTrailingAsLeadingComments(body, returnStatement, file, /* commentKind */ undefined, /* hasTrailingNewLine */ true); + copyTrailingAsLeadingComments( + body, + returnStatement, + file, + /* commentKind */ undefined, + /* hasTrailingNewLine */ true, + ); return factory.createBlock([returnStatement], /* multiLine */ true); } else { @@ -190,32 +213,62 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { function getVariableInfo(func: FunctionExpression | ArrowFunction): VariableInfo | undefined { const variableDeclaration = func.parent; - if (!isVariableDeclaration(variableDeclaration) || !isVariableDeclarationInVariableStatement(variableDeclaration)) return undefined; + if ( + !isVariableDeclaration(variableDeclaration) + || !isVariableDeclarationInVariableStatement(variableDeclaration) + ) return undefined; const variableDeclarationList = variableDeclaration.parent; const statement = variableDeclarationList.parent; - if (!isVariableDeclarationList(variableDeclarationList) || !isVariableStatement(statement) || !isIdentifier(variableDeclaration.name)) return undefined; + if ( + !isVariableDeclarationList(variableDeclarationList) || !isVariableStatement(statement) + || !isIdentifier(variableDeclaration.name) + ) return undefined; return { variableDeclaration, variableDeclarationList, statement, name: variableDeclaration.name }; } - function getEditInfoForConvertToAnonymousFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction): FileTextChanges[] { + function getEditInfoForConvertToAnonymousFunction( + context: RefactorContext, + func: FunctionExpression | ArrowFunction, + ): FileTextChanges[] { const { file } = context; const body = convertToBlock(func.body); - const newNode = factory.createFunctionExpression(func.modifiers, func.asteriskToken, /* name */ undefined, func.typeParameters, func.parameters, func.type, body); + const newNode = factory.createFunctionExpression( + func.modifiers, + func.asteriskToken, + /* name */ undefined, + func.typeParameters, + func.parameters, + func.type, + body, + ); return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode)); } - function getEditInfoForConvertToNamedFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction, variableInfo: VariableInfo): FileTextChanges[] { + function getEditInfoForConvertToNamedFunction( + context: RefactorContext, + func: FunctionExpression | ArrowFunction, + variableInfo: VariableInfo, + ): FileTextChanges[] { const { file } = context; const body = convertToBlock(func.body); const { variableDeclaration, variableDeclarationList, statement, name } = variableInfo; suppressLeadingTrivia(statement); - const modifiersFlags = (getCombinedModifierFlags(variableDeclaration) & ModifierFlags.Export) | getEffectiveModifierFlags(func); + const modifiersFlags = (getCombinedModifierFlags(variableDeclaration) & ModifierFlags.Export) + | getEffectiveModifierFlags(func); const modifiers = factory.createModifiersFromModifierFlags(modifiersFlags); - const newNode = factory.createFunctionDeclaration(length(modifiers) ? modifiers : undefined, func.asteriskToken, name, func.typeParameters, func.parameters, func.type, body); + const newNode = factory.createFunctionDeclaration( + length(modifiers) ? modifiers : undefined, + func.asteriskToken, + name, + func.typeParameters, + func.parameters, + func.type, + body, + ); if (variableDeclarationList.declarations.length === 1) { return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, statement, newNode)); @@ -228,7 +281,10 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { } } - function getEditInfoForConvertToArrowFunction(context: RefactorContext, func: FunctionExpression): FileTextChanges[] { + function getEditInfoForConvertToArrowFunction( + context: RefactorContext, + func: FunctionExpression, + ): FileTextChanges[] { const { file } = context; const statements = func.body.statements; const head = statements[0]; @@ -243,7 +299,14 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { body = func.body; } - const newNode = factory.createArrowFunction(func.modifiers, func.typeParameters, func.parameters, func.type, factory.createToken(SyntaxKind.EqualsGreaterThanToken), body); + const newNode = factory.createArrowFunction( + func.modifiers, + func.typeParameters, + func.parameters, + func.type, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + body, + ); return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode)); } @@ -251,7 +314,11 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { return body.statements.length === 1 && (isReturnStatement(head) && !!head.expression); } - function isFunctionReferencedInFile(sourceFile: SourceFile, typeChecker: TypeChecker, node: FunctionExpression): boolean { + function isFunctionReferencedInFile( + sourceFile: SourceFile, + typeChecker: TypeChecker, + node: FunctionExpression, + ): boolean { return !!node.name && FindAllReferences.Core.isSymbolReferencedInFile(node.name, typeChecker, sourceFile); } } diff --git a/src/services/refactors/convertExport.ts b/src/services/refactors/convertExport.ts index 7c0364ba73fa1..d94759a491c0a 100644 --- a/src/services/refactors/convertExport.ts +++ b/src/services/refactors/convertExport.ts @@ -18,7 +18,9 @@ namespace ts.refactor { defaultToNamedAction.kind, namedToDefaultAction.kind, ], - getAvailableActions: function getRefactorActionsToConvertBetweenNamedAndDefaultExports(context): readonly ApplicableRefactorInfo[] { + getAvailableActions: function getRefactorActionsToConvertBetweenNamedAndDefaultExports( + context, + ): readonly ApplicableRefactorInfo[] { const info = getInfo(context, context.triggerReason === "invoked"); if (!info) return emptyArray; @@ -42,17 +44,34 @@ namespace ts.refactor { return emptyArray; }, - getEditsForAction: function getRefactorEditsToConvertBetweenNamedAndDefaultExports(context, actionName): RefactorEditInfo { - Debug.assert(actionName === defaultToNamedAction.name || actionName === namedToDefaultAction.name, "Unexpected action name"); + getEditsForAction: function getRefactorEditsToConvertBetweenNamedAndDefaultExports( + context, + actionName, + ): RefactorEditInfo { + Debug.assert( + actionName === defaultToNamedAction.name || actionName === namedToDefaultAction.name, + "Unexpected action name", + ); const info = getInfo(context); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, info, t, context.cancellationToken)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(context.file, context.program, info, t, context.cancellationToken), + ); return { edits, renameFilename: undefined, renameLocation: undefined }; }, }); // If a VariableStatement, will have exactly one VariableDeclaration, with an Identifier for a name. - type ExportToConvert = FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | EnumDeclaration | NamespaceDeclaration | TypeAliasDeclaration | VariableStatement | ExportAssignment; + type ExportToConvert = + | FunctionDeclaration + | ClassDeclaration + | InterfaceDeclaration + | EnumDeclaration + | NamespaceDeclaration + | TypeAliasDeclaration + | VariableStatement + | ExportAssignment; interface ExportInfo { readonly exportNode: ExportToConvert; readonly exportName: Identifier; // This is exportNode.name except for VariableStatement_s. @@ -60,22 +79,36 @@ namespace ts.refactor { readonly exportingModuleSymbol: Symbol; } - function getInfo(context: RefactorContext, considerPartialSpans = true): ExportInfo | RefactorErrorInfo | undefined { + function getInfo( + context: RefactorContext, + considerPartialSpans = true, + ): ExportInfo | RefactorErrorInfo | undefined { const { file, program } = context; const span = getRefactorContextSpan(context); const token = getTokenAtPosition(file, span.start); - const exportNode = !!(token.parent && getSyntacticModifierFlags(token.parent) & ModifierFlags.Export) && considerPartialSpans ? token.parent : getParentNodeInSpan(token, file, span); - if (!exportNode || (!isSourceFile(exportNode.parent) && !(isModuleBlock(exportNode.parent) && isAmbientModule(exportNode.parent.parent)))) { + const exportNode = + !!(token.parent && getSyntacticModifierFlags(token.parent) & ModifierFlags.Export) && considerPartialSpans + ? token.parent : getParentNodeInSpan(token, file, span); + if ( + !exportNode + || (!isSourceFile(exportNode.parent) + && !(isModuleBlock(exportNode.parent) && isAmbientModule(exportNode.parent.parent))) + ) { return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_export_statement) }; } const checker = program.getTypeChecker(); const exportingModuleSymbol = getExportingModuleSymbol(exportNode, checker); - const flags = getSyntacticModifierFlags(exportNode) || ((isExportAssignment(exportNode) && !exportNode.isExportEquals) ? ModifierFlags.ExportDefault : ModifierFlags.None); + const flags = getSyntacticModifierFlags(exportNode) + || ((isExportAssignment(exportNode) && !exportNode.isExportEquals) ? ModifierFlags.ExportDefault + : ModifierFlags.None); const wasDefault = !!(flags & ModifierFlags.Default); // If source file already has a default export, don't offer refactor. - if (!(flags & ModifierFlags.Export) || !wasDefault && exportingModuleSymbol.exports!.has(InternalSymbolName.Default)) { + if ( + !(flags & ModifierFlags.Export) + || !wasDefault && exportingModuleSymbol.exports!.has(InternalSymbolName.Default) + ) { return { error: getLocaleSpecificMessage(Diagnostics.This_file_already_has_a_default_export) }; } @@ -90,7 +123,13 @@ namespace ts.refactor { case SyntaxKind.EnumDeclaration: case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.ModuleDeclaration: { - const node = exportNode as FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | EnumDeclaration | TypeAliasDeclaration | NamespaceDeclaration; + const node = exportNode as + | FunctionDeclaration + | ClassDeclaration + | InterfaceDeclaration + | EnumDeclaration + | TypeAliasDeclaration + | NamespaceDeclaration; if (!node.name) return undefined; return noSymbolError(node.name) || { exportNode: node, exportName: node.name, wasDefault, exportingModuleSymbol }; @@ -111,43 +150,89 @@ namespace ts.refactor { const node = exportNode as ExportAssignment; if (node.isExportEquals) return undefined; return noSymbolError(node.expression) - || { exportNode: node, exportName: node.expression as Identifier, wasDefault, exportingModuleSymbol }; + || { + exportNode: node, + exportName: node.expression as Identifier, + wasDefault, + exportingModuleSymbol, + }; } default: return undefined; } } - function doChange(exportingSourceFile: SourceFile, program: Program, info: ExportInfo, changes: textChanges.ChangeTracker, cancellationToken: CancellationToken | undefined): void { + function doChange( + exportingSourceFile: SourceFile, + program: Program, + info: ExportInfo, + changes: textChanges.ChangeTracker, + cancellationToken: CancellationToken | undefined, + ): void { changeExport(exportingSourceFile, info, changes, program.getTypeChecker()); changeImports(program, info, changes, cancellationToken); } - function changeExport(exportingSourceFile: SourceFile, { wasDefault, exportNode, exportName }: ExportInfo, changes: textChanges.ChangeTracker, checker: TypeChecker): void { + function changeExport( + exportingSourceFile: SourceFile, + { wasDefault, exportNode, exportName }: ExportInfo, + changes: textChanges.ChangeTracker, + checker: TypeChecker, + ): void { if (wasDefault) { if (isExportAssignment(exportNode) && !exportNode.isExportEquals) { const exp = exportNode.expression as Identifier; const spec = makeExportSpecifier(exp.text, exp.text); - changes.replaceNode(exportingSourceFile, exportNode, factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createNamedExports([spec]))); + changes.replaceNode( + exportingSourceFile, + exportNode, + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([spec]), + ), + ); } else { - changes.delete(exportingSourceFile, Debug.checkDefined(findModifier(exportNode, SyntaxKind.DefaultKeyword), "Should find a default keyword in modifier list")); + changes.delete( + exportingSourceFile, + Debug.checkDefined( + findModifier(exportNode, SyntaxKind.DefaultKeyword), + "Should find a default keyword in modifier list", + ), + ); } } else { - const exportKeyword = Debug.checkDefined(findModifier(exportNode, SyntaxKind.ExportKeyword), "Should find an export keyword in modifier list"); + const exportKeyword = Debug.checkDefined( + findModifier(exportNode, SyntaxKind.ExportKeyword), + "Should find an export keyword in modifier list", + ); switch (exportNode.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: - changes.insertNodeAfter(exportingSourceFile, exportKeyword, factory.createToken(SyntaxKind.DefaultKeyword)); + changes.insertNodeAfter( + exportingSourceFile, + exportKeyword, + factory.createToken(SyntaxKind.DefaultKeyword), + ); break; case SyntaxKind.VariableStatement: // If 'x' isn't used in this file and doesn't have type definition, `export const x = 0;` --> `export default 0;` const decl = first(exportNode.declarationList.declarations); - if (!FindAllReferences.Core.isSymbolReferencedInFile(exportName, checker, exportingSourceFile) && !decl.type) { + if ( + !FindAllReferences.Core.isSymbolReferencedInFile(exportName, checker, exportingSourceFile) + && !decl.type + ) { // We checked in `getInfo` that an initializer exists. - changes.replaceNode(exportingSourceFile, exportNode, factory.createExportDefault(Debug.checkDefined(decl.initializer, "Initializer was previously known to be present"))); + changes.replaceNode( + exportingSourceFile, + exportNode, + factory.createExportDefault( + Debug.checkDefined(decl.initializer, "Initializer was previously known to be present"), + ), + ); break; } // falls through @@ -156,7 +241,11 @@ namespace ts.refactor { case SyntaxKind.ModuleDeclaration: // `export type T = number;` -> `type T = number; export default T;` changes.deleteModifier(exportingSourceFile, exportKeyword); - changes.insertNodeAfter(exportingSourceFile, exportNode, factory.createExportDefault(factory.createIdentifier(exportName.text))); + changes.insertNodeAfter( + exportingSourceFile, + exportNode, + factory.createExportDefault(factory.createIdentifier(exportName.text)), + ); break; default: Debug.fail(`Unexpected exportNode kind ${(exportNode as ExportToConvert).kind}`); @@ -164,22 +253,44 @@ namespace ts.refactor { } } - function changeImports(program: Program, { wasDefault, exportName, exportingModuleSymbol }: ExportInfo, changes: textChanges.ChangeTracker, cancellationToken: CancellationToken | undefined): void { + function changeImports( + program: Program, + { wasDefault, exportName, exportingModuleSymbol }: ExportInfo, + changes: textChanges.ChangeTracker, + cancellationToken: CancellationToken | undefined, + ): void { const checker = program.getTypeChecker(); - const exportSymbol = Debug.checkDefined(checker.getSymbolAtLocation(exportName), "Export name should resolve to a symbol"); - FindAllReferences.Core.eachExportReference(program.getSourceFiles(), checker, cancellationToken, exportSymbol, exportingModuleSymbol, exportName.text, wasDefault, ref => { - if (exportName === ref) return; - const importingSourceFile = ref.getSourceFile(); - if (wasDefault) { - changeDefaultToNamedImport(importingSourceFile, ref, changes, exportName.text); - } - else { - changeNamedToDefaultImport(importingSourceFile, ref, changes); - } - }); + const exportSymbol = Debug.checkDefined( + checker.getSymbolAtLocation(exportName), + "Export name should resolve to a symbol", + ); + FindAllReferences.Core.eachExportReference( + program.getSourceFiles(), + checker, + cancellationToken, + exportSymbol, + exportingModuleSymbol, + exportName.text, + wasDefault, + ref => { + if (exportName === ref) return; + const importingSourceFile = ref.getSourceFile(); + if (wasDefault) { + changeDefaultToNamedImport(importingSourceFile, ref, changes, exportName.text); + } + else { + changeNamedToDefaultImport(importingSourceFile, ref, changes); + } + }, + ); } - function changeDefaultToNamedImport(importingSourceFile: SourceFile, ref: Identifier, changes: textChanges.ChangeTracker, exportName: string): void { + function changeDefaultToNamedImport( + importingSourceFile: SourceFile, + ref: Identifier, + changes: textChanges.ChangeTracker, + exportName: string, + ): void { const { parent } = ref; switch (parent.kind) { case SyntaxKind.PropertyAccessExpression: @@ -204,9 +315,19 @@ namespace ts.refactor { } else if (namedBindings.kind === SyntaxKind.NamespaceImport) { // `import foo, * as a from "./a";` --> `import * as a from ".a/"; import { foo } from "./a";` - changes.deleteRange(importingSourceFile, { pos: ref.getStart(importingSourceFile), end: namedBindings.getStart(importingSourceFile) }); - const quotePreference = isStringLiteral(clause.parent.moduleSpecifier) ? quotePreferenceFromString(clause.parent.moduleSpecifier, importingSourceFile) : QuotePreference.Double; - const newImport = makeImport(/*default*/ undefined, [makeImportSpecifier(exportName, ref.text)], clause.parent.moduleSpecifier, quotePreference); + changes.deleteRange(importingSourceFile, { + pos: ref.getStart(importingSourceFile), + end: namedBindings.getStart(importingSourceFile), + }); + const quotePreference = isStringLiteral(clause.parent.moduleSpecifier) + ? quotePreferenceFromString(clause.parent.moduleSpecifier, importingSourceFile) + : QuotePreference.Double; + const newImport = makeImport( + /*default*/ undefined, + [makeImportSpecifier(exportName, ref.text)], + clause.parent.moduleSpecifier, + quotePreference, + ); changes.insertNodeAfter(importingSourceFile, clause.parent, newImport); } else { @@ -218,14 +339,28 @@ namespace ts.refactor { } case SyntaxKind.ImportType: const importTypeNode = parent as ImportTypeNode; - changes.replaceNode(importingSourceFile, parent, factory.createImportTypeNode(importTypeNode.argument, importTypeNode.assertions, factory.createIdentifier(exportName), importTypeNode.typeArguments, importTypeNode.isTypeOf)); + changes.replaceNode( + importingSourceFile, + parent, + factory.createImportTypeNode( + importTypeNode.argument, + importTypeNode.assertions, + factory.createIdentifier(exportName), + importTypeNode.typeArguments, + importTypeNode.isTypeOf, + ), + ); break; default: Debug.failBadSyntaxKind(parent); } } - function changeNamedToDefaultImport(importingSourceFile: SourceFile, ref: Identifier, changes: textChanges.ChangeTracker): void { + function changeNamedToDefaultImport( + importingSourceFile: SourceFile, + ref: Identifier, + changes: textChanges.ChangeTracker, + ): void { const parent = ref.parent as PropertyAccessExpression | ImportSpecifier | ExportSpecifier; switch (parent.kind) { case SyntaxKind.PropertyAccessExpression: @@ -259,11 +394,19 @@ namespace ts.refactor { } function makeImportSpecifier(propertyName: string, name: string): ImportSpecifier { - return factory.createImportSpecifier(/*isTypeOnly*/ false, propertyName === name ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(name)); + return factory.createImportSpecifier( + /*isTypeOnly*/ false, + propertyName === name ? undefined : factory.createIdentifier(propertyName), + factory.createIdentifier(name), + ); } function makeExportSpecifier(propertyName: string, name: string): ExportSpecifier { - return factory.createExportSpecifier(/*isTypeOnly*/ false, propertyName === name ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(name)); + return factory.createExportSpecifier( + /*isTypeOnly*/ false, + propertyName === name ? undefined : factory.createIdentifier(propertyName), + factory.createIdentifier(name), + ); } function getExportingModuleSymbol(node: Node, checker: TypeChecker) { diff --git a/src/services/refactors/convertImport.ts b/src/services/refactors/convertImport.ts index cebe10b43ca5c..d2199ba942d60 100644 --- a/src/services/refactors/convertImport.ts +++ b/src/services/refactors/convertImport.ts @@ -22,7 +22,9 @@ namespace ts.refactor { registerRefactor(refactorName, { kinds: getOwnValues(actions).map(a => a.kind), - getAvailableActions: function getRefactorActionsToConvertBetweenNamedAndNamespacedImports(context): readonly ApplicableRefactorInfo[] { + getAvailableActions: function getRefactorActionsToConvertBetweenNamedAndNamespacedImports( + context, + ): readonly ApplicableRefactorInfo[] { const info = getImportConversionInfo(context, context.triggerReason === "invoked"); if (!info) return emptyArray; @@ -41,11 +43,17 @@ namespace ts.refactor { return emptyArray; }, - getEditsForAction: function getRefactorEditsToConvertBetweenNamedAndNamespacedImports(context, actionName): RefactorEditInfo { + getEditsForAction: function getRefactorEditsToConvertBetweenNamedAndNamespacedImports( + context, + actionName, + ): RefactorEditInfo { Debug.assert(some(getOwnValues(actions), action => action.name === actionName), "Unexpected action name"); const info = getImportConversionInfo(context); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, t, info)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(context.file, context.program, t, info), + ); return { edits, renameFilename: undefined, renameLocation: undefined }; }, }); @@ -56,12 +64,18 @@ namespace ts.refactor { | { convertTo: ImportKind.Namespace; import: NamedImports; } | { convertTo: ImportKind.Named; import: NamespaceImport; }; - function getImportConversionInfo(context: RefactorContext, considerPartialSpans = true): ImportConversionInfo | RefactorErrorInfo | undefined { + function getImportConversionInfo( + context: RefactorContext, + considerPartialSpans = true, + ): ImportConversionInfo | RefactorErrorInfo | undefined { const { file } = context; const span = getRefactorContextSpan(context); const token = getTokenAtPosition(file, span.start); - const importDecl = considerPartialSpans ? findAncestor(token, isImportDeclaration) : getParentNodeInSpan(token, file, span); - if (!importDecl || !isImportDeclaration(importDecl)) return { error: "Selection is not an import declaration." }; + const importDecl = considerPartialSpans ? findAncestor(token, isImportDeclaration) + : getParentNodeInSpan(token, file, span); + if (!importDecl || !isImportDeclaration(importDecl)) { + return { error: "Selection is not an import declaration." }; + } const end = span.start + span.length; const nextToken = findNextToken(importDecl, importDecl.parent, file); @@ -91,17 +105,40 @@ namespace ts.refactor { && isExportEqualsModule(importClause.parent.moduleSpecifier, program.getTypeChecker()); } - function doChange(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, info: ImportConversionInfo): void { + function doChange( + sourceFile: SourceFile, + program: Program, + changes: textChanges.ChangeTracker, + info: ImportConversionInfo, + ): void { const checker = program.getTypeChecker(); if (info.convertTo === ImportKind.Named) { - doChangeNamespaceToNamed(sourceFile, checker, changes, info.import, getAllowSyntheticDefaultImports(program.getCompilerOptions())); + doChangeNamespaceToNamed( + sourceFile, + checker, + changes, + info.import, + getAllowSyntheticDefaultImports(program.getCompilerOptions()), + ); } else { - doChangeNamedToNamespaceOrDefault(sourceFile, program, changes, info.import, info.convertTo === ImportKind.Default); + doChangeNamedToNamespaceOrDefault( + sourceFile, + program, + changes, + info.import, + info.convertTo === ImportKind.Default, + ); } } - function doChangeNamespaceToNamed(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, toConvert: NamespaceImport, allowSyntheticDefaultImports: boolean): void { + function doChangeNamespaceToNamed( + sourceFile: SourceFile, + checker: TypeChecker, + changes: textChanges.ChangeTracker, + toConvert: NamespaceImport, + allowSyntheticDefaultImports: boolean, + ): void { let usedAsNamespaceOrDefault = false; const nodesToReplace: (PropertyAccessExpression | QualifiedName)[] = []; @@ -116,7 +153,10 @@ namespace ts.refactor { if (checker.resolveName(exportName, id, SymbolFlags.All, /*excludeGlobals*/ true)) { conflictingNames.set(exportName, true); } - Debug.assert(getLeftOfPropertyAccessOrQualifiedName(id.parent) === id, "Parent expression should match id"); + Debug.assert( + getLeftOfPropertyAccessOrQualifiedName(id.parent) === id, + "Parent expression should match id", + ); nodesToReplace.push(id.parent); } }); @@ -128,35 +168,68 @@ namespace ts.refactor { const exportName = getRightOfPropertyAccessOrQualifiedName(propertyAccessOrQualifiedName).text; let importName = exportNameToImportName.get(exportName); if (importName === undefined) { - exportNameToImportName.set(exportName, importName = conflictingNames.has(exportName) ? getUniqueName(exportName, sourceFile) : exportName); + exportNameToImportName.set( + exportName, + importName = conflictingNames.has(exportName) ? getUniqueName(exportName, sourceFile) : exportName, + ); } changes.replaceNode(sourceFile, propertyAccessOrQualifiedName, factory.createIdentifier(importName)); } const importSpecifiers: ImportSpecifier[] = []; exportNameToImportName.forEach((name, propertyName) => { - importSpecifiers.push(factory.createImportSpecifier(/*isTypeOnly*/ false, name === propertyName ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(name))); + importSpecifiers.push( + factory.createImportSpecifier( + /*isTypeOnly*/ false, + name === propertyName ? undefined : factory.createIdentifier(propertyName), + factory.createIdentifier(name), + ), + ); }); const importDecl = toConvert.parent.parent; if (usedAsNamespaceOrDefault && !allowSyntheticDefaultImports) { // Need to leave the namespace import alone - changes.insertNodeAfter(sourceFile, importDecl, updateImport(importDecl, /*defaultImportName*/ undefined, importSpecifiers)); + changes.insertNodeAfter( + sourceFile, + importDecl, + updateImport(importDecl, /*defaultImportName*/ undefined, importSpecifiers), + ); } else { - changes.replaceNode(sourceFile, importDecl, updateImport(importDecl, usedAsNamespaceOrDefault ? factory.createIdentifier(toConvert.name.text) : undefined, importSpecifiers)); + changes.replaceNode( + sourceFile, + importDecl, + updateImport( + importDecl, + usedAsNamespaceOrDefault ? factory.createIdentifier(toConvert.name.text) : undefined, + importSpecifiers, + ), + ); } } - function getRightOfPropertyAccessOrQualifiedName(propertyAccessOrQualifiedName: PropertyAccessExpression | QualifiedName) { - return isPropertyAccessExpression(propertyAccessOrQualifiedName) ? propertyAccessOrQualifiedName.name : propertyAccessOrQualifiedName.right; + function getRightOfPropertyAccessOrQualifiedName( + propertyAccessOrQualifiedName: PropertyAccessExpression | QualifiedName, + ) { + return isPropertyAccessExpression(propertyAccessOrQualifiedName) ? propertyAccessOrQualifiedName.name + : propertyAccessOrQualifiedName.right; } - function getLeftOfPropertyAccessOrQualifiedName(propertyAccessOrQualifiedName: PropertyAccessExpression | QualifiedName) { - return isPropertyAccessExpression(propertyAccessOrQualifiedName) ? propertyAccessOrQualifiedName.expression : propertyAccessOrQualifiedName.left; + function getLeftOfPropertyAccessOrQualifiedName( + propertyAccessOrQualifiedName: PropertyAccessExpression | QualifiedName, + ) { + return isPropertyAccessExpression(propertyAccessOrQualifiedName) ? propertyAccessOrQualifiedName.expression + : propertyAccessOrQualifiedName.left; } - export function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, toConvert: NamedImports, shouldUseDefault = getShouldUseDefault(program, toConvert.parent)): void { + export function doChangeNamedToNamespaceOrDefault( + sourceFile: SourceFile, + program: Program, + changes: textChanges.ChangeTracker, + toConvert: NamedImports, + shouldUseDefault = getShouldUseDefault(program, toConvert.parent), + ): void { const checker = program.getTypeChecker(); const importDecl = toConvert.parent.parent; const { moduleSpecifier } = importDecl; @@ -168,7 +241,8 @@ namespace ts.refactor { toConvertSymbols.add(symbol); } }); - const preferredName = moduleSpecifier && isStringLiteral(moduleSpecifier) ? codefix.moduleSpecifierToValidIdentifier(moduleSpecifier.text, ScriptTarget.ESNext) : "module"; + const preferredName = moduleSpecifier && isStringLiteral(moduleSpecifier) + ? codefix.moduleSpecifierToValidIdentifier(moduleSpecifier.text, ScriptTarget.ESNext) : "module"; function hasNamespaceNameConflict(namedImport: ImportSpecifier): boolean { // We need to check if the preferred namespace name (`preferredName`) we'd like to use in the refactored code will present a name conflict. // A name conflict means that, in a scope where we would like to use the preferred namespace name, there already exists a symbol with that name in that scope. @@ -195,7 +269,10 @@ namespace ts.refactor { for (const element of toConvert.elements) { const propertyName = (element.propertyName || element.name).text; FindAllReferences.Core.eachSymbolReferenceInFile(element.name, checker, sourceFile, id => { - const access = factory.createPropertyAccessExpression(factory.createIdentifier(namespaceImportName), propertyName); + const access = factory.createPropertyAccessExpression( + factory.createIdentifier(namespaceImportName), + propertyName, + ); if (isShorthandPropertyAssignment(id.parent)) { changes.replaceNode(sourceFile, id.parent, factory.createPropertyAssignment(id.text, access)); } @@ -216,8 +293,18 @@ namespace ts.refactor { : factory.createNamespaceImport(factory.createIdentifier(namespaceImportName)), ); if (neededNamedImports.size) { - const newNamedImports: ImportSpecifier[] = arrayFrom(neededNamedImports.values()).map(element => factory.createImportSpecifier(element.isTypeOnly, element.propertyName && factory.createIdentifier(element.propertyName.text), factory.createIdentifier(element.name.text))); - changes.insertNodeAfter(sourceFile, toConvert.parent.parent, updateImport(importDecl, /*defaultImportName*/ undefined, newNamedImports)); + const newNamedImports: ImportSpecifier[] = arrayFrom(neededNamedImports.values()).map(element => + factory.createImportSpecifier( + element.isTypeOnly, + element.propertyName && factory.createIdentifier(element.propertyName.text), + factory.createIdentifier(element.name.text), + ) + ); + changes.insertNodeAfter( + sourceFile, + toConvert.parent.parent, + updateImport(importDecl, /*defaultImportName*/ undefined, newNamedImports), + ); } } @@ -228,7 +315,20 @@ namespace ts.refactor { return externalModule !== exportEquals; } - function updateImport(old: ImportDeclaration, defaultImportName: Identifier | undefined, elements: readonly ImportSpecifier[] | undefined): ImportDeclaration { - return factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, elements && elements.length ? factory.createNamedImports(elements) : undefined), old.moduleSpecifier, /*assertClause*/ undefined); + function updateImport( + old: ImportDeclaration, + defaultImportName: Identifier | undefined, + elements: readonly ImportSpecifier[] | undefined, + ): ImportDeclaration { + return factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause( + /*isTypeOnly*/ false, + defaultImportName, + elements && elements.length ? factory.createNamedImports(elements) : undefined, + ), + old.moduleSpecifier, + /*assertClause*/ undefined, + ); } } diff --git a/src/services/refactors/convertOverloadListToSingleSignature.ts b/src/services/refactors/convertOverloadListToSingleSignature.ts index 7f895d19eb9dc..50d9422d8d3d4 100644 --- a/src/services/refactors/convertOverloadListToSingleSignature.ts +++ b/src/services/refactors/convertOverloadListToSingleSignature.ts @@ -14,7 +14,9 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { getAvailableActions: getRefactorActionsToConvertOverloadsToOneSignature, }); - function getRefactorActionsToConvertOverloadsToOneSignature(context: RefactorContext): readonly ApplicableRefactorInfo[] { + function getRefactorActionsToConvertOverloadsToOneSignature( + context: RefactorContext, + ): readonly ApplicableRefactorInfo[] { const { file, startPosition, program } = context; const info = getConvertableOverloadListAtPosition(file, startPosition, program); if (!info) return emptyArray; @@ -103,7 +105,10 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { break; } default: - return Debug.failBadSyntaxKind(lastDeclaration, "Unhandled signature kind in overload list conversion refactoring"); + return Debug.failBadSyntaxKind( + lastDeclaration, + "Unhandled signature kind in overload list conversion refactoring", + ); } if (updated === lastDeclaration) { @@ -116,7 +121,16 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { return { renameFilename: undefined, renameLocation: undefined, edits }; - function getNewParametersForCombinedSignature(signatureDeclarations: (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[]): NodeArray { + function getNewParametersForCombinedSignature( + signatureDeclarations: ( + | MethodSignature + | MethodDeclaration + | CallSignatureDeclaration + | ConstructorDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration + )[], + ): NodeArray { const lastSig = signatureDeclarations[signatureDeclarations.length - 1]; if (isFunctionLikeDeclaration(lastSig) && lastSig.body) { // Trim away implementation signature arguments (they should already be compatible with overloads, but are likely less precise to guarantee compatability with the overloads) @@ -133,9 +147,20 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { ]); } - function convertSignatureParametersToTuple(decl: MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration): TupleTypeNode { + function convertSignatureParametersToTuple( + decl: + | MethodSignature + | MethodDeclaration + | CallSignatureDeclaration + | ConstructorDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration, + ): TupleTypeNode { const members = map(decl.parameters, convertParameterToNamedTupleMember); - return setEmitFlags(factory.createTupleTypeNode(members), some(members, m => !!length(getSyntheticLeadingComments(m))) ? EmitFlags.None : EmitFlags.SingleLine); + return setEmitFlags( + factory.createTupleTypeNode(members), + some(members, m => !!length(getSyntheticLeadingComments(m))) ? EmitFlags.None : EmitFlags.SingleLine, + ); } function convertParameterToNamedTupleMember(p: ParameterDeclaration): NamedTupleMember { @@ -169,7 +194,16 @@ ${newComment.split("\n").map(c => ` * ${c}`).join("\n")} } } - function isConvertableSignatureDeclaration(d: Node): d is MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration { + function isConvertableSignatureDeclaration( + d: Node, + ): d is + | MethodSignature + | MethodDeclaration + | CallSignatureDeclaration + | ConstructorDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration + { switch (d.kind) { case SyntaxKind.MethodSignature: case SyntaxKind.MethodDeclaration: @@ -188,7 +222,10 @@ ${newComment.split("\n").map(c => ` * ${c}`).join("\n")} if (!containingDecl) { return; } - if (isFunctionLikeDeclaration(containingDecl) && containingDecl.body && rangeContainsPosition(containingDecl.body, startPosition)) { + if ( + isFunctionLikeDeclaration(containingDecl) && containingDecl.body + && rangeContainsPosition(containingDecl.body, startPosition) + ) { return; } @@ -211,8 +248,20 @@ ${newComment.split("\n").map(c => ` * ${c}`).join("\n")} if (!every(decls, d => d.kind === kindOne)) { return; } - const signatureDecls = decls as (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[]; - if (some(signatureDecls, d => !!d.typeParameters || some(d.parameters, p => !!p.modifiers || !isIdentifier(p.name)))) { + const signatureDecls = decls as ( + | MethodSignature + | MethodDeclaration + | CallSignatureDeclaration + | ConstructorDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration + )[]; + if ( + some( + signatureDecls, + d => !!d.typeParameters || some(d.parameters, p => !!p.modifiers || !isIdentifier(p.name)), + ) + ) { return; } const signatures = mapDefined(signatureDecls, d => checker.getSignatureFromDeclaration(d)); diff --git a/src/services/refactors/convertParamsToDestructuredObject.ts b/src/services/refactors/convertParamsToDestructuredObject.ts index 3eb03223630f2..d0b6f5d093df0 100644 --- a/src/services/refactors/convertParamsToDestructuredObject.ts +++ b/src/services/refactors/convertParamsToDestructuredObject.ts @@ -15,11 +15,17 @@ namespace ts.refactor.convertParamsToDestructuredObject { getAvailableActions: getRefactorActionsToConvertParametersToDestructuredObject, }); - function getRefactorActionsToConvertParametersToDestructuredObject(context: RefactorContext): readonly ApplicableRefactorInfo[] { + function getRefactorActionsToConvertParametersToDestructuredObject( + context: RefactorContext, + ): readonly ApplicableRefactorInfo[] { const { file, startPosition } = context; const isJSFile = isSourceFileJS(file); if (isJSFile) return emptyArray; // TODO: GH#30113 - const functionDeclaration = getFunctionDeclarationAtPosition(file, startPosition, context.program.getTypeChecker()); + const functionDeclaration = getFunctionDeclarationAtPosition( + file, + startPosition, + context.program.getTypeChecker(), + ); if (!functionDeclaration) return emptyArray; return [{ @@ -29,7 +35,10 @@ namespace ts.refactor.convertParamsToDestructuredObject { }]; } - function getRefactorEditsToConvertParametersToDestructuredObject(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { + function getRefactorEditsToConvertParametersToDestructuredObject( + context: RefactorContext, + actionName: string, + ): RefactorEditInfo | undefined { Debug.assert(actionName === refactorName, "Unexpected action name"); const { file, startPosition, program, cancellationToken, host } = context; const functionDeclaration = getFunctionDeclarationAtPosition(file, startPosition, program.getTypeChecker()); @@ -37,7 +46,10 @@ namespace ts.refactor.convertParamsToDestructuredObject { const groupedReferences = getGroupedReferences(functionDeclaration, program, cancellationToken); if (groupedReferences.valid) { - const edits = textChanges.ChangeTracker.with(context, t => doChange(file, program, host, t, functionDeclaration, groupedReferences)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(file, program, host, t, functionDeclaration, groupedReferences), + ); return { renameFilename: undefined, renameLocation: undefined, edits }; } @@ -53,29 +65,47 @@ namespace ts.refactor.convertParamsToDestructuredObject { groupedReferences: GroupedReferences, ): void { const signature = groupedReferences.signature; - const newFunctionDeclarationParams = map(createNewParameters(functionDeclaration, program, host), param => getSynthesizedDeepClone(param)); + const newFunctionDeclarationParams = map( + createNewParameters(functionDeclaration, program, host), + param => getSynthesizedDeepClone(param), + ); if (signature) { - const newSignatureParams = map(createNewParameters(signature, program, host), param => getSynthesizedDeepClone(param)); + const newSignatureParams = map( + createNewParameters(signature, program, host), + param => getSynthesizedDeepClone(param), + ); replaceParameters(signature, newSignatureParams); } replaceParameters(functionDeclaration, newFunctionDeclarationParams); - const functionCalls = sortAndDeduplicate(groupedReferences.functionCalls, /*comparer*/ (a, b) => compareValues(a.pos, b.pos)); + const functionCalls = sortAndDeduplicate( + groupedReferences.functionCalls, + /*comparer*/ (a, b) => compareValues(a.pos, b.pos), + ); for (const call of functionCalls) { if (call.arguments && call.arguments.length) { - const newArgument = getSynthesizedDeepClone(createNewArgument(functionDeclaration, call.arguments), /*includeTrivia*/ true); + const newArgument = getSynthesizedDeepClone( + createNewArgument(functionDeclaration, call.arguments), + /*includeTrivia*/ true, + ); changes.replaceNodeRange( getSourceFileOfNode(call), first(call.arguments), last(call.arguments), newArgument, - { leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, trailingTriviaOption: textChanges.TrailingTriviaOption.Include }, + { + leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, + trailingTriviaOption: textChanges.TrailingTriviaOption.Include, + }, ); } } - function replaceParameters(declarationOrSignature: ValidFunctionDeclaration | ValidMethodSignature, parameterDeclarations: ParameterDeclaration[]) { + function replaceParameters( + declarationOrSignature: ValidFunctionDeclaration | ValidMethodSignature, + parameterDeclarations: ParameterDeclaration[], + ) { changes.replaceNodeRangeWithNodes( sourceFile, first(declarationOrSignature.parameters), @@ -92,13 +122,27 @@ namespace ts.refactor.convertParamsToDestructuredObject { } } - function getGroupedReferences(functionDeclaration: ValidFunctionDeclaration, program: Program, cancellationToken: CancellationToken): GroupedReferences { + function getGroupedReferences( + functionDeclaration: ValidFunctionDeclaration, + program: Program, + cancellationToken: CancellationToken, + ): GroupedReferences { const functionNames = getFunctionNames(functionDeclaration); const classNames = isConstructorDeclaration(functionDeclaration) ? getClassNames(functionDeclaration) : []; const names = deduplicate([...functionNames, ...classNames], equateValues); const checker = program.getTypeChecker(); - const references = flatMap(names, /*mapfn*/ name => FindAllReferences.getReferenceEntriesForNode(-1, name, program, program.getSourceFiles(), cancellationToken)); + const references = flatMap( + names, + /*mapfn*/ name => + FindAllReferences.getReferenceEntriesForNode( + -1, + name, + program, + program.getSourceFiles(), + cancellationToken, + ), + ); const groupedReferences = groupReferences(references); if (!every(groupedReferences.declarations, /*callback*/ decl => contains(names, decl))) { @@ -109,7 +153,12 @@ namespace ts.refactor.convertParamsToDestructuredObject { function groupReferences(referenceEntries: readonly FindAllReferences.Entry[]): GroupedReferences { const classReferences: ClassReferences = { accessExpressions: [], typeUsages: [] }; - const groupedReferences: GroupedReferences = { functionCalls: [], declarations: [], classReferences, valid: true }; + const groupedReferences: GroupedReferences = { + functionCalls: [], + declarations: [], + classReferences, + valid: true, + }; const functionSymbols = map(functionNames, getSymbolTargetAtLocation); const classSymbols = map(classNames, getSymbolTargetAtLocation); const isConstructor = isConstructorDeclaration(functionDeclaration); @@ -159,7 +208,10 @@ namespace ts.refactor.convertParamsToDestructuredObject { So we need to add a special case for this because when calling a constructor of a class through one of its subclasses, the symbols are going to be different. */ - if (contains(functionSymbols, getSymbolTargetAtLocation(entry.node)) || isNewExpressionTarget(entry.node)) { + if ( + contains(functionSymbols, getSymbolTargetAtLocation(entry.node)) + || isNewExpressionTarget(entry.node) + ) { const importOrExportReference = entryToImportOrExport(entry); if (importOrExportReference) { continue; @@ -223,7 +275,9 @@ namespace ts.refactor.convertParamsToDestructuredObject { function getSymbolForContextualType(node: Node, checker: TypeChecker): Symbol | undefined { const element = getContainingObjectLiteralElement(node); if (element) { - const contextualType = checker.getContextualTypeForObjectLiteralElement(element as ObjectLiteralElementLike); + const contextualType = checker.getContextualTypeForObjectLiteralElement( + element as ObjectLiteralElementLike, + ); const symbol = contextualType?.getSymbol(); if (symbol && !(getCheckFlags(symbol) & CheckFlags.Synthetic)) { return symbol; @@ -272,7 +326,10 @@ namespace ts.refactor.convertParamsToDestructuredObject { // x.foo(...) case SyntaxKind.PropertyAccessExpression: const propertyAccessExpression = tryCast(parent, isPropertyAccessExpression); - if (propertyAccessExpression && propertyAccessExpression.parent && propertyAccessExpression.name === functionReference) { + if ( + propertyAccessExpression && propertyAccessExpression.parent + && propertyAccessExpression.name === functionReference + ) { const callOrNewExpression = tryCast(propertyAccessExpression.parent, isCallOrNewExpression); if (callOrNewExpression && callOrNewExpression.expression === propertyAccessExpression) { return callOrNewExpression; @@ -282,7 +339,10 @@ namespace ts.refactor.convertParamsToDestructuredObject { // x["foo"](...) case SyntaxKind.ElementAccessExpression: const elementAccessExpression = tryCast(parent, isElementAccessExpression); - if (elementAccessExpression && elementAccessExpression.parent && elementAccessExpression.argumentExpression === functionReference) { + if ( + elementAccessExpression && elementAccessExpression.parent + && elementAccessExpression.argumentExpression === functionReference + ) { const callOrNewExpression = tryCast(elementAccessExpression.parent, isCallOrNewExpression); if (callOrNewExpression && callOrNewExpression.expression === elementAccessExpression) { return callOrNewExpression; @@ -294,7 +354,9 @@ namespace ts.refactor.convertParamsToDestructuredObject { return undefined; } - function entryToAccessExpression(entry: FindAllReferences.NodeEntry): ElementAccessExpression | PropertyAccessExpression | undefined { + function entryToAccessExpression( + entry: FindAllReferences.NodeEntry, + ): ElementAccessExpression | PropertyAccessExpression | undefined { if (entry.node.parent) { const reference = entry.node; const parent = reference.parent; @@ -320,13 +382,20 @@ namespace ts.refactor.convertParamsToDestructuredObject { function entryToType(entry: FindAllReferences.NodeEntry): Node | undefined { const reference = entry.node; - if (getMeaningFromLocation(reference) === SemanticMeaning.Type || isExpressionWithTypeArgumentsInClassExtendsClause(reference.parent)) { + if ( + getMeaningFromLocation(reference) === SemanticMeaning.Type + || isExpressionWithTypeArgumentsInClassExtendsClause(reference.parent) + ) { return reference; } return undefined; } - function getFunctionDeclarationAtPosition(file: SourceFile, startPosition: number, checker: TypeChecker): ValidFunctionDeclaration | undefined { + function getFunctionDeclarationAtPosition( + file: SourceFile, + startPosition: number, + checker: TypeChecker, + ): ValidFunctionDeclaration | undefined { const node = getTouchingToken(file, startPosition); const functionDeclaration = getContainingFunctionDeclaration(node); @@ -368,12 +437,14 @@ namespace ts.refactor.convertParamsToDestructuredObject { if (isObjectLiteralExpression(functionDeclaration.parent)) { const contextualSymbol = getSymbolForContextualType(functionDeclaration.name, checker); // don't offer the refactor when there are multiple signatures since we won't know which ones the user wants to change - return contextualSymbol?.declarations?.length === 1 && isSingleImplementation(functionDeclaration, checker); + return contextualSymbol?.declarations?.length === 1 + && isSingleImplementation(functionDeclaration, checker); } return isSingleImplementation(functionDeclaration, checker); case SyntaxKind.Constructor: if (isClassDeclaration(functionDeclaration.parent)) { - return hasNameOrDefault(functionDeclaration.parent) && isSingleImplementation(functionDeclaration, checker); + return hasNameOrDefault(functionDeclaration.parent) + && isSingleImplementation(functionDeclaration, checker); } else { return isValidVariableDeclaration(functionDeclaration.parent.parent) @@ -432,24 +503,33 @@ namespace ts.refactor.convertParamsToDestructuredObject { return parameters.length; } - function getRefactorableParameters(parameters: NodeArray): NodeArray { + function getRefactorableParameters( + parameters: NodeArray, + ): NodeArray { if (hasThisParameter(parameters)) { parameters = factory.createNodeArray(parameters.slice(1), parameters.hasTrailingComma); } return parameters; } - function createPropertyOrShorthandAssignment(name: string, initializer: Expression): PropertyAssignment | ShorthandPropertyAssignment { + function createPropertyOrShorthandAssignment( + name: string, + initializer: Expression, + ): PropertyAssignment | ShorthandPropertyAssignment { if (isIdentifier(initializer) && getTextOfIdentifierOrLiteral(initializer) === name) { return factory.createShorthandPropertyAssignment(name); } return factory.createPropertyAssignment(name, initializer); } - function createNewArgument(functionDeclaration: ValidFunctionDeclaration, functionArguments: NodeArray): ObjectLiteralExpression { + function createNewArgument( + functionDeclaration: ValidFunctionDeclaration, + functionArguments: NodeArray, + ): ObjectLiteralExpression { const parameters = getRefactorableParameters(functionDeclaration.parameters); const hasRestParameter = isRestParameter(last(parameters)); - const nonRestArguments = hasRestParameter ? functionArguments.slice(0, parameters.length - 1) : functionArguments; + const nonRestArguments = hasRestParameter ? functionArguments.slice(0, parameters.length - 1) + : functionArguments; const properties = map(nonRestArguments, (arg, i) => { const parameterName = getParameterName(parameters[i]); const property = createPropertyOrShorthandAssignment(parameterName, arg); @@ -462,7 +542,10 @@ namespace ts.refactor.convertParamsToDestructuredObject { if (hasRestParameter && functionArguments.length >= parameters.length) { const restArguments = functionArguments.slice(parameters.length - 1); - const restProperty = factory.createPropertyAssignment(getParameterName(last(parameters)), factory.createArrayLiteralExpression(restArguments)); + const restProperty = factory.createPropertyAssignment( + getParameterName(last(parameters)), + factory.createArrayLiteralExpression(restArguments), + ); properties.push(restProperty); } @@ -470,7 +553,11 @@ namespace ts.refactor.convertParamsToDestructuredObject { return objectLiteral; } - function createNewParameters(functionDeclaration: ValidFunctionDeclaration | ValidMethodSignature, program: Program, host: LanguageServiceHost): NodeArray { + function createNewParameters( + functionDeclaration: ValidFunctionDeclaration | ValidMethodSignature, + program: Program, + host: LanguageServiceHost, + ): NodeArray { const checker = program.getTypeChecker(); const refactorableParameters = getRefactorableParameters(functionDeclaration.parameters); const bindingElements = map(refactorableParameters, createBindingElementFromParameterDeclaration); @@ -513,12 +600,15 @@ namespace ts.refactor.convertParamsToDestructuredObject { } return factory.createNodeArray([objectParameter]); - function createBindingElementFromParameterDeclaration(parameterDeclaration: ValidParameterDeclaration): BindingElement { + function createBindingElementFromParameterDeclaration( + parameterDeclaration: ValidParameterDeclaration, + ): BindingElement { const element = factory.createBindingElement( /*dotDotDotToken*/ undefined, /*propertyName*/ undefined, getParameterName(parameterDeclaration), - isRestParameter(parameterDeclaration) && isOptionalParameter(parameterDeclaration) ? factory.createArrayLiteralExpression() : parameterDeclaration.initializer, + isRestParameter(parameterDeclaration) && isOptionalParameter(parameterDeclaration) + ? factory.createArrayLiteralExpression() : parameterDeclaration.initializer, ); suppressLeadingAndTrailingTrivia(element); @@ -534,7 +624,9 @@ namespace ts.refactor.convertParamsToDestructuredObject { return typeNode; } - function createPropertySignatureFromParameterDeclaration(parameterDeclaration: ValidParameterDeclaration): PropertySignature { + function createPropertySignatureFromParameterDeclaration( + parameterDeclaration: ValidParameterDeclaration, + ): PropertySignature { let parameterType = parameterDeclaration.type; if (!parameterType && (parameterDeclaration.initializer || isRestParameter(parameterDeclaration))) { parameterType = getTypeNode(parameterDeclaration); @@ -543,7 +635,8 @@ namespace ts.refactor.convertParamsToDestructuredObject { const propertySignature = factory.createPropertySignature( /*modifiers*/ undefined, getParameterName(parameterDeclaration), - isOptionalParameter(parameterDeclaration) ? factory.createToken(SyntaxKind.QuestionToken) : parameterDeclaration.questionToken, + isOptionalParameter(parameterDeclaration) ? factory.createToken(SyntaxKind.QuestionToken) + : parameterDeclaration.questionToken, parameterType, ); @@ -610,7 +703,11 @@ namespace ts.refactor.convertParamsToDestructuredObject { return [functionDeclaration.name]; case SyntaxKind.Constructor: const ctrKeyword = Debug.checkDefined( - findChildOfKind(functionDeclaration, SyntaxKind.ConstructorKeyword, functionDeclaration.getSourceFile()), + findChildOfKind( + functionDeclaration, + SyntaxKind.ConstructorKeyword, + functionDeclaration.getSourceFile(), + ), "Constructor declaration should have constructor keyword", ); if (functionDeclaration.parent.kind === SyntaxKind.ClassExpression) { @@ -624,7 +721,10 @@ namespace ts.refactor.convertParamsToDestructuredObject { if (functionDeclaration.name) return [functionDeclaration.name, functionDeclaration.parent.name]; return [functionDeclaration.parent.name]; default: - return Debug.assertNever(functionDeclaration, `Unexpected function declaration kind ${(functionDeclaration as ValidFunctionDeclaration).kind}`); + return Debug.assertNever( + functionDeclaration, + `Unexpected function declaration kind ${(functionDeclaration as ValidFunctionDeclaration).kind}`, + ); } } @@ -665,7 +765,12 @@ namespace ts.refactor.convertParamsToDestructuredObject { parameters: NodeArray; } - type ValidFunctionDeclaration = ValidConstructor | ValidFunction | ValidMethod | ValidArrowFunction | ValidFunctionExpression; + type ValidFunctionDeclaration = + | ValidConstructor + | ValidFunction + | ValidMethod + | ValidArrowFunction + | ValidFunctionExpression; interface ValidParameterDeclaration extends ParameterDeclaration { name: Identifier; diff --git a/src/services/refactors/convertStringOrTemplateLiteral.ts b/src/services/refactors/convertStringOrTemplateLiteral.ts index 094c67e4121d1..db890fb9ebbed 100644 --- a/src/services/refactors/convertStringOrTemplateLiteral.ts +++ b/src/services/refactors/convertStringOrTemplateLiteral.ts @@ -18,14 +18,21 @@ namespace ts.refactor.convertStringOrTemplateLiteral { const { file, startPosition } = context; const node = getNodeOrParentOfParentheses(file, startPosition); const maybeBinary = getParentBinaryExpression(node); - const refactorInfo: ApplicableRefactorInfo = { name: refactorName, description: refactorDescription, actions: [] }; + const refactorInfo: ApplicableRefactorInfo = { + name: refactorName, + description: refactorDescription, + actions: [], + }; if (isBinaryExpression(maybeBinary) && treeToArray(maybeBinary).isValidConcatenation) { refactorInfo.actions.push(convertStringAction); return [refactorInfo]; } else if (context.preferences.provideRefactorNotApplicableReason) { - refactorInfo.actions.push({ ...convertStringAction, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Can_only_convert_string_concatenation) }); + refactorInfo.actions.push({ + ...convertStringAction, + notApplicableReason: getLocaleSpecificMessage(Diagnostics.Can_only_convert_string_concatenation), + }); return [refactorInfo]; } return emptyArray; @@ -37,16 +44,19 @@ namespace ts.refactor.convertStringOrTemplateLiteral { const isNonStringBinary = !treeToArray(nestedBinary).isValidConcatenation; if ( - isNonStringBinary && - isParenthesizedExpression(nestedBinary.parent) && - isBinaryExpression(nestedBinary.parent.parent) + isNonStringBinary + && isParenthesizedExpression(nestedBinary.parent) + && isBinaryExpression(nestedBinary.parent.parent) ) { return nestedBinary.parent.parent; } return node; } - function getRefactorEditsToConvertToTemplateString(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { + function getRefactorEditsToConvertToTemplateString( + context: RefactorContext, + actionName: string, + ): RefactorEditInfo | undefined { const { file, startPosition } = context; const node = getNodeOrParentOfParentheses(file, startPosition); @@ -103,11 +113,25 @@ namespace ts.refactor.convertStringOrTemplateLiteral { } function treeToArray(current: Expression) { - const loop = (current: Node): { nodes: Expression[]; operators: Token[]; hasString: boolean; validOperators: boolean; } => { + const loop = ( + current: Node, + ): { + nodes: Expression[]; + operators: Token[]; + hasString: boolean; + validOperators: boolean; + } => { if (!isBinaryExpression(current)) { - return { nodes: [current as Expression], operators: [], validOperators: true, hasString: isStringLiteral(current) || isNoSubstitutionTemplateLiteral(current) }; + return { + nodes: [current as Expression], + operators: [], + validOperators: true, + hasString: isStringLiteral(current) || isNoSubstitutionTemplateLiteral(current), + }; } - const { nodes, operators, hasString: leftHasString, validOperators: leftOperatorValid } = loop(current.left); + const { nodes, operators, hasString: leftHasString, validOperators: leftOperatorValid } = loop( + current.left, + ); if (!(leftHasString || isStringLiteral(current.right) || isTemplateExpression(current.right))) { return { nodes: [current], operators: [], hasString: false, validOperators: true }; @@ -127,18 +151,36 @@ namespace ts.refactor.convertStringOrTemplateLiteral { // to copy comments following the operator // "foo" + /* comment */ "bar" - const copyTrailingOperatorComments = (operators: Token[], file: SourceFile) => (index: number, targetNode: Node) => { - if (index < operators.length) { - copyTrailingComments(operators[index], targetNode, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); - } - }; + const copyTrailingOperatorComments = + (operators: Token[], file: SourceFile) => (index: number, targetNode: Node) => { + if (index < operators.length) { + copyTrailingComments( + operators[index], + targetNode, + file, + SyntaxKind.MultiLineCommentTrivia, + /* hasTrailingNewLine */ false, + ); + } + }; // to copy comments following the string // "foo" /* comment */ + "bar" /* comment */ + "bar2" - const copyCommentFromMultiNode = (nodes: readonly Expression[], file: SourceFile, copyOperatorComments: (index: number, targetNode: Node) => void) => (indexes: number[], targetNode: Node) => { + const copyCommentFromMultiNode = ( + nodes: readonly Expression[], + file: SourceFile, + copyOperatorComments: (index: number, targetNode: Node) => void, + ) => + (indexes: number[], targetNode: Node) => { while (indexes.length > 0) { const index = indexes.shift()!; - copyTrailingComments(nodes[index], targetNode, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); + copyTrailingComments( + nodes[index], + targetNode, + file, + SyntaxKind.MultiLineCommentTrivia, + /* hasTrailingNewLine */ false, + ); copyOperatorComments(index, targetNode); } }; @@ -159,7 +201,10 @@ namespace ts.refactor.convertStringOrTemplateLiteral { return getTextOfNode(node).slice(1, rightShaving); } - function concatConsecutiveString(index: number, nodes: readonly Expression[]): [nextIndex: number, text: string, rawText: string, usedIndexes: number[]] { + function concatConsecutiveString( + index: number, + nodes: readonly Expression[], + ): [nextIndex: number, text: string, rawText: string, usedIndexes: number[]] { const indexes = []; let text = "", rawText = ""; while (index < nodes.length) { @@ -182,7 +227,10 @@ namespace ts.refactor.convertStringOrTemplateLiteral { return [index, text, rawText, indexes]; } - function nodesToTemplate({ nodes, operators }: { nodes: readonly Expression[]; operators: Token[]; }, file: SourceFile) { + function nodesToTemplate( + { nodes, operators }: { nodes: readonly Expression[]; operators: Token[]; }, + file: SourceFile, + ) { const copyOperatorComments = copyTrailingOperatorComments(operators, file); const copyCommentFromStringLiterals = copyCommentFromMultiNode(nodes, file, copyOperatorComments); const [begin, headText, rawHeadText, headIndexes] = concatConsecutiveString(0, nodes); @@ -236,8 +284,20 @@ namespace ts.refactor.convertStringOrTemplateLiteral { // "foo" + ( /* comment */ 5 + 5 ) /* comment */ + "bar" function copyExpressionComments(node: ParenthesizedExpression | TemplateSpan) { const file = node.getSourceFile(); - copyTrailingComments(node, node.expression, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); - copyTrailingAsLeadingComments(node.expression, node.expression, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); + copyTrailingComments( + node, + node.expression, + file, + SyntaxKind.MultiLineCommentTrivia, + /* hasTrailingNewLine */ false, + ); + copyTrailingAsLeadingComments( + node.expression, + node.expression, + file, + SyntaxKind.MultiLineCommentTrivia, + /* hasTrailingNewLine */ false, + ); } function getExpressionFromParenthesesOrExpression(node: Expression) { diff --git a/src/services/refactors/convertToOptionalChainExpression.ts b/src/services/refactors/convertToOptionalChainExpression.ts index 2f5aaa11a5772..13092c6766b99 100644 --- a/src/services/refactors/convertToOptionalChainExpression.ts +++ b/src/services/refactors/convertToOptionalChainExpression.ts @@ -1,7 +1,9 @@ /* @internal */ namespace ts.refactor.convertToOptionalChainExpression { const refactorName = "Convert to optional chain expression"; - const convertToOptionalChainExpressionMessage = getLocaleSpecificMessage(Diagnostics.Convert_to_optional_chain_expression); + const convertToOptionalChainExpressionMessage = getLocaleSpecificMessage( + Diagnostics.Convert_to_optional_chain_expression, + ); const toOptionalChainAction = { name: refactorName, @@ -36,10 +38,16 @@ namespace ts.refactor.convertToOptionalChainExpression { return emptyArray; } - function getRefactorEditsToConvertToOptionalChain(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { + function getRefactorEditsToConvertToOptionalChain( + context: RefactorContext, + actionName: string, + ): RefactorEditInfo | undefined { const info = getInfo(context); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program.getTypeChecker(), t, info, actionName)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(context.file, context.program.getTypeChecker(), t, info, actionName), + ); return { edits, renameFilename: undefined, renameLocation: undefined }; } @@ -75,7 +83,10 @@ namespace ts.refactor.convertToOptionalChainExpression { return isValidExpression(node) || isValidStatement(node); } - function getInfo(context: RefactorContext, considerEmptySpans = true): OptionalChainInfo | RefactorErrorInfo | undefined { + function getInfo( + context: RefactorContext, + considerEmptySpans = true, + ): OptionalChainInfo | RefactorErrorInfo | undefined { const { file, program } = context; const span = getRefactorContextSpan(context); @@ -85,17 +96,27 @@ namespace ts.refactor.convertToOptionalChainExpression { // selecting fo[|o && foo.ba|]r should be valid, so adjust span to fit start and end tokens const startToken = getTokenAtPosition(file, span.start); const endToken = findTokenOnLeftOfPosition(file, span.start + span.length); - const adjustedSpan = createTextSpanFromBounds(startToken.pos, endToken && endToken.end >= startToken.pos ? endToken.getEnd() : startToken.getEnd()); + const adjustedSpan = createTextSpanFromBounds( + startToken.pos, + endToken && endToken.end >= startToken.pos ? endToken.getEnd() : startToken.getEnd(), + ); - const parent = forEmptySpan ? getValidParentNodeOfEmptySpan(startToken) : getValidParentNodeContainingSpan(startToken, adjustedSpan); + const parent = forEmptySpan ? getValidParentNodeOfEmptySpan(startToken) + : getValidParentNodeContainingSpan(startToken, adjustedSpan); const expression = parent && isValidExpressionOrStatement(parent) ? getExpression(parent) : undefined; - if (!expression) return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; + if (!expression) { + return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; + } const checker = program.getTypeChecker(); - return isConditionalExpression(expression) ? getConditionalInfo(expression, checker) : getBinaryInfo(expression); + return isConditionalExpression(expression) ? getConditionalInfo(expression, checker) + : getBinaryInfo(expression); } - function getConditionalInfo(expression: ConditionalExpression, checker: TypeChecker): OptionalChainInfo | RefactorErrorInfo | undefined { + function getConditionalInfo( + expression: ConditionalExpression, + checker: TypeChecker, + ): OptionalChainInfo | RefactorErrorInfo | undefined { const condition = expression.condition; const finalExpression = getFinalExpressionInChain(expression.whenTrue); @@ -111,8 +132,8 @@ namespace ts.refactor.convertToOptionalChainExpression { } else if (isBinaryExpression(condition)) { const occurrences = getOccurrencesInExpression(finalExpression.expression, condition); - return occurrences ? { finalExpression, occurrences, expression } : - { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) }; + return occurrences ? { finalExpression, occurrences, expression } + : { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) }; } } @@ -122,11 +143,13 @@ namespace ts.refactor.convertToOptionalChainExpression { } const finalExpression = getFinalExpressionInChain(expression.right); - if (!finalExpression) return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; + if (!finalExpression) { + return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; + } const occurrences = getOccurrencesInExpression(finalExpression.expression, expression.left); - return occurrences ? { finalExpression, occurrences, expression } : - { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) }; + return occurrences ? { finalExpression, occurrences, expression } + : { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) }; } /** @@ -153,7 +176,10 @@ namespace ts.refactor.convertToOptionalChainExpression { /** * Returns subchain if chain begins with subchain syntactically. */ - function getMatchingStart(chain: Expression, subchain: Expression): PropertyAccessExpression | ElementAccessExpression | Identifier | undefined { + function getMatchingStart( + chain: Expression, + subchain: Expression, + ): PropertyAccessExpression | ElementAccessExpression | Identifier | undefined { if (!isIdentifier(subchain) && !isPropertyAccessExpression(subchain) && !isElementAccessExpression(subchain)) { return undefined; } @@ -171,8 +197,8 @@ namespace ts.refactor.convertToOptionalChainExpression { } // check that the chains match at each access. Call chains in subchain are not valid. while ( - (isPropertyAccessExpression(chain) && isPropertyAccessExpression(subchain)) || - (isElementAccessExpression(chain) && isElementAccessExpression(subchain)) + (isPropertyAccessExpression(chain) && isPropertyAccessExpression(subchain)) + || (isElementAccessExpression(chain) && isElementAccessExpression(subchain)) ) { if (getTextOfChainNode(chain) !== getTextOfChainNode(subchain)) return false; chain = chain.expression; @@ -242,7 +268,9 @@ namespace ts.refactor.convertToOptionalChainExpression { * it is followed by a different binary operator. * @param node the right child of a binary expression or a call expression. */ - function getFinalExpressionInChain(node: Expression): CallExpression | PropertyAccessExpression | ElementAccessExpression | undefined { + function getFinalExpressionInChain( + node: Expression, + ): CallExpression | PropertyAccessExpression | ElementAccessExpression | undefined { // foo && |foo.bar === 1|; - here the right child of the && binary expression is another binary expression. // the rightmost member of the && chain should be the leftmost child of that expression. node = skipParentheses(node); @@ -250,7 +278,10 @@ namespace ts.refactor.convertToOptionalChainExpression { return getFinalExpressionInChain(node.left); } // foo && |foo.bar()()| - nested calls are treated like further accesses. - else if ((isPropertyAccessExpression(node) || isElementAccessExpression(node) || isCallExpression(node)) && !isOptionalChain(node)) { + else if ( + (isPropertyAccessExpression(node) || isElementAccessExpression(node) || isCallExpression(node)) + && !isOptionalChain(node) + ) { return node; } return undefined; @@ -260,40 +291,78 @@ namespace ts.refactor.convertToOptionalChainExpression { * Creates an access chain from toConvert with '?.' accesses at expressions appearing in occurrences. */ function convertOccurrences(checker: TypeChecker, toConvert: Expression, occurrences: Occurrence[]): Expression { - if (isPropertyAccessExpression(toConvert) || isElementAccessExpression(toConvert) || isCallExpression(toConvert)) { + if ( + isPropertyAccessExpression(toConvert) || isElementAccessExpression(toConvert) || isCallExpression(toConvert) + ) { const chain = convertOccurrences(checker, toConvert.expression, occurrences); const lastOccurrence = occurrences.length > 0 ? occurrences[occurrences.length - 1] : undefined; const isOccurrence = lastOccurrence?.getText() === toConvert.expression.getText(); if (isOccurrence) occurrences.pop(); if (isCallExpression(toConvert)) { - return isOccurrence ? - factory.createCallChain(chain, factory.createToken(SyntaxKind.QuestionDotToken), toConvert.typeArguments, toConvert.arguments) : - factory.createCallChain(chain, toConvert.questionDotToken, toConvert.typeArguments, toConvert.arguments); + return isOccurrence + ? factory.createCallChain( + chain, + factory.createToken(SyntaxKind.QuestionDotToken), + toConvert.typeArguments, + toConvert.arguments, + ) + : factory.createCallChain( + chain, + toConvert.questionDotToken, + toConvert.typeArguments, + toConvert.arguments, + ); } else if (isPropertyAccessExpression(toConvert)) { - return isOccurrence ? - factory.createPropertyAccessChain(chain, factory.createToken(SyntaxKind.QuestionDotToken), toConvert.name) : - factory.createPropertyAccessChain(chain, toConvert.questionDotToken, toConvert.name); + return isOccurrence + ? factory.createPropertyAccessChain( + chain, + factory.createToken(SyntaxKind.QuestionDotToken), + toConvert.name, + ) + : factory.createPropertyAccessChain(chain, toConvert.questionDotToken, toConvert.name); } else if (isElementAccessExpression(toConvert)) { - return isOccurrence ? - factory.createElementAccessChain(chain, factory.createToken(SyntaxKind.QuestionDotToken), toConvert.argumentExpression) : - factory.createElementAccessChain(chain, toConvert.questionDotToken, toConvert.argumentExpression); + return isOccurrence + ? factory.createElementAccessChain( + chain, + factory.createToken(SyntaxKind.QuestionDotToken), + toConvert.argumentExpression, + ) + : factory.createElementAccessChain(chain, toConvert.questionDotToken, toConvert.argumentExpression); } } return toConvert; } - function doChange(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, info: OptionalChainInfo, _actionName: string): void { + function doChange( + sourceFile: SourceFile, + checker: TypeChecker, + changes: textChanges.ChangeTracker, + info: OptionalChainInfo, + _actionName: string, + ): void { const { finalExpression, occurrences, expression } = info; const firstOccurrence = occurrences[occurrences.length - 1]; const convertedChain = convertOccurrences(checker, finalExpression, occurrences); - if (convertedChain && (isPropertyAccessExpression(convertedChain) || isElementAccessExpression(convertedChain) || isCallExpression(convertedChain))) { + if ( + convertedChain + && (isPropertyAccessExpression(convertedChain) || isElementAccessExpression(convertedChain) + || isCallExpression(convertedChain)) + ) { if (isBinaryExpression(expression)) { changes.replaceNodeRange(sourceFile, firstOccurrence, finalExpression, convertedChain); } else if (isConditionalExpression(expression)) { - changes.replaceNode(sourceFile, expression, factory.createBinaryExpression(convertedChain, factory.createToken(SyntaxKind.QuestionQuestionToken), expression.whenFalse)); + changes.replaceNode( + sourceFile, + expression, + factory.createBinaryExpression( + convertedChain, + factory.createToken(SyntaxKind.QuestionQuestionToken), + expression.whenFalse, + ), + ); } } } diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 673d4cdec9514..bb5c334e21523 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -27,11 +27,18 @@ namespace ts.refactor.extractSymbol { */ export function getRefactorActionsToExtractSymbol(context: RefactorContext): readonly ApplicableRefactorInfo[] { const requestedRefactor = context.kind; - const rangeToExtract = getRangeToExtract(context.file, getRefactorContextSpan(context), context.triggerReason === "invoked"); + const rangeToExtract = getRangeToExtract( + context.file, + getRefactorContextSpan(context), + context.triggerReason === "invoked", + ); const targetRange = rangeToExtract.targetRange; if (targetRange === undefined) { - if (!rangeToExtract.errors || rangeToExtract.errors.length === 0 || !context.preferences.provideRefactorNotApplicableReason) { + if ( + !rangeToExtract.errors || rangeToExtract.errors.length === 0 + || !context.preferences.provideRefactorNotApplicableReason + ) { return emptyArray; } @@ -168,7 +175,10 @@ namespace ts.refactor.extractSymbol { } /* Exported for tests */ - export function getRefactorEditsToExtractSymbol(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { + export function getRefactorEditsToExtractSymbol( + context: RefactorContext, + actionName: string, + ): RefactorEditInfo | undefined { const rangeToExtract = getRangeToExtract(context.file, getRefactorContextSpan(context)); const targetRange = rangeToExtract.targetRange!; // TODO:GH#18217 @@ -202,22 +212,45 @@ namespace ts.refactor.extractSymbol { export const cannotExtractEmpty: DiagnosticMessage = createMessage("Cannot extract empty range."); export const expressionExpected: DiagnosticMessage = createMessage("expression expected."); export const uselessConstantType: DiagnosticMessage = createMessage("No reason to extract constant of type."); - export const statementOrExpressionExpected: DiagnosticMessage = createMessage("Statement or expression expected."); - export const cannotExtractRangeContainingConditionalBreakOrContinueStatements: DiagnosticMessage = createMessage("Cannot extract range containing conditional break or continue statements."); - export const cannotExtractRangeContainingConditionalReturnStatement: DiagnosticMessage = createMessage("Cannot extract range containing conditional return statement."); - export const cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange: DiagnosticMessage = createMessage("Cannot extract range containing labeled break or continue with target outside of the range."); - export const cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators: DiagnosticMessage = createMessage("Cannot extract range containing writes to references located outside of the target range in generators."); + export const statementOrExpressionExpected: DiagnosticMessage = createMessage( + "Statement or expression expected.", + ); + export const cannotExtractRangeContainingConditionalBreakOrContinueStatements: DiagnosticMessage = + createMessage("Cannot extract range containing conditional break or continue statements."); + export const cannotExtractRangeContainingConditionalReturnStatement: DiagnosticMessage = createMessage( + "Cannot extract range containing conditional return statement.", + ); + export const cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange: + DiagnosticMessage = createMessage( + "Cannot extract range containing labeled break or continue with target outside of the range.", + ); + export const cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators: + DiagnosticMessage = createMessage( + "Cannot extract range containing writes to references located outside of the target range in generators.", + ); export const typeWillNotBeVisibleInTheNewScope = createMessage("Type will not visible in the new scope."); - export const functionWillNotBeVisibleInTheNewScope = createMessage("Function will not visible in the new scope."); + export const functionWillNotBeVisibleInTheNewScope = createMessage( + "Function will not visible in the new scope.", + ); export const cannotExtractIdentifier = createMessage("Select more than a single identifier."); export const cannotExtractExportedEntity = createMessage("Cannot extract exported declaration"); - export const cannotWriteInExpression = createMessage("Cannot write back side-effects when extracting an expression"); - export const cannotExtractReadonlyPropertyInitializerOutsideConstructor = createMessage("Cannot move initialization of read-only class property outside of the constructor"); + export const cannotWriteInExpression = createMessage( + "Cannot write back side-effects when extracting an expression", + ); + export const cannotExtractReadonlyPropertyInitializerOutsideConstructor = createMessage( + "Cannot move initialization of read-only class property outside of the constructor", + ); export const cannotExtractAmbientBlock = createMessage("Cannot extract code from ambient contexts"); - export const cannotAccessVariablesFromNestedScopes = createMessage("Cannot access variables from nested scopes"); + export const cannotAccessVariablesFromNestedScopes = createMessage( + "Cannot access variables from nested scopes", + ); export const cannotExtractToJSClass = createMessage("Cannot extract constant to a class scope in JS"); - export const cannotExtractToExpressionArrowFunction = createMessage("Cannot extract constant to an arrow function without a block"); - export const cannotExtractFunctionsContainingThisToMethod = createMessage("Cannot extract functions containing this to method"); + export const cannotExtractToExpressionArrowFunction = createMessage( + "Cannot extract constant to an arrow function without a block", + ); + export const cannotExtractFunctionsContainingThisToMethod = createMessage( + "Cannot extract functions containing this to method", + ); } enum RangeFacts { @@ -280,11 +313,13 @@ namespace ts.refactor.extractSymbol { /* If the refactoring command is invoked through a keyboard action it's safe to assume that the user is actively looking for refactoring actions at the span location. As they may not know the exact range that will trigger a refactoring, we expand the searched span to cover a real node range making it more likely that something useful will show up. */ - const adjustedSpan = startToken && endToken && invoked ? getAdjustedSpanFromNodes(startToken, endToken, sourceFile) : span; + const adjustedSpan = startToken && endToken && invoked + ? getAdjustedSpanFromNodes(startToken, endToken, sourceFile) : span; // Walk up starting from the the start position until we find a non-SourceFile node that subsumes the selected span. // This may fail (e.g. you select two statements in the root of a source file) - const start = cursorRequest ? getExtractableParent(startToken) : getParentNodeInSpan(startToken, sourceFile, adjustedSpan); + const start = cursorRequest ? getExtractableParent(startToken) + : getParentNodeInSpan(startToken, sourceFile, adjustedSpan); // Do the same for the ending position const end = cursorRequest ? start : getParentNodeInSpan(endToken, sourceFile, adjustedSpan); @@ -429,12 +464,21 @@ namespace ts.refactor.extractSymbol { } // We believe it's true because the node is from the (unmodified) tree. - Debug.assert(nodeToCheck.pos <= nodeToCheck.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (1)"); + Debug.assert( + nodeToCheck.pos <= nodeToCheck.end, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (1)", + ); // For understanding how skipTrivia functioned: - Debug.assert(!positionIsSynthesized(nodeToCheck.pos), "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (2)"); + Debug.assert( + !positionIsSynthesized(nodeToCheck.pos), + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (2)", + ); - if (!isStatement(nodeToCheck) && !(isExpressionNode(nodeToCheck) && isExtractableExpression(nodeToCheck)) && !isStringLiteralJsxAttribute(nodeToCheck)) { + if ( + !isStatement(nodeToCheck) && !(isExpressionNode(nodeToCheck) && isExtractableExpression(nodeToCheck)) + && !isStringLiteralJsxAttribute(nodeToCheck) + ) { return [createDiagnosticForNode(nodeToCheck, Messages.statementOrExpressionExpected)]; } @@ -457,9 +501,10 @@ namespace ts.refactor.extractSymbol { if (rangeFacts & RangeFacts.UsesThis) { const container = getThisContainer(nodeToCheck, /** includeArrowFunctions */ false); if ( - container.kind === SyntaxKind.FunctionDeclaration || - (container.kind === SyntaxKind.MethodDeclaration && container.parent.kind === SyntaxKind.ObjectLiteralExpression) || - container.kind === SyntaxKind.FunctionExpression + container.kind === SyntaxKind.FunctionDeclaration + || (container.kind === SyntaxKind.MethodDeclaration + && container.parent.kind === SyntaxKind.ObjectLiteralExpression) + || container.kind === SyntaxKind.FunctionExpression ) { rangeFacts |= RangeFacts.UsesThisInFunction; } @@ -498,7 +543,10 @@ namespace ts.refactor.extractSymbol { if (node.parent.kind === SyntaxKind.CallExpression) { // Super constructor call const containingClass = getContainingClass(node); - if (containingClass === undefined || containingClass.pos < span.start || containingClass.end >= (span.start + span.length)) { + if ( + containingClass === undefined || containingClass.pos < span.start + || containingClass.end >= (span.start + span.length) + ) { (errors ||= []).push(createDiagnosticForNode(node, Messages.cannotExtractSuper)); return true; } @@ -527,7 +575,9 @@ namespace ts.refactor.extractSymbol { case SyntaxKind.FunctionDeclaration: if (isSourceFile(node.parent) && node.parent.externalModuleIndicator === undefined) { // You cannot extract global declarations - (errors ||= []).push(createDiagnosticForNode(node, Messages.functionWillNotBeVisibleInTheNewScope)); + (errors ||= []).push( + createDiagnosticForNode(node, Messages.functionWillNotBeVisibleInTheNewScope), + ); } // falls through case SyntaxKind.ClassExpression: @@ -550,7 +600,10 @@ namespace ts.refactor.extractSymbol { permittedJumps = PermittedJumps.None; break; case SyntaxKind.Block: - if (node.parent && node.parent.kind === SyntaxKind.TryStatement && (node.parent as TryStatement).finallyBlock === node) { + if ( + node.parent && node.parent.kind === SyntaxKind.TryStatement + && (node.parent as TryStatement).finallyBlock === node + ) { // allow unconditional returns from finally blocks permittedJumps = PermittedJumps.Return; } @@ -587,13 +640,28 @@ namespace ts.refactor.extractSymbol { if (label) { if (!contains(seenLabels, label.escapedText)) { // attempts to jump to label that is not in range to be extracted - (errors ||= []).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange)); + (errors ||= []).push( + createDiagnosticForNode( + node, + Messages + .cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange, + ), + ); } } else { - if (!(permittedJumps & (node.kind === SyntaxKind.BreakStatement ? PermittedJumps.Break : PermittedJumps.Continue))) { + if ( + !(permittedJumps + & (node.kind === SyntaxKind.BreakStatement ? PermittedJumps.Break + : PermittedJumps.Continue)) + ) { // attempt to break or continue in a forbidden context - (errors ||= []).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements)); + (errors ||= []).push( + createDiagnosticForNode( + node, + Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements, + ), + ); } } break; @@ -609,7 +677,12 @@ namespace ts.refactor.extractSymbol { rangeFacts |= RangeFacts.HasReturn; } else { - (errors ||= []).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalReturnStatement)); + (errors ||= []).push( + createDiagnosticForNode( + node, + Messages.cannotExtractRangeContainingConditionalReturnStatement, + ), + ); } break; default: @@ -653,8 +726,8 @@ namespace ts.refactor.extractSymbol { } function isScope(node: Node): node is Scope { - return isArrowFunction(node) ? isFunctionBody(node.body) : - isFunctionLikeDeclaration(node) || isSourceFile(node) || isModuleBlock(node) || isClassLike(node); + return isArrowFunction(node) ? isFunctionBody(node.body) + : isFunctionLikeDeclaration(node) || isSourceFile(node) || isModuleBlock(node) || isClassLike(node); } /** @@ -698,22 +771,52 @@ namespace ts.refactor.extractSymbol { } } - function getFunctionExtractionAtIndex(targetRange: TargetRange, context: RefactorContext, requestedChangesIndex: number): RefactorEditInfo { - const { scopes, readsAndWrites: { target, usagesPerScope, functionErrorsPerScope, exposedVariableDeclarations } } = getPossibleExtractionsWorker(targetRange, context); + function getFunctionExtractionAtIndex( + targetRange: TargetRange, + context: RefactorContext, + requestedChangesIndex: number, + ): RefactorEditInfo { + const { + scopes, + readsAndWrites: { target, usagesPerScope, functionErrorsPerScope, exposedVariableDeclarations }, + } = getPossibleExtractionsWorker(targetRange, context); Debug.assert(!functionErrorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?"); context.cancellationToken!.throwIfCancellationRequested(); // TODO: GH#18217 - return extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], exposedVariableDeclarations, targetRange, context); + return extractFunctionInScope( + target, + scopes[requestedChangesIndex], + usagesPerScope[requestedChangesIndex], + exposedVariableDeclarations, + targetRange, + context, + ); } - function getConstantExtractionAtIndex(targetRange: TargetRange, context: RefactorContext, requestedChangesIndex: number): RefactorEditInfo { - const { scopes, readsAndWrites: { target, usagesPerScope, constantErrorsPerScope, exposedVariableDeclarations } } = getPossibleExtractionsWorker(targetRange, context); + function getConstantExtractionAtIndex( + targetRange: TargetRange, + context: RefactorContext, + requestedChangesIndex: number, + ): RefactorEditInfo { + const { + scopes, + readsAndWrites: { target, usagesPerScope, constantErrorsPerScope, exposedVariableDeclarations }, + } = getPossibleExtractionsWorker(targetRange, context); Debug.assert(!constantErrorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?"); - Debug.assert(exposedVariableDeclarations.length === 0, "Extract constant accepted a range containing a variable declaration?"); + Debug.assert( + exposedVariableDeclarations.length === 0, + "Extract constant accepted a range containing a variable declaration?", + ); context.cancellationToken!.throwIfCancellationRequested(); const expression = isExpression(target) ? target : (target.statements[0] as ExpressionStatement).expression; - return extractConstantInScope(expression, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange.facts, context); + return extractConstantInScope( + expression, + scopes[requestedChangesIndex], + usagesPerScope[requestedChangesIndex], + targetRange.facts, + context, + ); } interface Extraction { @@ -731,8 +834,12 @@ namespace ts.refactor.extractSymbol { * Each returned ExtractResultForScope corresponds to a possible target scope and is either a set of changes * or an error explaining why we can't extract into that scope. */ - function getPossibleExtractions(targetRange: TargetRange, context: RefactorContext): readonly ScopeExtractions[] | undefined { - const { scopes, readsAndWrites: { functionErrorsPerScope, constantErrorsPerScope } } = getPossibleExtractionsWorker(targetRange, context); + function getPossibleExtractions( + targetRange: TargetRange, + context: RefactorContext, + ): readonly ScopeExtractions[] | undefined { + const { scopes, readsAndWrites: { functionErrorsPerScope, constantErrorsPerScope } } = + getPossibleExtractionsWorker(targetRange, context); // Need the inner type annotation to avoid https://github.com/Microsoft/TypeScript/issues/7547 const extractions = scopes.map((scope, i): ScopeExtractions => { const functionDescriptionPart = getDescriptionForFunctionInScope(scope); @@ -747,21 +854,42 @@ namespace ts.refactor.extractSymbol { let functionDescription: string; let constantDescription: string; if (scopeDescription === SpecialScope.Global) { - functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [functionDescriptionPart, "global"]); - constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [constantDescriptionPart, "global"]); + functionDescription = formatStringFromArgs( + getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), + [functionDescriptionPart, "global"], + ); + constantDescription = formatStringFromArgs( + getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), + [constantDescriptionPart, "global"], + ); } else if (scopeDescription === SpecialScope.Module) { - functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [functionDescriptionPart, "module"]); - constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [constantDescriptionPart, "module"]); + functionDescription = formatStringFromArgs( + getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), + [functionDescriptionPart, "module"], + ); + constantDescription = formatStringFromArgs( + getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), + [constantDescriptionPart, "module"], + ); } else { - functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [functionDescriptionPart, scopeDescription]); - constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [constantDescriptionPart, scopeDescription]); + functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [ + functionDescriptionPart, + scopeDescription, + ]); + constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [ + constantDescriptionPart, + scopeDescription, + ]); } // Customize the phrasing for the innermost scope to increase clarity. if (i === 0 && !isClassLike(scope)) { - constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_enclosing_scope), [constantDescriptionPart]); + constantDescription = formatStringFromArgs( + getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_enclosing_scope), + [constantDescriptionPart], + ); } return { @@ -778,7 +906,10 @@ namespace ts.refactor.extractSymbol { return extractions; } - function getPossibleExtractionsWorker(targetRange: TargetRange, context: RefactorContext): { readonly scopes: Scope[]; readonly readsAndWrites: ReadsAndWrites; } { + function getPossibleExtractionsWorker( + targetRange: TargetRange, + context: RefactorContext, + ): { readonly scopes: Scope[]; readonly readsAndWrites: ReadsAndWrites; } { const { file: sourceFile } = context; const scopes = collectEnclosingScopes(targetRange); @@ -876,7 +1007,14 @@ namespace ts.refactor.extractSymbol { let type = checker.getTypeOfSymbolAtLocation(usage.symbol, usage.node); // Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {" type = checker.getBaseTypeOfLiteralType(type); - typeNode = codefix.typeToAutoImportableTypeNode(checker, importAdder, type, scope, scriptTarget, NodeBuilderFlags.NoTruncation); + typeNode = codefix.typeToAutoImportableTypeNode( + checker, + importAdder, + type, + scope, + scriptTarget, + NodeBuilderFlags.NoTruncation, + ); } const paramDecl = factory.createParameterDeclaration( @@ -893,12 +1031,16 @@ namespace ts.refactor.extractSymbol { callArguments.push(factory.createIdentifier(name)); }); - const typeParametersAndDeclarations = arrayFrom(typeParameterUsages.values()).map(type => ({ type, declaration: getFirstDeclaration(type) })); + const typeParametersAndDeclarations = arrayFrom(typeParameterUsages.values()).map(type => ({ + type, + declaration: getFirstDeclaration(type), + })); const sortedTypeParametersAndDeclarations = typeParametersAndDeclarations.sort(compareTypesByDeclarationOrder); - const typeParameters: readonly TypeParameterDeclaration[] | undefined = sortedTypeParametersAndDeclarations.length === 0 - ? undefined - : sortedTypeParametersAndDeclarations.map(t => t.declaration as TypeParameterDeclaration); + const typeParameters: readonly TypeParameterDeclaration[] | undefined = + sortedTypeParametersAndDeclarations.length === 0 + ? undefined + : sortedTypeParametersAndDeclarations.map(t => t.declaration as TypeParameterDeclaration); // Strictly speaking, we should check whether each name actually binds to the appropriate type // parameter. In cases of shadowing, they may not. @@ -913,7 +1055,13 @@ namespace ts.refactor.extractSymbol { returnType = checker.typeToTypeNode(contextualType!, scope, NodeBuilderFlags.NoTruncation); // TODO: GH#18217 } - const { body, returnValueProperty } = transformFunctionBody(node, exposedVariableDeclarations, writes, substitutions, !!(range.facts & RangeFacts.HasReturn)); + const { body, returnValueProperty } = transformFunctionBody( + node, + exposedVariableDeclarations, + writes, + substitutions, + !!(range.facts & RangeFacts.HasReturn), + ); suppressLeadingAndTrailingTrivia(body); let newFunction: MethodDeclaration | FunctionDeclaration; @@ -1018,7 +1166,12 @@ namespace ts.refactor.extractSymbol { newNodes.push(factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - [factory.createVariableDeclaration(getSynthesizedDeepClone(variableDeclaration.name), /*exclamationToken*/ undefined, /*type*/ getSynthesizedDeepClone(variableDeclaration.type), /*initializer*/ call)], // TODO (acasey): test binding patterns + [factory.createVariableDeclaration( + getSynthesizedDeepClone(variableDeclaration.name), + /*exclamationToken*/ undefined, + /*type*/ getSynthesizedDeepClone(variableDeclaration.type), + /*initializer*/ call, + )], // TODO (acasey): test binding patterns variableDeclaration.parent.flags, ), )); @@ -1054,7 +1207,8 @@ namespace ts.refactor.extractSymbol { commonNodeFlags = commonNodeFlags & variableDeclaration.parent.flags; } - const typeLiteral: TypeLiteralNode | undefined = sawExplicitType ? factory.createTypeLiteralNode(typeElements) : undefined; + const typeLiteral: TypeLiteralNode | undefined = sawExplicitType + ? factory.createTypeLiteralNode(typeElements) : undefined; if (typeLiteral) { setEmitFlags(typeLiteral, EmitFlags.SingleLine); } @@ -1085,7 +1239,11 @@ namespace ts.refactor.extractSymbol { newNodes.push(factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - [factory.createVariableDeclaration(variableDeclaration.symbol.name, /*exclamationToken*/ undefined, getTypeDeepCloneUnionUndefined(variableDeclaration.type))], + [factory.createVariableDeclaration( + variableDeclaration.symbol.name, + /*exclamationToken*/ undefined, + getTypeDeepCloneUnionUndefined(variableDeclaration.type), + )], flags, ), )); @@ -1097,13 +1255,20 @@ namespace ts.refactor.extractSymbol { newNodes.push(factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - [factory.createVariableDeclaration(returnValueProperty, /*exclamationToken*/ undefined, getTypeDeepCloneUnionUndefined(returnType))], + [factory.createVariableDeclaration( + returnValueProperty, + /*exclamationToken*/ undefined, + getTypeDeepCloneUnionUndefined(returnType), + )], NodeFlags.Let, ), )); } - const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes); + const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations( + exposedVariableDeclarations, + writes, + ); if (returnValueProperty) { assignments.unshift(factory.createShorthandPropertyAssignment(returnValueProperty)); } @@ -1124,7 +1289,11 @@ namespace ts.refactor.extractSymbol { // emit e.g. // { a, b, __return } = newFunction(a, b); // return __return; - newNodes.push(factory.createExpressionStatement(factory.createAssignment(factory.createObjectLiteralExpression(assignments), call))); + newNodes.push( + factory.createExpressionStatement( + factory.createAssignment(factory.createObjectLiteralExpression(assignments), call), + ), + ); if (returnValueProperty) { newNodes.push(factory.createReturnStatement(factory.createIdentifier(returnValueProperty))); } @@ -1153,7 +1322,12 @@ namespace ts.refactor.extractSymbol { const renameRange = isReadonlyArray(range.range) ? first(range.range) : range.range; const renameFilename = renameRange.getSourceFile().fileName; - const renameLocation = getRenameLocation(edits, renameFilename, functionNameText, /*isDeclaredBeforeUse*/ false); + const renameLocation = getRenameLocation( + edits, + renameFilename, + functionNameText, + /*isDeclaredBeforeUse*/ false, + ); return { renameFilename, renameLocation, edits }; function getTypeDeepCloneUnionUndefined(typeNode: TypeNode | undefined): TypeNode | undefined { @@ -1166,7 +1340,8 @@ namespace ts.refactor.extractSymbol { while (isParenthesizedTypeNode(withoutParens)) { withoutParens = withoutParens.type; } - return isUnionTypeNode(withoutParens) && find(withoutParens.types, t => t.kind === SyntaxKind.UndefinedKeyword) + return isUnionTypeNode(withoutParens) + && find(withoutParens.types, t => t.kind === SyntaxKind.UndefinedKeyword) ? clone : factory.createUnionTypeNode([clone, factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]); } @@ -1187,7 +1362,9 @@ namespace ts.refactor.extractSymbol { // Make a unique name for the extracted variable const file = scope.getSourceFile(); - const localNameText = isPropertyAccessExpression(node) && !isClassLike(scope) && !checker.resolveName(node.name.text, node, SymbolFlags.Value, /*excludeGlobals*/ false) && !isPrivateIdentifier(node.name) && !isKeyword(node.name.originalKeywordKind!) + const localNameText = isPropertyAccessExpression(node) && !isClassLike(scope) + && !checker.resolveName(node.name.text, node, SymbolFlags.Value, /*excludeGlobals*/ false) + && !isPrivateIdentifier(node.name) && !isKeyword(node.name.originalKeywordKind!) ? node.name.text : getUniqueName(isClassLike(scope) ? "newProperty" : "newLocal", file); const isJS = isInJSFile(scope); @@ -1241,7 +1418,12 @@ namespace ts.refactor.extractSymbol { changeTracker.replaceNode(context.file, node, localReference); } else { - const newVariableDeclaration = factory.createVariableDeclaration(localNameText, /*exclamationToken*/ undefined, variableType, initializer); + const newVariableDeclaration = factory.createVariableDeclaration( + localNameText, + /*exclamationToken*/ undefined, + variableType, + initializer, + ); // If the node is part of an initializer in a list of variable declarations, insert a new // variable declaration into the list (in case it depends on earlier ones). @@ -1278,7 +1460,12 @@ namespace ts.refactor.extractSymbol { changeTracker.insertNodeAtTopOfFile(context.file, newVariableStatement, /*blankLineBetween*/ false); } else { - changeTracker.insertNodeBefore(context.file, nodeToInsertBefore, newVariableStatement, /*blankLineBetween*/ false); + changeTracker.insertNodeBefore( + context.file, + nodeToInsertBefore, + newVariableStatement, + /*blankLineBetween*/ false, + ); } // Consume @@ -1304,11 +1491,16 @@ namespace ts.refactor.extractSymbol { const renameLocation = getRenameLocation(edits, renameFilename, localNameText, /*isDeclaredBeforeUse*/ true); return { renameFilename, renameLocation, edits }; - function transformFunctionInitializerAndType(variableType: TypeNode | undefined, initializer: Expression): { variableType: TypeNode | undefined; initializer: Expression; } { + function transformFunctionInitializerAndType( + variableType: TypeNode | undefined, + initializer: Expression, + ): { variableType: TypeNode | undefined; initializer: Expression; } { // If no contextual type exists there is nothing to transfer to the function signature if (variableType === undefined) return { variableType, initializer }; // Only do this for function expressions and arrow functions that are not generic - if (!isFunctionExpression(initializer) && !isArrowFunction(initializer) || !!initializer.typeParameters) return { variableType, initializer }; + if (!isFunctionExpression(initializer) && !isArrowFunction(initializer) || !!initializer.typeParameters) { + return { variableType, initializer }; + } const functionType = checker.getTypeAtLocation(node); const functionSignature = singleOrUndefined(checker.getSignaturesOfType(functionType, SignatureKind.Call)); @@ -1328,7 +1520,17 @@ namespace ts.refactor.extractSymbol { const paramType = checker.getTypeAtLocation(p); if (paramType === checker.getAnyType()) hasAny = true; - parameters.push(factory.updateParameterDeclaration(p, p.modifiers, p.dotDotDotToken, p.name, p.questionToken, p.type || checker.typeToTypeNode(paramType, scope, NodeBuilderFlags.NoTruncation), p.initializer)); + parameters.push( + factory.updateParameterDeclaration( + p, + p.modifiers, + p.dotDotDotToken, + p.name, + p.questionToken, + p.type || checker.typeToTypeNode(paramType, scope, NodeBuilderFlags.NoTruncation), + p.initializer, + ), + ); } } // If a parameter was inferred as any we skip adding function parameters at all. @@ -1337,14 +1539,30 @@ namespace ts.refactor.extractSymbol { if (hasAny) return { variableType, initializer }; variableType = undefined; if (isArrowFunction(initializer)) { - initializer = factory.updateArrowFunction(initializer, canHaveModifiers(node) ? getModifiers(node) : undefined, initializer.typeParameters, parameters, initializer.type || checker.typeToTypeNode(functionSignature.getReturnType(), scope, NodeBuilderFlags.NoTruncation), initializer.equalsGreaterThanToken, initializer.body); + initializer = factory.updateArrowFunction( + initializer, + canHaveModifiers(node) ? getModifiers(node) : undefined, + initializer.typeParameters, + parameters, + initializer.type + || checker.typeToTypeNode( + functionSignature.getReturnType(), + scope, + NodeBuilderFlags.NoTruncation, + ), + initializer.equalsGreaterThanToken, + initializer.body, + ); } else { if (functionSignature && !!functionSignature.thisParameter) { const firstParameter = firstOrUndefined(parameters); // If the function signature has a this parameter and if the first defined parameter is not the this parameter, we must add it // Note: If this parameter was already there, it would have been previously updated with the type if not type was present - if ((!firstParameter || (isIdentifier(firstParameter.name) && firstParameter.name.escapedText !== "this"))) { + if ( + (!firstParameter + || (isIdentifier(firstParameter.name) && firstParameter.name.escapedText !== "this")) + ) { const thisType = checker.getTypeOfSymbolAtLocation(functionSignature.thisParameter, node); parameters.splice( 0, @@ -1359,7 +1577,21 @@ namespace ts.refactor.extractSymbol { ); } } - initializer = factory.updateFunctionExpression(initializer, canHaveModifiers(node) ? getModifiers(node) : undefined, initializer.asteriskToken, initializer.name, initializer.typeParameters, parameters, initializer.type || checker.typeToTypeNode(functionSignature.getReturnType(), scope, NodeBuilderFlags.NoTruncation), initializer.body); + initializer = factory.updateFunctionExpression( + initializer, + canHaveModifiers(node) ? getModifiers(node) : undefined, + initializer.asteriskToken, + initializer.name, + initializer.typeParameters, + parameters, + initializer.type + || checker.typeToTypeNode( + functionSignature.getReturnType(), + scope, + NodeBuilderFlags.NoTruncation, + ), + initializer.body, + ); } return { variableType, initializer }; } @@ -1369,10 +1601,10 @@ namespace ts.refactor.extractSymbol { let prevNode; while (node !== undefined && node !== scope) { if ( - isVariableDeclaration(node) && - node.initializer === prevNode && - isVariableDeclarationList(node.parent) && - node.parent.declarations.length > 1 + isVariableDeclaration(node) + && node.initializer === prevNode + && isVariableDeclarationList(node.parent) + && node.parent.declarations.length > 1 ) { return node; } @@ -1412,7 +1644,8 @@ namespace ts.refactor.extractSymbol { function getCalledExpression(scope: Node, range: TargetRange, functionNameText: string): Expression { const functionReference = factory.createIdentifier(functionNameText); if (isClassLike(scope)) { - const lhs = range.facts & RangeFacts.InStaticRegion ? factory.createIdentifier(scope.name!.text) : factory.createThis(); // TODO: GH#18217 + const lhs = range.facts & RangeFacts.InStaticRegion ? factory.createIdentifier(scope.name!.text) + : factory.createThis(); // TODO: GH#18217 return factory.createPropertyAccessExpression(lhs, functionReference); } else { @@ -1420,7 +1653,13 @@ namespace ts.refactor.extractSymbol { } } - function transformFunctionBody(body: Node, exposedVariableDeclarations: readonly VariableDeclaration[], writes: readonly UsageEntry[] | undefined, substitutions: ReadonlyESMap, hasReturn: boolean): { body: Block; returnValueProperty: string | undefined; } { + function transformFunctionBody( + body: Node, + exposedVariableDeclarations: readonly VariableDeclaration[], + writes: readonly UsageEntry[] | undefined, + substitutions: ReadonlyESMap, + hasReturn: boolean, + ): { body: Block; returnValueProperty: string | undefined; } { const hasWritesOrVariableDeclarations = writes !== undefined || exposedVariableDeclarations.length > 0; if (isBlock(body) && !hasWritesOrVariableDeclarations && substitutions.size === 0) { // already block, no declarations or writes to propagate back, no substitutions - can use node as is @@ -1428,19 +1667,27 @@ namespace ts.refactor.extractSymbol { } let returnValueProperty: string | undefined; let ignoreReturns = false; - const statements = factory.createNodeArray(isBlock(body) ? body.statements.slice(0) : [isStatement(body) ? body : factory.createReturnStatement(skipParentheses(body as Expression))]); + const statements = factory.createNodeArray( + isBlock(body) ? body.statements.slice(0) + : [isStatement(body) ? body : factory.createReturnStatement(skipParentheses(body as Expression))], + ); // rewrite body if either there are writes that should be propagated back via return statements or there are substitutions if (hasWritesOrVariableDeclarations || substitutions.size) { const rewrittenStatements = visitNodes(statements, visitor).slice(); if (hasWritesOrVariableDeclarations && !hasReturn && isStatement(body)) { // add return at the end to propagate writes back in case if control flow falls out of the function body // it is ok to know that range has at least one return since it we only allow unconditional returns - const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes); + const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations( + exposedVariableDeclarations, + writes, + ); if (assignments.length === 1) { rewrittenStatements.push(factory.createReturnStatement(assignments[0].name)); } else { - rewrittenStatements.push(factory.createReturnStatement(factory.createObjectLiteralExpression(assignments))); + rewrittenStatements.push( + factory.createReturnStatement(factory.createObjectLiteralExpression(assignments)), + ); } } return { body: factory.createBlock(rewrittenStatements, /*multiLine*/ true), returnValueProperty }; @@ -1451,12 +1698,17 @@ namespace ts.refactor.extractSymbol { function visitor(node: Node): VisitResult { if (!ignoreReturns && isReturnStatement(node) && hasWritesOrVariableDeclarations) { - const assignments: ObjectLiteralElementLike[] = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes); + const assignments: ObjectLiteralElementLike[] = getPropertyAssignmentsForWritesAndVariableDeclarations( + exposedVariableDeclarations, + writes, + ); if (node.expression) { if (!returnValueProperty) { returnValueProperty = "__return"; } - assignments.unshift(factory.createPropertyAssignment(returnValueProperty, visitNode(node.expression, visitor))); + assignments.unshift( + factory.createPropertyAssignment(returnValueProperty, visitNode(node.expression, visitor)), + ); } if (assignments.length === 1) { return factory.createReturnStatement(assignments[0].name as Expression); @@ -1469,21 +1721,26 @@ namespace ts.refactor.extractSymbol { const oldIgnoreReturns = ignoreReturns; ignoreReturns = ignoreReturns || isFunctionLikeDeclaration(node) || isClassLike(node); const substitution = substitutions.get(getNodeId(node).toString()); - const result = substitution ? getSynthesizedDeepClone(substitution) : visitEachChild(node, visitor, nullTransformationContext); + const result = substitution ? getSynthesizedDeepClone(substitution) + : visitEachChild(node, visitor, nullTransformationContext); ignoreReturns = oldIgnoreReturns; return result; } } } - function transformConstantInitializer(initializer: Expression, substitutions: ReadonlyESMap): Expression { + function transformConstantInitializer( + initializer: Expression, + substitutions: ReadonlyESMap, + ): Expression { return substitutions.size ? visitor(initializer) as Expression : initializer; function visitor(node: Node): VisitResult { const substitution = substitutions.get(getNodeId(node).toString()); - return substitution ? getSynthesizedDeepClone(substitution) : visitEachChild(node, visitor, nullTransformationContext); + return substitution ? getSynthesizedDeepClone(substitution) + : visitEachChild(node, visitor, nullTransformationContext); } } @@ -1512,7 +1769,10 @@ namespace ts.refactor.extractSymbol { * Otherwise, return `undefined`. */ function getNodeToInsertFunctionBefore(minPos: number, scope: Scope): Statement | ClassElement | undefined { - return find(getStatementsOrClassElements(scope), child => child.pos >= minPos && isFunctionLikeDeclaration(child) && !isConstructorDeclaration(child)); + return find( + getStatementsOrClassElements(scope), + child => child.pos >= minPos && isFunctionLikeDeclaration(child) && !isConstructorDeclaration(child), + ); } function getNodeToInsertPropertyBefore(maxPos: number, scope: ClassLikeDeclaration): ClassElement { @@ -1579,7 +1839,10 @@ namespace ts.refactor.extractSymbol { exposedVariableDeclarations: readonly VariableDeclaration[], writes: readonly UsageEntry[] | undefined, ): ShorthandPropertyAssignment[] { - const variableAssignments = map(exposedVariableDeclarations, v => factory.createShorthandPropertyAssignment(v.symbol.name)); + const variableAssignments = map( + exposedVariableDeclarations, + v => factory.createShorthandPropertyAssignment(v.symbol.name), + ); const writeAssignments = map(writes, w => factory.createShorthandPropertyAssignment(w.symbol.name)); // TODO: GH#18217 `variableAssignments` not possibly undefined! @@ -1672,7 +1935,11 @@ namespace ts.refactor.extractSymbol { // initialize results for (const scope of scopes) { - usagesPerScope.push({ usages: new Map(), typeParameterUsages: new Map(), substitutions: new Map() }); + usagesPerScope.push({ + usages: new Map(), + typeParameterUsages: new Map(), + substitutions: new Map(), + }); substitutionsPerScope.push(new Map()); functionErrorsPerScope.push([]); @@ -1754,11 +2021,18 @@ namespace ts.refactor.extractSymbol { // local will actually be declared at the same level as the extracted expression). if (i > 0 && (scopeUsages.usages.size > 0 || scopeUsages.typeParameterUsages.size > 0)) { const errorNode = isReadonlyArray(targetRange.range) ? targetRange.range[0] : targetRange.range; - constantErrorsPerScope[i].push(createDiagnosticForNode(errorNode, Messages.cannotAccessVariablesFromNestedScopes)); + constantErrorsPerScope[i].push( + createDiagnosticForNode(errorNode, Messages.cannotAccessVariablesFromNestedScopes), + ); } if (targetRange.facts & RangeFacts.UsesThisInFunction && isClassLike(scopes[i])) { - functionErrorsPerScope[i].push(createDiagnosticForNode(targetRange.thisNode!, Messages.cannotExtractFunctionsContainingThisToMethod)); + functionErrorsPerScope[i].push( + createDiagnosticForNode( + targetRange.thisNode!, + Messages.cannotExtractFunctionsContainingThisToMethod, + ), + ); } let hasWrite = false; @@ -1767,9 +2041,9 @@ namespace ts.refactor.extractSymbol { if (value.usage === Usage.Write) { hasWrite = true; if ( - value.symbol.flags & SymbolFlags.ClassMember && - value.symbol.valueDeclaration && - hasEffectiveModifier(value.symbol.valueDeclaration, ModifierFlags.Readonly) + value.symbol.flags & SymbolFlags.ClassMember + && value.symbol.valueDeclaration + && hasEffectiveModifier(value.symbol.valueDeclaration, ModifierFlags.Readonly) ) { readonlyClassPropertyWrite = value.symbol.valueDeclaration; } @@ -1777,7 +2051,10 @@ namespace ts.refactor.extractSymbol { }); // If an expression was extracted, then there shouldn't have been any variable declarations. - Debug.assert(isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0, "No variable declarations expected if something was extracted"); + Debug.assert( + isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0, + "No variable declarations expected if something was extracted", + ); if (hasWrite && !isReadonlyArray(targetRange.range)) { const diag = createDiagnosticForNode(targetRange.range, Messages.cannotWriteInExpression); @@ -1785,12 +2062,18 @@ namespace ts.refactor.extractSymbol { constantErrorsPerScope[i].push(diag); } else if (readonlyClassPropertyWrite && i > 0) { - const diag = createDiagnosticForNode(readonlyClassPropertyWrite, Messages.cannotExtractReadonlyPropertyInitializerOutsideConstructor); + const diag = createDiagnosticForNode( + readonlyClassPropertyWrite, + Messages.cannotExtractReadonlyPropertyInitializerOutsideConstructor, + ); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } else if (firstExposedNonVariableDeclaration) { - const diag = createDiagnosticForNode(firstExposedNonVariableDeclaration, Messages.cannotExtractExportedEntity); + const diag = createDiagnosticForNode( + firstExposedNonVariableDeclaration, + Messages.cannotExtractExportedEntity, + ); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } @@ -1799,14 +2082,19 @@ namespace ts.refactor.extractSymbol { return { target, usagesPerScope, functionErrorsPerScope, constantErrorsPerScope, exposedVariableDeclarations }; function isInGenericContext(node: Node) { - return !!findAncestor(node, n => isDeclarationWithTypeParameters(n) && getEffectiveTypeParameterDeclarations(n).length !== 0); + return !!findAncestor( + node, + n => isDeclarationWithTypeParameters(n) && getEffectiveTypeParameterDeclarations(n).length !== 0, + ); } function recordTypeParameterUsages(type: Type) { // PERF: This is potentially very expensive. `type` could be a library type with // a lot of properties, each of which the walker will visit. Unfortunately, the // solution isn't as trivial as filtering to user types because of (e.g.) Array. - const symbolWalker = checker.getSymbolWalker(() => (cancellationToken.throwIfCancellationRequested(), true)); + const symbolWalker = checker.getSymbolWalker( + () => (cancellationToken.throwIfCancellationRequested(), true), + ); const { visitedTypes } = symbolWalker.walkType(type); for (const visitedType of visitedTypes) { @@ -1911,7 +2199,10 @@ namespace ts.refactor.extractSymbol { if (targetRange.facts & RangeFacts.IsGenerator && usage === Usage.Write) { // this is write to a reference located outside of the target scope and range is extracted into generator // currently this is unsupported scenario - const diag = createDiagnosticForNode(identifier, Messages.cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators); + const diag = createDiagnosticForNode( + identifier, + Messages.cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators, + ); for (const errors of functionErrorsPerScope) { errors.push(diag); } @@ -1926,7 +2217,11 @@ namespace ts.refactor.extractSymbol { continue; } if (!substitutionsPerScope[i].has(symbolId)) { - const substitution = tryReplaceWithQualifiedNameOrPropertyAccess(symbol.exportSymbol || symbol, scope, isTypeName); + const substitution = tryReplaceWithQualifiedNameOrPropertyAccess( + symbol.exportSymbol || symbol, + scope, + isTypeName, + ); if (substitution) { substitutionsPerScope[i].set(symbolId, substitution); } @@ -1934,7 +2229,10 @@ namespace ts.refactor.extractSymbol { // If the symbol is a type parameter that won't be in scope, we'll pass it as a type argument // so there's no problem. if (!(symbol.flags & SymbolFlags.TypeParameter)) { - const diag = createDiagnosticForNode(identifier, Messages.typeWillNotBeVisibleInTheNewScope); + const diag = createDiagnosticForNode( + identifier, + Messages.typeWillNotBeVisibleInTheNewScope, + ); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } @@ -1949,7 +2247,10 @@ namespace ts.refactor.extractSymbol { function checkForUsedDeclarations(node: Node) { // If this node is entirely within the original extraction range, we don't need to do anything. - if (node === targetRange.range || (isReadonlyArray(targetRange.range) && targetRange.range.indexOf(node as Statement) >= 0)) { + if ( + node === targetRange.range + || (isReadonlyArray(targetRange.range) && targetRange.range.indexOf(node as Statement) >= 0) + ) { return; } @@ -1984,12 +2285,17 @@ namespace ts.refactor.extractSymbol { function getSymbolReferencedByIdentifier(identifier: Identifier) { // If the identifier is both a property name and its value, we're only interested in its value // (since the name is a declaration and will be included in the extracted range). - return identifier.parent && isShorthandPropertyAssignment(identifier.parent) && identifier.parent.name === identifier + return identifier.parent && isShorthandPropertyAssignment(identifier.parent) + && identifier.parent.name === identifier ? checker.getShorthandAssignmentValueSymbol(identifier.parent) : checker.getSymbolAtLocation(identifier); } - function tryReplaceWithQualifiedNameOrPropertyAccess(symbol: Symbol | undefined, scopeDecl: Node, isTypeNode: boolean): PropertyAccessExpression | EntityName | undefined { + function tryReplaceWithQualifiedNameOrPropertyAccess( + symbol: Symbol | undefined, + scopeDecl: Node, + isTypeNode: boolean, + ): PropertyAccessExpression | EntityName | undefined { if (!symbol) { return undefined; } @@ -2008,7 +2314,10 @@ namespace ts.refactor.extractSymbol { } function getExtractableParent(node: Node | undefined): Node | undefined { - return findAncestor(node, node => node.parent && isExtractableExpression(node) && !isBinaryExpression(node.parent)); + return findAncestor( + node, + node => node.parent && isExtractableExpression(node) && !isBinaryExpression(node.parent), + ); } /** @@ -2027,8 +2336,8 @@ namespace ts.refactor.extractSymbol { switch (node.kind) { case SyntaxKind.StringLiteral: - return parent.kind !== SyntaxKind.ImportDeclaration && - parent.kind !== SyntaxKind.ImportSpecifier; + return parent.kind !== SyntaxKind.ImportDeclaration + && parent.kind !== SyntaxKind.ImportSpecifier; case SyntaxKind.SpreadElement: case SyntaxKind.ObjectBindingPattern: @@ -2036,9 +2345,9 @@ namespace ts.refactor.extractSymbol { return false; case SyntaxKind.Identifier: - return parent.kind !== SyntaxKind.BindingElement && - parent.kind !== SyntaxKind.ImportSpecifier && - parent.kind !== SyntaxKind.ExportSpecifier; + return parent.kind !== SyntaxKind.BindingElement + && parent.kind !== SyntaxKind.ImportSpecifier + && parent.kind !== SyntaxKind.ExportSpecifier; } return true; } @@ -2056,8 +2365,9 @@ namespace ts.refactor.extractSymbol { } function isInJSXContent(node: Node) { - return isStringLiteralJsxAttribute(node) || - (isJsxElement(node) || isJsxSelfClosingElement(node) || isJsxFragment(node)) && (isJsxElement(node.parent) || isJsxFragment(node.parent)); + return isStringLiteralJsxAttribute(node) + || (isJsxElement(node) || isJsxSelfClosingElement(node) || isJsxFragment(node)) + && (isJsxElement(node.parent) || isJsxFragment(node.parent)); } function isStringLiteralJsxAttribute(node: Node): node is StringLiteral { diff --git a/src/services/refactors/extractType.ts b/src/services/refactors/extractType.ts index cb9d580ae3b04..6396831dce207 100644 --- a/src/services/refactors/extractType.ts +++ b/src/services/refactors/extractType.ts @@ -32,8 +32,9 @@ namespace ts.refactor { return [{ name: refactorName, description: getLocaleSpecificMessage(Diagnostics.Extract_type), - actions: info.isJS ? - [extractToTypeDefAction] : append([extractToTypeAliasAction], info.typeElements && extractToInterfaceAction), + actions: info.isJS + ? [extractToTypeDefAction] + : append([extractToTypeAliasAction], info.typeElements && extractToInterfaceAction), }]; } @@ -97,35 +98,53 @@ namespace ts.refactor { type ExtractInfo = TypeAliasInfo | InterfaceInfo; - function getRangeToExtract(context: RefactorContext, considerEmptySpans = true): ExtractInfo | RefactorErrorInfo | undefined { + function getRangeToExtract( + context: RefactorContext, + considerEmptySpans = true, + ): ExtractInfo | RefactorErrorInfo | undefined { const { file, startPosition } = context; const isJS = isSourceFileJS(file); const current = getTokenAtPosition(file, startPosition); const range = createTextRangeFromSpan(getRefactorContextSpan(context)); const cursorRequest = range.pos === range.end && considerEmptySpans; - const selection = findAncestor(current, node => - node.parent && isTypeNode(node) && !rangeContainsSkipTrivia(range, node.parent, file) && - (cursorRequest || nodeOverlapsWithStartEnd(current, file, range.pos, range.end))); - if (!selection || !isTypeNode(selection)) return { error: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_type_node) }; + const selection = findAncestor( + current, + node => + node.parent && isTypeNode(node) && !rangeContainsSkipTrivia(range, node.parent, file) + && (cursorRequest || nodeOverlapsWithStartEnd(current, file, range.pos, range.end)), + ); + if (!selection || !isTypeNode(selection)) { + return { error: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_type_node) }; + } const checker = context.program.getTypeChecker(); const firstStatement = Debug.checkDefined(findAncestor(selection, isStatement), "Should find a statement"); const typeParameters = collectTypeParameters(checker, selection, firstStatement, file); - if (!typeParameters) return { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }; + if (!typeParameters) { + return { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }; + } const typeElements = flattenTypeLiteralNodeReference(checker, selection); return { isJS, selection, firstStatement, typeParameters, typeElements }; } - function flattenTypeLiteralNodeReference(checker: TypeChecker, node: TypeNode | undefined): readonly TypeElement[] | undefined { + function flattenTypeLiteralNodeReference( + checker: TypeChecker, + node: TypeNode | undefined, + ): readonly TypeElement[] | undefined { if (!node) return undefined; if (isIntersectionTypeNode(node)) { const result: TypeElement[] = []; const seen = new Map(); for (const type of node.types) { const flattenedTypeMembers = flattenTypeLiteralNodeReference(checker, type); - if (!flattenedTypeMembers || !flattenedTypeMembers.every(type => type.name && addToSeen(seen, getNameFromPropertyName(type.name) as string))) { + if ( + !flattenedTypeMembers + || !flattenedTypeMembers.every(type => + type.name && addToSeen(seen, getNameFromPropertyName(type.name) as string) + ) + ) { return undefined; } @@ -146,7 +165,12 @@ namespace ts.refactor { return rangeContainsStartEnd(r1, skipTrivia(file.text, node.pos), node.end); } - function collectTypeParameters(checker: TypeChecker, selection: TypeNode, statement: Statement, file: SourceFile): TypeParameterDeclaration[] | undefined { + function collectTypeParameters( + checker: TypeChecker, + selection: TypeNode, + statement: Statement, + file: SourceFile, + ): TypeParameterDeclaration[] | undefined { const result: TypeParameterDeclaration[] = []; return visitor(selection) ? undefined : result; @@ -154,16 +178,27 @@ namespace ts.refactor { if (isTypeReferenceNode(node)) { if (isIdentifier(node.typeName)) { const typeName = node.typeName; - const symbol = checker.resolveName(typeName.text, typeName, SymbolFlags.TypeParameter, /* excludeGlobals */ true); + const symbol = checker.resolveName( + typeName.text, + typeName, + SymbolFlags.TypeParameter, + /* excludeGlobals */ true, + ); for (const decl of symbol?.declarations || emptyArray) { if (isTypeParameterDeclaration(decl) && decl.getSourceFile() === file) { // skip extraction if the type node is in the range of the type parameter declaration. // function foo(): void; - if (decl.name.escapedText === typeName.escapedText && rangeContainsSkipTrivia(decl, selection, file)) { + if ( + decl.name.escapedText === typeName.escapedText + && rangeContainsSkipTrivia(decl, selection, file) + ) { return true; } - if (rangeContainsSkipTrivia(statement, decl, file) && !rangeContainsSkipTrivia(selection, decl, file)) { + if ( + rangeContainsSkipTrivia(statement, decl, file) + && !rangeContainsSkipTrivia(selection, decl, file) + ) { pushIfUnique(result, decl); break; } @@ -172,32 +207,53 @@ namespace ts.refactor { } } else if (isInferTypeNode(node)) { - const conditionalTypeNode = findAncestor(node, n => isConditionalTypeNode(n) && rangeContainsSkipTrivia(n.extendsType, node, file)); + const conditionalTypeNode = findAncestor( + node, + n => isConditionalTypeNode(n) && rangeContainsSkipTrivia(n.extendsType, node, file), + ); if (!conditionalTypeNode || !rangeContainsSkipTrivia(selection, conditionalTypeNode, file)) { return true; } } else if ((isTypePredicateNode(node) || isThisTypeNode(node))) { const functionLikeNode = findAncestor(node.parent, isFunctionLike); - if (functionLikeNode && functionLikeNode.type && rangeContainsSkipTrivia(functionLikeNode.type, node, file) && !rangeContainsSkipTrivia(selection, functionLikeNode, file)) { + if ( + functionLikeNode && functionLikeNode.type + && rangeContainsSkipTrivia(functionLikeNode.type, node, file) + && !rangeContainsSkipTrivia(selection, functionLikeNode, file) + ) { return true; } } else if (isTypeQueryNode(node)) { if (isIdentifier(node.exprName)) { - const symbol = checker.resolveName(node.exprName.text, node.exprName, SymbolFlags.Value, /* excludeGlobals */ false); - if (symbol?.valueDeclaration && rangeContainsSkipTrivia(statement, symbol.valueDeclaration, file) && !rangeContainsSkipTrivia(selection, symbol.valueDeclaration, file)) { + const symbol = checker.resolveName( + node.exprName.text, + node.exprName, + SymbolFlags.Value, + /* excludeGlobals */ false, + ); + if ( + symbol?.valueDeclaration && rangeContainsSkipTrivia(statement, symbol.valueDeclaration, file) + && !rangeContainsSkipTrivia(selection, symbol.valueDeclaration, file) + ) { return true; } } else { - if (isThisIdentifier(node.exprName.left) && !rangeContainsSkipTrivia(selection, node.parent, file)) { + if ( + isThisIdentifier(node.exprName.left) && !rangeContainsSkipTrivia(selection, node.parent, file) + ) { return true; } } } - if (file && isTupleTypeNode(node) && (getLineAndCharacterOfPosition(file, node.pos).line === getLineAndCharacterOfPosition(file, node.end).line)) { + if ( + file && isTupleTypeNode(node) + && (getLineAndCharacterOfPosition(file, node.pos).line + === getLineAndCharacterOfPosition(file, node.end).line) + ) { setEmitFlags(node, EmitFlags.SingleLine); } @@ -205,20 +261,49 @@ namespace ts.refactor { } } - function doTypeAliasChange(changes: textChanges.ChangeTracker, file: SourceFile, name: string, info: TypeAliasInfo) { + function doTypeAliasChange( + changes: textChanges.ChangeTracker, + file: SourceFile, + name: string, + info: TypeAliasInfo, + ) { const { firstStatement, selection, typeParameters } = info; const newTypeNode = factory.createTypeAliasDeclaration( /* modifiers */ undefined, name, - typeParameters.map(id => factory.updateTypeParameterDeclaration(id, id.modifiers, id.name, id.constraint, /* defaultType */ undefined)), + typeParameters.map(id => + factory.updateTypeParameterDeclaration( + id, + id.modifiers, + id.name, + id.constraint, + /* defaultType */ undefined, + ) + ), selection, ); changes.insertNodeBefore(file, firstStatement, ignoreSourceNewlines(newTypeNode), /* blankLineBetween */ true); - changes.replaceNode(file, selection, factory.createTypeReferenceNode(name, typeParameters.map(id => factory.createTypeReferenceNode(id.name, /* typeArguments */ undefined))), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.ExcludeWhitespace }); + changes.replaceNode( + file, + selection, + factory.createTypeReferenceNode( + name, + typeParameters.map(id => factory.createTypeReferenceNode(id.name, /* typeArguments */ undefined)), + ), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.ExcludeWhitespace, + }, + ); } - function doInterfaceChange(changes: textChanges.ChangeTracker, file: SourceFile, name: string, info: InterfaceInfo) { + function doInterfaceChange( + changes: textChanges.ChangeTracker, + file: SourceFile, + name: string, + info: InterfaceInfo, + ) { const { firstStatement, selection, typeParameters, typeElements } = info; const newTypeNode = factory.createInterfaceDeclaration( @@ -230,7 +315,18 @@ namespace ts.refactor { ); setTextRange(newTypeNode, typeElements[0]?.parent); changes.insertNodeBefore(file, firstStatement, ignoreSourceNewlines(newTypeNode), /* blankLineBetween */ true); - changes.replaceNode(file, selection, factory.createTypeReferenceNode(name, typeParameters.map(id => factory.createTypeReferenceNode(id.name, /* typeArguments */ undefined))), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.ExcludeWhitespace }); + changes.replaceNode( + file, + selection, + factory.createTypeReferenceNode( + name, + typeParameters.map(id => factory.createTypeReferenceNode(id.name, /* typeArguments */ undefined)), + ), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.ExcludeWhitespace, + }, + ); } function doTypedefChange(changes: textChanges.ChangeTracker, file: SourceFile, name: string, info: ExtractInfo) { @@ -256,7 +352,22 @@ namespace ts.refactor { templates.push(template); }); - changes.insertNodeBefore(file, firstStatement, factory.createJSDocComment(/* comment */ undefined, factory.createNodeArray(concatenate(templates, [node]))), /* blankLineBetween */ true); - changes.replaceNode(file, selection, factory.createTypeReferenceNode(name, typeParameters.map(id => factory.createTypeReferenceNode(id.name, /* typeArguments */ undefined)))); + changes.insertNodeBefore( + file, + firstStatement, + factory.createJSDocComment( + /* comment */ undefined, + factory.createNodeArray(concatenate(templates, [node])), + ), + /* blankLineBetween */ true, + ); + changes.replaceNode( + file, + selection, + factory.createTypeReferenceNode( + name, + typeParameters.map(id => factory.createTypeReferenceNode(id.name, /* typeArguments */ undefined)), + ), + ); } } diff --git a/src/services/refactors/generateGetAccessorAndSetAccessor.ts b/src/services/refactors/generateGetAccessorAndSetAccessor.ts index a5f2201047e52..b18186b7d39ef 100644 --- a/src/services/refactors/generateGetAccessorAndSetAccessor.ts +++ b/src/services/refactors/generateGetAccessorAndSetAccessor.ts @@ -12,21 +12,45 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor { kinds: [generateGetSetAction.kind], getEditsForAction: function getRefactorActionsToGenerateGetAndSetAccessors(context, actionName) { if (!context.endPosition) return undefined; - const info = codefix.getAccessorConvertiblePropertyAtPosition(context.file, context.program, context.startPosition, context.endPosition); + const info = codefix.getAccessorConvertiblePropertyAtPosition( + context.file, + context.program, + context.startPosition, + context.endPosition, + ); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); - const edits = codefix.generateAccessorFromProperty(context.file, context.program, context.startPosition, context.endPosition, context, actionName); + const edits = codefix.generateAccessorFromProperty( + context.file, + context.program, + context.startPosition, + context.endPosition, + context, + actionName, + ); if (!edits) return undefined; const renameFilename = context.file.fileName; const nameNeedRename = info.renameAccessor ? info.accessorName : info.fieldName; const renameLocationOffset = isIdentifier(nameNeedRename) ? 0 : -1; - const renameLocation = renameLocationOffset + getRenameLocation(edits, renameFilename, nameNeedRename.text, /*preferLastLocation*/ isParameter(info.declaration)); + const renameLocation = renameLocationOffset + + getRenameLocation( + edits, + renameFilename, + nameNeedRename.text, + /*preferLastLocation*/ isParameter(info.declaration), + ); return { renameFilename, renameLocation, edits }; }, getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] { if (!context.endPosition) return emptyArray; - const info = codefix.getAccessorConvertiblePropertyAtPosition(context.file, context.program, context.startPosition, context.endPosition, context.triggerReason === "invoked"); + const info = codefix.getAccessorConvertiblePropertyAtPosition( + context.file, + context.program, + context.startPosition, + context.endPosition, + context.triggerReason === "invoked", + ); if (!info) return emptyArray; if (!isRefactorErrorInfo(info)) { diff --git a/src/services/refactors/inferFunctionReturnType.ts b/src/services/refactors/inferFunctionReturnType.ts index 0e9a4edd5e919..07d43ea212200 100644 --- a/src/services/refactors/inferFunctionReturnType.ts +++ b/src/services/refactors/inferFunctionReturnType.ts @@ -17,7 +17,10 @@ namespace ts.refactor.inferFunctionReturnType { function getRefactorEditsToInferReturnType(context: RefactorContext): RefactorEditInfo | undefined { const info = getInfo(context); if (info && !isRefactorErrorInfo(info)) { - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, t, info.declaration, info.returnTypeNode)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(context.file, t, info.declaration, info.returnTypeNode), + ); return { renameFilename: undefined, renameLocation: undefined, edits }; } return undefined; @@ -54,7 +57,12 @@ namespace ts.refactor.inferFunctionReturnType { returnTypeNode: TypeNode; } - function doChange(sourceFile: SourceFile, changes: textChanges.ChangeTracker, declaration: ConvertibleDeclaration, typeNode: TypeNode) { + function doChange( + sourceFile: SourceFile, + changes: textChanges.ChangeTracker, + declaration: ConvertibleDeclaration, + typeNode: TypeNode, + ) { const closeParen = findChildOfKind(declaration, SyntaxKind.CloseParenToken, sourceFile); const needParens = isArrowFunction(declaration) && closeParen === undefined; const endNode = needParens ? first(declaration.parameters) : closeParen; @@ -71,9 +79,13 @@ namespace ts.refactor.inferFunctionReturnType { if (isInJSFile(context.file) || !refactorKindBeginsWith(inferReturnTypeAction.kind, context.kind)) return; const token = getTokenAtPosition(context.file, context.startPosition); - const declaration = findAncestor(token, n => - isBlock(n) || n.parent && isArrowFunction(n.parent) && (n.kind === SyntaxKind.EqualsGreaterThanToken || n.parent.body === n) ? "quit" : - isConvertibleDeclaration(n)) as ConvertibleDeclaration | undefined; + const declaration = findAncestor( + token, + n => isBlock(n) + || n.parent && isArrowFunction(n.parent) + && (n.kind === SyntaxKind.EqualsGreaterThanToken || n.parent.body === n) ? "quit" + : isConvertibleDeclaration(n), + ) as ConvertibleDeclaration | undefined; if (!declaration || !declaration.body || declaration.type) { return { error: getLocaleSpecificMessage(Diagnostics.Return_type_must_be_inferred_from_a_function) }; } diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts index 6e8cf53a7f45d..9d42a973cd94a 100644 --- a/src/services/refactors/moveToNewFile.ts +++ b/src/services/refactors/moveToNewFile.ts @@ -16,14 +16,26 @@ namespace ts.refactor { return [{ name: refactorName, description, actions: [moveToNewFileAction] }]; } if (context.preferences.provideRefactorNotApplicableReason) { - return [{ name: refactorName, description, actions: [{ ...moveToNewFileAction, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_statement_or_statements) }] }]; + return [{ + name: refactorName, + description, + actions: [{ + ...moveToNewFileAction, + notApplicableReason: getLocaleSpecificMessage( + Diagnostics.Selection_is_not_a_valid_statement_or_statements, + ), + }], + }]; } return emptyArray; }, getEditsForAction: function getRefactorEditsToMoveToNewFile(context, actionName): RefactorEditInfo { Debug.assert(actionName === refactorName, "Wrong refactor invoked"); const statements = Debug.checkDefined(getStatementsToMove(context)); - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, statements, t, context.host, context.preferences)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(context.file, context.program, statements, t, context.host, context.preferences), + ); return { edits, renameFilename: undefined, renameLocation: undefined }; }, }); @@ -41,7 +53,9 @@ namespace ts.refactor { if (startNodeIndex === -1) return undefined; const startStatement = statements[startNodeIndex]; - if (isNamedDeclaration(startStatement) && startStatement.name && rangeContainsRange(startStatement.name, range)) { + if ( + isNamedDeclaration(startStatement) && startStatement.name && rangeContainsRange(startStatement.name, range) + ) { return { toMove: [statements[startNodeIndex]], afterLast: statements[startNodeIndex + 1] }; } @@ -49,7 +63,10 @@ namespace ts.refactor { if (range.pos > startStatement.getStart(file)) return undefined; const afterEndNodeIndex = findIndex(statements, s => s.end > range.end, startNodeIndex); // Can't be partially into the next node - if (afterEndNodeIndex !== -1 && (afterEndNodeIndex === 0 || statements[afterEndNodeIndex].getStart(file) < range.end)) return undefined; + if ( + afterEndNodeIndex !== -1 + && (afterEndNodeIndex === 0 || statements[afterEndNodeIndex].getStart(file) < range.end) + ) return undefined; return { toMove: statements.slice(startNodeIndex, afterEndNodeIndex === -1 ? statements.length : afterEndNodeIndex), @@ -57,19 +74,41 @@ namespace ts.refactor { }; } - function doChange(oldFile: SourceFile, program: Program, toMove: ToMove, changes: textChanges.ChangeTracker, host: LanguageServiceHost, preferences: UserPreferences): void { + function doChange( + oldFile: SourceFile, + program: Program, + toMove: ToMove, + changes: textChanges.ChangeTracker, + host: LanguageServiceHost, + preferences: UserPreferences, + ): void { const checker = program.getTypeChecker(); const usage = getUsageInfo(oldFile, toMove.all, checker); const currentDirectory = getDirectoryPath(oldFile.fileName); const extension = extensionFromPath(oldFile.fileName); - const newModuleName = makeUniqueModuleName(getNewModuleName(usage.oldFileImportsFromNewFile, usage.movedSymbols), extension, currentDirectory, host); + const newModuleName = makeUniqueModuleName( + getNewModuleName(usage.oldFileImportsFromNewFile, usage.movedSymbols), + extension, + currentDirectory, + host, + ); const newFileNameWithExtension = newModuleName + extension; // If previous file was global, this is easy. - changes.createNewFile(oldFile, combinePaths(currentDirectory, newFileNameWithExtension), getNewStatementsAndRemoveFromOldFile(oldFile, usage, changes, toMove, program, newModuleName, preferences)); + changes.createNewFile( + oldFile, + combinePaths(currentDirectory, newFileNameWithExtension), + getNewStatementsAndRemoveFromOldFile(oldFile, usage, changes, toMove, program, newModuleName, preferences), + ); - addNewFileToTsconfig(program, changes, oldFile.fileName, newFileNameWithExtension, hostGetCanonicalFileName(host)); + addNewFileToTsconfig( + program, + changes, + oldFile.fileName, + newFileNameWithExtension, + hostGetCanonicalFileName(host), + ); } interface StatementRange { @@ -108,13 +147,21 @@ namespace ts.refactor { case SyntaxKind.ImportEqualsDeclaration: return !hasSyntacticModifier(node, ModifierFlags.Export); case SyntaxKind.VariableStatement: - return (node as VariableStatement).declarationList.declarations.every(d => !!d.initializer && isRequireCall(d.initializer, /*checkArgumentIsStringLiteralLike*/ true)); + return (node as VariableStatement).declarationList.declarations.every(d => + !!d.initializer && isRequireCall(d.initializer, /*checkArgumentIsStringLiteralLike*/ true) + ); default: return false; } } - function addNewFileToTsconfig(program: Program, changes: textChanges.ChangeTracker, oldFileName: string, newFileNameWithExtension: string, getCanonicalFileName: GetCanonicalFileName): void { + function addNewFileToTsconfig( + program: Program, + changes: textChanges.ChangeTracker, + oldFileName: string, + newFileNameWithExtension: string, + getCanonicalFileName: GetCanonicalFileName, + ): void { const cfg = program.getCompilerOptions().configFile; if (!cfg) return; @@ -122,9 +169,19 @@ namespace ts.refactor { const newFilePath = getRelativePathFromFile(cfg.fileName, newFileAbsolutePath, getCanonicalFileName); const cfgObject = cfg.statements[0] && tryCast(cfg.statements[0].expression, isObjectLiteralExpression); - const filesProp = cfgObject && find(cfgObject.properties, (prop): prop is PropertyAssignment => isPropertyAssignment(prop) && isStringLiteral(prop.name) && prop.name.text === "files"); + const filesProp = cfgObject + && find( + cfgObject.properties, + (prop): prop is PropertyAssignment => + isPropertyAssignment(prop) && isStringLiteral(prop.name) && prop.name.text === "files", + ); if (filesProp && isArrayLiteralExpression(filesProp.initializer)) { - changes.insertNodeInListAfter(cfg, last(filesProp.initializer.elements), factory.createStringLiteral(newFilePath), filesProp.initializer.elements); + changes.insertNodeInListAfter( + cfg, + last(filesProp.initializer.elements), + factory.createStringLiteral(newFilePath), + filesProp.initializer.elements, + ); } } @@ -146,7 +203,12 @@ namespace ts.refactor { const useEsModuleSyntax = !!oldFile.externalModuleIndicator; const quotePreference = getQuotePreference(oldFile, preferences); - const importsFromNewFile = createOldFileImportsFromNewFile(usage.oldFileImportsFromNewFile, newModuleName, useEsModuleSyntax, quotePreference); + const importsFromNewFile = createOldFileImportsFromNewFile( + usage.oldFileImportsFromNewFile, + newModuleName, + useEsModuleSyntax, + quotePreference, + ); if (importsFromNewFile) { insertImports(changes, oldFile, importsFromNewFile, /*blankLineBetween*/ true); } @@ -155,7 +217,15 @@ namespace ts.refactor { deleteMovedStatements(oldFile, toMove.ranges, changes); updateImportsInOtherFiles(changes, program, oldFile, usage.movedSymbols, newModuleName); - const imports = getNewFileImportsAndAddExportInOldFile(oldFile, usage.oldImportsNeededByNewFile, usage.newFileImportsFromOldFile, changes, checker, useEsModuleSyntax, quotePreference); + const imports = getNewFileImportsAndAddExportInOldFile( + oldFile, + usage.oldImportsNeededByNewFile, + usage.newFileImportsFromOldFile, + changes, + checker, + useEsModuleSyntax, + quotePreference, + ); const body = addExports(oldFile, toMove.all, usage.oldFileImportsFromNewFile, useEsModuleSyntax); if (imports.length && body.length) { return [ @@ -173,20 +243,39 @@ namespace ts.refactor { ]; } - function deleteMovedStatements(sourceFile: SourceFile, moved: readonly StatementRange[], changes: textChanges.ChangeTracker) { + function deleteMovedStatements( + sourceFile: SourceFile, + moved: readonly StatementRange[], + changes: textChanges.ChangeTracker, + ) { for (const { first, afterLast } of moved) { changes.deleteNodeRangeExcludingEnd(sourceFile, first, afterLast); } } - function deleteUnusedOldImports(oldFile: SourceFile, toMove: readonly Statement[], changes: textChanges.ChangeTracker, toDelete: ReadonlySymbolSet, checker: TypeChecker) { + function deleteUnusedOldImports( + oldFile: SourceFile, + toMove: readonly Statement[], + changes: textChanges.ChangeTracker, + toDelete: ReadonlySymbolSet, + checker: TypeChecker, + ) { for (const statement of oldFile.statements) { if (contains(toMove, statement)) continue; - forEachImportInStatement(statement, i => deleteUnusedImports(oldFile, i, changes, name => toDelete.has(checker.getSymbolAtLocation(name)!))); + forEachImportInStatement( + statement, + i => deleteUnusedImports(oldFile, i, changes, name => toDelete.has(checker.getSymbolAtLocation(name)!)), + ); } } - function updateImportsInOtherFiles(changes: textChanges.ChangeTracker, program: Program, oldFile: SourceFile, movedSymbols: ReadonlySymbolSet, newModuleName: string): void { + function updateImportsInOtherFiles( + changes: textChanges.ChangeTracker, + program: Program, + oldFile: SourceFile, + movedSymbols: ReadonlySymbolSet, + newModuleName: string, + ): void { const checker = program.getTypeChecker(); for (const sourceFile of program.getSourceFiles()) { if (sourceFile === oldFile) continue; @@ -196,17 +285,38 @@ namespace ts.refactor { const shouldMove = (name: Identifier): boolean => { const symbol = isBindingElement(name.parent) - ? getPropertySymbolFromBindingElement(checker, name.parent as ObjectBindingElementWithoutPropertyName) + ? getPropertySymbolFromBindingElement( + checker, + name.parent as ObjectBindingElementWithoutPropertyName, + ) : skipAlias(checker.getSymbolAtLocation(name)!, checker); // TODO: GH#18217 return !!symbol && movedSymbols.has(symbol); }; deleteUnusedImports(sourceFile, importNode, changes, shouldMove); // These will be changed to imports from the new file - const newModuleSpecifier = combinePaths(getDirectoryPath(moduleSpecifierFromImport(importNode).text), newModuleName); - const newImportDeclaration = filterImport(importNode, factory.createStringLiteral(newModuleSpecifier), shouldMove); + const newModuleSpecifier = combinePaths( + getDirectoryPath(moduleSpecifierFromImport(importNode).text), + newModuleName, + ); + const newImportDeclaration = filterImport( + importNode, + factory.createStringLiteral(newModuleSpecifier), + shouldMove, + ); if (newImportDeclaration) changes.insertNodeAfter(sourceFile, statement, newImportDeclaration); const ns = getNamespaceLikeImport(importNode); - if (ns) updateNamespaceLikeImport(changes, sourceFile, checker, movedSymbols, newModuleName, newModuleSpecifier, ns, importNode); + if (ns) { + updateNamespaceLikeImport( + changes, + sourceFile, + checker, + movedSymbols, + newModuleName, + newModuleSpecifier, + ns, + importNode, + ); + } }); } } @@ -215,8 +325,9 @@ namespace ts.refactor { function getNamespaceLikeImport(node: SupportedImport): Identifier | undefined { switch (node.kind) { case SyntaxKind.ImportDeclaration: - return node.importClause && node.importClause.namedBindings && node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport ? - node.importClause.namedBindings.name : undefined; + return node.importClause && node.importClause.namedBindings + && node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport + ? node.importClause.namedBindings.name : undefined; case SyntaxKind.ImportEqualsDeclaration: return node.name; case SyntaxKind.VariableDeclaration: @@ -241,36 +352,60 @@ namespace ts.refactor { const toChange: Identifier[] = []; FindAllReferences.Core.eachSymbolReferenceInFile(oldImportId, checker, sourceFile, ref => { if (!isPropertyAccessExpression(ref.parent)) return; - needUniqueName = needUniqueName || !!checker.resolveName(preferredNewNamespaceName, ref, SymbolFlags.All, /*excludeGlobals*/ true); + needUniqueName = needUniqueName + || !!checker.resolveName(preferredNewNamespaceName, ref, SymbolFlags.All, /*excludeGlobals*/ true); if (movedSymbols.has(checker.getSymbolAtLocation(ref.parent.name)!)) { toChange.push(ref); } }); if (toChange.length) { - const newNamespaceName = needUniqueName ? getUniqueName(preferredNewNamespaceName, sourceFile) : preferredNewNamespaceName; + const newNamespaceName = needUniqueName ? getUniqueName(preferredNewNamespaceName, sourceFile) + : preferredNewNamespaceName; for (const ref of toChange) { changes.replaceNode(sourceFile, ref, factory.createIdentifier(newNamespaceName)); } - changes.insertNodeAfter(sourceFile, oldImportNode, updateNamespaceLikeImportNode(oldImportNode, newModuleName, newModuleSpecifier)); + changes.insertNodeAfter( + sourceFile, + oldImportNode, + updateNamespaceLikeImportNode(oldImportNode, newModuleName, newModuleSpecifier), + ); } } - function updateNamespaceLikeImportNode(node: SupportedImport, newNamespaceName: string, newModuleSpecifier: string): Node { + function updateNamespaceLikeImportNode( + node: SupportedImport, + newNamespaceName: string, + newModuleSpecifier: string, + ): Node { const newNamespaceId = factory.createIdentifier(newNamespaceName); const newModuleString = factory.createStringLiteral(newModuleSpecifier); switch (node.kind) { case SyntaxKind.ImportDeclaration: return factory.createImportDeclaration( /*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(newNamespaceId)), + factory.createImportClause( + /*isTypeOnly*/ false, + /*name*/ undefined, + factory.createNamespaceImport(newNamespaceId), + ), newModuleString, /*assertClause*/ undefined, ); case SyntaxKind.ImportEqualsDeclaration: - return factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, newNamespaceId, factory.createExternalModuleReference(newModuleString)); + return factory.createImportEqualsDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + newNamespaceId, + factory.createExternalModuleReference(newModuleString), + ); case SyntaxKind.VariableDeclaration: - return factory.createVariableDeclaration(newNamespaceId, /*exclamationToken*/ undefined, /*type*/ undefined, createRequireCall(newModuleString)); + return factory.createVariableDeclaration( + newNamespaceId, + /*exclamationToken*/ undefined, + /*type*/ undefined, + createRequireCall(newModuleString), + ); default: return Debug.assertNever(node, `Unexpected node kind ${(node as SupportedImport).kind}`); } @@ -287,7 +422,10 @@ namespace ts.refactor { if (isStringLiteral(statement.moduleSpecifier)) cb(statement as SupportedImport); } else if (isImportEqualsDeclaration(statement)) { - if (isExternalModuleReference(statement.moduleReference) && isStringLiteralLike(statement.moduleReference.expression)) { + if ( + isExternalModuleReference(statement.moduleReference) + && isStringLiteralLike(statement.moduleReference.expression) + ) { cb(statement as SupportedImport); } } @@ -309,7 +447,12 @@ namespace ts.refactor { | ImportEqualsDeclaration | VariableStatement; - function createOldFileImportsFromNewFile(newFileNeedExport: ReadonlySymbolSet, newFileNameWithExtension: string, useEs6Imports: boolean, quotePreference: QuotePreference): AnyImportOrRequireStatement | undefined { + function createOldFileImportsFromNewFile( + newFileNeedExport: ReadonlySymbolSet, + newFileNameWithExtension: string, + useEs6Imports: boolean, + quotePreference: QuotePreference, + ): AnyImportOrRequireStatement | undefined { let defaultImport: Identifier | undefined; const imports: string[] = []; newFileNeedExport.forEach(symbol => { @@ -323,35 +466,70 @@ namespace ts.refactor { return makeImportOrRequire(defaultImport, imports, newFileNameWithExtension, useEs6Imports, quotePreference); } - function makeImportOrRequire(defaultImport: Identifier | undefined, imports: readonly string[], path: string, useEs6Imports: boolean, quotePreference: QuotePreference): AnyImportOrRequireStatement | undefined { + function makeImportOrRequire( + defaultImport: Identifier | undefined, + imports: readonly string[], + path: string, + useEs6Imports: boolean, + quotePreference: QuotePreference, + ): AnyImportOrRequireStatement | undefined { path = ensurePathIsNonModuleName(path); if (useEs6Imports) { - const specifiers = imports.map(i => factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, factory.createIdentifier(i))); + const specifiers = imports.map(i => + factory.createImportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + factory.createIdentifier(i), + ) + ); return makeImportIfNecessary(defaultImport, specifiers, path, quotePreference); } else { Debug.assert(!defaultImport, "No default import should exist"); // If there's a default export, it should have been an es6 module. - const bindingElements = imports.map(i => factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, i)); + const bindingElements = imports.map(i => + factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, i) + ); return bindingElements.length - ? makeVariableStatement(factory.createObjectBindingPattern(bindingElements), /*type*/ undefined, createRequireCall(factory.createStringLiteral(path))) as RequireVariableStatement + ? makeVariableStatement( + factory.createObjectBindingPattern(bindingElements), + /*type*/ undefined, + createRequireCall(factory.createStringLiteral(path)), + ) as RequireVariableStatement : undefined; } } - function makeVariableStatement(name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined, flags: NodeFlags = NodeFlags.Const) { - return factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, initializer)], flags)); + function makeVariableStatement( + name: BindingName, + type: TypeNode | undefined, + initializer: Expression | undefined, + flags: NodeFlags = NodeFlags.Const, + ) { + return factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([ + factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, initializer), + ], flags), + ); } function createRequireCall(moduleSpecifier: StringLiteralLike): CallExpression { - return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [moduleSpecifier]); + return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [ + moduleSpecifier, + ]); } - function addExports(sourceFile: SourceFile, toMove: readonly Statement[], needExport: ReadonlySymbolSet, useEs6Exports: boolean): readonly Statement[] { + function addExports( + sourceFile: SourceFile, + toMove: readonly Statement[], + needExport: ReadonlySymbolSet, + useEs6Exports: boolean, + ): readonly Statement[] { return flatMap(toMove, statement => { if ( - isTopLevelDeclarationStatement(statement) && - !isExported(sourceFile, statement, useEs6Exports) && - forEachTopLevelDeclaration(statement, d => needExport.has(Debug.checkDefined(d.symbol))) + isTopLevelDeclarationStatement(statement) + && !isExported(sourceFile, statement, useEs6Exports) + && forEachTopLevelDeclaration(statement, d => needExport.has(Debug.checkDefined(d.symbol))) ) { const exports = addExport(statement, useEs6Exports); if (exports) return exports; @@ -360,7 +538,12 @@ namespace ts.refactor { }); } - function deleteUnusedImports(sourceFile: SourceFile, importDecl: SupportedImport, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean): void { + function deleteUnusedImports( + sourceFile: SourceFile, + importDecl: SupportedImport, + changes: textChanges.ChangeTracker, + isUnused: (name: Identifier) => boolean, + ): void { switch (importDecl.kind) { case SyntaxKind.ImportDeclaration: deleteUnusedImportsInDeclaration(sourceFile, importDecl, changes, isUnused); @@ -377,12 +560,18 @@ namespace ts.refactor { Debug.assertNever(importDecl, `Unexpected import decl kind ${(importDecl as SupportedImport).kind}`); } } - function deleteUnusedImportsInDeclaration(sourceFile: SourceFile, importDecl: ImportDeclaration, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean): void { + function deleteUnusedImportsInDeclaration( + sourceFile: SourceFile, + importDecl: ImportDeclaration, + changes: textChanges.ChangeTracker, + isUnused: (name: Identifier) => boolean, + ): void { if (!importDecl.importClause) return; const { name, namedBindings } = importDecl.importClause; const defaultUnused = !name || isUnused(name); - const namedBindingsUnused = !namedBindings || - (namedBindings.kind === SyntaxKind.NamespaceImport ? isUnused(namedBindings.name) : namedBindings.elements.length !== 0 && namedBindings.elements.every(e => isUnused(e.name))); + const namedBindingsUnused = !namedBindings + || (namedBindings.kind === SyntaxKind.NamespaceImport ? isUnused(namedBindings.name) + : namedBindings.elements.length !== 0 && namedBindings.elements.every(e => isUnused(e.name))); if (defaultUnused && namedBindingsUnused) { changes.delete(sourceFile, importDecl); } @@ -395,7 +584,12 @@ namespace ts.refactor { changes.replaceNode( sourceFile, importDecl.importClause, - factory.updateImportClause(importDecl.importClause, importDecl.importClause.isTypeOnly, name, /*namedBindings*/ undefined), + factory.updateImportClause( + importDecl.importClause, + importDecl.importClause.isTypeOnly, + name, + /*namedBindings*/ undefined, + ), ); } else if (namedBindings.kind === SyntaxKind.NamedImports) { @@ -406,7 +600,12 @@ namespace ts.refactor { } } } - function deleteUnusedImportsInVariableDeclaration(sourceFile: SourceFile, varDecl: VariableDeclaration, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean) { + function deleteUnusedImportsInVariableDeclaration( + sourceFile: SourceFile, + varDecl: VariableDeclaration, + changes: textChanges.ChangeTracker, + isUnused: (name: Identifier) => boolean, + ) { const { name } = varDecl; switch (name.kind) { case SyntaxKind.Identifier: @@ -418,7 +617,11 @@ namespace ts.refactor { break; case SyntaxKind.ObjectBindingPattern: if (name.elements.every(e => isIdentifier(e.name) && isUnused(e.name))) { - changes.delete(sourceFile, isVariableDeclarationList(varDecl.parent) && varDecl.parent.declarations.length === 1 ? varDecl.parent.parent : varDecl); + changes.delete( + sourceFile, + isVariableDeclarationList(varDecl.parent) && varDecl.parent.declarations.length === 1 + ? varDecl.parent.parent : varDecl, + ); } else { for (const element of name.elements) { @@ -443,7 +646,14 @@ namespace ts.refactor { const copiedOldImports: SupportedImportStatement[] = []; for (const oldStatement of oldFile.statements) { forEachImportInStatement(oldStatement, i => { - append(copiedOldImports, filterImport(i, moduleSpecifierFromImport(i), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + append( + copiedOldImports, + filterImport( + i, + moduleSpecifierFromImport(i), + name => importsToCopy.has(checker.getSymbolAtLocation(name)!), + ), + ); }); } @@ -473,11 +683,25 @@ namespace ts.refactor { } }); - append(copiedOldImports, makeImportOrRequire(oldFileDefault, oldFileNamedImports, removeFileExtension(getBaseFileName(oldFile.fileName)), useEsModuleSyntax, quotePreference)); + append( + copiedOldImports, + makeImportOrRequire( + oldFileDefault, + oldFileNamedImports, + removeFileExtension(getBaseFileName(oldFile.fileName)), + useEsModuleSyntax, + quotePreference, + ), + ); return copiedOldImports; } - function makeUniqueModuleName(moduleName: string, extension: string, inDirectory: string, host: LanguageServiceHost): string { + function makeUniqueModuleName( + moduleName: string, + extension: string, + inDirectory: string, + host: LanguageServiceHost, + ): string { let newModuleName = moduleName; for (let i = 1;; i++) { const name = combinePaths(inDirectory, newModuleName + extension); @@ -487,7 +711,8 @@ namespace ts.refactor { } function getNewModuleName(importsFromNewFile: ReadonlySymbolSet, movedSymbols: ReadonlySymbolSet): string { - return importsFromNewFile.forEachEntry(symbolNameNoDefault) || movedSymbols.forEachEntry(symbolNameNoDefault) || "newFile"; + return importsFromNewFile.forEachEntry(symbolNameNoDefault) || movedSymbols.forEachEntry(symbolNameNoDefault) + || "newFile"; } interface UsageInfo { @@ -516,7 +741,12 @@ namespace ts.refactor { for (const statement of toMove) { forEachTopLevelDeclaration(statement, decl => { - movedSymbols.add(Debug.checkDefined(isExpressionStatement(decl) ? checker.getSymbolAtLocation(decl.expression.left) : decl.symbol, "Need a symbol here")); + movedSymbols.add( + Debug.checkDefined( + isExpressionStatement(decl) ? checker.getSymbolAtLocation(decl.expression.left) : decl.symbol, + "Need a symbol here", + ), + ); }); } for (const statement of toMove) { @@ -526,7 +756,10 @@ namespace ts.refactor { if (isInImport(decl)) { oldImportsNeededByNewFile.add(symbol); } - else if (isTopLevelDeclaration(decl) && sourceFileOfTopLevelDeclaration(decl) === oldFile && !movedSymbols.has(symbol)) { + else if ( + isTopLevelDeclaration(decl) && sourceFileOfTopLevelDeclaration(decl) === oldFile + && !movedSymbols.has(symbol) + ) { newFileImportsFromOldFile.add(symbol); } } @@ -550,7 +783,13 @@ namespace ts.refactor { }); } - return { movedSymbols, newFileImportsFromOldFile, oldFileImportsFromNewFile, oldImportsNeededByNewFile, unusedImportsFromOldFile }; + return { + movedSymbols, + newFileImportsFromOldFile, + oldFileImportsFromNewFile, + oldImportsNeededByNewFile, + unusedImportsFromOldFile, + }; function getJsxNamespaceSymbol(containsJsx: Node | undefined) { if (containsJsx === undefined) { @@ -562,7 +801,12 @@ namespace ts.refactor { // Strictly speaking, this could resolve to a symbol other than the JSX namespace. // This will produce erroneous output (probably, an incorrectly copied import) but // is expected to be very rare and easily reversible. - const jsxNamespaceSymbol = checker.resolveName(jsxNamespace, containsJsx, SymbolFlags.Namespace, /*excludeGlobals*/ true); + const jsxNamespaceSymbol = checker.resolveName( + jsxNamespace, + containsJsx, + SymbolFlags.Namespace, + /*excludeGlobals*/ true, + ); return !!jsxNamespaceSymbol && some(jsxNamespaceSymbol.declarations, isInImport) ? jsxNamespaceSymbol @@ -588,11 +832,15 @@ namespace ts.refactor { } } function isVariableDeclarationInImport(decl: VariableDeclaration) { - return isSourceFile(decl.parent.parent.parent) && - !!decl.initializer && isRequireCall(decl.initializer, /*checkArgumentIsStringLiteralLike*/ true); + return isSourceFile(decl.parent.parent.parent) + && !!decl.initializer && isRequireCall(decl.initializer, /*checkArgumentIsStringLiteralLike*/ true); } - function filterImport(i: SupportedImport, moduleSpecifier: StringLiteralLike, keep: (name: Identifier) => boolean): SupportedImportStatement | undefined { + function filterImport( + i: SupportedImport, + moduleSpecifier: StringLiteralLike, + keep: (name: Identifier) => boolean, + ): SupportedImportStatement | undefined { switch (i.kind) { case SyntaxKind.ImportDeclaration: { const clause = i.importClause; @@ -600,20 +848,29 @@ namespace ts.refactor { const defaultImport = clause.name && keep(clause.name) ? clause.name : undefined; const namedBindings = clause.namedBindings && filterNamedBindings(clause.namedBindings, keep); return defaultImport || namedBindings - ? factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImport, namedBindings), moduleSpecifier, /*assertClause*/ undefined) + ? factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause(/*isTypeOnly*/ false, defaultImport, namedBindings), + moduleSpecifier, + /*assertClause*/ undefined, + ) : undefined; } case SyntaxKind.ImportEqualsDeclaration: return keep(i.name) ? i : undefined; case SyntaxKind.VariableDeclaration: { const name = filterBindingName(i.name, keep); - return name ? makeVariableStatement(name, i.type, createRequireCall(moduleSpecifier), i.parent.flags) : undefined; + return name ? makeVariableStatement(name, i.type, createRequireCall(moduleSpecifier), i.parent.flags) + : undefined; } default: return Debug.assertNever(i, `Unexpected import kind ${(i as SupportedImport).kind}`); } } - function filterNamedBindings(namedBindings: NamedImportBindings, keep: (name: Identifier) => boolean): NamedImportBindings | undefined { + function filterNamedBindings( + namedBindings: NamedImportBindings, + keep: (name: Identifier) => boolean, + ): NamedImportBindings | undefined { if (namedBindings.kind === SyntaxKind.NamespaceImport) { return keep(namedBindings.name) ? namedBindings : undefined; } @@ -630,7 +887,9 @@ namespace ts.refactor { return name; case SyntaxKind.ObjectBindingPattern: { // We can't handle nested destructurings or property names well here, so just copy them all. - const newElements = name.elements.filter(prop => prop.propertyName || !isIdentifier(prop.name) || keep(prop.name)); + const newElements = name.elements.filter(prop => + prop.propertyName || !isIdentifier(prop.name) || keep(prop.name) + ); return newElements.length ? factory.createObjectBindingPattern(newElements) : undefined; } } @@ -677,7 +936,9 @@ namespace ts.refactor { } } - type TopLevelExpressionStatement = ExpressionStatement & { expression: BinaryExpression & { left: PropertyAccessExpression; }; }; // 'exports.x = ...' + type TopLevelExpressionStatement = ExpressionStatement & { + expression: BinaryExpression & { left: PropertyAccessExpression; }; + }; // 'exports.x = ...' type NonVariableTopLevelDeclaration = | FunctionDeclaration | ClassDeclaration @@ -693,7 +954,8 @@ namespace ts.refactor { } type TopLevelDeclaration = NonVariableTopLevelDeclaration | TopLevelVariableDeclaration | BindingElement; function isTopLevelDeclaration(node: Node): node is TopLevelDeclaration { - return isNonVariableTopLevelDeclaration(node) && isSourceFile(node.parent) || isVariableDeclaration(node) && isSourceFile(node.parent.parent.parent); + return isNonVariableTopLevelDeclaration(node) && isSourceFile(node.parent) + || isVariableDeclaration(node) && isSourceFile(node.parent.parent.parent); } function sourceFileOfTopLevelDeclaration(node: TopLevelDeclaration): Node { @@ -729,26 +991,51 @@ namespace ts.refactor { case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.ImportEqualsDeclaration: - return cb(statement as FunctionDeclaration | ClassDeclaration | EnumDeclaration | ModuleDeclaration | TypeAliasDeclaration | InterfaceDeclaration | ImportEqualsDeclaration); + return cb( + statement as + | FunctionDeclaration + | ClassDeclaration + | EnumDeclaration + | ModuleDeclaration + | TypeAliasDeclaration + | InterfaceDeclaration + | ImportEqualsDeclaration, + ); case SyntaxKind.VariableStatement: - return firstDefined((statement as VariableStatement).declarationList.declarations, decl => forEachTopLevelDeclarationInBindingName(decl.name, cb)); + return firstDefined( + (statement as VariableStatement).declarationList.declarations, + decl => forEachTopLevelDeclarationInBindingName(decl.name, cb), + ); case SyntaxKind.ExpressionStatement: { const { expression } = statement as ExpressionStatement; - return isBinaryExpression(expression) && getAssignmentDeclarationKind(expression) === AssignmentDeclarationKind.ExportsProperty + return isBinaryExpression(expression) + && getAssignmentDeclarationKind(expression) === AssignmentDeclarationKind.ExportsProperty ? cb(statement as TopLevelExpressionStatement) : undefined; } } } - function forEachTopLevelDeclarationInBindingName(name: BindingName, cb: (node: TopLevelDeclaration) => T): T | undefined { + function forEachTopLevelDeclarationInBindingName( + name: BindingName, + cb: (node: TopLevelDeclaration) => T, + ): T | undefined { switch (name.kind) { case SyntaxKind.Identifier: - return cb(cast(name.parent, (x): x is TopLevelVariableDeclaration | BindingElement => isVariableDeclaration(x) || isBindingElement(x))); + return cb( + cast( + name.parent, + (x): x is TopLevelVariableDeclaration | BindingElement => + isVariableDeclaration(x) || isBindingElement(x), + ), + ); case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ObjectBindingPattern: - return firstDefined(name.elements, em => isOmittedExpression(em) ? undefined : forEachTopLevelDeclarationInBindingName(em.name, cb)); + return firstDefined( + name.elements, + em => isOmittedExpression(em) ? undefined : forEachTopLevelDeclarationInBindingName(em.name, cb), + ); default: return Debug.assertNever(name, `Unexpected name kind ${(name as BindingName).kind}`); } @@ -764,14 +1051,24 @@ namespace ts.refactor { return d.parent.parent; case SyntaxKind.BindingElement: return getTopLevelDeclarationStatement( - cast(d.parent.parent, (p): p is TopLevelVariableDeclaration | BindingElement => isVariableDeclaration(p) || isBindingElement(p)), + cast( + d.parent.parent, + (p): p is TopLevelVariableDeclaration | BindingElement => + isVariableDeclaration(p) || isBindingElement(p), + ), ); default: return d; } } - function addExportToChanges(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, name: Identifier, changes: textChanges.ChangeTracker, useEs6Exports: boolean): void { + function addExportToChanges( + sourceFile: SourceFile, + decl: TopLevelDeclarationStatement, + name: Identifier, + changes: textChanges.ChangeTracker, + useEs6Exports: boolean, + ): void { if (isExported(sourceFile, decl, useEs6Exports, name)) return; if (useEs6Exports) { if (!isExpressionStatement(decl)) changes.insertExportModifier(sourceFile, decl); @@ -782,24 +1079,49 @@ namespace ts.refactor { } } - function isExported(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, useEs6Exports: boolean, name?: Identifier): boolean { + function isExported( + sourceFile: SourceFile, + decl: TopLevelDeclarationStatement, + useEs6Exports: boolean, + name?: Identifier, + ): boolean { if (useEs6Exports) { - return !isExpressionStatement(decl) && hasSyntacticModifier(decl, ModifierFlags.Export) || !!(name && sourceFile.symbol.exports?.has(name.escapedText)); + return !isExpressionStatement(decl) && hasSyntacticModifier(decl, ModifierFlags.Export) + || !!(name && sourceFile.symbol.exports?.has(name.escapedText)); } - return getNamesToExportInCommonJS(decl).some(name => sourceFile.symbol.exports!.has(escapeLeadingUnderscores(name))); + return getNamesToExportInCommonJS(decl).some(name => + sourceFile.symbol.exports!.has(escapeLeadingUnderscores(name)) + ); } function addExport(decl: TopLevelDeclarationStatement, useEs6Exports: boolean): readonly Statement[] | undefined { return useEs6Exports ? [addEs6Export(decl)] : addCommonjsExport(decl); } function addEs6Export(d: TopLevelDeclarationStatement): TopLevelDeclarationStatement { - const modifiers = canHaveModifiers(d) ? concatenate([factory.createModifier(SyntaxKind.ExportKeyword)], getModifiers(d)) : undefined; + const modifiers = canHaveModifiers(d) + ? concatenate([factory.createModifier(SyntaxKind.ExportKeyword)], getModifiers(d)) : undefined; switch (d.kind) { case SyntaxKind.FunctionDeclaration: - return factory.updateFunctionDeclaration(d, modifiers, d.asteriskToken, d.name, d.typeParameters, d.parameters, d.type, d.body); + return factory.updateFunctionDeclaration( + d, + modifiers, + d.asteriskToken, + d.name, + d.typeParameters, + d.parameters, + d.type, + d.body, + ); case SyntaxKind.ClassDeclaration: const decorators = canHaveDecorators(d) ? getDecorators(d) : undefined; - return factory.updateClassDeclaration(d, concatenate(decorators, modifiers), d.name, d.typeParameters, d.heritageClauses, d.members); + return factory.updateClassDeclaration( + d, + concatenate(decorators, modifiers), + d.name, + d.typeParameters, + d.heritageClauses, + d.members, + ); case SyntaxKind.VariableStatement: return factory.updateVariableStatement(d, modifiers, d.declarationList); case SyntaxKind.ModuleDeclaration: @@ -809,7 +1131,14 @@ namespace ts.refactor { case SyntaxKind.TypeAliasDeclaration: return factory.updateTypeAliasDeclaration(d, modifiers, d.name, d.typeParameters, d.type); case SyntaxKind.InterfaceDeclaration: - return factory.updateInterfaceDeclaration(d, modifiers, d.name, d.typeParameters, d.heritageClauses, d.members); + return factory.updateInterfaceDeclaration( + d, + modifiers, + d.name, + d.typeParameters, + d.heritageClauses, + d.members, + ); case SyntaxKind.ImportEqualsDeclaration: return factory.updateImportEqualsDeclaration(d, modifiers, d.isTypeOnly, d.name, d.moduleReference); case SyntaxKind.ExpressionStatement: @@ -827,7 +1156,10 @@ namespace ts.refactor { case SyntaxKind.ClassDeclaration: return [decl.name!.text]; // TODO: GH#18217 case SyntaxKind.VariableStatement: - return mapDefined(decl.declarationList.declarations, d => isIdentifier(d.name) ? d.name.text : undefined); + return mapDefined( + decl.declarationList.declarations, + d => isIdentifier(d.name) ? d.name.text : undefined, + ); case SyntaxKind.ModuleDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.TypeAliasDeclaration: @@ -845,7 +1177,10 @@ namespace ts.refactor { function createExportAssignment(name: string): Statement { return factory.createExpressionStatement( factory.createBinaryExpression( - factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(name)), + factory.createPropertyAccessExpression( + factory.createIdentifier("exports"), + factory.createIdentifier(name), + ), SyntaxKind.EqualsToken, factory.createIdentifier(name), ), diff --git a/src/services/rename.ts b/src/services/rename.ts index 283f81ac07fb1..a432df1ea652a 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -1,6 +1,11 @@ /* @internal */ namespace ts.Rename { - export function getRenameInfo(program: Program, sourceFile: SourceFile, position: number, preferences: UserPreferences): RenameInfo { + export function getRenameInfo( + program: Program, + sourceFile: SourceFile, + position: number, + preferences: UserPreferences, + ): RenameInfo { const node = getAdjustedRenameLocation(getTouchingPropertyName(sourceFile, position)); if (nodeIsEligibleForRename(node)) { const renameInfo = getRenameInfoForNode(node, program.getTypeChecker(), sourceFile, program, preferences); @@ -24,7 +29,8 @@ namespace ts.Rename { const type = getContextualTypeFromParentOrAncestorTypeNode(node, typeChecker); if ( type && ((type.flags & TypeFlags.StringLiteral) || ( - (type.flags & TypeFlags.Union) && every((type as UnionType).types, type => !!(type.flags & TypeFlags.StringLiteral)) + (type.flags & TypeFlags.Union) + && every((type as UnionType).types, type => !!(type.flags & TypeFlags.StringLiteral)) )) ) { return getRenameInfoSuccess(node.text, node.text, ScriptElementKind.string, "", node, sourceFile); @@ -32,7 +38,14 @@ namespace ts.Rename { } else if (isLabelName(node)) { const name = getTextOfNode(node); - return getRenameInfoSuccess(name, name, ScriptElementKind.label, ScriptElementKindModifier.none, node, sourceFile); + return getRenameInfoSuccess( + name, + name, + ScriptElementKind.label, + ScriptElementKindModifier.none, + node, + sourceFile, + ); } return undefined; } @@ -42,11 +55,16 @@ namespace ts.Rename { // Disallow rename for elements that are defined in the standard TypeScript library. if (declarations.some(declaration => isDefinedInLibraryFile(program, declaration))) { - return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library); + return getRenameInfoError( + Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library, + ); } // Cannot rename `default` as in `import { default as foo } from "./someModule"; - if (isIdentifier(node) && node.originalKeywordKind === SyntaxKind.DefaultKeyword && symbol.parent && symbol.parent.flags & SymbolFlags.Module) { + if ( + isIdentifier(node) && node.originalKeywordKind === SyntaxKind.DefaultKeyword && symbol.parent + && symbol.parent.flags & SymbolFlags.Module + ) { return undefined; } @@ -61,12 +79,20 @@ namespace ts.Rename { } const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); - const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteralLike(node) && node.parent.kind === SyntaxKind.ComputedPropertyName) + const specifierName = (isImportOrExportSpecifierName(node) + || isStringOrNumericLiteralLike(node) && node.parent.kind === SyntaxKind.ComputedPropertyName) ? stripQuotes(getTextOfIdentifierOrLiteral(node)) : undefined; const displayName = specifierName || typeChecker.symbolToString(symbol); const fullDisplayName = specifierName || typeChecker.getFullyQualifiedName(symbol); - return getRenameInfoSuccess(displayName, fullDisplayName, kind, SymbolDisplay.getSymbolModifiers(typeChecker, symbol), node, sourceFile); + return getRenameInfoSuccess( + displayName, + fullDisplayName, + kind, + SymbolDisplay.getSymbolModifiers(typeChecker, symbol), + node, + sourceFile, + ); } function isDefinedInLibraryFile(program: Program, declaration: Node) { @@ -123,19 +149,27 @@ namespace ts.Rename { return components.slice(0, nodeModulesIdx + 2); } - function getRenameInfoForModule(node: StringLiteralLike, sourceFile: SourceFile, moduleSymbol: Symbol): RenameInfo | undefined { + function getRenameInfoForModule( + node: StringLiteralLike, + sourceFile: SourceFile, + moduleSymbol: Symbol, + ): RenameInfo | undefined { if (!isExternalModuleNameRelative(node.text)) { return getRenameInfoError(Diagnostics.You_cannot_rename_a_module_via_a_global_import); } const moduleSourceFile = moduleSymbol.declarations && find(moduleSymbol.declarations, isSourceFile); if (!moduleSourceFile) return undefined; - const withoutIndex = endsWith(node.text, "/index") || endsWith(node.text, "/index.js") ? undefined : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index"); + const withoutIndex = endsWith(node.text, "/index") || endsWith(node.text, "/index.js") ? undefined + : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index"); const name = withoutIndex === undefined ? moduleSourceFile.fileName : withoutIndex; const kind = withoutIndex === undefined ? ScriptElementKind.moduleElement : ScriptElementKind.directory; const indexAfterLastSlash = node.text.lastIndexOf("/") + 1; // Span should only be the last component of the path. + 1 to account for the quote character. - const triggerSpan = createTextSpan(node.getStart(sourceFile) + 1 + indexAfterLastSlash, node.text.length - indexAfterLastSlash); + const triggerSpan = createTextSpan( + node.getStart(sourceFile) + 1 + indexAfterLastSlash, + node.text.length - indexAfterLastSlash, + ); return { canRename: true, fileToRename: name, @@ -147,7 +181,14 @@ namespace ts.Rename { }; } - function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind: ScriptElementKind, kindModifiers: string, node: Node, sourceFile: SourceFile): RenameInfoSuccess { + function getRenameInfoSuccess( + displayName: string, + fullDisplayName: string, + kind: ScriptElementKind, + kindModifiers: string, + node: Node, + sourceFile: SourceFile, + ): RenameInfoSuccess { return { canRename: true, fileToRename: undefined, diff --git a/src/services/services.ts b/src/services/services.ts index 08060dbfc1334..2abf9fb78c11e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2,11 +2,17 @@ namespace ts { /** The version of the language service API */ export const servicesVersion = "0.8"; - function createNode(kind: TKind, pos: number, end: number, parent: Node): NodeObject | TokenObject | IdentifierObject | PrivateIdentifierObject { - const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) : - kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) : - kind === SyntaxKind.PrivateIdentifier ? new PrivateIdentifierObject(SyntaxKind.PrivateIdentifier, pos, end) : - new TokenObject(kind, pos, end); + function createNode( + kind: TKind, + pos: number, + end: number, + parent: Node, + ): NodeObject | TokenObject | IdentifierObject | PrivateIdentifierObject { + const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) + : kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) + : kind === SyntaxKind.PrivateIdentifier + ? new PrivateIdentifierObject(SyntaxKind.PrivateIdentifier, pos, end) + : new TokenObject(kind, pos, end); node.parent = parent; node.flags = parent.flags & NodeFlags.ContextFlags; return node; @@ -37,7 +43,10 @@ namespace ts { private assertHasRealPosition(message?: string) { // eslint-disable-next-line local/debug-assert - Debug.assert(!positionIsSynthesized(this.pos) && !positionIsSynthesized(this.end), message || "Node must have a real position for this operation"); + Debug.assert( + !positionIsSynthesized(this.pos) && !positionIsSynthesized(this.end), + message || "Node must have a real position for this operation", + ); } public getSourceFile(): SourceFile { @@ -96,7 +105,9 @@ namespace ts { } public getChildren(sourceFile?: SourceFileLike): Node[] { - this.assertHasRealPosition("Node without a real position cannot be scanned and thus has no token nodes - use forEachChild and collect the result if that's fine"); + this.assertHasRealPosition( + "Node without a real position cannot be scanned and thus has no token nodes - use forEachChild and collect the result if that's fine", + ); return this._children || (this._children = createChildren(this, sourceFile)); } @@ -107,10 +118,13 @@ namespace ts { return undefined; } - const child = find(children, kid => kid.kind < SyntaxKind.FirstJSDocNode || kid.kind > SyntaxKind.LastJSDocNode)!; - return child.kind < SyntaxKind.FirstNode ? - child : - child.getFirstToken(sourceFile); + const child = find( + children, + kid => kid.kind < SyntaxKind.FirstJSDocNode || kid.kind > SyntaxKind.LastJSDocNode, + )!; + return child.kind < SyntaxKind.FirstNode + ? child + : child.getFirstToken(sourceFile); } public getLastToken(sourceFile?: SourceFileLike): Node | undefined { @@ -176,7 +190,9 @@ namespace ts { const textPos = scanner.getTextPos(); if (textPos <= end) { if (token === SyntaxKind.Identifier) { - Debug.fail(`Did not expect ${Debug.formatSyntaxKind(parent.kind)} to have an Identifier in its trivia`); + Debug.fail( + `Did not expect ${Debug.formatSyntaxKind(parent.kind)} to have an Identifier in its trivia`, + ); } nodes.push(createNode(token, pos, textPos, parent)); } @@ -331,8 +347,12 @@ namespace ts { if (!this.documentationComment) { this.documentationComment = emptyArray; // Set temporarily to avoid an infinite loop finding inherited docs - if (!this.declarations && (this as Symbol as TransientSymbol).target && ((this as Symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration) { - const labelDecl = ((this as Symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration!; + if ( + !this.declarations && (this as Symbol as TransientSymbol).target + && ((this as Symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration + ) { + const labelDecl = ((this as Symbol as TransientSymbol).target as TransientSymbol) + .tupleLabelDeclaration!; this.documentationComment = getDocumentationComment([labelDecl], checker); } else { @@ -342,11 +362,17 @@ namespace ts { return this.documentationComment; } - getContextualDocumentationComment(context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] { + getContextualDocumentationComment( + context: Node | undefined, + checker: TypeChecker | undefined, + ): SymbolDisplayPart[] { if (context) { if (isGetAccessor(context)) { if (!this.contextualGetAccessorDocumentationComment) { - this.contextualGetAccessorDocumentationComment = getDocumentationComment(filter(this.declarations, isGetAccessor), checker); + this.contextualGetAccessorDocumentationComment = getDocumentationComment( + filter(this.declarations, isGetAccessor), + checker, + ); } if (length(this.contextualGetAccessorDocumentationComment)) { return this.contextualGetAccessorDocumentationComment; @@ -354,7 +380,10 @@ namespace ts { } if (isSetAccessor(context)) { if (!this.contextualSetAccessorDocumentationComment) { - this.contextualSetAccessorDocumentationComment = getDocumentationComment(filter(this.declarations, isSetAccessor), checker); + this.contextualSetAccessorDocumentationComment = getDocumentationComment( + filter(this.declarations, isSetAccessor), + checker, + ); } if (length(this.contextualSetAccessorDocumentationComment)) { return this.contextualSetAccessorDocumentationComment; @@ -376,7 +405,10 @@ namespace ts { if (context) { if (isGetAccessor(context)) { if (!this.contextualGetAccessorTags) { - this.contextualGetAccessorTags = getJsDocTagsOfDeclarations(filter(this.declarations, isGetAccessor), checker); + this.contextualGetAccessorTags = getJsDocTagsOfDeclarations( + filter(this.declarations, isGetAccessor), + checker, + ); } if (length(this.contextualGetAccessorTags)) { return this.contextualGetAccessorTags; @@ -384,7 +416,10 @@ namespace ts { } if (isSetAccessor(context)) { if (!this.contextualSetAccessorTags) { - this.contextualSetAccessorTags = getJsDocTagsOfDeclarations(filter(this.declarations, isSetAccessor), checker); + this.contextualSetAccessorTags = getJsDocTagsOfDeclarations( + filter(this.declarations, isSetAccessor), + checker, + ); } if (length(this.contextualSetAccessorTags)) { return this.contextualSetAccessorTags; @@ -588,11 +623,16 @@ namespace ts { } getDocumentationComment(): SymbolDisplayPart[] { - return this.documentationComment || (this.documentationComment = getDocumentationComment(singleElementArray(this.declaration), this.checker)); + return this.documentationComment + || (this.documentationComment = getDocumentationComment( + singleElementArray(this.declaration), + this.checker, + )); } getJsDocTags(): JSDocTagInfo[] { - return this.jsDocTags || (this.jsDocTags = getJsDocTagsOfDeclarations(singleElementArray(this.declaration), this.checker)); + return this.jsDocTags + || (this.jsDocTags = getJsDocTagsOfDeclarations(singleElementArray(this.declaration), this.checker)); } } @@ -605,7 +645,10 @@ namespace ts { return getJSDocTags(node).some(tag => tag.tagName.text === "inheritDoc" || tag.tagName.text === "inheritdoc"); } - function getJsDocTagsOfDeclarations(declarations: Declaration[] | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] { + function getJsDocTagsOfDeclarations( + declarations: Declaration[] | undefined, + checker: TypeChecker | undefined, + ): JSDocTagInfo[] { if (!declarations) return emptyArray; let tags = JsDoc.getJsDocTagsFromDeclarations(declarations, checker); @@ -615,7 +658,9 @@ namespace ts { const inheritedTags = findBaseOfDeclaration(checker, declaration, symbol => { if (!seenSymbols.has(symbol)) { seenSymbols.add(symbol); - if (declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) { + if ( + declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor + ) { return symbol.getContextualJsDocTags(declaration, checker); } return symbol.declarations?.length === 1 ? symbol.getJsDocTags() : undefined; @@ -629,7 +674,10 @@ namespace ts { return tags; } - function getDocumentationComment(declarations: readonly Declaration[] | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] { + function getDocumentationComment( + declarations: readonly Declaration[] | undefined, + checker: TypeChecker | undefined, + ): SymbolDisplayPart[] { if (!declarations) return emptyArray; let doc = JsDoc.getJsDocCommentsFromDeclarations(declarations, checker); @@ -639,21 +687,30 @@ namespace ts { const inheritedDocs = findBaseOfDeclaration(checker, declaration, symbol => { if (!seenSymbols.has(symbol)) { seenSymbols.add(symbol); - if (declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) { + if ( + declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor + ) { return symbol.getContextualDocumentationComment(declaration, checker); } return symbol.getDocumentationComment(checker); } }); // TODO: GH#16312 Return a ReadonlyArray, avoid copying inheritedDocs - if (inheritedDocs) doc = doc.length === 0 ? inheritedDocs.slice() : inheritedDocs.concat(lineBreakPart(), doc); + if (inheritedDocs) { + doc = doc.length === 0 ? inheritedDocs.slice() : inheritedDocs.concat(lineBreakPart(), doc); + } } } return doc; } - function findBaseOfDeclaration(checker: TypeChecker, declaration: Declaration, cb: (symbol: Symbol) => T[] | undefined): T[] | undefined { - const classOrInterfaceDeclaration = declaration.parent?.kind === SyntaxKind.Constructor ? declaration.parent.parent : declaration.parent; + function findBaseOfDeclaration( + checker: TypeChecker, + declaration: Declaration, + cb: (symbol: Symbol) => T[] | undefined, + ): T[] | undefined { + const classOrInterfaceDeclaration = declaration.parent?.kind === SyntaxKind.Constructor + ? declaration.parent.parent : declaration.parent; if (!classOrInterfaceDeclaration) return; const isStaticMember = hasStaticModifier(declaration); @@ -786,8 +843,10 @@ namespace ts { function getDeclarationName(declaration: Declaration) { const name = getNonAssignedNameOfDeclaration(declaration); - return name && (isComputedPropertyName(name) && isPropertyAccessExpression(name.expression) ? name.expression.name.text - : isPropertyName(name) ? getNameFromPropertyName(name) : undefined); + return name + && (isComputedPropertyName(name) && isPropertyAccessExpression(name.expression) + ? name.expression.name.text + : isPropertyName(name) ? getNameFromPropertyName(name) : undefined); } function visit(node: Node): void { @@ -804,7 +863,10 @@ namespace ts { const lastDeclaration = lastOrUndefined(declarations); // Check whether this declaration belongs to an "overload group". - if (lastDeclaration && functionDeclaration.parent === lastDeclaration.parent && functionDeclaration.symbol === lastDeclaration.symbol) { + if ( + lastDeclaration && functionDeclaration.parent === lastDeclaration.parent + && functionDeclaration.symbol === lastDeclaration.symbol + ) { // Overwrite the last declaration if it was an overload // and this one is an implementation. if (functionDeclaration.body && !(lastDeclaration as FunctionLikeDeclaration).body) { @@ -1017,19 +1079,35 @@ namespace ts { const options: CreateSourceFileOptions = { languageVersion: ScriptTarget.Latest, impliedNodeFormat: getImpliedNodeFormatForFile( - toPath(fileName, this.host.getCurrentDirectory(), this.host.getCompilerHost?.()?.getCanonicalFileName || hostGetCanonicalFileName(this.host)), + toPath( + fileName, + this.host.getCurrentDirectory(), + this.host.getCompilerHost?.()?.getCanonicalFileName || hostGetCanonicalFileName(this.host), + ), this.host.getCompilerHost?.()?.getModuleResolutionCache?.()?.getPackageJsonInfoCache(), this.host, this.host.getCompilationSettings(), ), setExternalModuleIndicator: getSetExternalModuleIndicator(this.host.getCompilationSettings()), }; - sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, options, version, /*setNodeParents*/ true, scriptKind); + sourceFile = createLanguageServiceSourceFile( + fileName, + scriptSnapshot, + options, + version, + /*setNodeParents*/ true, + scriptKind, + ); } else if (this.currentFileVersion !== version) { // This is the same file, just a newer version. Incrementally parse the file. const editRange = scriptSnapshot.getChangeRange(this.currentFileScriptSnapshot!); - sourceFile = updateLanguageServiceSourceFile(this.currentSourceFile!, scriptSnapshot, version, editRange); + sourceFile = updateLanguageServiceSourceFile( + this.currentSourceFile!, + scriptSnapshot, + version, + editRange, + ); } if (sourceFile) { @@ -1049,13 +1127,32 @@ namespace ts { sourceFile.scriptSnapshot = scriptSnapshot; } - export function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTargetOrOptions: ScriptTarget | CreateSourceFileOptions, version: string, setNodeParents: boolean, scriptKind?: ScriptKind): SourceFile { - const sourceFile = createSourceFile(fileName, getSnapshotText(scriptSnapshot), scriptTargetOrOptions, setNodeParents, scriptKind); + export function createLanguageServiceSourceFile( + fileName: string, + scriptSnapshot: IScriptSnapshot, + scriptTargetOrOptions: ScriptTarget | CreateSourceFileOptions, + version: string, + setNodeParents: boolean, + scriptKind?: ScriptKind, + ): SourceFile { + const sourceFile = createSourceFile( + fileName, + getSnapshotText(scriptSnapshot), + scriptTargetOrOptions, + setNodeParents, + scriptKind, + ); setSourceFileFields(sourceFile, scriptSnapshot, version); return sourceFile; } - export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange | undefined, aggressiveChecks?: boolean): SourceFile { + export function updateLanguageServiceSourceFile( + sourceFile: SourceFile, + scriptSnapshot: IScriptSnapshot, + version: string, + textChangeRange: TextChangeRange | undefined, + aggressiveChecks?: boolean, + ): SourceFile { // If we were given a text change range, and our version or open-ness changed, then // incrementally parse this file. if (textChangeRange) { @@ -1078,7 +1175,10 @@ namespace ts { } else { // it was actual edit, fetch the fragment of new text that correspond to new span - const changedText = scriptSnapshot.getText(textChangeRange.span.start, textChangeRange.span.start + textChangeRange.newLength); + const changedText = scriptSnapshot.getText( + textChangeRange.span.start, + textChangeRange.span.start + textChangeRange.newLength, + ); // combine prefix, changed text and suffix newText = prefix && suffix ? prefix + changedText + suffix @@ -1112,7 +1212,14 @@ namespace ts { setExternalModuleIndicator: sourceFile.setExternalModuleIndicator, }; // Otherwise, just create a new source file. - return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, options, version, /*setNodeParents*/ true, sourceFile.scriptKind); + return createLanguageServiceSourceFile( + sourceFile.fileName, + scriptSnapshot, + options, + version, + /*setNodeParents*/ true, + sourceFile.scriptKind, + ); } const NoopCancellationToken: CancellationToken = { @@ -1144,7 +1251,10 @@ namespace ts { // time has passed. private lastCancellationCheckTime = 0; - constructor(private hostCancellationToken: HostCancellationToken, private readonly throttleWaitMilliseconds = 20) { + constructor( + private hostCancellationToken: HostCancellationToken, + private readonly throttleWaitMilliseconds = 20, + ) { } public isCancellationRequested(): boolean { @@ -1209,7 +1319,10 @@ namespace ts { ]; export function createLanguageService( host: LanguageServiceHost, - documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory()), + documentRegistry: DocumentRegistry = createDocumentRegistry( + host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), + host.getCurrentDirectory(), + ), syntaxOnlyOrLanguageServiceMode?: boolean | LanguageServiceMode, ): LanguageService { let languageServiceMode: LanguageServiceMode; @@ -1218,7 +1331,8 @@ namespace ts { } else if (typeof syntaxOnlyOrLanguageServiceMode === "boolean") { // languageServiceMode = SyntaxOnly - languageServiceMode = syntaxOnlyOrLanguageServiceMode ? LanguageServiceMode.Syntactic : LanguageServiceMode.Semantic; + languageServiceMode = syntaxOnlyOrLanguageServiceMode ? LanguageServiceMode.Syntactic + : LanguageServiceMode.Semantic; } else { languageServiceMode = syntaxOnlyOrLanguageServiceMode; @@ -1326,8 +1440,17 @@ namespace ts { getDirectories: path => { return host.getDirectories ? host.getDirectories(path) : []; }, - readDirectory: (path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number) => { - Debug.checkDefined(host.readDirectory, "'LanguageServiceHost.readDirectory' must be implemented to correctly process 'projectReferences'"); + readDirectory: ( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ) => { + Debug.checkDefined( + host.readDirectory, + "'LanguageServiceHost.readDirectory' must be implemented to correctly process 'projectReferences'", + ); return host.readDirectory!(path, extensions, exclude, include, depth); }, onReleaseOldSourceFile, @@ -1369,7 +1492,19 @@ namespace ts { const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings); // If the program is already up-to-date, we can reuse it - if (isProgramUptoDate(program, rootFileNames, newSettings, (_path, fileName) => host.getScriptVersion(fileName), fileName => compilerHost!.fileExists(fileName), hasInvalidatedResolutions, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { + if ( + isProgramUptoDate( + program, + rootFileNames, + newSettings, + (_path, fileName) => host.getScriptVersion(fileName), + fileName => compilerHost!.fileExists(fileName), + hasInvalidatedResolutions, + hasChangedAutomaticTypeDirectiveNames, + getParsedCommandLine, + projectReferences, + ) + ) { return; } @@ -1408,14 +1543,16 @@ namespace ts { const existing = parsedCommandLines?.get(path); if (existing !== undefined) return existing || undefined; - const result = host.getParsedCommandLine ? - host.getParsedCommandLine(fileName) : - getParsedCommandLineOfConfigFileUsingSourceFile(fileName); + const result = host.getParsedCommandLine + ? host.getParsedCommandLine(fileName) + : getParsedCommandLineOfConfigFileUsingSourceFile(fileName); (parsedCommandLines ||= new Map()).set(path, result || false); return result; } - function getParsedCommandLineOfConfigFileUsingSourceFile(configFileName: string): ParsedCommandLine | undefined { + function getParsedCommandLineOfConfigFileUsingSourceFile( + configFileName: string, + ): ParsedCommandLine | undefined { const result = getOrCreateSourceFile(configFileName, ScriptTarget.JSON) as JsonSourceFile | undefined; if (!result) return undefined; result.path = toPath(configFileName, currentDirectory, getCanonicalFileName); @@ -1430,7 +1567,11 @@ namespace ts { ); } - function onReleaseParsedCommandLine(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, oldOptions: CompilerOptions) { + function onReleaseParsedCommandLine( + configFileName: string, + oldResolvedRef: ResolvedProjectReference | undefined, + oldOptions: CompilerOptions, + ) { if (host.getParsedCommandLine) { host.onReleaseParsedCommandLine?.(configFileName, oldResolvedRef, oldOptions); } @@ -1443,15 +1584,40 @@ namespace ts { // not part of the new program. function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) { const oldSettingsKey = documentRegistry.getKeyForCompilationSettings(oldOptions); - documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath, oldSettingsKey, oldSourceFile.scriptKind, oldSourceFile.impliedNodeFormat); + documentRegistry.releaseDocumentWithKey( + oldSourceFile.resolvedPath, + oldSettingsKey, + oldSourceFile.scriptKind, + oldSourceFile.impliedNodeFormat, + ); } - function getOrCreateSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined { - return getOrCreateSourceFileByPath(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), languageVersionOrOptions, onError, shouldCreateNewSourceFile); + function getOrCreateSourceFile( + fileName: string, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean, + ): SourceFile | undefined { + return getOrCreateSourceFileByPath( + fileName, + toPath(fileName, currentDirectory, getCanonicalFileName), + languageVersionOrOptions, + onError, + shouldCreateNewSourceFile, + ); } - function getOrCreateSourceFileByPath(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, _onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined { - Debug.assert(compilerHost, "getOrCreateSourceFileByPath called after typical CompilerHost lifetime, check the callstack something with a reference to an old host."); + function getOrCreateSourceFileByPath( + fileName: string, + path: Path, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + _onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean, + ): SourceFile | undefined { + Debug.assert( + compilerHost, + "getOrCreateSourceFileByPath called after typical CompilerHost lifetime, check the callstack something with a reference to an old host.", + ); // The program is asking for this file, check first if the host can locate it. // If the host can not locate the file, then it does not exist. return undefined // to the program to allow reporting of errors for missing files. @@ -1496,11 +1662,25 @@ namespace ts { // file's script kind, i.e. in one project some file is treated as ".ts" // and in another as ".js" if (scriptKind === oldSourceFile.scriptKind) { - return documentRegistry.updateDocumentWithKey(fileName, path, host, documentRegistryBucketKey, scriptSnapshot, scriptVersion, scriptKind, languageVersionOrOptions); + return documentRegistry.updateDocumentWithKey( + fileName, + path, + host, + documentRegistryBucketKey, + scriptSnapshot, + scriptVersion, + scriptKind, + languageVersionOrOptions, + ); } else { // Release old source file and fall through to aquire new file with new script kind - documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath, documentRegistry.getKeyForCompilationSettings(program.getCompilerOptions()), oldSourceFile.scriptKind, oldSourceFile.impliedNodeFormat); + documentRegistry.releaseDocumentWithKey( + oldSourceFile.resolvedPath, + documentRegistry.getKeyForCompilationSettings(program.getCompilerOptions()), + oldSourceFile.scriptKind, + oldSourceFile.impliedNodeFormat, + ); } } @@ -1508,7 +1688,16 @@ namespace ts { } // Could not find this file in the old program, create a new SourceFile for it. - return documentRegistry.acquireDocumentWithKey(fileName, path, host, documentRegistryBucketKey, scriptSnapshot, scriptVersion, scriptKind, languageVersionOrOptions); + return documentRegistry.acquireDocumentWithKey( + fileName, + path, + host, + documentRegistryBucketKey, + scriptSnapshot, + scriptVersion, + scriptKind, + languageVersionOrOptions, + ); } } @@ -1528,7 +1717,10 @@ namespace ts { return host.getPackageJsonAutoImportProvider?.(); } - function updateIsDefinitionOfReferencedSymbols(referencedSymbols: readonly ReferencedSymbol[], knownSymbolSpans: Set): boolean { + function updateIsDefinitionOfReferencedSymbols( + referencedSymbols: readonly ReferencedSymbol[], + knownSymbolSpans: Set, + ): boolean { const checker = program.getTypeChecker(); const symbol = getSymbolForProgram(); @@ -1579,7 +1771,9 @@ namespace ts { const sourceFile = program.getSourceFile(docSpan.fileName); if (!sourceFile) return undefined; const rawNode = getTouchingPropertyName(sourceFile, docSpan.textSpan.start); - const adjustedNode = FindAllReferences.Core.getAdjustedNode(rawNode, { use: FindAllReferences.FindReferencesUse.References }); + const adjustedNode = FindAllReferences.Core.getAdjustedNode(rawNode, { + use: FindAllReferences.FindReferencesUse.References, + }); return adjustedNode; } } @@ -1592,7 +1786,15 @@ namespace ts { if (program) { // Use paths to ensure we are using correct key and paths as document registry could be created with different current directory than host const key = documentRegistry.getKeyForCompilationSettings(program.getCompilerOptions()); - forEach(program.getSourceFiles(), f => documentRegistry.releaseDocumentWithKey(f.resolvedPath, key, f.scriptKind, f.impliedNodeFormat)); + forEach( + program.getSourceFiles(), + f => documentRegistry.releaseDocumentWithKey( + f.resolvedPath, + key, + f.scriptKind, + f.impliedNodeFormat, + ), + ); program = undefined!; // TODO: GH#18217 } host = undefined!; @@ -1634,15 +1836,25 @@ namespace ts { function getCompilerOptionsDiagnostics() { synchronizeHostData(); - return [...program.getOptionsDiagnostics(cancellationToken), ...program.getGlobalDiagnostics(cancellationToken)]; + return [ + ...program.getOptionsDiagnostics(cancellationToken), + ...program.getGlobalDiagnostics(cancellationToken), + ]; } - function getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions = emptyOptions, formattingSettings?: FormatCodeSettings): CompletionInfo | undefined { + function getCompletionsAtPosition( + fileName: string, + position: number, + options: GetCompletionsAtPositionOptions = emptyOptions, + formattingSettings?: FormatCodeSettings, + ): CompletionInfo | undefined { // Convert from deprecated options names to new names const fullPreferences: UserPreferences = { ...identity(options), // avoid excess property check - includeCompletionsForModuleExports: options.includeCompletionsForModuleExports || options.includeExternalModuleExports, - includeCompletionsWithInsertText: options.includeCompletionsWithInsertText || options.includeInsertTextCompletions, + includeCompletionsForModuleExports: options.includeCompletionsForModuleExports + || options.includeExternalModuleExports, + includeCompletionsWithInsertText: options.includeCompletionsWithInsertText + || options.includeInsertTextCompletions, }; synchronizeHostData(); return Completions.getCompletionsAtPosition( @@ -1659,7 +1871,15 @@ namespace ts { ); } - function getCompletionEntryDetails(fileName: string, position: number, name: string, formattingOptions: FormatCodeSettings | undefined, source: string | undefined, preferences: UserPreferences = emptyOptions, data?: CompletionEntryData): CompletionEntryDetails | undefined { + function getCompletionEntryDetails( + fileName: string, + position: number, + name: string, + formattingOptions: FormatCodeSettings | undefined, + source: string | undefined, + preferences: UserPreferences = emptyOptions, + data?: CompletionEntryData, + ): CompletionEntryDetails | undefined { synchronizeHostData(); return Completions.getCompletionEntryDetails( program, @@ -1674,9 +1894,23 @@ namespace ts { ); } - function getCompletionEntrySymbol(fileName: string, position: number, name: string, source?: string, preferences: UserPreferences = emptyOptions): Symbol | undefined { + function getCompletionEntrySymbol( + fileName: string, + position: number, + name: string, + source?: string, + preferences: UserPreferences = emptyOptions, + ): Symbol | undefined { synchronizeHostData(); - return Completions.getCompletionEntrySymbol(program, log, getValidSourceFile(fileName), position, { name, source }, host, preferences); + return Completions.getCompletionEntrySymbol( + program, + log, + getValidSourceFile(fileName), + position, + { name, source }, + host, + preferences, + ); } function getQuickInfoAtPosition(fileName: string, position: number): QuickInfo | undefined { @@ -1694,18 +1928,32 @@ namespace ts { const symbol = getSymbolAtLocationForQuickInfo(nodeForQuickInfo, typeChecker); if (!symbol || typeChecker.isUnknownSymbol(symbol)) { - const type = shouldGetType(sourceFile, nodeForQuickInfo, position) ? typeChecker.getTypeAtLocation(nodeForQuickInfo) : undefined; + const type = shouldGetType(sourceFile, nodeForQuickInfo, position) + ? typeChecker.getTypeAtLocation(nodeForQuickInfo) : undefined; return type && { kind: ScriptElementKind.unknown, kindModifiers: ScriptElementKindModifier.none, textSpan: createTextSpanFromNode(nodeForQuickInfo, sourceFile), - displayParts: typeChecker.runWithCancellationToken(cancellationToken, typeChecker => typeToDisplayParts(typeChecker, type, getContainerNode(nodeForQuickInfo))), + displayParts: typeChecker.runWithCancellationToken( + cancellationToken, + typeChecker => typeToDisplayParts(typeChecker, type, getContainerNode(nodeForQuickInfo)), + ), documentation: type.symbol ? type.symbol.getDocumentationComment(typeChecker) : undefined, tags: type.symbol ? type.symbol.getJsDocTags(typeChecker) : undefined, }; } - const { symbolKind, displayParts, documentation, tags } = typeChecker.runWithCancellationToken(cancellationToken, typeChecker => SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, getContainerNode(nodeForQuickInfo), nodeForQuickInfo)); + const { symbolKind, displayParts, documentation, tags } = typeChecker.runWithCancellationToken( + cancellationToken, + typeChecker => + SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind( + typeChecker, + symbol, + sourceFile, + getContainerNode(nodeForQuickInfo), + nodeForQuickInfo, + ), + ); return { kind: symbolKind, kindModifiers: SymbolDisplay.getSymbolModifiers(typeChecker, symbol), @@ -1750,9 +1998,20 @@ namespace ts { } /// Goto definition - function getDefinitionAtPosition(fileName: string, position: number, searchOtherFilesOnly?: boolean, stopAtAlias?: boolean): readonly DefinitionInfo[] | undefined { + function getDefinitionAtPosition( + fileName: string, + position: number, + searchOtherFilesOnly?: boolean, + stopAtAlias?: boolean, + ): readonly DefinitionInfo[] | undefined { synchronizeHostData(); - return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position, searchOtherFilesOnly, stopAtAlias); + return GoToDefinition.getDefinitionAtPosition( + program, + getValidSourceFile(fileName), + position, + searchOtherFilesOnly, + stopAtAlias, + ); } function getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined { @@ -1760,16 +2019,29 @@ namespace ts { return GoToDefinition.getDefinitionAndBoundSpan(program, getValidSourceFile(fileName), position); } - function getTypeDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined { + function getTypeDefinitionAtPosition( + fileName: string, + position: number, + ): readonly DefinitionInfo[] | undefined { synchronizeHostData(); - return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position); + return GoToDefinition.getTypeDefinitionAtPosition( + program.getTypeChecker(), + getValidSourceFile(fileName), + position, + ); } /// Goto implementation function getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[] | undefined { synchronizeHostData(); - return FindAllReferences.getImplementationsAtPosition(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position); + return FindAllReferences.getImplementationsAtPosition( + program, + cancellationToken, + program.getSourceFiles(), + getValidSourceFile(fileName), + position, + ); } /// References and Occurrences @@ -1787,21 +2059,40 @@ namespace ts { ); } - function getDocumentHighlights(fileName: string, position: number, filesToSearch: readonly string[]): DocumentHighlights[] | undefined { + function getDocumentHighlights( + fileName: string, + position: number, + filesToSearch: readonly string[], + ): DocumentHighlights[] | undefined { const normalizedFileName = normalizePath(fileName); Debug.assert(filesToSearch.some(f => normalizePath(f) === normalizedFileName)); synchronizeHostData(); const sourceFilesToSearch = mapDefined(filesToSearch, fileName => program.getSourceFile(fileName)); const sourceFile = getValidSourceFile(fileName); - return DocumentHighlights.getDocumentHighlights(program, cancellationToken, sourceFile, position, sourceFilesToSearch); + return DocumentHighlights.getDocumentHighlights( + program, + cancellationToken, + sourceFile, + position, + sourceFilesToSearch, + ); } - function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): RenameLocation[] | undefined { + function findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + providePrefixAndSuffixTextForRename?: boolean, + ): RenameLocation[] | undefined { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); const node = getAdjustedRenameLocation(getTouchingPropertyName(sourceFile, position)); if (!Rename.nodeIsEligibleForRename(node)) return undefined; - if (isIdentifier(node) && (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) && isIntrinsicJsxName(node.escapedText)) { + if ( + isIdentifier(node) && (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) + && isIntrinsicJsxName(node.escapedText) + ) { const { openingElement, closingElement } = node.parent.parent; return [openingElement, closingElement].map((node): RenameLocation => { const textSpan = createTextSpanFromNode(node.tagName, sourceFile); @@ -1813,16 +2104,39 @@ namespace ts { }); } else { - return getReferencesWorker(node, position, { findInStrings, findInComments, providePrefixAndSuffixTextForRename, use: FindAllReferences.FindReferencesUse.Rename }, (entry, originalNode, checker) => FindAllReferences.toRenameLocation(entry, originalNode, checker, providePrefixAndSuffixTextForRename || false)); + return getReferencesWorker( + node, + position, + { + findInStrings, + findInComments, + providePrefixAndSuffixTextForRename, + use: FindAllReferences.FindReferencesUse.Rename, + }, + (entry, originalNode, checker) => + FindAllReferences.toRenameLocation( + entry, + originalNode, + checker, + providePrefixAndSuffixTextForRename || false, + ), + ); } } function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined { synchronizeHostData(); - return getReferencesWorker(getTouchingPropertyName(getValidSourceFile(fileName), position), position, { use: FindAllReferences.FindReferencesUse.References }, FindAllReferences.toReferenceEntry); + return getReferencesWorker(getTouchingPropertyName(getValidSourceFile(fileName), position), position, { + use: FindAllReferences.FindReferencesUse.References, + }, FindAllReferences.toReferenceEntry); } - function getReferencesWorker(node: Node, position: number, options: FindAllReferences.Options, cb: FindAllReferences.ToReferenceOrRenameEntry): T[] | undefined { + function getReferencesWorker( + node: Node, + position: number, + options: FindAllReferences.Options, + cb: FindAllReferences.ToReferenceOrRenameEntry, + ): T[] | undefined { synchronizeHostData(); // Exclude default library when renaming as commonly user don't want to change that file. @@ -1830,23 +2144,51 @@ namespace ts { ? program.getSourceFiles().filter(sourceFile => !program.isSourceFileDefaultLibrary(sourceFile)) : program.getSourceFiles(); - return FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, sourceFiles, node, position, options, cb); + return FindAllReferences.findReferenceOrRenameEntries( + program, + cancellationToken, + sourceFiles, + node, + position, + options, + cb, + ); } function findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined { synchronizeHostData(); - return FindAllReferences.findReferencedSymbols(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position); + return FindAllReferences.findReferencedSymbols( + program, + cancellationToken, + program.getSourceFiles(), + getValidSourceFile(fileName), + position, + ); } function getFileReferences(fileName: string): ReferenceEntry[] { synchronizeHostData(); - return FindAllReferences.Core.getReferencesForFileName(fileName, program, program.getSourceFiles()).map(FindAllReferences.toReferenceEntry); + return FindAllReferences.Core.getReferencesForFileName(fileName, program, program.getSourceFiles()).map( + FindAllReferences.toReferenceEntry, + ); } - function getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles = false): NavigateToItem[] { + function getNavigateToItems( + searchValue: string, + maxResultCount?: number, + fileName?: string, + excludeDtsFiles = false, + ): NavigateToItem[] { synchronizeHostData(); const sourceFiles = fileName ? [getValidSourceFile(fileName)] : program.getSourceFiles(); - return NavigateTo.getNavigateToItems(sourceFiles, program.getTypeChecker(), cancellationToken, searchValue, maxResultCount, excludeDtsFiles); + return NavigateTo.getNavigateToItems( + sourceFiles, + program.getTypeChecker(), + cancellationToken, + searchValue, + maxResultCount, + excludeDtsFiles, + ); } function getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean) { @@ -1854,14 +2196,25 @@ namespace ts { const sourceFile = getValidSourceFile(fileName); const customTransformers = host.getCustomTransformers && host.getCustomTransformers(); - return getFileEmitOutput(program, sourceFile, !!emitOnlyDtsFiles, cancellationToken, customTransformers, forceDtsEmit); + return getFileEmitOutput( + program, + sourceFile, + !!emitOnlyDtsFiles, + cancellationToken, + customTransformers, + forceDtsEmit, + ); } // Signature help /** * This is a semantic operation. */ - function getSignatureHelpItems(fileName: string, position: number, { triggerReason }: SignatureHelpItemsOptions = emptyOptions): SignatureHelpItems | undefined { + function getSignatureHelpItems( + fileName: string, + position: number, + { triggerReason }: SignatureHelpItemsOptions = emptyOptions, + ): SignatureHelpItems | undefined { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); @@ -1913,8 +2266,8 @@ namespace ts { // If parent of the module declaration which is parent of this node is module declaration and its body is the module declaration that this node is name of // Then this name is name from dotted module if ( - nodeForStartPos.parent.parent.kind === SyntaxKind.ModuleDeclaration && - (nodeForStartPos.parent.parent as ModuleDeclaration).body === nodeForStartPos.parent + nodeForStartPos.parent.parent.kind === SyntaxKind.ModuleDeclaration + && (nodeForStartPos.parent.parent as ModuleDeclaration).body === nodeForStartPos.parent ) { // Use parent module declarations name for start pos nodeForStartPos = (nodeForStartPos.parent.parent as ModuleDeclaration).name; @@ -1941,7 +2294,10 @@ namespace ts { } function getNavigationBarItems(fileName: string): NavigationBarItem[] { - return NavigationBar.getNavigationBarItems(syntaxTreeCache.getCurrentSourceFile(fileName), cancellationToken); + return NavigationBar.getNavigationBarItems( + syntaxTreeCache.getCurrentSourceFile(fileName), + cancellationToken, + ); } function getNavigationTree(fileName: string): NavigationTree { @@ -1949,38 +2305,76 @@ namespace ts { } function getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; - function getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[] { + function getSemanticClassifications( + fileName: string, + span: TextSpan, + format?: SemanticClassificationFormat, + ): ClassifiedSpan[] | ClassifiedSpan2020[] { synchronizeHostData(); const responseFormat = format || SemanticClassificationFormat.Original; if (responseFormat === SemanticClassificationFormat.TwentyTwenty) { - return classifier.v2020.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + return classifier.v2020.getSemanticClassifications( + program, + cancellationToken, + getValidSourceFile(fileName), + span, + ); } else { - return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + return ts.getSemanticClassifications( + program.getTypeChecker(), + cancellationToken, + getValidSourceFile(fileName), + program.getClassifiableNames(), + span, + ); } } - function getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications { + function getEncodedSemanticClassifications( + fileName: string, + span: TextSpan, + format?: SemanticClassificationFormat, + ): Classifications { synchronizeHostData(); const responseFormat = format || SemanticClassificationFormat.Original; if (responseFormat === SemanticClassificationFormat.Original) { - return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + return ts.getEncodedSemanticClassifications( + program.getTypeChecker(), + cancellationToken, + getValidSourceFile(fileName), + program.getClassifiableNames(), + span, + ); } else { - return classifier.v2020.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + return classifier.v2020.getEncodedSemanticClassifications( + program, + cancellationToken, + getValidSourceFile(fileName), + span, + ); } } function getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { // doesn't use compiler - no need to synchronize with host - return ts.getSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); + return ts.getSyntacticClassifications( + cancellationToken, + syntaxTreeCache.getCurrentSourceFile(fileName), + span, + ); } function getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications { // doesn't use compiler - no need to synchronize with host - return ts.getEncodedSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); + return ts.getEncodedSyntacticClassifications( + cancellationToken, + syntaxTreeCache.getCurrentSourceFile(fileName), + span, + ); } function getOutliningSpans(fileName: string): OutliningSpan[] { @@ -2000,13 +2394,21 @@ namespace ts { function getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const token = getTouchingToken(sourceFile, position); - const matchKind = token.getStart(sourceFile) === position ? braceMatching.get(token.kind.toString()) : undefined; + const matchKind = token.getStart(sourceFile) === position ? braceMatching.get(token.kind.toString()) + : undefined; const match = matchKind && findChildOfKind(token.parent, matchKind, sourceFile); // We want to order the braces when we return the result. - return match ? [createTextSpanFromNode(token, sourceFile), createTextSpanFromNode(match, sourceFile)].sort((a, b) => a.start - b.start) : emptyArray; + return match + ? [createTextSpanFromNode(token, sourceFile), createTextSpanFromNode(match, sourceFile)].sort((a, b) => + a.start - b.start + ) : emptyArray; } - function getIndentationAtPosition(fileName: string, position: number, editorOptions: EditorOptions | EditorSettings) { + function getIndentationAtPosition( + fileName: string, + position: number, + editorOptions: EditorOptions | EditorSettings, + ) { let start = timestamp(); const settings = toEditorSettings(editorOptions); const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); @@ -2020,16 +2422,37 @@ namespace ts { return result; } - function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[] { + function getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); - return formatting.formatSelection(start, end, sourceFile, formatting.getFormatContext(toEditorSettings(options), host)); + return formatting.formatSelection( + start, + end, + sourceFile, + formatting.getFormatContext(toEditorSettings(options), host), + ); } - function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] { - return formatting.formatDocument(syntaxTreeCache.getCurrentSourceFile(fileName), formatting.getFormatContext(toEditorSettings(options), host)); + function getFormattingEditsForDocument( + fileName: string, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[] { + return formatting.formatDocument( + syntaxTreeCache.getCurrentSourceFile(fileName), + formatting.getFormatContext(toEditorSettings(options), host), + ); } - function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] { + function getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const formatContext = formatting.getFormatContext(toEditorSettings(options), host); @@ -2049,7 +2472,14 @@ namespace ts { return []; } - function getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): readonly CodeFixAction[] { + function getCodeFixesAtPosition( + fileName: string, + start: number, + end: number, + errorCodes: readonly number[], + formatOptions: FormatCodeSettings, + preferences: UserPreferences = emptyOptions, + ): readonly CodeFixAction[] { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); const span = createTextSpanFromBounds(start, end); @@ -2057,41 +2487,102 @@ namespace ts { return flatMap(deduplicate(errorCodes, equateValues, compareValues), errorCode => { cancellationToken.throwIfCancellationRequested(); - return codefix.getFixes({ errorCode, sourceFile, span, program, host, cancellationToken, formatContext, preferences }); + return codefix.getFixes({ + errorCode, + sourceFile, + span, + program, + host, + cancellationToken, + formatContext, + preferences, + }); }); } - function getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): CombinedCodeActions { + function getCombinedCodeFix( + scope: CombinedCodeFixScope, + fixId: {}, + formatOptions: FormatCodeSettings, + preferences: UserPreferences = emptyOptions, + ): CombinedCodeActions { synchronizeHostData(); Debug.assert(scope.type === "file"); const sourceFile = getValidSourceFile(scope.fileName); const formatContext = formatting.getFormatContext(formatOptions, host); - return codefix.getAllFixes({ fixId, sourceFile, program, host, cancellationToken, formatContext, preferences }); + return codefix.getAllFixes({ + fixId, + sourceFile, + program, + host, + cancellationToken, + formatContext, + preferences, + }); } - function organizeImports(args: OrganizeImportsArgs, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): readonly FileTextChanges[] { + function organizeImports( + args: OrganizeImportsArgs, + formatOptions: FormatCodeSettings, + preferences: UserPreferences = emptyOptions, + ): readonly FileTextChanges[] { synchronizeHostData(); Debug.assert(args.type === "file"); const sourceFile = getValidSourceFile(args.fileName); const formatContext = formatting.getFormatContext(formatOptions, host); - const mode = args.mode ?? (args.skipDestructiveCodeActions ? OrganizeImportsMode.SortAndCombine : OrganizeImportsMode.All); + const mode = args.mode + ?? (args.skipDestructiveCodeActions ? OrganizeImportsMode.SortAndCombine : OrganizeImportsMode.All); return OrganizeImports.organizeImports(sourceFile, formatContext, host, program, preferences, mode); } - function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): readonly FileTextChanges[] { - return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions, host), preferences, sourceMapper); + function getEditsForFileRename( + oldFilePath: string, + newFilePath: string, + formatOptions: FormatCodeSettings, + preferences: UserPreferences = emptyOptions, + ): readonly FileTextChanges[] { + return ts.getEditsForFileRename( + getProgram()!, + oldFilePath, + newFilePath, + host, + formatting.getFormatContext(formatOptions, host), + preferences, + sourceMapper, + ); } - function applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise; - function applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise; - function applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise; - function applyCodeActionCommand(fileName: Path, action: CodeActionCommand): Promise; - function applyCodeActionCommand(fileName: Path, action: CodeActionCommand[]): Promise; - function applyCodeActionCommand(fileName: Path | CodeActionCommand | CodeActionCommand[], actionOrFormatSettingsOrUndefined?: CodeActionCommand | CodeActionCommand[] | FormatCodeSettings): Promise { - const action = typeof fileName === "string" ? actionOrFormatSettingsOrUndefined as CodeActionCommand | CodeActionCommand[] : fileName as CodeActionCommand[]; - return isArray(action) ? Promise.all(action.map(a => applySingleCodeActionCommand(a))) : applySingleCodeActionCommand(action); + function applyCodeActionCommand( + action: CodeActionCommand, + formatSettings?: FormatCodeSettings, + ): Promise; + function applyCodeActionCommand( + action: CodeActionCommand[], + formatSettings?: FormatCodeSettings, + ): Promise; + function applyCodeActionCommand( + action: CodeActionCommand | CodeActionCommand[], + formatSettings?: FormatCodeSettings, + ): Promise; + function applyCodeActionCommand( + fileName: Path, + action: CodeActionCommand, + ): Promise; + function applyCodeActionCommand( + fileName: Path, + action: CodeActionCommand[], + ): Promise; + function applyCodeActionCommand( + fileName: Path | CodeActionCommand | CodeActionCommand[], + actionOrFormatSettingsOrUndefined?: CodeActionCommand | CodeActionCommand[] | FormatCodeSettings, + ): Promise { + const action = typeof fileName === "string" + ? actionOrFormatSettingsOrUndefined as CodeActionCommand | CodeActionCommand[] + : fileName as CodeActionCommand[]; + return isArray(action) ? Promise.all(action.map(a => applySingleCodeActionCommand(a))) + : applySingleCodeActionCommand(action); } function applySingleCodeActionCommand(action: CodeActionCommand): Promise { @@ -2102,8 +2593,17 @@ namespace ts { : Promise.reject("Host does not implement `installPackage`"); } - function getDocCommentTemplateAtPosition(fileName: string, position: number, options?: DocCommentTemplateOptions): TextInsertion | undefined { - return JsDoc.getDocCommentTemplateAtPosition(getNewLineOrDefaultFromHost(host), syntaxTreeCache.getCurrentSourceFile(fileName), position, options); + function getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: DocCommentTemplateOptions, + ): TextInsertion | undefined { + return JsDoc.getDocCommentTemplateAtPosition( + getNewLineOrDefaultFromHost(host), + syntaxTreeCache.getCurrentSourceFile(fileName), + position, + options, + ); } function isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean { @@ -2146,12 +2646,14 @@ namespace ts { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const token = findPrecedingToken(position, sourceFile); if (!token) return undefined; - const element = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent) ? token.parent.parent + const element = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent) + ? token.parent.parent : isJsxText(token) && isJsxElement(token.parent) ? token.parent : undefined; if (element && isUnclosedTag(element)) { return { newText: `` }; } - const fragment = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningFragment(token.parent) ? token.parent.parent + const fragment = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningFragment(token.parent) + ? token.parent.parent : isJsxText(token) && isJsxFragment(token.parent) ? token.parent : undefined; if (fragment && isUnclosedFragment(fragment)) { return { newText: "" }; @@ -2180,7 +2682,10 @@ namespace ts { // Check each line before any text changes. for (let i = firstLine; i <= lastLine; i++) { - const lineText = sourceFile.text.substring(lineStarts[i], sourceFile.getLineEndOfPosition(lineStarts[i])); + const lineText = sourceFile.text.substring( + lineStarts[i], + sourceFile.getLineEndOfPosition(lineStarts[i]), + ); // Find the start of text and the left-most character. No-op on empty lines. const regExec = firstNonWhitespaceCharacterRegex.exec(lineText); @@ -2206,7 +2711,18 @@ namespace ts { // If the line is not an empty line; otherwise no-op. if (lineTextStart !== undefined) { if (isJsx) { - textChanges.push.apply(textChanges, toggleMultilineComment(fileName, { pos: lineStarts[i] + leftMostPosition, end: sourceFile.getLineEndOfPosition(lineStarts[i]) }, isCommenting, isJsx)); + textChanges.push.apply( + textChanges, + toggleMultilineComment( + fileName, + { + pos: lineStarts[i] + leftMostPosition, + end: sourceFile.getLineEndOfPosition(lineStarts[i]), + }, + isCommenting, + isJsx, + ), + ); } else if (isCommenting) { textChanges.push({ @@ -2217,7 +2733,9 @@ namespace ts { }, }); } - else if (sourceFile.text.substr(lineStarts[i] + lineTextStart, openComment.length) === openComment) { + else if ( + sourceFile.text.substr(lineStarts[i] + lineTextStart, openComment.length) === openComment + ) { textChanges.push({ newText: "", span: { @@ -2232,7 +2750,12 @@ namespace ts { return textChanges; } - function toggleMultilineComment(fileName: string, textRange: TextRange, insertComment?: boolean, isInsideJsx?: boolean): TextChange[] { + function toggleMultilineComment( + fileName: string, + textRange: TextRange, + insertComment?: boolean, + isInsideJsx?: boolean, + ): TextChange[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const textChanges: TextChange[] = []; const { text } = sourceFile; @@ -2272,11 +2795,14 @@ namespace ts { pos = commentRange.end + 1; } else { // If it's not in a comment range, then we need to comment the uncommented portions. - const newPos = text.substring(pos, textRange.end).search(`(${openMultilineRegex})|(${closeMultilineRegex})`); + const newPos = text.substring(pos, textRange.end).search( + `(${openMultilineRegex})|(${closeMultilineRegex})`, + ); isCommenting = insertComment !== undefined ? insertComment - : isCommenting || !isTextWhiteSpaceLike(text, pos, newPos === -1 ? textRange.end : pos + newPos); // If isCommenting is already true we don't need to check whitespace again. + : isCommenting + || !isTextWhiteSpaceLike(text, pos, newPos === -1 ? textRange.end : pos + newPos); // If isCommenting is already true we don't need to check whitespace again. pos = newPos === -1 ? textRange.end + 1 : pos + newPos + closeMultiline.length; } } @@ -2339,7 +2865,8 @@ namespace ts { // If is not commenting then remove all comments found. for (const pos of positions) { const from = pos - closeMultiline.length > 0 ? pos - closeMultiline.length : 0; - const offset = text.substr(from, closeMultiline.length) === closeMultiline ? closeMultiline.length : 0; + const offset = text.substr(from, closeMultiline.length) === closeMultiline ? closeMultiline.length + : 0; textChanges.push({ newText: "", span: { @@ -2380,10 +2907,24 @@ namespace ts { if (commentRange) { switch (commentRange.kind) { case SyntaxKind.SingleLineCommentTrivia: - textChanges.push.apply(textChanges, toggleLineComment(fileName, { end: commentRange.end, pos: commentRange.pos + 1 }, /*insertComment*/ false)); + textChanges.push.apply( + textChanges, + toggleLineComment( + fileName, + { end: commentRange.end, pos: commentRange.pos + 1 }, + /*insertComment*/ false, + ), + ); break; case SyntaxKind.MultiLineCommentTrivia: - textChanges.push.apply(textChanges, toggleMultilineComment(fileName, { end: commentRange.end, pos: commentRange.pos + 1 }, /*insertComment*/ false)); + textChanges.push.apply( + textChanges, + toggleMultilineComment( + fileName, + { end: commentRange.end, pos: commentRange.pos + 1 }, + /*insertComment*/ false, + ), + ); } i = commentRange.end + 1; @@ -2394,18 +2935,25 @@ namespace ts { } function isUnclosedTag({ openingElement, closingElement, parent }: JsxElement): boolean { - return !tagNamesAreEquivalent(openingElement.tagName, closingElement.tagName) || - isJsxElement(parent) && tagNamesAreEquivalent(openingElement.tagName, parent.openingElement.tagName) && isUnclosedTag(parent); + return !tagNamesAreEquivalent(openingElement.tagName, closingElement.tagName) + || isJsxElement(parent) && tagNamesAreEquivalent(openingElement.tagName, parent.openingElement.tagName) + && isUnclosedTag(parent); } function isUnclosedFragment({ closingFragment, parent }: JsxFragment): boolean { - return !!(closingFragment.flags & NodeFlags.ThisNodeHasError) || (isJsxFragment(parent) && isUnclosedFragment(parent)); + return !!(closingFragment.flags & NodeFlags.ThisNodeHasError) + || (isJsxFragment(parent) && isUnclosedFragment(parent)); } - function getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined { + function getSpanOfEnclosingComment( + fileName: string, + position: number, + onlyMultiLine: boolean, + ): TextSpan | undefined { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const range = formatting.getRangeOfEnclosingComment(sourceFile, position); - return range && (!onlyMultiLine || range.kind === SyntaxKind.MultiLineCommentTrivia) ? createTextSpanFromRange(range) : undefined; + return range && (!onlyMultiLine || range.kind === SyntaxKind.MultiLineCommentTrivia) + ? createTextSpanFromRange(range) : undefined; } function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] { @@ -2509,7 +3057,8 @@ namespace ts { // Match any of the above three TODO comment start regexps. // Note that the outermost group *is* a capture group. We want to capture the preamble // so that we can determine the starting position of the TODO comment match. - const preamble = "(" + anyNumberOfSpacesAndAsterisksAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")"; + const preamble = "(" + anyNumberOfSpacesAndAsterisksAtStartOfLine + "|" + singleLineCommentStart + "|" + + multiLineCommentStart + ")"; // Takes the descriptors and forms a regexp that matches them as if they were literals. // For example, if the descriptors are "TODO(jason)" and "HACK", then this will be: @@ -2545,9 +3094,9 @@ namespace ts { } function isLetterOrDigit(char: number): boolean { - return (char >= CharacterCodes.a && char <= CharacterCodes.z) || - (char >= CharacterCodes.A && char <= CharacterCodes.Z) || - (char >= CharacterCodes._0 && char <= CharacterCodes._9); + return (char >= CharacterCodes.a && char <= CharacterCodes.z) + || (char >= CharacterCodes.A && char <= CharacterCodes.Z) + || (char >= CharacterCodes._0 && char <= CharacterCodes._9); } function isNodeModulesFile(path: string): boolean { @@ -2555,13 +3104,25 @@ namespace ts { } } - function getRenameInfo(fileName: string, position: number, preferences: UserPreferences | RenameInfoOptions | undefined): RenameInfo { + function getRenameInfo( + fileName: string, + position: number, + preferences: UserPreferences | RenameInfoOptions | undefined, + ): RenameInfo { synchronizeHostData(); return Rename.getRenameInfo(program, getValidSourceFile(fileName), position, preferences || {}); } - function getRefactorContext(file: SourceFile, positionOrRange: number | TextRange, preferences: UserPreferences, formatOptions?: FormatCodeSettings, triggerReason?: RefactorTriggerReason, kind?: string): RefactorContext { - const [startPosition, endPosition] = typeof positionOrRange === "number" ? [positionOrRange, undefined] : [positionOrRange.pos, positionOrRange.end]; + function getRefactorContext( + file: SourceFile, + positionOrRange: number | TextRange, + preferences: UserPreferences, + formatOptions?: FormatCodeSettings, + triggerReason?: RefactorTriggerReason, + kind?: string, + ): RefactorContext { + const [startPosition, endPosition] = typeof positionOrRange === "number" ? [positionOrRange, undefined] + : [positionOrRange.pos, positionOrRange.end]; return { file, startPosition, @@ -2576,7 +3137,11 @@ namespace ts { }; } - function getInlayHintsContext(file: SourceFile, span: TextSpan, preferences: UserPreferences): InlayHintsContext { + function getInlayHintsContext( + file: SourceFile, + span: TextSpan, + preferences: UserPreferences, + ): InlayHintsContext { return { file, program: getProgram()!, @@ -2591,10 +3156,18 @@ namespace ts { return SmartSelectionRange.getSmartSelectionRange(position, syntaxTreeCache.getCurrentSourceFile(fileName)); } - function getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = emptyOptions, triggerReason: RefactorTriggerReason, kind: string): ApplicableRefactorInfo[] { + function getApplicableRefactors( + fileName: string, + positionOrRange: number | TextRange, + preferences: UserPreferences = emptyOptions, + triggerReason: RefactorTriggerReason, + kind: string, + ): ApplicableRefactorInfo[] { synchronizeHostData(); const file = getValidSourceFile(fileName); - return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange, preferences, emptyOptions, triggerReason, kind)); + return refactor.getApplicableRefactors( + getRefactorContext(file, positionOrRange, preferences, emptyOptions, triggerReason, kind), + ); } function getEditsForRefactor( @@ -2607,7 +3180,11 @@ namespace ts { ): RefactorEditInfo | undefined { synchronizeHostData(); const file = getValidSourceFile(fileName); - return refactor.getEditsForRefactor(getRefactorContext(file, positionOrRange, preferences, formatOptions), refactorName, actionName); + return refactor.getEditsForRefactor( + getRefactorContext(file, positionOrRange, preferences, formatOptions), + refactorName, + actionName, + ); } function toLineColumnOffset(fileName: string, position: number): LineAndCharacter { @@ -2621,27 +3198,51 @@ namespace ts { return sourceMapper.toLineColumnOffset(fileName, position); } - function prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined { + function prepareCallHierarchy( + fileName: string, + position: number, + ): CallHierarchyItem | CallHierarchyItem[] | undefined { synchronizeHostData(); - const declarations = CallHierarchy.resolveCallHierarchyDeclaration(program, getTouchingPropertyName(getValidSourceFile(fileName), position)); - return declarations && mapOneOrMany(declarations, declaration => CallHierarchy.createCallHierarchyItem(program, declaration)); + const declarations = CallHierarchy.resolveCallHierarchyDeclaration( + program, + getTouchingPropertyName(getValidSourceFile(fileName), position), + ); + return declarations + && mapOneOrMany( + declarations, + declaration => CallHierarchy.createCallHierarchyItem(program, declaration), + ); } function provideCallHierarchyIncomingCalls(fileName: string, position: number): CallHierarchyIncomingCall[] { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); - const declaration = firstOrOnly(CallHierarchy.resolveCallHierarchyDeclaration(program, position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position))); + const declaration = firstOrOnly( + CallHierarchy.resolveCallHierarchyDeclaration( + program, + position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position), + ), + ); return declaration ? CallHierarchy.getIncomingCalls(program, declaration, cancellationToken) : []; } function provideCallHierarchyOutgoingCalls(fileName: string, position: number): CallHierarchyOutgoingCall[] { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); - const declaration = firstOrOnly(CallHierarchy.resolveCallHierarchyDeclaration(program, position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position))); + const declaration = firstOrOnly( + CallHierarchy.resolveCallHierarchyDeclaration( + program, + position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position), + ), + ); return declaration ? CallHierarchy.getOutgoingCalls(program, declaration) : []; } - function provideInlayHints(fileName: string, span: TextSpan, preferences: UserPreferences = emptyOptions): InlayHint[] { + function provideInlayHints( + fileName: string, + span: TextSpan, + preferences: UserPreferences = emptyOptions, + ): InlayHint[] { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); return InlayHints.provideInlayHints(getInlayHintsContext(sourceFile, span, preferences)); @@ -2723,14 +3324,18 @@ namespace ts { case LanguageServiceMode.PartialSemantic: invalidOperationsInPartialSemanticMode.forEach(key => ls[key] = () => { - throw new Error(`LanguageService Operation: ${key} not allowed in LanguageServiceMode.PartialSemantic`); + throw new Error( + `LanguageService Operation: ${key} not allowed in LanguageServiceMode.PartialSemantic`, + ); } ); break; case LanguageServiceMode.Syntactic: invalidOperationsInSyntacticMode.forEach(key => ls[key] = () => { - throw new Error(`LanguageService Operation: ${key} not allowed in LanguageServiceMode.Syntactic`); + throw new Error( + `LanguageService Operation: ${key} not allowed in LanguageServiceMode.Syntactic`, + ); } ); break; @@ -2753,7 +3358,10 @@ namespace ts { function initializeNameTable(sourceFile: SourceFile): void { const nameTable = sourceFile.nameTable = new Map(); sourceFile.forEachChild(function walk(node) { - if (isIdentifier(node) && !isTagName(node) && node.escapedText || isStringOrNumericLiteralLike(node) && literalIsName(node)) { + if ( + isIdentifier(node) && !isTagName(node) && node.escapedText + || isStringOrNumericLiteralLike(node) && literalIsName(node) + ) { const text = getEscapedTextOfIdentifierOrLiteral(node); nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1); } @@ -2778,10 +3386,10 @@ namespace ts { * "a['propname']" then we want to store "propname" in the name table. */ function literalIsName(node: StringLiteralLike | NumericLiteral): boolean { - return isDeclarationName(node) || - node.parent.kind === SyntaxKind.ExternalModuleReference || - isArgumentOfElementAccessExpression(node) || - isLiteralComputedPropertyDeclarationName(node); + return isDeclarationName(node) + || node.parent.kind === SyntaxKind.ExternalModuleReference + || isArgumentOfElementAccessExpression(node) + || isLiteralComputedPropertyDeclarationName(node); } /** @@ -2790,7 +3398,8 @@ namespace ts { /* @internal */ export function getContainingObjectLiteralElement(node: Node): ObjectLiteralElementWithName | undefined { const element = getContainingObjectLiteralElementWorker(node); - return element && (isObjectLiteralExpression(element.parent) || isJsxAttributes(element.parent)) ? element as ObjectLiteralElementWithName : undefined; + return element && (isObjectLiteralExpression(element.parent) || isJsxAttributes(element.parent)) + ? element as ObjectLiteralElementWithName : undefined; } function getContainingObjectLiteralElementWorker(node: Node): ObjectLiteralElement | undefined { switch (node.kind) { @@ -2803,21 +3412,26 @@ namespace ts { // falls through case SyntaxKind.Identifier: - return isObjectLiteralElement(node.parent) && - (node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression || node.parent.parent.kind === SyntaxKind.JsxAttributes) && - node.parent.name === node ? node.parent : undefined; + return isObjectLiteralElement(node.parent) + && (node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression + || node.parent.parent.kind === SyntaxKind.JsxAttributes) + && node.parent.name === node ? node.parent : undefined; } return undefined; } /* @internal */ - export type ObjectLiteralElementWithName = ObjectLiteralElement & { name: PropertyName; parent: ObjectLiteralExpression | JsxAttributes; }; + export type ObjectLiteralElementWithName = ObjectLiteralElement & { + name: PropertyName; + parent: ObjectLiteralExpression | JsxAttributes; + }; function getSymbolAtLocationForQuickInfo(node: Node, checker: TypeChecker): Symbol | undefined { const object = getContainingObjectLiteralElement(node); if (object) { const contextualType = checker.getContextualType(object.parent); - const properties = contextualType && getPropertySymbolsFromContextualType(object, checker, contextualType, /*unionSymbolOk*/ false); + const properties = contextualType + && getPropertySymbolsFromContextualType(object, checker, contextualType, /*unionSymbolOk*/ false); if (properties && properties.length === 1) { return first(properties); } @@ -2827,7 +3441,12 @@ namespace ts { /** Gets all symbols for one property. Does not get symbols for every property. */ /* @internal */ - export function getPropertySymbolsFromContextualType(node: ObjectLiteralElementWithName, checker: TypeChecker, contextualType: Type, unionSymbolOk: boolean): readonly Symbol[] { + export function getPropertySymbolsFromContextualType( + node: ObjectLiteralElementWithName, + checker: TypeChecker, + contextualType: Type, + unionSymbolOk: boolean, + ): readonly Symbol[] { const name = getNameFromPropertyName(node.name); if (!name) return emptyArray; if (!contextualType.isUnion()) { @@ -2835,8 +3454,16 @@ namespace ts { return symbol ? [symbol] : emptyArray; } - const discriminatedPropertySymbols = mapDefined(contextualType.types, t => (isObjectLiteralExpression(node.parent) || isJsxAttributes(node.parent)) && checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent) ? undefined : t.getProperty(name)); - if (unionSymbolOk && (discriminatedPropertySymbols.length === 0 || discriminatedPropertySymbols.length === contextualType.types.length)) { + const discriminatedPropertySymbols = mapDefined( + contextualType.types, + t => (isObjectLiteralExpression(node.parent) || isJsxAttributes(node.parent)) + && checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent) ? undefined : t.getProperty(name), + ); + if ( + unionSymbolOk + && (discriminatedPropertySymbols.length === 0 + || discriminatedPropertySymbols.length === contextualType.types.length) + ) { const symbol = contextualType.getProperty(name); if (symbol) return [symbol]; } @@ -2848,10 +3475,10 @@ namespace ts { } function isArgumentOfElementAccessExpression(node: Node) { - return node && - node.parent && - node.parent.kind === SyntaxKind.ElementAccessExpression && - (node.parent as ElementAccessExpression).argumentExpression === node; + return node + && node.parent + && node.parent.kind === SyntaxKind.ElementAccessExpression + && (node.parent as ElementAccessExpression).argumentExpression === node; } /// getDefaultLibraryFilePath diff --git a/src/services/shims.ts b/src/services/shims.ts index ee4e49cfb30d6..7e9424433a33b 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -78,7 +78,15 @@ namespace ts { useCaseSensitiveFileNames?(): boolean; getTypeRootsVersion?(): number; - readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string; + readDirectory( + rootDir: string, + extension: string, + basePaths?: string, + excludeEx?: string, + includeFileEx?: string, + includeDirEx?: string, + depth?: number, + ): string; readFile(path: string, encoding?: string): string | undefined; fileExists(path: string): boolean; @@ -100,7 +108,15 @@ namespace ts { * @param exclude A JSON encoded string[] containing the paths to exclude * when enumerating the directory. */ - readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string; + readDirectory( + rootDir: string, + extension: string, + basePaths?: string, + excludeEx?: string, + includeFileEx?: string, + includeDirEx?: string, + depth?: number, + ): string; /** * Read arbitrary text files on disk, i.e. when resolution procedure needs the content of 'package.json' to determine location of bundled typings for node modules @@ -147,19 +163,46 @@ namespace ts { getCompilerOptionsDiagnostics(): string; getSyntacticClassifications(fileName: string, start: number, length: number): string; - getSemanticClassifications(fileName: string, start: number, length: number, format?: SemanticClassificationFormat): string; + getSemanticClassifications( + fileName: string, + start: number, + length: number, + format?: SemanticClassificationFormat, + ): string; getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string; - getEncodedSemanticClassifications(fileName: string, start: number, length: number, format?: SemanticClassificationFormat): string; - - getCompletionsAtPosition(fileName: string, position: number, preferences: UserPreferences | undefined, formattingSettings: FormatCodeSettings | undefined): string; - getCompletionEntryDetails(fileName: string, position: number, entryName: string, formatOptions: string /*Services.FormatCodeOptions*/ | undefined, source: string | undefined, preferences: UserPreferences | undefined, data: CompletionEntryData | undefined): string; + getEncodedSemanticClassifications( + fileName: string, + start: number, + length: number, + format?: SemanticClassificationFormat, + ): string; + + getCompletionsAtPosition( + fileName: string, + position: number, + preferences: UserPreferences | undefined, + formattingSettings: FormatCodeSettings | undefined, + ): string; + getCompletionEntryDetails( + fileName: string, + position: number, + entryName: string, + formatOptions: string /*Services.FormatCodeOptions*/ | undefined, + source: string | undefined, + preferences: UserPreferences | undefined, + data: CompletionEntryData | undefined, + ): string; getQuickInfoAtPosition(fileName: string, position: number): string; getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string; getBreakpointStatementAtPosition(fileName: string, position: number): string; - getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): string; + getSignatureHelpItems( + fileName: string, + position: number, + options: SignatureHelpItemsOptions | undefined, + ): string; /** * Returns a JSON-encoded value of the type: @@ -172,7 +215,13 @@ namespace ts { * Returns a JSON-encoded value of the type: * { fileName: string, textSpan: { start: number, length: number } }[] */ - findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): string; + findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + providePrefixAndSuffixTextForRename?: boolean, + ): string; /** * Returns a JSON-encoded value of the type: @@ -256,16 +305,34 @@ namespace ts { getTodoComments(fileName: string, todoCommentDescriptors: string): string; getBraceMatchingAtPosition(fileName: string, position: number): string; - getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string; - - getFormattingEditsForRange(fileName: string, start: number, end: number, options: string /*Services.FormatCodeOptions*/): string; + getIndentationAtPosition( + fileName: string, + position: number, + options: string, /*Services.EditorOptions*/ + ): string; + + getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: string, /*Services.FormatCodeOptions*/ + ): string; getFormattingEditsForDocument(fileName: string, options: string /*Services.FormatCodeOptions*/): string; - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string /*Services.FormatCodeOptions*/): string; + getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: string, /*Services.FormatCodeOptions*/ + ): string; /** * Returns JSON-encoded value of the type TextInsertion. */ - getDocCommentTemplateAtPosition(fileName: string, position: number, options?: DocCommentTemplateOptions): string; + getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: DocCommentTemplateOptions, + ): string; /** * Returns JSON-encoded boolean to indicate whether we should support brace location @@ -293,7 +360,11 @@ namespace ts { } export interface ClassifierShim extends Shim { - getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string; + getEncodedLexicalClassifications( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent?: boolean, + ): string; getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string; } @@ -352,8 +423,15 @@ namespace ts { private loggingEnabled = false; private tracingEnabled = false; - public resolveModuleNames: ((moduleName: string[], containingFile: string) => (ResolvedModuleFull | undefined)[]) | undefined; - public resolveTypeReferenceDirectives: ((typeDirectiveNames: string[] | readonly FileReference[], containingFile: string) => (ResolvedTypeReferenceDirective | undefined)[]) | undefined; + public resolveModuleNames: + | ((moduleName: string[], containingFile: string) => (ResolvedModuleFull | undefined)[]) + | undefined; + public resolveTypeReferenceDirectives: + | (( + typeDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + ) => (ResolvedTypeReferenceDirective | undefined)[]) + | undefined; public directoryExists: ((directoryName: string) => boolean) | undefined; constructor(private shimHost: LanguageServiceShimHost) { @@ -361,10 +439,17 @@ namespace ts { // 'in' does not have this effect. if ("getModuleResolutionsForFile" in this.shimHost) { this.resolveModuleNames = (moduleNames, containingFile) => { - const resolutionsInFile = JSON.parse(this.shimHost.getModuleResolutionsForFile!(containingFile)) as MapLike; // TODO: GH#18217 + const resolutionsInFile = JSON.parse( + this.shimHost.getModuleResolutionsForFile!(containingFile), + ) as MapLike; // TODO: GH#18217 return map(moduleNames, name => { const result = getProperty(resolutionsInFile, name); - return result ? { resolvedFileName: result, extension: extensionFromPath(result), isExternalLibraryImport: false } : undefined; + return result + ? { + resolvedFileName: result, + extension: extensionFromPath(result), + isExternalLibraryImport: false, + } : undefined; }); }; } @@ -373,8 +458,13 @@ namespace ts { } if ("getTypeReferenceDirectiveResolutionsForFile" in this.shimHost) { this.resolveTypeReferenceDirectives = (typeDirectiveNames, containingFile) => { - const typeDirectivesForFile = JSON.parse(this.shimHost.getTypeReferenceDirectiveResolutionsForFile!(containingFile)) as MapLike; // TODO: GH#18217 - return map(typeDirectiveNames as (string | FileReference)[], name => getProperty(typeDirectivesForFile, isString(name) ? name : name.fileName.toLowerCase())); + const typeDirectivesForFile = JSON.parse( + this.shimHost.getTypeReferenceDirectiveResolutionsForFile!(containingFile), + ) as MapLike; // TODO: GH#18217 + return map( + typeDirectiveNames as (string | FileReference)[], + name => getProperty(typeDirectivesForFile, isString(name) ? name : name.fileName.toLowerCase()), + ); }; } } @@ -484,8 +574,20 @@ namespace ts { return this.shimHost.getDefaultLibFileName(JSON.stringify(options)); } - public readDirectory(path: string, extensions?: readonly string[], exclude?: string[], include?: string[], depth?: number): string[] { - const pattern = getFileMatcherPatterns(path, exclude, include, this.shimHost.useCaseSensitiveFileNames!(), this.shimHost.getCurrentDirectory()); // TODO: GH#18217 + public readDirectory( + path: string, + extensions?: readonly string[], + exclude?: string[], + include?: string[], + depth?: number, + ): string[] { + const pattern = getFileMatcherPatterns( + path, + exclude, + include, + this.shimHost.useCaseSensitiveFileNames!(), + this.shimHost.getCurrentDirectory(), + ); // TODO: GH#18217 return JSON.parse(this.shimHost.readDirectory( path, JSON.stringify(extensions), @@ -506,13 +608,16 @@ namespace ts { } } - export class CoreServicesShimHostAdapter implements ParseConfigHost, ModuleResolutionHost, JsTyping.TypingResolutionHost { + export class CoreServicesShimHostAdapter + implements ParseConfigHost, ModuleResolutionHost, JsTyping.TypingResolutionHost + { public directoryExists: (directoryName: string) => boolean; public realpath: (path: string) => string; public useCaseSensitiveFileNames: boolean; constructor(private shimHost: CoreServicesShimHost) { - this.useCaseSensitiveFileNames = this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false; + this.useCaseSensitiveFileNames = this.shimHost.useCaseSensitiveFileNames + ? this.shimHost.useCaseSensitiveFileNames() : false; if ("directoryExists" in this.shimHost) { this.directoryExists = directoryName => this.shimHost.directoryExists(directoryName); } @@ -527,8 +632,20 @@ namespace ts { } } - public readDirectory(rootDir: string, extensions: readonly string[], exclude: readonly string[], include: readonly string[], depth?: number): string[] { - const pattern = getFileMatcherPatterns(rootDir, exclude, include, this.shimHost.useCaseSensitiveFileNames!(), this.shimHost.getCurrentDirectory()); // TODO: GH#18217 + public readDirectory( + rootDir: string, + extensions: readonly string[], + exclude: readonly string[], + include: readonly string[], + depth?: number, + ): string[] { + const pattern = getFileMatcherPatterns( + rootDir, + exclude, + include, + this.shimHost.useCaseSensitiveFileNames!(), + this.shimHost.getCurrentDirectory(), + ); // TODO: GH#18217 return JSON.parse(this.shimHost.readDirectory( rootDir, JSON.stringify(extensions), @@ -553,7 +670,12 @@ namespace ts { } } - function simpleForwardCall(logger: Logger, actionDescription: string, action: () => unknown, logPerformance: boolean): unknown { + function simpleForwardCall( + logger: Logger, + actionDescription: string, + action: () => unknown, + logPerformance: boolean, + ): unknown { let start: number | undefined; if (logPerformance) { logger.log(actionDescription); @@ -577,11 +699,22 @@ namespace ts { return result; } - function forwardJSONCall(logger: Logger, actionDescription: string, action: () => {} | null | undefined, logPerformance: boolean): string { + function forwardJSONCall( + logger: Logger, + actionDescription: string, + action: () => {} | null | undefined, + logPerformance: boolean, + ): string { return forwardCall(logger, actionDescription, /*returnJson*/ true, action, logPerformance) as string; } - function forwardCall(logger: Logger, actionDescription: string, returnJson: boolean, action: () => T, logPerformance: boolean): T | string { + function forwardCall( + logger: Logger, + actionDescription: string, + returnJson: boolean, + action: () => T, + logPerformance: boolean, + ): T | string { try { const result = simpleForwardCall(logger, actionDescription, action, logPerformance); return returnJson ? JSON.stringify({ result }) : result as T; @@ -634,7 +767,11 @@ namespace ts { private logger: Logger; private logPerformance = false; - constructor(factory: ShimFactory, private host: LanguageServiceShimHost, public languageService: LanguageService) { + constructor( + factory: ShimFactory, + private host: LanguageServiceShimHost, + public languageService: LanguageService, + ) { super(factory); this.logger = this.host; } @@ -687,7 +824,9 @@ namespace ts { ); } - private realizeDiagnostics(diagnostics: readonly Diagnostic[]): { message: string; start: number; length: number; category: string; }[] { + private realizeDiagnostics( + diagnostics: readonly Diagnostic[], + ): { message: string; start: number; length: number; category: string; }[] { const newLine = getNewLineOrDefaultFromHost(this.host); return realizeDiagnostics(diagnostics, newLine); } @@ -711,7 +850,13 @@ namespace ts { `getEncodedSyntacticClassifications('${fileName}', ${start}, ${length})`, // directly serialize the spans out to a string. This is much faster to decode // on the managed side versus a full JSON array. - () => convertClassifications(this.languageService.getEncodedSyntacticClassifications(fileName, createTextSpan(start, length))), + () => + convertClassifications( + this.languageService.getEncodedSyntacticClassifications( + fileName, + createTextSpan(start, length), + ), + ), ); } @@ -720,7 +865,10 @@ namespace ts { `getEncodedSemanticClassifications('${fileName}', ${start}, ${length})`, // directly serialize the spans out to a string. This is much faster to decode // on the managed side versus a full JSON array. - () => convertClassifications(this.languageService.getEncodedSemanticClassifications(fileName, createTextSpan(start, length))), + () => + convertClassifications( + this.languageService.getEncodedSemanticClassifications(fileName, createTextSpan(start, length)), + ), ); } @@ -745,7 +893,10 @@ namespace ts { } public getSuggestionDiagnostics(fileName: string): string { - return this.forwardJSONCall(`getSuggestionDiagnostics('${fileName}')`, () => this.realizeDiagnostics(this.languageService.getSuggestionDiagnostics(fileName))); + return this.forwardJSONCall( + `getSuggestionDiagnostics('${fileName}')`, + () => this.realizeDiagnostics(this.languageService.getSuggestionDiagnostics(fileName)), + ); } public getCompilerOptionsDiagnostics(): string { @@ -797,7 +948,11 @@ namespace ts { /// SIGNATUREHELP - public getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): string { + public getSignatureHelpItems( + fileName: string, + position: number, + options: SignatureHelpItemsOptions | undefined, + ): string { return this.forwardJSONCall( `getSignatureHelpItems('${fileName}', ${position})`, () => this.languageService.getSignatureHelpItems(fileName, position, options), @@ -868,10 +1023,23 @@ namespace ts { ); } - public findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): string { + public findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + providePrefixAndSuffixTextForRename?: boolean, + ): string { return this.forwardJSONCall( `findRenameLocations('${fileName}', ${position}, ${findInStrings}, ${findInComments}, ${providePrefixAndSuffixTextForRename})`, - () => this.languageService.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename), + () => + this.languageService.findRenameLocations( + fileName, + position, + findInStrings, + findInComments, + providePrefixAndSuffixTextForRename, + ), ); } @@ -898,7 +1066,11 @@ namespace ts { } /// GET SMART INDENT - public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string { + public getIndentationAtPosition( + fileName: string, + position: number, + options: string, /*Services.EditorOptions*/ + ): string { return this.forwardJSONCall( `getIndentationAtPosition('${fileName}', ${position})`, () => { @@ -942,7 +1114,11 @@ namespace ts { return this.forwardJSONCall( `getDocumentHighlights('${fileName}', ${position})`, () => { - const results = this.languageService.getDocumentHighlights(fileName, position, JSON.parse(filesToSearch)); + const results = this.languageService.getDocumentHighlights( + fileName, + position, + JSON.parse(filesToSearch), + ); // workaround for VS document highlighting issue - keep only items from the initial file const normalizedName = toFileNameLowerCase(normalizeSlashes(fileName)); return filter(results, r => toFileNameLowerCase(normalizeSlashes(r.fileName)) === normalizedName); @@ -957,25 +1133,53 @@ namespace ts { * to provide at the given source position and providing a member completion * list if requested. */ - public getCompletionsAtPosition(fileName: string, position: number, preferences: GetCompletionsAtPositionOptions | undefined, formattingSettings: FormatCodeSettings | undefined) { + public getCompletionsAtPosition( + fileName: string, + position: number, + preferences: GetCompletionsAtPositionOptions | undefined, + formattingSettings: FormatCodeSettings | undefined, + ) { return this.forwardJSONCall( `getCompletionsAtPosition('${fileName}', ${position}, ${preferences}, ${formattingSettings})`, - () => this.languageService.getCompletionsAtPosition(fileName, position, preferences, formattingSettings), + () => + this.languageService.getCompletionsAtPosition(fileName, position, preferences, formattingSettings), ); } /** Get a string based representation of a completion list entry details */ - public getCompletionEntryDetails(fileName: string, position: number, entryName: string, formatOptions: string /*Services.FormatCodeOptions*/ | undefined, source: string | undefined, preferences: UserPreferences | undefined, data: CompletionEntryData | undefined) { + public getCompletionEntryDetails( + fileName: string, + position: number, + entryName: string, + formatOptions: string /*Services.FormatCodeOptions*/ | undefined, + source: string | undefined, + preferences: UserPreferences | undefined, + data: CompletionEntryData | undefined, + ) { return this.forwardJSONCall( `getCompletionEntryDetails('${fileName}', ${position}, '${entryName}')`, () => { - const localOptions: FormatCodeOptions = formatOptions === undefined ? undefined : JSON.parse(formatOptions); - return this.languageService.getCompletionEntryDetails(fileName, position, entryName, localOptions, source, preferences, data); + const localOptions: FormatCodeOptions = formatOptions === undefined ? undefined + : JSON.parse(formatOptions); + return this.languageService.getCompletionEntryDetails( + fileName, + position, + entryName, + localOptions, + source, + preferences, + data, + ); }, ); } - public getFormattingEditsForRange(fileName: string, start: number, end: number, options: string /*Services.FormatCodeOptions*/): string { + public getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: string, /*Services.FormatCodeOptions*/ + ): string { return this.forwardJSONCall( `getFormattingEditsForRange('${fileName}', ${start}, ${end})`, () => { @@ -995,7 +1199,12 @@ namespace ts { ); } - public getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string /*Services.FormatCodeOptions*/): string { + public getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: string, /*Services.FormatCodeOptions*/ + ): string { return this.forwardJSONCall( `getFormattingEditsAfterKeystroke('${fileName}', ${position}, '${key}')`, () => { @@ -1005,7 +1214,11 @@ namespace ts { ); } - public getDocCommentTemplateAtPosition(fileName: string, position: number, options?: DocCommentTemplateOptions): string { + public getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: DocCommentTemplateOptions, + ): string { return this.forwardJSONCall( `getDocCommentTemplateAtPosition('${fileName}', ${position})`, () => this.languageService.getDocCommentTemplateAtPosition(fileName, position, options), @@ -1130,7 +1343,9 @@ namespace ts { } } - function convertClassifications(classifications: Classifications): { spans: string; endOfLineState: EndOfLineState; } { + function convertClassifications( + classifications: Classifications, + ): { spans: string; endOfLineState: EndOfLineState; } { return { spans: classifications.spans.join(","), endOfLineState: classifications.endOfLineState }; } @@ -1143,13 +1358,33 @@ namespace ts { this.classifier = createClassifier(); } - public getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent = false): string { - return forwardJSONCall(this.logger, "getEncodedLexicalClassifications", () => convertClassifications(this.classifier.getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent)), this.logPerformance); + public getEncodedLexicalClassifications( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent = false, + ): string { + return forwardJSONCall( + this.logger, + "getEncodedLexicalClassifications", + () => + convertClassifications( + this.classifier.getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent), + ), + this.logPerformance, + ); } /// COLORIZATION - public getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics = false): string { - const classification = this.classifier.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics); + public getClassificationsForLine( + text: string, + lexState: EndOfLineState, + classifyKeywordsInGenerics = false, + ): string { + const classification = this.classifier.getClassificationsForLine( + text, + lexState, + classifyKeywordsInGenerics, + ); let result = ""; for (const item of classification.entries) { result += item.length + "\n"; @@ -1164,7 +1399,11 @@ namespace ts { private logPerformance = false; private safeList: JsTyping.SafeList | undefined; - constructor(factory: ShimFactory, public readonly logger: Logger, private readonly host: CoreServicesShimHostAdapter) { + constructor( + factory: ShimFactory, + public readonly logger: Logger, + private readonly host: CoreServicesShimHostAdapter, + ) { super(factory); } @@ -1177,7 +1416,11 @@ namespace ts { const compilerOptions = JSON.parse(compilerOptionsJson) as CompilerOptions; const result = resolveModuleName(moduleName, normalizeSlashes(fileName), compilerOptions, this.host); let resolvedFileName = result.resolvedModule ? result.resolvedModule.resolvedFileName : undefined; - if (result.resolvedModule && result.resolvedModule.extension !== Extension.Ts && result.resolvedModule.extension !== Extension.Tsx && result.resolvedModule.extension !== Extension.Dts) { + if ( + result.resolvedModule && result.resolvedModule.extension !== Extension.Ts + && result.resolvedModule.extension !== Extension.Tsx + && result.resolvedModule.extension !== Extension.Dts + ) { resolvedFileName = undefined; } @@ -1189,13 +1432,24 @@ namespace ts { }); } - public resolveTypeReferenceDirective(fileName: string, typeReferenceDirective: string, compilerOptionsJson: string): string { + public resolveTypeReferenceDirective( + fileName: string, + typeReferenceDirective: string, + compilerOptionsJson: string, + ): string { return this.forwardJSONCall(`resolveTypeReferenceDirective(${fileName})`, () => { const compilerOptions = JSON.parse(compilerOptionsJson) as CompilerOptions; - const result = resolveTypeReferenceDirective(typeReferenceDirective, normalizeSlashes(fileName), compilerOptions, this.host); + const result = resolveTypeReferenceDirective( + typeReferenceDirective, + normalizeSlashes(fileName), + compilerOptions, + this.host, + ); return { - resolvedFileName: result.resolvedTypeReferenceDirective ? result.resolvedTypeReferenceDirective.resolvedFileName : undefined, - primary: result.resolvedTypeReferenceDirective ? result.resolvedTypeReferenceDirective.primary : true, + resolvedFileName: result.resolvedTypeReferenceDirective + ? result.resolvedTypeReferenceDirective.resolvedFileName : undefined, + primary: result.resolvedTypeReferenceDirective ? result.resolvedTypeReferenceDirective.primary + : true, failedLookupLocations: result.failedLookupLocations, }; }); @@ -1206,7 +1460,11 @@ namespace ts { `getPreProcessedFileInfo('${fileName}')`, () => { // for now treat files as JavaScript - const result = preProcessFile(getSnapshotText(sourceTextSnapshot), /* readImportFiles */ true, /* detectJavaScriptImports */ true); + const result = preProcessFile( + getSnapshotText(sourceTextSnapshot), + /* readImportFiles */ true, + /* detectJavaScriptImports */ true, + ); return { referencedFiles: this.convertFileReferences(result.referencedFiles), importedFiles: this.convertFileReferences(result.importedFiles), @@ -1250,7 +1508,13 @@ namespace ts { () => { const result = parseJsonText(fileName, getSnapshotText(sourceTextSnapshot)); const normalizedFileName = normalizeSlashes(fileName); - const configFile = parseJsonSourceFileConfigFileContent(result, this.host, getDirectoryPath(normalizedFileName), /*existingOptions*/ {}, normalizedFileName); + const configFile = parseJsonSourceFileConfigFileContent( + result, + this.host, + getDirectoryPath(normalizedFileName), + /*existingOptions*/ {}, + normalizedFileName, + ); return { options: configFile.options, @@ -1275,7 +1539,10 @@ namespace ts { return this.forwardJSONCall("discoverTypings()", () => { const info = JSON.parse(discoverTypingsJson) as DiscoverTypingsInfo; if (this.safeList === undefined) { - this.safeList = JsTyping.loadSafeList(this.host, toPath(info.safeListPath, info.safeListPath, getCanonicalFileName)); + this.safeList = JsTyping.loadSafeList( + this.host, + toPath(info.safeListPath, info.safeListPath, getCanonicalFileName), + ); } return JsTyping.discoverTypings( this.host, @@ -1307,7 +1574,10 @@ namespace ts { public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim { try { if (this.documentRegistry === undefined) { - this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory()); + this.documentRegistry = createDocumentRegistry( + host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), + host.getCurrentDirectory(), + ); } const hostAdapter = new LanguageServiceShimHostAdapter(host); const languageService = createLanguageService(hostAdapter, this.documentRegistry, /*syntaxOnly*/ false); diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index d14dad5e90f2f..0310df19d5f44 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -30,7 +30,13 @@ namespace ts.SignatureHelp { readonly argumentCount: number; } - export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, triggerReason: SignatureHelpTriggerReason | undefined, cancellationToken: CancellationToken): SignatureHelpItems | undefined { + export function getSignatureHelpItems( + program: Program, + sourceFile: SourceFile, + position: number, + triggerReason: SignatureHelpTriggerReason | undefined, + cancellationToken: CancellationToken, + ): SignatureHelpItems | undefined { const typeChecker = program.getTypeChecker(); // Decide whether to show signature help @@ -44,30 +50,55 @@ namespace ts.SignatureHelp { const onlyUseSyntacticOwners = !!triggerReason && triggerReason.kind === "characterTyped"; // Bail out quickly in the middle of a string or comment, don't provide signature help unless the user explicitly requested it. - if (onlyUseSyntacticOwners && (isInString(sourceFile, position, startingToken) || isInComment(sourceFile, position))) { + if ( + onlyUseSyntacticOwners + && (isInString(sourceFile, position, startingToken) || isInComment(sourceFile, position)) + ) { return undefined; } const isManuallyInvoked = !!triggerReason && triggerReason.kind === "invoked"; - const argumentInfo = getContainingArgumentInfo(startingToken, position, sourceFile, typeChecker, isManuallyInvoked); + const argumentInfo = getContainingArgumentInfo( + startingToken, + position, + sourceFile, + typeChecker, + isManuallyInvoked, + ); if (!argumentInfo) return undefined; cancellationToken.throwIfCancellationRequested(); // Extra syntactic and semantic filtering of signature help - const candidateInfo = getCandidateOrTypeInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners); + const candidateInfo = getCandidateOrTypeInfo( + argumentInfo, + typeChecker, + sourceFile, + startingToken, + onlyUseSyntacticOwners, + ); cancellationToken.throwIfCancellationRequested(); if (!candidateInfo) { // We didn't have any sig help items produced by the TS compiler. If this is a JS // file, then see if we can figure out anything better. - return isSourceFileJS(sourceFile) ? createJSSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined; + return isSourceFileJS(sourceFile) ? createJSSignatureHelpItems(argumentInfo, program, cancellationToken) + : undefined; } - return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => - candidateInfo.kind === CandidateOrTypeKind.Candidate - ? createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker) - : createTypeHelpItems(candidateInfo.symbol, argumentInfo, sourceFile, typeChecker)); + return typeChecker.runWithCancellationToken( + cancellationToken, + typeChecker => + candidateInfo.kind === CandidateOrTypeKind.Candidate + ? createSignatureHelpItems( + candidateInfo.candidates, + candidateInfo.resolvedSignature, + argumentInfo, + sourceFile, + typeChecker, + ) + : createTypeHelpItems(candidateInfo.symbol, argumentInfo, sourceFile, typeChecker), + ); } const enum CandidateOrTypeKind { @@ -84,29 +115,49 @@ namespace ts.SignatureHelp { readonly symbol: Symbol; } - function getCandidateOrTypeInfo({ invocation, argumentCount }: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | TypeInfo | undefined { + function getCandidateOrTypeInfo( + { invocation, argumentCount }: ArgumentListInfo, + checker: TypeChecker, + sourceFile: SourceFile, + startingToken: Node, + onlyUseSyntacticOwners: boolean, + ): CandidateInfo | TypeInfo | undefined { switch (invocation.kind) { case InvocationKind.Call: { if (onlyUseSyntacticOwners && !isSyntacticOwner(startingToken, invocation.node, sourceFile)) { return undefined; } const candidates: Signature[] = []; - const resolvedSignature = checker.getResolvedSignatureForSignatureHelp(invocation.node, candidates, argumentCount)!; // TODO: GH#18217 - return candidates.length === 0 ? undefined : { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature }; + const resolvedSignature = checker.getResolvedSignatureForSignatureHelp( + invocation.node, + candidates, + argumentCount, + )!; // TODO: GH#18217 + return candidates.length === 0 ? undefined + : { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature }; } case InvocationKind.TypeArgs: { const { called } = invocation; - if (onlyUseSyntacticOwners && !containsPrecedingToken(startingToken, sourceFile, isIdentifier(called) ? called.parent : called)) { + if ( + onlyUseSyntacticOwners + && !containsPrecedingToken(startingToken, sourceFile, isIdentifier(called) ? called.parent : called) + ) { return undefined; } const candidates = getPossibleGenericSignatures(called, argumentCount, checker); - if (candidates.length !== 0) return { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature: first(candidates) }; + if (candidates.length !== 0) { + return { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature: first(candidates) }; + } const symbol = checker.getSymbolAtLocation(called); return symbol && { kind: CandidateOrTypeKind.Type, symbol }; } case InvocationKind.Contextual: - return { kind: CandidateOrTypeKind.Candidate, candidates: [invocation.signature], resolvedSignature: invocation.signature }; + return { + kind: CandidateOrTypeKind.Candidate, + candidates: [invocation.signature], + resolvedSignature: invocation.signature, + }; default: return Debug.assertNever(invocation); } @@ -129,31 +180,40 @@ namespace ts.SignatureHelp { } } - function createJSSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined { + function createJSSignatureHelpItems( + argumentInfo: ArgumentListInfo, + program: Program, + cancellationToken: CancellationToken, + ): SignatureHelpItems | undefined { if (argumentInfo.invocation.kind === InvocationKind.Contextual) return undefined; // See if we can find some symbol with the call expression name that has call signatures. const expression = getExpressionFromInvocation(argumentInfo.invocation); const name = isPropertyAccessExpression(expression) ? expression.name.text : undefined; const typeChecker = program.getTypeChecker(); - return name === undefined ? undefined : firstDefined(program.getSourceFiles(), sourceFile => - firstDefined(sourceFile.getNamedDeclarations().get(name), declaration => { - const type = declaration.symbol && typeChecker.getTypeOfSymbolAtLocation(declaration.symbol, declaration); - const callSignatures = type && type.getCallSignatures(); - if (callSignatures && callSignatures.length) { - return typeChecker.runWithCancellationToken( - cancellationToken, - typeChecker => - createSignatureHelpItems( - callSignatures, - callSignatures[0], - argumentInfo, - sourceFile, - typeChecker, - /*useFullPrefix*/ true, - ), - ); - } - })); + return name === undefined ? undefined + : firstDefined( + program.getSourceFiles(), + sourceFile => + firstDefined(sourceFile.getNamedDeclarations().get(name), declaration => { + const type = declaration.symbol + && typeChecker.getTypeOfSymbolAtLocation(declaration.symbol, declaration); + const callSignatures = type && type.getCallSignatures(); + if (callSignatures && callSignatures.length) { + return typeChecker.runWithCancellationToken( + cancellationToken, + typeChecker => + createSignatureHelpItems( + callSignatures, + callSignatures[0], + argumentInfo, + sourceFile, + typeChecker, + /*useFullPrefix*/ true, + ), + ); + } + }), + ); } function containsPrecedingToken(startingToken: Node, sourceFile: SourceFile, container: Node) { @@ -179,13 +239,30 @@ namespace ts.SignatureHelp { readonly argumentIndex: number; readonly argumentCount: number; } - export function getArgumentInfoForCompletions(node: Node, position: number, sourceFile: SourceFile): ArgumentInfoForCompletions | undefined { + export function getArgumentInfoForCompletions( + node: Node, + position: number, + sourceFile: SourceFile, + ): ArgumentInfoForCompletions | undefined { const info = getImmediatelyContainingArgumentInfo(node, position, sourceFile); return !info || info.isTypeParameterList || info.invocation.kind !== InvocationKind.Call ? undefined - : { invocation: info.invocation.node, argumentCount: info.argumentCount, argumentIndex: info.argumentIndex }; + : { + invocation: info.invocation.node, + argumentCount: info.argumentCount, + argumentIndex: info.argumentIndex, + }; } - function getArgumentOrParameterListInfo(node: Node, position: number, sourceFile: SourceFile): { readonly list: Node; readonly argumentIndex: number; readonly argumentCount: number; readonly argumentsSpan: TextSpan; } | undefined { + function getArgumentOrParameterListInfo( + node: Node, + position: number, + sourceFile: SourceFile, + ): { + readonly list: Node; + readonly argumentIndex: number; + readonly argumentCount: number; + readonly argumentsSpan: TextSpan; + } | undefined { const info = getArgumentOrParameterListAndIndex(node, sourceFile); if (!info) return undefined; const { list, argumentIndex } = info; @@ -197,7 +274,10 @@ namespace ts.SignatureHelp { const argumentsSpan = getApplicableSpanForArguments(list, sourceFile); return { list, argumentIndex, argumentCount, argumentsSpan }; } - function getArgumentOrParameterListAndIndex(node: Node, sourceFile: SourceFile): { readonly list: Node; readonly argumentIndex: number; } | undefined { + function getArgumentOrParameterListAndIndex( + node: Node, + sourceFile: SourceFile, + ): { readonly list: Node; readonly argumentIndex: number; } | undefined { if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) { // Find the list that starts right *after* the < or ( token. // If the user has just opened a list, consider this item 0. @@ -219,7 +299,11 @@ namespace ts.SignatureHelp { * Returns relevant information for the argument list and the current argument if we are * in the argument of an invocation; returns undefined otherwise. */ - function getImmediatelyContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo | undefined { + function getImmediatelyContainingArgumentInfo( + node: Node, + position: number, + sourceFile: SourceFile, + ): ArgumentListInfo | undefined { const { parent } = node; if (isCallOrNewExpression(parent)) { const invocation = parent; @@ -242,7 +326,13 @@ namespace ts.SignatureHelp { if (!info) return undefined; const { list, argumentIndex, argumentCount, argumentsSpan } = info; const isTypeParameterList = !!parent.typeArguments && parent.typeArguments.pos === list.pos; - return { isTypeParameterList, invocation: { kind: InvocationKind.Call, node: invocation }, argumentsSpan, argumentIndex, argumentCount }; + return { + isTypeParameterList, + invocation: { kind: InvocationKind.Call, node: invocation }, + argumentsSpan, + argumentIndex, + argumentCount, + }; } else if (isNoSubstitutionTemplateLiteral(node) && isTaggedTemplateExpression(parent)) { // Check if we're actually inside the template; @@ -297,14 +387,26 @@ namespace ts.SignatureHelp { const { called, nTypeArguments } = typeArgInfo; const invocation: Invocation = { kind: InvocationKind.TypeArgs, called }; const argumentsSpan = createTextSpanFromBounds(called.getStart(sourceFile), node.end); - return { isTypeParameterList: true, invocation, argumentsSpan, argumentIndex: nTypeArguments, argumentCount: nTypeArguments + 1 }; + return { + isTypeParameterList: true, + invocation, + argumentsSpan, + argumentIndex: nTypeArguments, + argumentCount: nTypeArguments + 1, + }; } return undefined; } } - function getImmediatelyContainingArgumentOrContextualParameterInfo(node: Node, position: number, sourceFile: SourceFile, checker: TypeChecker): ArgumentListInfo | undefined { - return tryGetParameterInfo(node, position, sourceFile, checker) || getImmediatelyContainingArgumentInfo(node, position, sourceFile); + function getImmediatelyContainingArgumentOrContextualParameterInfo( + node: Node, + position: number, + sourceFile: SourceFile, + checker: TypeChecker, + ): ArgumentListInfo | undefined { + return tryGetParameterInfo(node, position, sourceFile, checker) + || getImmediatelyContainingArgumentInfo(node, position, sourceFile); } function getHighestBinary(b: BinaryExpression): BinaryExpression { @@ -315,7 +417,12 @@ namespace ts.SignatureHelp { return isBinaryExpression(b.left) ? countBinaryExpressionParameters(b.left) + 1 : 2; } - function tryGetParameterInfo(startingToken: Node, position: number, sourceFile: SourceFile, checker: TypeChecker): ArgumentListInfo | undefined { + function tryGetParameterInfo( + startingToken: Node, + position: number, + sourceFile: SourceFile, + checker: TypeChecker, + ): ArgumentListInfo | undefined { const info = getContextualSignatureLocationInfo(startingToken, sourceFile, position, checker); if (!info) return undefined; const { contextualType, argumentIndex, argumentCount, argumentsSpan } = info; @@ -329,7 +436,12 @@ namespace ts.SignatureHelp { const signature = lastOrUndefined(nonNullableContextualType.getCallSignatures()); if (signature === undefined) return undefined; - const invocation: ContextualInvocation = { kind: InvocationKind.Contextual, signature, node: startingToken, symbol: chooseBetterSymbol(symbol) }; + const invocation: ContextualInvocation = { + kind: InvocationKind.Contextual, + signature, + node: startingToken, + symbol: chooseBetterSymbol(symbol), + }; return { isTypeParameterList: false, invocation, argumentsSpan, argumentIndex, argumentCount }; } @@ -339,8 +451,15 @@ namespace ts.SignatureHelp { readonly argumentCount: number; readonly argumentsSpan: TextSpan; } - function getContextualSignatureLocationInfo(startingToken: Node, sourceFile: SourceFile, position: number, checker: TypeChecker): ContextualSignatureLocationInfo | undefined { - if (startingToken.kind !== SyntaxKind.OpenParenToken && startingToken.kind !== SyntaxKind.CommaToken) return undefined; + function getContextualSignatureLocationInfo( + startingToken: Node, + sourceFile: SourceFile, + position: number, + checker: TypeChecker, + ): ContextualSignatureLocationInfo | undefined { + if (startingToken.kind !== SyntaxKind.OpenParenToken && startingToken.kind !== SyntaxKind.CommaToken) { + return undefined; + } const { parent } = startingToken; switch (parent.kind) { case SyntaxKind.ParenthesizedExpression: @@ -350,14 +469,18 @@ namespace ts.SignatureHelp { const info = getArgumentOrParameterListInfo(startingToken, position, sourceFile); if (!info) return undefined; const { argumentIndex, argumentCount, argumentsSpan } = info; - const contextualType = isMethodDeclaration(parent) ? checker.getContextualTypeForObjectLiteralElement(parent) : checker.getContextualType(parent as ParenthesizedExpression | FunctionExpression | ArrowFunction); + const contextualType = isMethodDeclaration(parent) + ? checker.getContextualTypeForObjectLiteralElement(parent) + : checker.getContextualType(parent as ParenthesizedExpression | FunctionExpression | ArrowFunction); return contextualType && { contextualType, argumentIndex, argumentCount, argumentsSpan }; case SyntaxKind.BinaryExpression: { const highestBinary = getHighestBinary(parent as BinaryExpression); const contextualType = checker.getContextualType(highestBinary); - const argumentIndex = startingToken.kind === SyntaxKind.OpenParenToken ? 0 : countBinaryExpressionParameters(parent as BinaryExpression) - 1; + const argumentIndex = startingToken.kind === SyntaxKind.OpenParenToken ? 0 + : countBinaryExpressionParameters(parent as BinaryExpression) - 1; const argumentCount = countBinaryExpressionParameters(highestBinary); - return contextualType && { contextualType, argumentIndex, argumentCount, argumentsSpan: createTextSpanFromNode(parent) }; + return contextualType + && { contextualType, argumentIndex, argumentCount, argumentsSpan: createTextSpanFromNode(parent) }; } default: return undefined; @@ -419,7 +542,12 @@ namespace ts.SignatureHelp { // spanIndex is either the index for a given template span. // This does not give appropriate results for a NoSubstitutionTemplateLiteral - function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node, position: number, sourceFile: SourceFile): number { + function getArgumentIndexForTemplatePiece( + spanIndex: number, + node: Node, + position: number, + sourceFile: SourceFile, + ): number { // Because the TemplateStringsArray is the first argument, we have to offset each substitution expression by 1. // There are three cases we can encounter: // 1. We are precisely in the template literal (argIndex = 0). @@ -443,9 +571,14 @@ namespace ts.SignatureHelp { return spanIndex + 1; } - function getArgumentListInfoForTemplate(tagExpression: TaggedTemplateExpression, argumentIndex: number, sourceFile: SourceFile): ArgumentListInfo { + function getArgumentListInfoForTemplate( + tagExpression: TaggedTemplateExpression, + argumentIndex: number, + sourceFile: SourceFile, + ): ArgumentListInfo { // argumentCount is either 1 or (numSpans + 1) to account for the template strings array argument. - const argumentCount = isNoSubstitutionTemplateLiteral(tagExpression.template) ? 1 : tagExpression.template.templateSpans.length + 1; + const argumentCount = isNoSubstitutionTemplateLiteral(tagExpression.template) ? 1 + : tagExpression.template.templateSpans.length + 1; if (argumentIndex !== 0) { Debug.assertLessThan(argumentIndex, argumentCount); } @@ -472,7 +605,10 @@ namespace ts.SignatureHelp { return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); } - function getApplicableSpanForTaggedTemplate(taggedTemplate: TaggedTemplateExpression, sourceFile: SourceFile): TextSpan { + function getApplicableSpanForTaggedTemplate( + taggedTemplate: TaggedTemplateExpression, + sourceFile: SourceFile, + ): TextSpan { const template = taggedTemplate.template; const applicableSpanStart = template.getStart(); let applicableSpanEnd = template.getEnd(); @@ -495,12 +631,27 @@ namespace ts.SignatureHelp { return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); } - function getContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile, checker: TypeChecker, isManuallyInvoked: boolean): ArgumentListInfo | undefined { + function getContainingArgumentInfo( + node: Node, + position: number, + sourceFile: SourceFile, + checker: TypeChecker, + isManuallyInvoked: boolean, + ): ArgumentListInfo | undefined { for (let n = node; !isSourceFile(n) && (isManuallyInvoked || !isBlock(n)); n = n.parent) { // If the node is not a subspan of its parent, this is a big problem. // There have been crashes that might be caused by this violation. - Debug.assert(rangeContainsRange(n.parent, n), "Not a subspan", () => `Child: ${Debug.formatSyntaxKind(n.kind)}, parent: ${Debug.formatSyntaxKind(n.parent.kind)}`); - const argumentInfo = getImmediatelyContainingArgumentOrContextualParameterInfo(n, position, sourceFile, checker); + Debug.assert( + rangeContainsRange(n.parent, n), + "Not a subspan", + () => `Child: ${Debug.formatSyntaxKind(n.kind)}, parent: ${Debug.formatSyntaxKind(n.parent.kind)}`, + ); + const argumentInfo = getImmediatelyContainingArgumentOrContextualParameterInfo( + n, + position, + sourceFile, + checker, + ); if (argumentInfo) { return argumentInfo; } @@ -520,22 +671,44 @@ namespace ts.SignatureHelp { } function getEnclosingDeclarationFromInvocation(invocation: Invocation): Node { - return invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node; + return invocation.kind === InvocationKind.Call ? invocation.node + : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node; } - const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; + const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors + | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; function createSignatureHelpItems( candidates: readonly Signature[], resolvedSignature: Signature, - { isTypeParameterList, argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex }: ArgumentListInfo, + { isTypeParameterList, argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex }: + ArgumentListInfo, sourceFile: SourceFile, typeChecker: TypeChecker, useFullPrefix?: boolean, ): SignatureHelpItems { const enclosingDeclaration = getEnclosingDeclarationFromInvocation(invocation); - const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol : (typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation)) || useFullPrefix && resolvedSignature.declaration?.symbol); - const callTargetDisplayParts = callTargetSymbol ? symbolToDisplayParts(typeChecker, callTargetSymbol, useFullPrefix ? sourceFile : undefined, /*meaning*/ undefined) : emptyArray; - const items = map(candidates, candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile)); + const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol + : (typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation)) + || useFullPrefix && resolvedSignature.declaration?.symbol); + const callTargetDisplayParts = callTargetSymbol + ? symbolToDisplayParts( + typeChecker, + callTargetSymbol, + useFullPrefix ? sourceFile : undefined, + /*meaning*/ undefined, + ) : emptyArray; + const items = map( + candidates, + candidateSignature => + getSignatureHelpItem( + candidateSignature, + callTargetDisplayParts, + isTypeParameterList, + typeChecker, + enclosingDeclaration, + sourceFile, + ), + ); if (argumentIndex !== 0) { Debug.assertLessThan(argumentIndex, argumentCount); @@ -563,7 +736,13 @@ namespace ts.SignatureHelp { } Debug.assert(selectedItemIndex !== -1); // If candidates is non-empty it should always include bestSignature. We check for an empty candidates before calling this function. - const help = { items: flatMapToMutable(items, identity), applicableSpan, selectedItemIndex, argumentIndex, argumentCount }; + const help = { + items: flatMapToMutable(items, identity), + applicableSpan, + selectedItemIndex, + argumentIndex, + argumentCount, + }; const selected = help.items[selectedItemIndex]; if (selected.isVariadic) { const firstRest = findIndex(selected.parameters, p => !!p.isRest); @@ -586,36 +765,87 @@ namespace ts.SignatureHelp { ): SignatureHelpItems | undefined { const typeParameters = checker.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); if (!typeParameters) return undefined; - const items = [getTypeHelpItem(symbol, typeParameters, checker, getEnclosingDeclarationFromInvocation(invocation), sourceFile)]; + const items = [ + getTypeHelpItem( + symbol, + typeParameters, + checker, + getEnclosingDeclarationFromInvocation(invocation), + sourceFile, + ), + ]; return { items, applicableSpan, selectedItemIndex: 0, argumentIndex, argumentCount }; } - function getTypeHelpItem(symbol: Symbol, typeParameters: readonly TypeParameter[], checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem { + function getTypeHelpItem( + symbol: Symbol, + typeParameters: readonly TypeParameter[], + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, + ): SignatureHelpItem { const typeSymbolDisplay = symbolToDisplayParts(checker, symbol); const printer = createPrinter({ removeComments: true }); - const parameters = typeParameters.map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer)); + const parameters = typeParameters.map(t => + createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer) + ); const documentation = symbol.getDocumentationComment(checker); const tags = symbol.getJsDocTags(checker); const prefixDisplayParts = [...typeSymbolDisplay, punctuationPart(SyntaxKind.LessThanToken)]; - return { isVariadic: false, prefixDisplayParts, suffixDisplayParts: [punctuationPart(SyntaxKind.GreaterThanToken)], separatorDisplayParts, parameters, documentation, tags }; + return { + isVariadic: false, + prefixDisplayParts, + suffixDisplayParts: [punctuationPart(SyntaxKind.GreaterThanToken)], + separatorDisplayParts, + parameters, + documentation, + tags, + }; } const separatorDisplayParts: SymbolDisplayPart[] = [punctuationPart(SyntaxKind.CommaToken), spacePart()]; - function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: readonly SymbolDisplayPart[], isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem[] { - const infos = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile); + function getSignatureHelpItem( + candidateSignature: Signature, + callTargetDisplayParts: readonly SymbolDisplayPart[], + isTypeParameterList: boolean, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, + ): SignatureHelpItem[] { + const infos = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)( + candidateSignature, + checker, + enclosingDeclaration, + sourceFile, + ); return map(infos, ({ isVariadic, parameters, prefix, suffix }) => { const prefixDisplayParts = [...callTargetDisplayParts, ...prefix]; - const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)]; + const suffixDisplayParts = [ + ...suffix, + ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker), + ]; const documentation = candidateSignature.getDocumentationComment(checker); const tags = candidateSignature.getJsDocTags(); - return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags }; + return { + isVariadic, + prefixDisplayParts, + suffixDisplayParts, + separatorDisplayParts, + parameters, + documentation, + tags, + }; }); } - function returnTypeToDisplayParts(candidateSignature: Signature, enclosingDeclaration: Node, checker: TypeChecker): readonly SymbolDisplayPart[] { + function returnTypeToDisplayParts( + candidateSignature: Signature, + enclosingDeclaration: Node, + checker: TypeChecker, + ): readonly SymbolDisplayPart[] { return mapToDisplayParts(writer => { writer.writePunctuation(":"); writer.writeSpace(" "); @@ -624,7 +854,12 @@ namespace ts.SignatureHelp { checker.writeTypePredicate(predicate, enclosingDeclaration, /*flags*/ undefined, writer); } else { - checker.writeType(checker.getReturnTypeOfSignature(candidateSignature), enclosingDeclaration, /*flags*/ undefined, writer); + checker.writeType( + checker.getReturnTypeOfSignature(candidateSignature), + enclosingDeclaration, + /*flags*/ undefined, + writer, + ); } }); } @@ -636,56 +871,132 @@ namespace ts.SignatureHelp { readonly suffix: readonly SymbolDisplayPart[]; } - function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] { + function itemInfoForTypeParameters( + candidateSignature: Signature, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, + ): SignatureHelpItemInfo[] { const typeParameters = (candidateSignature.target || candidateSignature).typeParameters; const printer = createPrinter({ removeComments: true }); - const parameters = (typeParameters || emptyArray).map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer)); - const thisParameter = candidateSignature.thisParameter ? [checker.symbolToParameterDeclaration(candidateSignature.thisParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!] : []; + const parameters = (typeParameters || emptyArray).map(t => + createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer) + ); + const thisParameter = candidateSignature.thisParameter + ? [ + checker.symbolToParameterDeclaration( + candidateSignature.thisParameter, + enclosingDeclaration, + signatureHelpNodeBuilderFlags, + )!, + ] : []; return checker.getExpandedParameters(candidateSignature).map(paramList => { - const params = factory.createNodeArray([...thisParameter, ...map(paramList, param => checker.symbolToParameterDeclaration(param, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)]); + const params = factory.createNodeArray([ + ...thisParameter, + ...map( + paramList, + param => + checker.symbolToParameterDeclaration( + param, + enclosingDeclaration, + signatureHelpNodeBuilderFlags, + )!, + ), + ]); const parameterParts = mapToDisplayParts(writer => { printer.writeList(ListFormat.CallExpressionArguments, params, sourceFile, writer); }); - return { isVariadic: false, parameters, prefix: [punctuationPart(SyntaxKind.LessThanToken)], suffix: [punctuationPart(SyntaxKind.GreaterThanToken), ...parameterParts] }; + return { + isVariadic: false, + parameters, + prefix: [punctuationPart(SyntaxKind.LessThanToken)], + suffix: [punctuationPart(SyntaxKind.GreaterThanToken), ...parameterParts], + }; }); } - function itemInfoForParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] { + function itemInfoForParameters( + candidateSignature: Signature, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, + ): SignatureHelpItemInfo[] { const printer = createPrinter({ removeComments: true }); const typeParameterParts = mapToDisplayParts(writer => { if (candidateSignature.typeParameters && candidateSignature.typeParameters.length) { - const args = factory.createNodeArray(candidateSignature.typeParameters.map(p => checker.typeParameterToDeclaration(p, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)); + const args = factory.createNodeArray( + candidateSignature.typeParameters.map(p => + checker.typeParameterToDeclaration(p, enclosingDeclaration, signatureHelpNodeBuilderFlags)! + ), + ); printer.writeList(ListFormat.TypeParameters, args, sourceFile, writer); } }); const lists = checker.getExpandedParameters(candidateSignature); - const isVariadic: (parameterList: readonly Symbol[]) => boolean = !checker.hasEffectiveRestParameter(candidateSignature) ? _ => false - : lists.length === 1 ? _ => true - : pList => !!(pList.length && (pList[pList.length - 1] as TransientSymbol).checkFlags & CheckFlags.RestParameter); + const isVariadic: (parameterList: readonly Symbol[]) => boolean = + !checker.hasEffectiveRestParameter(candidateSignature) ? _ => false + : lists.length === 1 ? _ => true + : pList => + !!(pList.length + && (pList[pList.length - 1] as TransientSymbol).checkFlags & CheckFlags.RestParameter); return lists.map(parameterList => ({ isVariadic: isVariadic(parameterList), - parameters: parameterList.map(p => createSignatureHelpParameterForParameter(p, checker, enclosingDeclaration, sourceFile, printer)), + parameters: parameterList.map(p => + createSignatureHelpParameterForParameter(p, checker, enclosingDeclaration, sourceFile, printer) + ), prefix: [...typeParameterParts, punctuationPart(SyntaxKind.OpenParenToken)], suffix: [punctuationPart(SyntaxKind.CloseParenToken)], })); } - function createSignatureHelpParameterForParameter(parameter: Symbol, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile, printer: Printer): SignatureHelpParameter { + function createSignatureHelpParameterForParameter( + parameter: Symbol, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, + printer: Printer, + ): SignatureHelpParameter { const displayParts = mapToDisplayParts(writer => { - const param = checker.symbolToParameterDeclaration(parameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!; + const param = checker.symbolToParameterDeclaration( + parameter, + enclosingDeclaration, + signatureHelpNodeBuilderFlags, + )!; printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer); }); const isOptional = checker.isOptionalParameter(parameter.valueDeclaration as ParameterDeclaration); const isRest = !!((parameter as TransientSymbol).checkFlags & CheckFlags.RestParameter); - return { name: parameter.name, documentation: parameter.getDocumentationComment(checker), displayParts, isOptional, isRest }; + return { + name: parameter.name, + documentation: parameter.getDocumentationComment(checker), + displayParts, + isOptional, + isRest, + }; } - function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile, printer: Printer): SignatureHelpParameter { + function createSignatureHelpParameterForTypeParameter( + typeParameter: TypeParameter, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, + printer: Printer, + ): SignatureHelpParameter { const displayParts = mapToDisplayParts(writer => { - const param = checker.typeParameterToDeclaration(typeParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!; + const param = checker.typeParameterToDeclaration( + typeParameter, + enclosingDeclaration, + signatureHelpNodeBuilderFlags, + )!; printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer); }); - return { name: typeParameter.symbol.name, documentation: typeParameter.symbol.getDocumentationComment(checker), displayParts, isOptional: false, isRest: false }; + return { + name: typeParameter.symbol.name, + documentation: typeParameter.symbol.getDocumentationComment(checker), + displayParts, + isOptional: false, + isRest: false, + }; } } diff --git a/src/services/smartSelection.ts b/src/services/smartSelection.ts index 13d3ce2dd7021..ad992a65c8562 100644 --- a/src/services/smartSelection.ts +++ b/src/services/smartSelection.ts @@ -27,7 +27,8 @@ namespace ts.SmartSelectionRange { if (positionShouldSnapToNode(sourceFile, pos, node)) { if ( isFunctionBody(node) - && isFunctionLikeDeclaration(parentNode) && !positionsAreOnSameLine(node.getStart(sourceFile), node.getEnd(), sourceFile) + && isFunctionLikeDeclaration(parentNode) + && !positionsAreOnSameLine(node.getStart(sourceFile), node.getEnd(), sourceFile) ) { pushSelectionRange(node.getStart(sourceFile), node.getEnd()); } @@ -60,7 +61,8 @@ namespace ts.SmartSelectionRange { // Blocks with braces, brackets, parens, or JSX tags on separate lines should be // selected from open to close, including whitespace but not including the braces/etc. themselves. - const isBetweenMultiLineBookends = isSyntaxList(node) && isListOpener(prevNode) && isListCloser(nextNode) + const isBetweenMultiLineBookends = isSyntaxList(node) && isListOpener(prevNode) + && isListCloser(nextNode) && !positionsAreOnSameLine(prevNode.getStart(), nextNode.getStart(), sourceFile); let start = isBetweenMultiLineBookends ? prevNode.getEnd() : node.getStart(); const end = isBetweenMultiLineBookends ? nextNode.getStart() : getEndPos(sourceFile, node); @@ -76,7 +78,10 @@ namespace ts.SmartSelectionRange { // covering the JSDoc comment before diving further. if (isSyntaxList(node)) { const firstChild = node.getChildren()[0]; - if (firstChild && hasJSDocNodes(firstChild) && firstChild.jsDoc?.length && firstChild.getStart() !== node.pos) { + if ( + firstChild && hasJSDocNodes(firstChild) && firstChild.jsDoc?.length + && firstChild.getStart() !== node.pos + ) { start = Math.min(start, first(firstChild.jsDoc).getStart()); } } @@ -109,9 +114,9 @@ namespace ts.SmartSelectionRange { if ( !selectionRange || ( // Skip ranges that are identical to the parent - !textSpansEqual(textSpan, selectionRange.textSpan) && + !textSpansEqual(textSpan, selectionRange.textSpan) // Skip ranges that don’t contain the original position - textSpanIntersectsWithPosition(textSpan, pos) + && textSpanIntersectsWithPosition(textSpan, pos) ) ) { selectionRange = { textSpan, ...selectionRange && { parent: selectionRange } }; @@ -186,14 +191,20 @@ namespace ts.SmartSelectionRange { Debug.assertEqual(openBraceToken.kind, SyntaxKind.OpenBraceToken); Debug.assertEqual(closeBraceToken.kind, SyntaxKind.CloseBraceToken); // Group `-/+readonly` and `-/+?` - const groupedWithPlusMinusTokens = groupChildren(children, child => - child === node.readonlyToken || child.kind === SyntaxKind.ReadonlyKeyword || - child === node.questionToken || child.kind === SyntaxKind.QuestionToken); + const groupedWithPlusMinusTokens = groupChildren( + children, + child => + child === node.readonlyToken || child.kind === SyntaxKind.ReadonlyKeyword + || child === node.questionToken || child.kind === SyntaxKind.QuestionToken, + ); // Group type parameter with surrounding brackets - const groupedWithBrackets = groupChildren(groupedWithPlusMinusTokens, ({ kind }) => - kind === SyntaxKind.OpenBracketToken || - kind === SyntaxKind.TypeParameter || - kind === SyntaxKind.CloseBracketToken); + const groupedWithBrackets = groupChildren( + groupedWithPlusMinusTokens, + ({ kind }) => + kind === SyntaxKind.OpenBracketToken + || kind === SyntaxKind.TypeParameter + || kind === SyntaxKind.CloseBracketToken, + ); return [ openBraceToken, // Pivot on `:` @@ -204,7 +215,10 @@ namespace ts.SmartSelectionRange { // Group modifiers and property name, then pivot on `:`. if (isPropertySignature(node)) { - const children = groupChildren(node.getChildren(), child => child === node.name || contains(node.modifiers, child)); + const children = groupChildren( + node.getChildren(), + child => child === node.name || contains(node.modifiers, child), + ); const firstJSDocChild = children[0]?.kind === SyntaxKind.JSDoc ? children[0] : undefined; const withJSDocSeparated = firstJSDocChild ? children.slice(1) : children; const splittedChildren = splitChildren(withJSDocSeparated, ({ kind }) => kind === SyntaxKind.ColonToken); @@ -213,8 +227,14 @@ namespace ts.SmartSelectionRange { // Group the parameter name with its `...`, then that group with its `?`, then pivot on `=`. if (isParameter(node)) { - const groupedDotDotDotAndName = groupChildren(node.getChildren(), child => child === node.dotDotDotToken || child === node.name); - const groupedWithQuestionToken = groupChildren(groupedDotDotDotAndName, child => child === groupedDotDotDotAndName[0] || child === node.questionToken); + const groupedDotDotDotAndName = groupChildren( + node.getChildren(), + child => child === node.dotDotDotToken || child === node.name, + ); + const groupedWithQuestionToken = groupChildren( + groupedDotDotDotAndName, + child => child === groupedDotDotDotAndName[0] || child === node.questionToken, + ); return splitChildren(groupedWithQuestionToken, ({ kind }) => kind === SyntaxKind.EqualsToken); } @@ -266,7 +286,11 @@ namespace ts.SmartSelectionRange { * @param separateTrailingSemicolon If the last token is a semicolon, it will be returned as a separate * child rather than be included in the right-hand group. */ - function splitChildren(children: Node[], pivotOn: (child: Node) => boolean, separateTrailingSemicolon = true): Node[] { + function splitChildren( + children: Node[], + pivotOn: (child: Node) => boolean, + separateTrailingSemicolon = true, + ): Node[] { if (children.length < 2) { return children; } diff --git a/src/services/sourcemaps.ts b/src/services/sourcemaps.ts index 627a8a196cde7..c344a3ae0b739 100644 --- a/src/services/sourcemaps.ts +++ b/src/services/sourcemaps.ts @@ -16,7 +16,10 @@ namespace ts { fileExists?(path: string): boolean; readFile?(path: string, encoding?: string): string | undefined; getSourceFileLike?(fileName: string): SourceFileLike | undefined; - getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined; + getDocumentPositionMapper?( + generatedFileName: string, + sourceFileName?: string, + ): DocumentPositionMapper | undefined; log(s: string): void; } @@ -78,9 +81,15 @@ namespace ts { const options = program.getCompilerOptions(); const outPath = outFile(options); - const declarationPath = outPath ? - removeFileExtension(outPath) + Extension.Dts : - getDeclarationEmitOutputFilePathWorker(info.fileName, program.getCompilerOptions(), currentDirectory, program.getCommonSourceDirectory(), getCanonicalFileName); + const declarationPath = outPath + ? removeFileExtension(outPath) + Extension.Dts + : getDeclarationEmitOutputFilePathWorker( + info.fileName, + program.getCompilerOptions(), + currentDirectory, + program.getCommonSourceDirectory(), + getCanonicalFileName, + ); if (declarationPath === undefined) return undefined; const newLoc = getDocumentPositionMapper(declarationPath, info.fileName).getGeneratedPosition(info); @@ -116,9 +125,9 @@ namespace ts { // This can be called from source mapper in either source program or program that includes generated file function getSourceFileLike(fileName: string) { - return !host.getSourceFileLike ? - getSourceFile(fileName) || getOrCreateSourceFileLike(fileName) : - host.getSourceFileLike(fileName); + return !host.getSourceFileLike + ? getSourceFile(fileName) || getOrCreateSourceFileLike(fileName) + : host.getSourceFileLike(fileName); } function toLineColumnOffset(fileName: string, position: number): LineAndCharacter { @@ -136,7 +145,10 @@ namespace ts { * string | undefined to contents of map file to create DocumentPositionMapper from it * DocumentPositionMapper | false to give back cached DocumentPositionMapper */ - export type ReadMapFile = (mapFileName: string, mapFileNameFromDts: string | undefined) => string | undefined | DocumentPositionMapper | false; + export type ReadMapFile = ( + mapFileName: string, + mapFileNameFromDts: string | undefined, + ) => string | undefined | DocumentPositionMapper | false; export function getDocumentPositionMapper( host: DocumentPositionMapperHost, @@ -161,7 +173,8 @@ namespace ts { possibleMapLocations.push(mapFileName); } possibleMapLocations.push(generatedFileName + ".map"); - const originalMapFileName = mapFileName && getNormalizedAbsolutePath(mapFileName, getDirectoryPath(generatedFileName)); + const originalMapFileName = mapFileName + && getNormalizedAbsolutePath(mapFileName, getDirectoryPath(generatedFileName)); for (const location of possibleMapLocations) { const mapFileName = getNormalizedAbsolutePath(location, getDirectoryPath(generatedFileName)); const mapFileContents = readMapFile(mapFileName, originalMapFileName); diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index cb8428a7aa655..a30aef9e60f38 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -41,8 +41,25 @@ namespace ts.Completions.StringCompletions { } if (isInString(sourceFile, position, contextToken)) { if (!contextToken || !isStringLiteralLike(contextToken)) return undefined; - const entries = getStringLiteralCompletionEntries(sourceFile, contextToken, position, program.getTypeChecker(), options, host, preferences); - return convertStringLiteralCompletions(entries, contextToken, sourceFile, host, program, log, options, preferences); + const entries = getStringLiteralCompletionEntries( + sourceFile, + contextToken, + position, + program.getTypeChecker(), + options, + host, + preferences, + ); + return convertStringLiteralCompletions( + entries, + contextToken, + sourceFile, + host, + program, + log, + options, + preferences, + ); } } @@ -82,7 +99,13 @@ namespace ts.Completions.StringCompletions { options, /*formatContext*/ undefined, ); // Target will not be used, so arbitrary - return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: completion.hasIndexSignature, optionalReplacementSpan, entries }; + return { + isGlobalCompletion: false, + isMemberCompletion: true, + isNewIdentifierLocation: completion.hasIndexSignature, + optionalReplacementSpan, + entries, + }; } case StringLiteralCompletionKind.Types: { const entries = completion.types.map(type => ({ @@ -92,31 +115,70 @@ namespace ts.Completions.StringCompletions { sortText: SortText.LocationPriority, replacementSpan: getReplacementSpanForContextToken(contextToken), })); - return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: completion.isNewIdentifier, optionalReplacementSpan, entries }; + return { + isGlobalCompletion: false, + isMemberCompletion: false, + isNewIdentifierLocation: completion.isNewIdentifier, + optionalReplacementSpan, + entries, + }; } default: return Debug.assertNever(completion); } } - export function getStringLiteralCompletionDetails(name: string, sourceFile: SourceFile, position: number, contextToken: Node | undefined, checker: TypeChecker, options: CompilerOptions, host: LanguageServiceHost, cancellationToken: CancellationToken, preferences: UserPreferences) { + export function getStringLiteralCompletionDetails( + name: string, + sourceFile: SourceFile, + position: number, + contextToken: Node | undefined, + checker: TypeChecker, + options: CompilerOptions, + host: LanguageServiceHost, + cancellationToken: CancellationToken, + preferences: UserPreferences, + ) { if (!contextToken || !isStringLiteralLike(contextToken)) return undefined; - const completions = getStringLiteralCompletionEntries(sourceFile, contextToken, position, checker, options, host, preferences); - return completions && stringLiteralCompletionDetails(name, contextToken, completions, sourceFile, checker, cancellationToken); + const completions = getStringLiteralCompletionEntries( + sourceFile, + contextToken, + position, + checker, + options, + host, + preferences, + ); + return completions + && stringLiteralCompletionDetails(name, contextToken, completions, sourceFile, checker, cancellationToken); } - function stringLiteralCompletionDetails(name: string, location: Node, completion: StringLiteralCompletion, sourceFile: SourceFile, checker: TypeChecker, cancellationToken: CancellationToken): CompletionEntryDetails | undefined { + function stringLiteralCompletionDetails( + name: string, + location: Node, + completion: StringLiteralCompletion, + sourceFile: SourceFile, + checker: TypeChecker, + cancellationToken: CancellationToken, + ): CompletionEntryDetails | undefined { switch (completion.kind) { case StringLiteralCompletionKind.Paths: { const match = find(completion.paths, p => p.name === name); - return match && createCompletionDetails(name, kindModifiersFromExtension(match.extension), match.kind, [textPart(name)]); + return match + && createCompletionDetails(name, kindModifiersFromExtension(match.extension), match.kind, [ + textPart(name), + ]); } case StringLiteralCompletionKind.Properties: { const match = find(completion.symbols, s => s.name === name); - return match && createCompletionDetailsForSymbol(match, checker, sourceFile, location, cancellationToken); + return match + && createCompletionDetailsForSymbol(match, checker, sourceFile, location, cancellationToken); } case StringLiteralCompletionKind.Types: - return find(completion.types, t => t.value === name) ? createCompletionDetails(name, ScriptElementKindModifier.none, ScriptElementKind.typeElement, [textPart(name)]) : undefined; + return find(completion.types, t => t.value === name) + ? createCompletionDetails(name, ScriptElementKindModifier.none, ScriptElementKind.typeElement, [ + textPart(name), + ]) : undefined; default: return Debug.assertNever(completion); } @@ -125,7 +187,13 @@ namespace ts.Completions.StringCompletions { function convertPathCompletions(pathCompletions: readonly PathCompletion[]): CompletionInfo { const isGlobalCompletion = false; // We don't want the editor to offer any other completions, such as snippets, inside a comment. const isNewIdentifierLocation = true; // The user may type in a path that doesn't yet exist, creating a "new identifier" with respect to the collection of identifiers the server is aware of. - const entries = pathCompletions.map(({ name, kind, span, extension }): CompletionEntry => ({ name, kind, kindModifiers: kindModifiersFromExtension(extension), sortText: SortText.LocationPriority, replacementSpan: span })); + const entries = pathCompletions.map(({ name, kind, span, extension }): CompletionEntry => ({ + name, + kind, + kindModifiers: kindModifiersFromExtension(extension), + sortText: SortText.LocationPriority, + replacementSpan: span, + })); return { isGlobalCompletion, isMemberCompletion: false, isNewIdentifierLocation, entries }; } function kindModifiersFromExtension(extension: Extension | undefined): ScriptElementKindModifier { @@ -178,8 +246,19 @@ namespace ts.Completions.StringCompletions { readonly types: readonly StringLiteralType[]; readonly isNewIdentifier: boolean; } - type StringLiteralCompletion = { readonly kind: StringLiteralCompletionKind.Paths; readonly paths: readonly PathCompletion[]; } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes; - function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost, preferences: UserPreferences): StringLiteralCompletion | undefined { + type StringLiteralCompletion = + | { readonly kind: StringLiteralCompletionKind.Paths; readonly paths: readonly PathCompletion[]; } + | StringLiteralCompletionsFromProperties + | StringLiteralCompletionsFromTypes; + function getStringLiteralCompletionEntries( + sourceFile: SourceFile, + node: StringLiteralLike, + position: number, + typeChecker: TypeChecker, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + preferences: UserPreferences, + ): StringLiteralCompletion | undefined { const parent = walkUpParentheses(node.parent); switch (parent.kind) { case SyntaxKind.LiteralType: { @@ -189,7 +268,11 @@ namespace ts.Completions.StringCompletions { case SyntaxKind.TypeReference: { const typeArgument = findAncestor(parent, n => n.parent === grandParent) as LiteralTypeNode; if (typeArgument) { - return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(typeArgument)), isNewIdentifier: false }; + return { + kind: StringLiteralCompletionKind.Types, + types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(typeArgument)), + isNewIdentifier: false, + }; } return undefined; } @@ -206,13 +289,28 @@ namespace ts.Completions.StringCompletions { } return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode(objectType)); case SyntaxKind.ImportType: - return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) }; + return { + kind: StringLiteralCompletionKind.Paths, + paths: getStringLiteralCompletionsFromModuleNames( + sourceFile, + node, + compilerOptions, + host, + typeChecker, + preferences, + ), + }; case SyntaxKind.UnionType: { if (!isTypeReferenceNode(grandParent.parent)) { return undefined; } - const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion(grandParent as UnionTypeNode, parent as LiteralTypeNode); - const types = getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(grandParent as UnionTypeNode)).filter(t => !contains(alreadyUsedTypes, t.value)); + const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion( + grandParent as UnionTypeNode, + parent as LiteralTypeNode, + ); + const types = getStringLiteralTypes( + typeChecker.getTypeArgumentConstraint(grandParent as UnionTypeNode), + ).filter(t => !contains(alreadyUsedTypes, t.value)); return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false }; } default: @@ -255,11 +353,21 @@ namespace ts.Completions.StringCompletions { case SyntaxKind.NewExpression: case SyntaxKind.JsxAttribute: if (!isRequireCallArgument(node) && !isImportCall(parent)) { - const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(parent.kind === SyntaxKind.JsxAttribute ? parent.parent : node, position, sourceFile); + const argumentInfo = SignatureHelp.getArgumentInfoForCompletions( + parent.kind === SyntaxKind.JsxAttribute ? parent.parent : node, + position, + sourceFile, + ); // Get string literal completions from specialized signatures of the target // i.e. declare function f(a: 'A'); // f("/*completion position*/") - return argumentInfo && getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker) || fromContextualType(); + return argumentInfo + && getStringLiteralCompletionsFromSignature( + argumentInfo.invocation, + node, + argumentInfo, + typeChecker, + ) || fromContextualType(); } // falls through (is `require("")` or `require(""` or `import("")`) @@ -272,7 +380,17 @@ namespace ts.Completions.StringCompletions { // import x = require("/*completion position*/"); // var y = require("/*completion position*/"); // export * from "/*completion position*/"; - return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) }; + return { + kind: StringLiteralCompletionKind.Paths, + paths: getStringLiteralCompletionsFromModuleNames( + sourceFile, + node, + compilerOptions, + host, + typeChecker, + preferences, + ), + }; default: return fromContextualType(); @@ -281,7 +399,11 @@ namespace ts.Completions.StringCompletions { function fromContextualType(): StringLiteralCompletion { // Get completion for string literal from string literal type // i.e. var x: "hi" | "hello" = "/*completion position*/" - return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(getContextualTypeFromParent(node, typeChecker)), isNewIdentifier: false }; + return { + kind: StringLiteralCompletionKind.Types, + types: getStringLiteralTypes(getContextualTypeFromParent(node, typeChecker)), + isNewIdentifier: false, + }; } } @@ -296,18 +418,34 @@ namespace ts.Completions.StringCompletions { } } - function getAlreadyUsedTypesInStringLiteralUnion(union: UnionTypeNode, current: LiteralTypeNode): readonly string[] { - return mapDefined(union.types, type => type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text : undefined); + function getAlreadyUsedTypesInStringLiteralUnion( + union: UnionTypeNode, + current: LiteralTypeNode, + ): readonly string[] { + return mapDefined( + union.types, + type => + type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text + : undefined, + ); } - function getStringLiteralCompletionsFromSignature(call: CallLikeExpression, arg: StringLiteralLike, argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker): StringLiteralCompletionsFromTypes | undefined { + function getStringLiteralCompletionsFromSignature( + call: CallLikeExpression, + arg: StringLiteralLike, + argumentInfo: SignatureHelp.ArgumentInfoForCompletions, + checker: TypeChecker, + ): StringLiteralCompletionsFromTypes | undefined { let isNewIdentifier = false; const uniques = new Map(); const candidates: Signature[] = []; - const editingArgument = isJsxOpeningLikeElement(call) ? Debug.checkDefined(findAncestor(arg.parent, isJsxAttribute)) : arg; + const editingArgument = isJsxOpeningLikeElement(call) + ? Debug.checkDefined(findAncestor(arg.parent, isJsxAttribute)) : arg; checker.getResolvedSignatureForStringLiteralCompletions(call, editingArgument, candidates); const types = flatMap(candidates, candidate => { - if (!signatureHasRestParameter(candidate) && argumentInfo.argumentCount > candidate.parameters.length) return; + if (!signatureHasRestParameter(candidate) && argumentInfo.argumentCount > candidate.parameters.length) { + return; + } let type = candidate.getTypeParameterAtPosition(argumentInfo.argumentIndex); if (isJsxOpeningLikeElement(call)) { const propType = checker.getTypeOfPropertyOfType(type, (editingArgument as JsxAttribute).name.text); @@ -321,15 +459,23 @@ namespace ts.Completions.StringCompletions { return length(types) ? { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier } : undefined; } - function stringLiteralCompletionsFromProperties(type: Type | undefined): StringLiteralCompletionsFromProperties | undefined { + function stringLiteralCompletionsFromProperties( + type: Type | undefined, + ): StringLiteralCompletionsFromProperties | undefined { return type && { kind: StringLiteralCompletionKind.Properties, - symbols: filter(type.getApparentProperties(), prop => !(prop.valueDeclaration && isPrivateIdentifierClassElementDeclaration(prop.valueDeclaration))), + symbols: filter( + type.getApparentProperties(), + prop => !(prop.valueDeclaration && isPrivateIdentifierClassElementDeclaration(prop.valueDeclaration)), + ), hasIndexSignature: hasIndexSignature(type), }; } - function stringLiteralCompletionsForObjectLiteral(checker: TypeChecker, objectLiteralExpression: ObjectLiteralExpression): StringLiteralCompletionsFromProperties | undefined { + function stringLiteralCompletionsForObjectLiteral( + checker: TypeChecker, + objectLiteralExpression: ObjectLiteralExpression, + ): StringLiteralCompletionsFromProperties | undefined { const contextualType = checker.getContextualType(objectLiteralExpression); if (!contextualType) return undefined; @@ -348,16 +494,23 @@ namespace ts.Completions.StringCompletions { }; } - function getStringLiteralTypes(type: Type | undefined, uniques = new Map()): readonly StringLiteralType[] { + function getStringLiteralTypes( + type: Type | undefined, + uniques = new Map(), + ): readonly StringLiteralType[] { if (!type) return emptyArray; type = skipConstraint(type); - return type.isUnion() ? flatMap(type.types, t => getStringLiteralTypes(t, uniques)) : - type.isStringLiteral() && !(type.flags & TypeFlags.EnumLiteral) && addToSeen(uniques, type.value) ? [type] : emptyArray; + return type.isUnion() ? flatMap(type.types, t => getStringLiteralTypes(t, uniques)) + : type.isStringLiteral() && !(type.flags & TypeFlags.EnumLiteral) && addToSeen(uniques, type.value) ? [type] + : emptyArray; } interface NameAndKind { readonly name: string; - readonly kind: ScriptElementKind.scriptElement | ScriptElementKind.directory | ScriptElementKind.externalModuleName; + readonly kind: + | ScriptElementKind.scriptElement + | ScriptElementKind.directory + | ScriptElementKind.externalModuleName; readonly extension: Extension | undefined; } interface PathCompletion extends NameAndKind { @@ -371,30 +524,79 @@ namespace ts.Completions.StringCompletions { return nameAndKind(name, ScriptElementKind.directory, /*extension*/ undefined); } - function addReplacementSpans(text: string, textStart: number, names: readonly NameAndKind[]): readonly PathCompletion[] { + function addReplacementSpans( + text: string, + textStart: number, + names: readonly NameAndKind[], + ): readonly PathCompletion[] { const span = getDirectoryFragmentTextSpan(text, textStart); const wholeSpan = text.length === 0 ? undefined : createTextSpan(textStart, text.length); - return names.map(({ name, kind, extension }): PathCompletion => Math.max(name.indexOf(directorySeparator), name.indexOf(altDirectorySeparator)) !== -1 ? { name, kind, extension, span: wholeSpan } : { name, kind, extension, span }); + return names.map(({ name, kind, extension }): PathCompletion => + Math.max(name.indexOf(directorySeparator), name.indexOf(altDirectorySeparator)) !== -1 + ? { name, kind, extension, span: wholeSpan } : { name, kind, extension, span } + ); } - function getStringLiteralCompletionsFromModuleNames(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker, preferences: UserPreferences): readonly PathCompletion[] { - return addReplacementSpans(node.text, node.getStart(sourceFile) + 1, getStringLiteralCompletionsFromModuleNamesWorker(sourceFile, node, compilerOptions, host, typeChecker, preferences)); + function getStringLiteralCompletionsFromModuleNames( + sourceFile: SourceFile, + node: LiteralExpression, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + typeChecker: TypeChecker, + preferences: UserPreferences, + ): readonly PathCompletion[] { + return addReplacementSpans( + node.text, + node.getStart(sourceFile) + 1, + getStringLiteralCompletionsFromModuleNamesWorker( + sourceFile, + node, + compilerOptions, + host, + typeChecker, + preferences, + ), + ); } - function getStringLiteralCompletionsFromModuleNamesWorker(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker, preferences: UserPreferences): readonly NameAndKind[] { + function getStringLiteralCompletionsFromModuleNamesWorker( + sourceFile: SourceFile, + node: LiteralExpression, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + typeChecker: TypeChecker, + preferences: UserPreferences, + ): readonly NameAndKind[] { const literalValue = normalizeSlashes(node.text); const mode = isStringLiteralLike(node) ? getModeForUsageLocation(sourceFile, node) : undefined; const scriptPath = sourceFile.path; const scriptDirectory = getDirectoryPath(scriptPath); - return isPathRelativeToScript(literalValue) || !compilerOptions.baseUrl && (isRootedDiskPath(literalValue) || isUrl(literalValue)) - ? getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath, getIncludeExtensionOption()) - : getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, mode, compilerOptions, host, getIncludeExtensionOption(), typeChecker); + return isPathRelativeToScript(literalValue) + || !compilerOptions.baseUrl && (isRootedDiskPath(literalValue) || isUrl(literalValue)) + ? getCompletionEntriesForRelativeModules( + literalValue, + scriptDirectory, + compilerOptions, + host, + scriptPath, + getIncludeExtensionOption(), + ) + : getCompletionEntriesForNonRelativeModules( + literalValue, + scriptDirectory, + mode, + compilerOptions, + host, + getIncludeExtensionOption(), + typeChecker, + ); function getIncludeExtensionOption() { const mode = isStringLiteralLike(node) ? getModeForUsageLocation(sourceFile, node) : undefined; - return preferences.importModuleSpecifierEnding === "js" || mode === ModuleKind.ESNext ? IncludeExtensionsOption.ModuleSpecifierCompletion : IncludeExtensionsOption.Exclude; + return preferences.importModuleSpecifierEnding === "js" || mode === ModuleKind.ESNext + ? IncludeExtensionsOption.ModuleSpecifierCompletion : IncludeExtensionsOption.Exclude; } } @@ -402,10 +604,23 @@ namespace ts.Completions.StringCompletions { readonly extensions: readonly Extension[]; readonly includeExtensionsOption: IncludeExtensionsOption; } - function getExtensionOptions(compilerOptions: CompilerOptions, includeExtensionsOption = IncludeExtensionsOption.Exclude): ExtensionOptions { - return { extensions: flatten(getSupportedExtensionsForModuleResolution(compilerOptions)), includeExtensionsOption }; + function getExtensionOptions( + compilerOptions: CompilerOptions, + includeExtensionsOption = IncludeExtensionsOption.Exclude, + ): ExtensionOptions { + return { + extensions: flatten(getSupportedExtensionsForModuleResolution(compilerOptions)), + includeExtensionsOption, + }; } - function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path, includeExtensions: IncludeExtensionsOption) { + function getCompletionEntriesForRelativeModules( + literalValue: string, + scriptDirectory: string, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + scriptPath: Path, + includeExtensions: IncludeExtensionsOption, + ) { const extensionOptions = getExtensionOptions(compilerOptions, includeExtensions); if (compilerOptions.rootDirs) { return getCompletionEntriesForDirectoryFragmentWithRootDirs( @@ -419,38 +634,58 @@ namespace ts.Completions.StringCompletions { ); } else { - return arrayFrom(getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, scriptPath).values()); + return arrayFrom( + getCompletionEntriesForDirectoryFragment( + literalValue, + scriptDirectory, + extensionOptions, + host, + scriptPath, + ).values(), + ); } } function isEmitResolutionKindUsingNodeModules(compilerOptions: CompilerOptions): boolean { - return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs || - getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || - getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext; + return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs + || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext; } function isEmitModuleResolutionRespectingExportMaps(compilerOptions: CompilerOptions) { - return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || - getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext; + return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext; } function getSupportedExtensionsForModuleResolution(compilerOptions: CompilerOptions): readonly Extension[][] { const extensions = getSupportedExtensions(compilerOptions); - return isEmitResolutionKindUsingNodeModules(compilerOptions) ? - getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, extensions) : - extensions; + return isEmitResolutionKindUsingNodeModules(compilerOptions) + ? getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, extensions) + : extensions; } /** * Takes a script path and returns paths for all potential folders that could be merged with its * containing folder via the "rootDirs" compiler option */ - function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, scriptDirectory: string, ignoreCase: boolean): readonly string[] { + function getBaseDirectoriesFromRootDirs( + rootDirs: string[], + basePath: string, + scriptDirectory: string, + ignoreCase: boolean, + ): readonly string[] { // Make all paths absolute/normalized if they are not already - rootDirs = rootDirs.map(rootDirectory => normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory))); + rootDirs = rootDirs.map(rootDirectory => + normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory)) + ); // Determine the path to the directory containing the script relative to the root directory it is contained within - const relativeDirectory = firstDefined(rootDirs, rootDirectory => containsPath(rootDirectory, scriptDirectory, basePath, ignoreCase) ? scriptDirectory.substr(rootDirectory.length) : undefined)!; // TODO: GH#18217 + const relativeDirectory = firstDefined( + rootDirs, + rootDirectory => + containsPath(rootDirectory, scriptDirectory, basePath, ignoreCase) + ? scriptDirectory.substr(rootDirectory.length) : undefined, + )!; // TODO: GH#18217 // Now find a path for each potential directory that is to be merged with the one containing the script return deduplicate( @@ -460,11 +695,26 @@ namespace ts.Completions.StringCompletions { ); } - function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptDirectory: string, extensionOptions: ExtensionOptions, compilerOptions: CompilerOptions, host: LanguageServiceHost, exclude: string): readonly NameAndKind[] { + function getCompletionEntriesForDirectoryFragmentWithRootDirs( + rootDirs: string[], + fragment: string, + scriptDirectory: string, + extensionOptions: ExtensionOptions, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + exclude: string, + ): readonly NameAndKind[] { const basePath = compilerOptions.project || host.getCurrentDirectory(); const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames()); const baseDirectories = getBaseDirectoriesFromRootDirs(rootDirs, basePath, scriptDirectory, ignoreCase); - return flatMap(baseDirectories, baseDirectory => arrayFrom(getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, host, exclude).values())); + return flatMap( + baseDirectories, + baseDirectory => + arrayFrom( + getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, host, exclude) + .values(), + ), + ); } const enum IncludeExtensionsOption { @@ -504,19 +754,32 @@ namespace ts.Completions.StringCompletions { fragment = ensureTrailingDirectorySeparator(fragment); const absolutePath = resolvePath(scriptPath, fragment); - const baseDirectory = hasTrailingDirectorySeparator(absolutePath) ? absolutePath : getDirectoryPath(absolutePath); + const baseDirectory = hasTrailingDirectorySeparator(absolutePath) ? absolutePath + : getDirectoryPath(absolutePath); // check for a version redirect const packageJsonPath = findPackageJson(baseDirectory, host); if (packageJsonPath) { - const packageJson = readJson(packageJsonPath, host as { readFile: (filename: string) => string | undefined; }); + const packageJson = readJson( + packageJsonPath, + host as { readFile: (filename: string) => string | undefined; }, + ); const typesVersions = (packageJson as any).typesVersions; if (typeof typesVersions === "object") { const versionPaths = getPackageJsonTypesVersionsPaths(typesVersions)?.paths; if (versionPaths) { const packageDirectory = getDirectoryPath(packageJsonPath); const pathInPackage = absolutePath.slice(ensureTrailingDirectorySeparator(packageDirectory).length); - if (addCompletionEntriesFromPaths(result, pathInPackage, packageDirectory, extensionOptions, host, versionPaths)) { + if ( + addCompletionEntriesFromPaths( + result, + pathInPackage, + packageDirectory, + extensionOptions, + host, + versionPaths, + ) + ) { // A true result means one of the `versionPaths` was matched, which will block relative resolution // to files and folders from here. All reachable paths given the pattern match are already added. return result; @@ -529,7 +792,13 @@ namespace ts.Completions.StringCompletions { if (!tryDirectoryExists(host, baseDirectory)) return result; // Enumerate the available files if possible - const files = tryReadDirectory(host, baseDirectory, extensionOptions.extensions, /*exclude*/ undefined, /*include*/ ["./*"]); + const files = tryReadDirectory( + host, + baseDirectory, + extensionOptions.extensions, + /*exclude*/ undefined, + /*include*/ ["./*"], + ); if (files) { for (let filePath of files) { @@ -538,7 +807,11 @@ namespace ts.Completions.StringCompletions { continue; } - const { name, extension } = getFilenameWithExtensionOption(getBaseFileName(filePath), host.getCompilationSettings(), extensionOptions.includeExtensionsOption); + const { name, extension } = getFilenameWithExtensionOption( + getBaseFileName(filePath), + host.getCompilationSettings(), + extensionOptions.includeExtensionsOption, + ); result.add(nameAndKind(name, ScriptElementKind.scriptElement, extension)); } } @@ -558,12 +831,36 @@ namespace ts.Completions.StringCompletions { return result; } - function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerOptions, includeExtensionsOption: IncludeExtensionsOption): { name: string; extension: Extension | undefined; } { + function getFilenameWithExtensionOption( + name: string, + compilerOptions: CompilerOptions, + includeExtensionsOption: IncludeExtensionsOption, + ): { name: string; extension: Extension | undefined; } { const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(name, compilerOptions); - if (includeExtensionsOption === IncludeExtensionsOption.Exclude && !fileExtensionIsOneOf(name, [Extension.Json, Extension.Mts, Extension.Cts, Extension.Dmts, Extension.Dcts, Extension.Mjs, Extension.Cjs])) { + if ( + includeExtensionsOption === IncludeExtensionsOption.Exclude + && !fileExtensionIsOneOf(name, [ + Extension.Json, + Extension.Mts, + Extension.Cts, + Extension.Dmts, + Extension.Dcts, + Extension.Mjs, + Extension.Cjs, + ]) + ) { return { name: removeFileExtension(name), extension: tryGetExtensionFromPath(name) }; } - else if ((fileExtensionIsOneOf(name, [Extension.Mts, Extension.Cts, Extension.Dmts, Extension.Dcts, Extension.Mjs, Extension.Cjs]) || includeExtensionsOption === IncludeExtensionsOption.ModuleSpecifierCompletion) && outputExtension) { + else if ( + (fileExtensionIsOneOf(name, [ + Extension.Mts, + Extension.Cts, + Extension.Dmts, + Extension.Dcts, + Extension.Mjs, + Extension.Cjs, + ]) || includeExtensionsOption === IncludeExtensionsOption.ModuleSpecifierCompletion) && outputExtension + ) { return { name: changeExtension(name, outputExtension), extension: outputExtension }; } else { @@ -588,7 +885,16 @@ namespace ts.Completions.StringCompletions { const lengthB = typeof patternB === "object" ? patternB.prefix.length : b.length; return compareValues(lengthB, lengthA); }; - return addCompletionEntriesFromPathsOrExports(result, fragment, baseDirectory, extensionOptions, host, getOwnKeys(paths), getPatternsForKey, comparePaths); + return addCompletionEntriesFromPathsOrExports( + result, + fragment, + baseDirectory, + extensionOptions, + host, + getOwnKeys(paths), + getPatternsForKey, + comparePaths, + ); } /** @returns whether `fragment` was a match for any `paths` (which should indicate whether any other path completions should be offered) */ @@ -612,7 +918,8 @@ namespace ts.Completions.StringCompletions { const pathPattern = tryParsePattern(keyWithoutLeadingDotSlash); if (!pathPattern) continue; const isMatch = typeof pathPattern === "object" && isPatternMatch(pathPattern, fragment); - const isLongestMatch = isMatch && (matchedPath === undefined || comparePaths(key, matchedPath) === Comparison.LessThan); + const isLongestMatch = isMatch + && (matchedPath === undefined || comparePaths(key, matchedPath) === Comparison.LessThan); if (isLongestMatch) { // If this is a higher priority match than anything we've seen so far, previous results from matches are invalid, e.g. // for `import {} from "some-package/|"` with a typesVersions: @@ -628,10 +935,20 @@ namespace ts.Completions.StringCompletions { matchedPath = key; pathResults = pathResults.filter(r => !r.matchedPattern); } - if (typeof pathPattern === "string" || matchedPath === undefined || comparePaths(key, matchedPath) !== Comparison.GreaterThan) { + if ( + typeof pathPattern === "string" || matchedPath === undefined + || comparePaths(key, matchedPath) !== Comparison.GreaterThan + ) { pathResults.push({ matchedPattern: isMatch, - results: getCompletionsForPathMapping(keyWithoutLeadingDotSlash, patterns, fragment, baseDirectory, extensionOptions, host) + results: getCompletionsForPathMapping( + keyWithoutLeadingDotSlash, + patterns, + fragment, + baseDirectory, + extensionOptions, + host, + ) .map(({ name, kind, extension }) => nameAndKind(name, kind, extension)), }); } @@ -665,7 +982,14 @@ namespace ts.Completions.StringCompletions { if (baseUrl) { const projectDir = compilerOptions.project || host.getCurrentDirectory(); const absolute = normalizePath(combinePaths(projectDir, baseUrl)); - getCompletionEntriesForDirectoryFragment(fragment, absolute, extensionOptions, host, /*exclude*/ undefined, result); + getCompletionEntriesForDirectoryFragment( + fragment, + absolute, + extensionOptions, + host, + /*exclude*/ undefined, + result, + ); if (paths) { addCompletionEntriesFromPaths(result, fragment, absolute, extensionOptions, host, paths); } @@ -684,7 +1008,11 @@ namespace ts.Completions.StringCompletions { let foundGlobal = false; if (fragmentDirectory === undefined) { for (const moduleName of enumerateNodeModulesVisibleToScript(host, scriptPath)) { - const moduleResult = nameAndKind(moduleName, ScriptElementKind.externalModuleName, /*extension*/ undefined); + const moduleResult = nameAndKind( + moduleName, + ScriptElementKind.externalModuleName, + /*extension*/ undefined, + ); if (!result.has(moduleResult.name)) { foundGlobal = true; result.add(moduleResult); @@ -695,7 +1023,14 @@ namespace ts.Completions.StringCompletions { let ancestorLookup: (directory: string) => void | undefined = ancestor => { const nodeModules = combinePaths(ancestor, "node_modules"); if (tryDirectoryExists(host, nodeModules)) { - getCompletionEntriesForDirectoryFragment(fragment, nodeModules, extensionOptions, host, /*exclude*/ undefined, result); + getCompletionEntriesForDirectoryFragment( + fragment, + nodeModules, + extensionOptions, + host, + /*exclude*/ undefined, + result, + ); } }; if (fragmentDirectory && isEmitModuleResolutionRespectingExportMaps(compilerOptions)) { @@ -724,8 +1059,10 @@ namespace ts.Completions.StringCompletions { return; // null exports or entrypoint only, no sub-modules available } const keys = getOwnKeys(exports); - const fragmentSubpath = components.join("/") + (components.length && hasTrailingDirectorySeparator(fragment) ? "/" : ""); - const conditions = mode === ModuleKind.ESNext ? ["node", "import", "types"] : ["node", "require", "types"]; + const fragmentSubpath = components.join("/") + + (components.length && hasTrailingDirectorySeparator(fragment) ? "/" : ""); + const conditions = mode === ModuleKind.ESNext ? ["node", "import", "types"] + : ["node", "require", "types"]; addCompletionEntriesFromPathsOrExports( result, fragmentSubpath, @@ -733,7 +1070,10 @@ namespace ts.Completions.StringCompletions { extensionOptions, host, keys, - key => singleElementArray(getPatternFromFirstMatchingCondition(exports[key], conditions)), + key => + singleElementArray( + getPatternFromFirstMatchingCondition(exports[key], conditions), + ), comparePatternKeys, ); return; @@ -755,7 +1095,10 @@ namespace ts.Completions.StringCompletions { } if (target && typeof target === "object" && !isArray(target)) { for (const condition in target) { - if (condition === "default" || conditions.indexOf(condition) > -1 || isApplicableVersionedTypesKey(conditions, condition)) { + if ( + condition === "default" || conditions.indexOf(condition) > -1 + || isApplicableVersionedTypesKey(conditions, condition) + ) { const pattern = (target as MapLike)[condition]; return getPatternFromFirstMatchingCondition(pattern, conditions); } @@ -764,7 +1107,8 @@ namespace ts.Completions.StringCompletions { } function getFragmentDirectory(fragment: string): string | undefined { - return containsSlash(fragment) ? hasTrailingDirectorySeparator(fragment) ? fragment : getDirectoryPath(fragment) : undefined; + return containsSlash(fragment) ? hasTrailingDirectorySeparator(fragment) ? fragment : getDirectoryPath(fragment) + : undefined; } function getCompletionsForPathMapping( @@ -784,12 +1128,26 @@ namespace ts.Completions.StringCompletions { const remainingFragment = tryRemovePrefix(fragment, pathPrefix); if (remainingFragment === undefined) { const starIsFullPathComponent = path[path.length - 2] === "/"; - return starIsFullPathComponent ? justPathMappingName(pathPrefix, ScriptElementKind.directory) : flatMap(patterns, pattern => getModulesForPathsPattern("", packageDirectory, pattern, extensionOptions, host)?.map(({ name, ...rest }) => ({ name: pathPrefix + name, ...rest }))); + return starIsFullPathComponent ? justPathMappingName(pathPrefix, ScriptElementKind.directory) + : flatMap( + patterns, + pattern => + getModulesForPathsPattern("", packageDirectory, pattern, extensionOptions, host)?.map(( + { name, ...rest }, + ) => ({ name: pathPrefix + name, ...rest })), + ); } - return flatMap(patterns, pattern => getModulesForPathsPattern(remainingFragment, packageDirectory, pattern, extensionOptions, host)); + return flatMap( + patterns, + pattern => getModulesForPathsPattern(remainingFragment, packageDirectory, pattern, extensionOptions, host), + ); - function justPathMappingName(name: string, kind: ScriptElementKind.directory | ScriptElementKind.scriptElement): readonly NameAndKind[] { - return startsWith(name, fragment) ? [{ name: removeTrailingDirectorySeparator(name), kind, extension: undefined }] : emptyArray; + function justPathMappingName( + name: string, + kind: ScriptElementKind.directory | ScriptElementKind.scriptElement, + ): readonly NameAndKind[] { + return startsWith(name, fragment) + ? [{ name: removeTrailingDirectorySeparator(name), kind, extension: undefined }] : emptyArray; } } @@ -812,19 +1170,25 @@ namespace ts.Completions.StringCompletions { // The prefix has two effective parts: the directory path and the base component after the filepath that is not a // full directory component. For example: directory/path/of/prefix/base* const normalizedPrefix = resolvePath(parsed.prefix); - const normalizedPrefixDirectory = hasTrailingDirectorySeparator(parsed.prefix) ? normalizedPrefix : getDirectoryPath(normalizedPrefix); - const normalizedPrefixBase = hasTrailingDirectorySeparator(parsed.prefix) ? "" : getBaseFileName(normalizedPrefix); + const normalizedPrefixDirectory = hasTrailingDirectorySeparator(parsed.prefix) ? normalizedPrefix + : getDirectoryPath(normalizedPrefix); + const normalizedPrefixBase = hasTrailingDirectorySeparator(parsed.prefix) ? "" + : getBaseFileName(normalizedPrefix); const fragmentHasPath = containsSlash(fragment); - const fragmentDirectory = fragmentHasPath ? hasTrailingDirectorySeparator(fragment) ? fragment : getDirectoryPath(fragment) : undefined; + const fragmentDirectory = fragmentHasPath + ? hasTrailingDirectorySeparator(fragment) ? fragment : getDirectoryPath(fragment) : undefined; // Try and expand the prefix to include any path from the fragment so that we can limit the readDirectory call - const expandedPrefixDirectory = fragmentHasPath ? combinePaths(normalizedPrefixDirectory, normalizedPrefixBase + fragmentDirectory) : normalizedPrefixDirectory; + const expandedPrefixDirectory = fragmentHasPath + ? combinePaths(normalizedPrefixDirectory, normalizedPrefixBase + fragmentDirectory) + : normalizedPrefixDirectory; const normalizedSuffix = normalizePath(parsed.suffix); // Need to normalize after combining: If we combinePaths("a", "../b"), we want "b" and not "a/../b". const baseDirectory = normalizePath(combinePaths(packageDirectory, expandedPrefixDirectory)); - const completePrefix = fragmentHasPath ? baseDirectory : ensureTrailingDirectorySeparator(baseDirectory) + normalizedPrefixBase; + const completePrefix = fragmentHasPath ? baseDirectory + : ensureTrailingDirectorySeparator(baseDirectory) + normalizedPrefixBase; // If we have a suffix, then we read the directory all the way down to avoid returning completions for // directories that don't contain files that would match the suffix. A previous comment here was concerned @@ -836,23 +1200,35 @@ namespace ts.Completions.StringCompletions { // done. const includeGlob = normalizedSuffix ? "**/*" + normalizedSuffix : "./*"; - const matches = mapDefined(tryReadDirectory(host, baseDirectory, extensionOptions.extensions, /*exclude*/ undefined, [includeGlob]), match => { - const trimmedWithPattern = trimPrefixAndSuffix(match); - if (trimmedWithPattern) { - if (containsSlash(trimmedWithPattern)) { - return directoryResult(getPathComponents(removeLeadingDirectorySeparator(trimmedWithPattern))[1]); + const matches = mapDefined( + tryReadDirectory(host, baseDirectory, extensionOptions.extensions, /*exclude*/ undefined, [includeGlob]), + match => { + const trimmedWithPattern = trimPrefixAndSuffix(match); + if (trimmedWithPattern) { + if (containsSlash(trimmedWithPattern)) { + return directoryResult( + getPathComponents(removeLeadingDirectorySeparator(trimmedWithPattern))[1], + ); + } + const { name, extension } = getFilenameWithExtensionOption( + trimmedWithPattern, + host.getCompilationSettings(), + extensionOptions.includeExtensionsOption, + ); + return nameAndKind(name, ScriptElementKind.scriptElement, extension); } - const { name, extension } = getFilenameWithExtensionOption(trimmedWithPattern, host.getCompilationSettings(), extensionOptions.includeExtensionsOption); - return nameAndKind(name, ScriptElementKind.scriptElement, extension); - } - }); + }, + ); // If we had a suffix, we already recursively searched for all possible files that could match // it and returned the directories leading to those files. Otherwise, assume any directory could // have something valid to import. const directories = normalizedSuffix ? emptyArray - : mapDefined(tryGetDirectories(host, baseDirectory), dir => dir === "node_modules" ? undefined : directoryResult(dir)); + : mapDefined( + tryGetDirectories(host, baseDirectory), + dir => dir === "node_modules" ? undefined : directoryResult(dir), + ); return [...matches, ...directories]; function trimPrefixAndSuffix(path: string): string | undefined { @@ -869,7 +1245,11 @@ namespace ts.Completions.StringCompletions { return path[0] === directorySeparator ? path.slice(1) : path; } - function getAmbientModuleCompletions(fragment: string, fragmentDirectory: string | undefined, checker: TypeChecker): readonly string[] { + function getAmbientModuleCompletions( + fragment: string, + fragmentDirectory: string | undefined, + checker: TypeChecker, + ): readonly string[] { // Get modules that the type checker picked up const ambientModules = checker.getAmbientModules().map(sym => stripQuotes(sym.name)); const nonRelativeModuleNames = ambientModules.filter(moduleName => startsWith(moduleName, fragment)); @@ -879,15 +1259,23 @@ namespace ts.Completions.StringCompletions { // starts if (fragmentDirectory !== undefined) { const moduleNameWithSeparator = ensureTrailingDirectorySeparator(fragmentDirectory); - return nonRelativeModuleNames.map(nonRelativeModuleName => removePrefix(nonRelativeModuleName, moduleNameWithSeparator)); + return nonRelativeModuleNames.map(nonRelativeModuleName => + removePrefix(nonRelativeModuleName, moduleNameWithSeparator) + ); } return nonRelativeModuleNames; } - function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): readonly PathCompletion[] | undefined { + function getTripleSlashReferenceCompletion( + sourceFile: SourceFile, + position: number, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + ): readonly PathCompletion[] | undefined { const token = getTokenAtPosition(sourceFile, position); const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos); - const range = commentRanges && find(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end); + const range = commentRanges + && find(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end); if (!range) { return undefined; } @@ -899,13 +1287,34 @@ namespace ts.Completions.StringCompletions { const [, prefix, kind, toComplete] = match; const scriptPath = getDirectoryPath(sourceFile.path); - const names = kind === "path" ? getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getExtensionOptions(compilerOptions, IncludeExtensionsOption.Include), host, sourceFile.path) - : kind === "types" ? getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, getFragmentDirectory(toComplete), getExtensionOptions(compilerOptions)) + const names = kind === "path" + ? getCompletionEntriesForDirectoryFragment( + toComplete, + scriptPath, + getExtensionOptions(compilerOptions, IncludeExtensionsOption.Include), + host, + sourceFile.path, + ) + : kind === "types" + ? getCompletionEntriesFromTypings( + host, + compilerOptions, + scriptPath, + getFragmentDirectory(toComplete), + getExtensionOptions(compilerOptions), + ) : Debug.fail(); return addReplacementSpans(toComplete, range.pos + prefix.length, arrayFrom(names.values())); } - function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: CompilerOptions, scriptPath: string, fragmentDirectory: string | undefined, extensionOptions: ExtensionOptions, result = createNameAndKindSet()): NameAndKindSet { + function getCompletionEntriesFromTypings( + host: LanguageServiceHost, + options: CompilerOptions, + scriptPath: string, + fragmentDirectory: string | undefined, + extensionOptions: ExtensionOptions, + result = createNameAndKindSet(), + ): NameAndKindSet { // Check for typings specified in compiler options const seen = new Map(); @@ -932,15 +1341,28 @@ namespace ts.Completions.StringCompletions { if (fragmentDirectory === undefined) { if (!seen.has(packageName)) { - result.add(nameAndKind(packageName, ScriptElementKind.externalModuleName, /*extension*/ undefined)); + result.add( + nameAndKind(packageName, ScriptElementKind.externalModuleName, /*extension*/ undefined), + ); seen.set(packageName, true); } } else { const baseDirectory = combinePaths(directory, typeDirectoryName); - const remainingFragment = tryRemoveDirectoryPrefix(fragmentDirectory, packageName, hostGetCanonicalFileName(host)); + const remainingFragment = tryRemoveDirectoryPrefix( + fragmentDirectory, + packageName, + hostGetCanonicalFileName(host), + ); if (remainingFragment !== undefined) { - getCompletionEntriesForDirectoryFragment(remainingFragment, baseDirectory, extensionOptions, host, /*exclude*/ undefined, result); + getCompletionEntriesForDirectoryFragment( + remainingFragment, + baseDirectory, + extensionOptions, + host, + /*exclude*/ undefined, + result, + ); } } } @@ -973,7 +1395,8 @@ namespace ts.Completions.StringCompletions { const offset = index !== -1 ? index + 1 : 0; // If the range is an identifier, span is unnecessary. const length = text.length - offset; - return length === 0 || isIdentifierText(text.substr(offset, length), ScriptTarget.ESNext) ? undefined : createTextSpan(textStart + offset, length); + return length === 0 || isIdentifierText(text.substr(offset, length), ScriptTarget.ESNext) ? undefined + : createTextSpan(textStart + offset, length); } // Returns true if the path is explicitly relative to the script (i.e. relative to . or ..) @@ -1000,7 +1423,12 @@ namespace ts.Completions.StringCompletions { */ const tripleSlashDirectiveFragmentRegex = /^(\/\/\/\s*(); - export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[] { + export function computeSuggestionDiagnostics( + sourceFile: SourceFile, + program: Program, + cancellationToken: CancellationToken, + ): DiagnosticWithLocation[] { program.getSemanticDiagnostics(sourceFile, cancellationToken); const diags: DiagnosticWithLocation[] = []; const checker = program.getTypeChecker(); - const isCommonJSFile = sourceFile.impliedNodeFormat === ModuleKind.CommonJS || fileExtensionIsOneOf(sourceFile.fileName, [Extension.Cts, Extension.Cjs]); + const isCommonJSFile = sourceFile.impliedNodeFormat === ModuleKind.CommonJS + || fileExtensionIsOneOf(sourceFile.fileName, [Extension.Cts, Extension.Cjs]); if ( - !isCommonJSFile && - sourceFile.commonJsModuleIndicator && - (programContainsEsModules(program) || compilerOptionsIndicateEsModules(program.getCompilerOptions())) && - containsTopLevelCommonjs(sourceFile) + !isCommonJSFile + && sourceFile.commonJsModuleIndicator + && (programContainsEsModules(program) || compilerOptionsIndicateEsModules(program.getCompilerOptions())) + && containsTopLevelCommonjs(sourceFile) ) { - diags.push(createDiagnosticForNode(getErrorNodeFromCommonJsIndicator(sourceFile.commonJsModuleIndicator), Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module)); + diags.push( + createDiagnosticForNode( + getErrorNodeFromCommonJsIndicator(sourceFile.commonJsModuleIndicator), + Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module, + ), + ); } const isJsFile = isSourceFileJS(sourceFile); @@ -27,9 +37,18 @@ namespace ts { const importNode = importFromModuleSpecifier(moduleSpecifier); const name = importNameForConvertToDefaultImport(importNode); if (!name) continue; - const module = getResolvedModule(sourceFile, moduleSpecifier.text, getModeForUsageLocation(sourceFile, moduleSpecifier)); + const module = getResolvedModule( + sourceFile, + moduleSpecifier.text, + getModeForUsageLocation(sourceFile, moduleSpecifier), + ); const resolvedFile = module && program.getSourceFile(module.resolvedFileName); - if (resolvedFile && resolvedFile.externalModuleIndicator && resolvedFile.externalModuleIndicator !== true && isExportAssignment(resolvedFile.externalModuleIndicator) && resolvedFile.externalModuleIndicator.isExportEquals) { + if ( + resolvedFile && resolvedFile.externalModuleIndicator + && resolvedFile.externalModuleIndicator !== true + && isExportAssignment(resolvedFile.externalModuleIndicator) + && resolvedFile.externalModuleIndicator.isExportEquals + ) { diags.push(createDiagnosticForNode(name, Diagnostics.Import_may_be_converted_to_a_default_import)); } } @@ -42,24 +61,36 @@ namespace ts { function check(node: Node) { if (isJsFile) { if (canBeConvertedToClass(node, checker)) { - diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_constructor_function_may_be_converted_to_a_class_declaration)); + diags.push( + createDiagnosticForNode( + isVariableDeclaration(node.parent) ? node.parent.name : node, + Diagnostics.This_constructor_function_may_be_converted_to_a_class_declaration, + ), + ); } } else { if ( - isVariableStatement(node) && - node.parent === sourceFile && - node.declarationList.flags & NodeFlags.Const && - node.declarationList.declarations.length === 1 + isVariableStatement(node) + && node.parent === sourceFile + && node.declarationList.flags & NodeFlags.Const + && node.declarationList.declarations.length === 1 ) { const init = node.declarationList.declarations[0].initializer; if (init && isRequireCall(init, /*checkArgumentIsStringLiteralLike*/ true)) { - diags.push(createDiagnosticForNode(init, Diagnostics.require_call_may_be_converted_to_an_import)); + diags.push( + createDiagnosticForNode(init, Diagnostics.require_call_may_be_converted_to_an_import), + ); } } if (codefix.parameterShouldGetTypeFromJSDoc(node)) { - diags.push(createDiagnosticForNode(node.name || node, Diagnostics.JSDoc_types_may_be_moved_to_TypeScript_types)); + diags.push( + createDiagnosticForNode( + node.name || node, + Diagnostics.JSDoc_types_may_be_moved_to_TypeScript_types, + ), + ); } } @@ -75,12 +106,21 @@ namespace ts { return sourceFile.statements.some(statement => { switch (statement.kind) { case SyntaxKind.VariableStatement: - return (statement as VariableStatement).declarationList.declarations.some(decl => !!decl.initializer && isRequireCall(propertyAccessLeftHandSide(decl.initializer), /*checkArgumentIsStringLiteralLike*/ true)); + return (statement as VariableStatement).declarationList.declarations.some(decl => + !!decl.initializer + && isRequireCall( + propertyAccessLeftHandSide(decl.initializer), + /*checkArgumentIsStringLiteralLike*/ true, + ) + ); case SyntaxKind.ExpressionStatement: { const { expression } = statement as ExpressionStatement; - if (!isBinaryExpression(expression)) return isRequireCall(expression, /*checkArgumentIsStringLiteralLike*/ true); + if (!isBinaryExpression(expression)) { + return isRequireCall(expression, /*checkArgumentIsStringLiteralLike*/ true); + } const kind = getAssignmentDeclarationKind(expression); - return kind === AssignmentDeclarationKind.ExportsProperty || kind === AssignmentDeclarationKind.ModuleExports; + return kind === AssignmentDeclarationKind.ExportsProperty + || kind === AssignmentDeclarationKind.ModuleExports; } default: return false; @@ -96,7 +136,9 @@ namespace ts { switch (node.kind) { case SyntaxKind.ImportDeclaration: const { importClause, moduleSpecifier } = node; - return importClause && !importClause.name && importClause.namedBindings && importClause.namedBindings.kind === SyntaxKind.NamespaceImport && isStringLiteral(moduleSpecifier) + return importClause && !importClause.name && importClause.namedBindings + && importClause.namedBindings.kind === SyntaxKind.NamespaceImport + && isStringLiteral(moduleSpecifier) ? importClause.namedBindings.name : undefined; case SyntaxKind.ImportEqualsDeclaration: @@ -106,22 +148,27 @@ namespace ts { } } - function addConvertToAsyncFunctionDiagnostics(node: FunctionLikeDeclaration, checker: TypeChecker, diags: Push): void { + function addConvertToAsyncFunctionDiagnostics( + node: FunctionLikeDeclaration, + checker: TypeChecker, + diags: Push, + ): void { // need to check function before checking map so that deeper levels of nested callbacks are checked if (isConvertibleFunction(node, checker) && !visitedNestedConvertibleFunctions.has(getKeyFromNode(node))) { diags.push(createDiagnosticForNode( - !node.name && isVariableDeclaration(node.parent) && isIdentifier(node.parent.name) ? node.parent.name : node, + !node.name && isVariableDeclaration(node.parent) && isIdentifier(node.parent.name) ? node.parent.name + : node, Diagnostics.This_may_be_converted_to_an_async_function, )); } } function isConvertibleFunction(node: FunctionLikeDeclaration, checker: TypeChecker) { - return !isAsyncFunction(node) && - node.body && - isBlock(node.body) && - hasReturnStatementWithPromiseHandler(node.body, checker) && - returnsPromise(node, checker); + return !isAsyncFunction(node) + && node.body + && isBlock(node.body) + && hasReturnStatementWithPromiseHandler(node.body, checker) + && returnsPromise(node, checker); } export function returnsPromise(node: FunctionLikeDeclaration, checker: TypeChecker): boolean { @@ -135,17 +182,26 @@ namespace ts { } function hasReturnStatementWithPromiseHandler(body: Block, checker: TypeChecker): boolean { - return !!forEachReturnStatement(body, statement => isReturnStatementWithFixablePromiseHandler(statement, checker)); + return !!forEachReturnStatement( + body, + statement => isReturnStatementWithFixablePromiseHandler(statement, checker), + ); } - export function isReturnStatementWithFixablePromiseHandler(node: Node, checker: TypeChecker): node is ReturnStatement & { expression: CallExpression; } { + export function isReturnStatementWithFixablePromiseHandler( + node: Node, + checker: TypeChecker, + ): node is ReturnStatement & { expression: CallExpression; } { return isReturnStatement(node) && !!node.expression && isFixablePromiseHandler(node.expression, checker); } // Should be kept up to date with transformExpression in convertToAsyncFunction.ts export function isFixablePromiseHandler(node: Node, checker: TypeChecker): boolean { // ensure outermost call exists and is a promise handler - if (!isPromiseHandler(node) || !hasSupportedNumberOfArguments(node) || !node.arguments.every(arg => isFixablePromiseArgument(arg, checker))) { + if ( + !isPromiseHandler(node) || !hasSupportedNumberOfArguments(node) + || !node.arguments.every(arg => isFixablePromiseArgument(arg, checker)) + ) { return false; } @@ -153,7 +209,10 @@ namespace ts { let currentNode = node.expression.expression; while (isPromiseHandler(currentNode) || isPropertyAccessExpression(currentNode)) { if (isCallExpression(currentNode)) { - if (!hasSupportedNumberOfArguments(currentNode) || !currentNode.arguments.every(arg => isFixablePromiseArgument(arg, checker))) { + if ( + !hasSupportedNumberOfArguments(currentNode) + || !currentNode.arguments.every(arg => isFixablePromiseArgument(arg, checker)) + ) { return false; } currentNode = currentNode.expression.expression; @@ -167,9 +226,9 @@ namespace ts { function isPromiseHandler(node: Node): node is CallExpression & { readonly expression: PropertyAccessExpression; } { return isCallExpression(node) && ( - hasPropertyAccessExpressionWithName(node, "then") || - hasPropertyAccessExpressionWithName(node, "catch") || - hasPropertyAccessExpressionWithName(node, "finally") + hasPropertyAccessExpressionWithName(node, "then") + || hasPropertyAccessExpressionWithName(node, "catch") + || hasPropertyAccessExpressionWithName(node, "finally") ); } @@ -204,8 +263,11 @@ namespace ts { if (!symbol) { return false; } - return checker.isUndefinedSymbol(symbol) || - some(skipAlias(symbol, checker).declarations, d => isFunctionLike(d) || hasInitializer(d) && !!d.initializer && isFunctionLike(d.initializer)); + return checker.isUndefinedSymbol(symbol) + || some( + skipAlias(symbol, checker).declarations, + d => isFunctionLike(d) || hasInitializer(d) && !!d.initializer && isFunctionLike(d.initializer), + ); } default: return false; @@ -233,7 +295,9 @@ namespace ts { return false; } - export function canBeConvertedToAsync(node: Node): node is FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction { + export function canBeConvertedToAsync( + node: Node, + ): node is FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction { switch (node.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.MethodDeclaration: diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 9fa46c24472e3..521a83dee972d 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -1,6 +1,7 @@ /* @internal */ namespace ts.SymbolDisplay { - const symbolDisplayNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; + const symbolDisplayNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors + | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; // TODO(drosen): use contextual SemanticMeaning. export function getSymbolKind(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind { @@ -11,8 +12,8 @@ namespace ts.SymbolDisplay { const flags = getCombinedLocalAndExportSymbolFlags(symbol); if (flags & SymbolFlags.Class) { - return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ? - ScriptElementKind.localClassElement : ScriptElementKind.classElement; + return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) + ? ScriptElementKind.localClassElement : ScriptElementKind.classElement; } if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement; if (flags & SymbolFlags.TypeAlias) return ScriptElementKind.typeElement; @@ -25,14 +26,19 @@ namespace ts.SymbolDisplay { return result; } - function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind { + function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar( + typeChecker: TypeChecker, + symbol: Symbol, + location: Node, + ): ScriptElementKind { const roots = typeChecker.getRootSymbols(symbol); // If this is a method from a mapped type, leave as a method so long as it still has a call signature. if ( roots.length === 1 && first(roots).flags & SymbolFlags.Method // Ensure the mapped version is still a method, as opposed to `{ [K in keyof I]: number }`. - && typeChecker.getTypeOfSymbolAtLocation(symbol, location).getNonNullableType().getCallSignatures().length !== 0 + && typeChecker.getTypeOfSymbolAtLocation(symbol, location).getNonNullableType().getCallSignatures().length + !== 0 ) { return ScriptElementKind.memberFunctionElement; } @@ -57,9 +63,13 @@ namespace ts.SymbolDisplay { else if (forEach(symbol.declarations, isLet)) { return ScriptElementKind.letElement; } - return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement : ScriptElementKind.variableElement; + return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement + : ScriptElementKind.variableElement; + } + if (flags & SymbolFlags.Function) { + return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localFunctionElement + : ScriptElementKind.functionElement; } - if (flags & SymbolFlags.Function) return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localFunctionElement : ScriptElementKind.functionElement; // FIXME: getter and setter use the same symbol. And it is rare to use only setter without getter, so in most cases the symbol always has getter flag. // So, even when the location is just on the declaration of setter, this function returns getter. if (flags & SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; @@ -99,7 +109,8 @@ namespace ts.SymbolDisplay { if (symbol.declarations && symbol.declarations.length) { const [declaration, ...declarations] = symbol.declarations; // omit deprecated flag if some declarations are not deprecated - const excludeFlags = length(declarations) && isDeprecatedDeclaration(declaration) && some(declarations, d => !isDeprecatedDeclaration(d)) + const excludeFlags = length(declarations) && isDeprecatedDeclaration(declaration) && some(declarations, d => + !isDeprecatedDeclaration(d)) ? ModifierFlags.Deprecated : ModifierFlags.None; const modifiers = getNodeModifiers(declaration, excludeFlags); @@ -138,14 +149,25 @@ namespace ts.SymbolDisplay { } // TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location - export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: TypeChecker, symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node | undefined, location: Node, semanticMeaning = getMeaningFromLocation(location), alias?: Symbol): SymbolDisplayPartsDocumentationAndSymbolKind { + export function getSymbolDisplayPartsDocumentationAndSymbolKind( + typeChecker: TypeChecker, + symbol: Symbol, + sourceFile: SourceFile, + enclosingDeclaration: Node | undefined, + location: Node, + semanticMeaning = getMeaningFromLocation(location), + alias?: Symbol, + ): SymbolDisplayPartsDocumentationAndSymbolKind { const displayParts: SymbolDisplayPart[] = []; let documentation: SymbolDisplayPart[] = []; let tags: JSDocTagInfo[] = []; const symbolFlags = getCombinedLocalAndExportSymbolFlags(symbol); - let symbolKind = semanticMeaning & SemanticMeaning.Value ? getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location) : ScriptElementKind.unknown; + let symbolKind = semanticMeaning & SemanticMeaning.Value + ? getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location) + : ScriptElementKind.unknown; let hasAddedSymbolInfo = false; - const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isInExpressionContext(location) || isThisInTypeQuery(location); + const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isInExpressionContext(location) + || isThisInTypeQuery(location); let type: Type | undefined; let printer: Printer; let documentationFromAlias: SymbolDisplayPart[] | undefined; @@ -153,14 +175,28 @@ namespace ts.SymbolDisplay { let hasMultipleSignatures = false; if (location.kind === SyntaxKind.ThisKeyword && !isThisExpression) { - return { displayParts: [keywordPart(SyntaxKind.ThisKeyword)], documentation: [], symbolKind: ScriptElementKind.primitiveType, tags: undefined }; + return { + displayParts: [keywordPart(SyntaxKind.ThisKeyword)], + documentation: [], + symbolKind: ScriptElementKind.primitiveType, + tags: undefined, + }; } // Class at constructor site need to be shown as constructor apart from property,method, vars - if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class || symbolFlags & SymbolFlags.Alias) { + if ( + symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class + || symbolFlags & SymbolFlags.Alias + ) { // If symbol is accessor, they are allowed only if location is at declaration identifier of the accessor - if (symbolKind === ScriptElementKind.memberGetAccessorElement || symbolKind === ScriptElementKind.memberSetAccessorElement) { - const declaration = find(symbol.declarations as ((GetAccessorDeclaration | SetAccessorDeclaration | PropertyDeclaration)[]), declaration => declaration.name === location); + if ( + symbolKind === ScriptElementKind.memberGetAccessorElement + || symbolKind === ScriptElementKind.memberSetAccessorElement + ) { + const declaration = find( + symbol.declarations as ((GetAccessorDeclaration | SetAccessorDeclaration | PropertyDeclaration)[]), + declaration => declaration.name === location, + ); if (declaration) { switch (declaration.kind) { case SyntaxKind.GetAccessor: @@ -182,7 +218,8 @@ namespace ts.SymbolDisplay { } let signature: Signature | undefined; - type = isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol, location); + type = isThisExpression ? typeChecker.getTypeAtLocation(location) + : typeChecker.getTypeOfSymbolAtLocation(symbol, location); if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) { const right = (location.parent as PropertyAccessExpression).name; @@ -193,21 +230,32 @@ namespace ts.SymbolDisplay { } // try get the call/construct signature from the type if it matches - let callExpressionLike: CallExpression | NewExpression | JsxOpeningLikeElement | TaggedTemplateExpression | undefined; + let callExpressionLike: + | CallExpression + | NewExpression + | JsxOpeningLikeElement + | TaggedTemplateExpression + | undefined; if (isCallOrNewExpression(location)) { callExpressionLike = location; } else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) { callExpressionLike = location.parent as CallExpression | NewExpression; } - else if (location.parent && (isJsxOpeningLikeElement(location.parent) || isTaggedTemplateExpression(location.parent)) && isFunctionLike(symbol.valueDeclaration)) { + else if ( + location.parent + && (isJsxOpeningLikeElement(location.parent) || isTaggedTemplateExpression(location.parent)) + && isFunctionLike(symbol.valueDeclaration) + ) { callExpressionLike = location.parent; } if (callExpressionLike) { signature = typeChecker.getResolvedSignature(callExpressionLike); // TODO: GH#18217 - const useConstructSignatures = callExpressionLike.kind === SyntaxKind.NewExpression || (isCallExpression(callExpressionLike) && callExpressionLike.expression.kind === SyntaxKind.SuperKeyword); + const useConstructSignatures = callExpressionLike.kind === SyntaxKind.NewExpression + || (isCallExpression(callExpressionLike) + && callExpressionLike.expression.kind === SyntaxKind.SuperKeyword); const allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures(); @@ -253,7 +301,17 @@ namespace ts.SymbolDisplay { displayParts.push(punctuationPart(SyntaxKind.ColonToken)); displayParts.push(spacePart()); if (!(getObjectFlags(type) & ObjectFlags.Anonymous) && type.symbol) { - addRange(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.AllowAnyNodeKind | SymbolFormatFlags.WriteTypeParametersOrArguments)); + addRange( + displayParts, + symbolToDisplayParts( + typeChecker, + type.symbol, + enclosingDeclaration, + /*meaning*/ undefined, + SymbolFormatFlags.AllowAnyNodeKind + | SymbolFormatFlags.WriteTypeParametersOrArguments, + ), + ); displayParts.push(lineBreakPart()); } if (useConstructSignatures) { @@ -264,7 +322,11 @@ namespace ts.SymbolDisplay { displayParts.push(keywordPart(SyntaxKind.NewKeyword)); displayParts.push(spacePart()); } - addSignatureDisplayParts(signature, allSignatures, TypeFormatFlags.WriteArrowStyleSignature); + addSignatureDisplayParts( + signature, + allSignatures, + TypeFormatFlags.WriteArrowStyleSignature, + ); break; default: @@ -276,16 +338,25 @@ namespace ts.SymbolDisplay { } } else if ( - (isNameOfFunctionDeclaration(location) && !(symbolFlags & SymbolFlags.Accessor)) || // name of function declaration - (location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor) + (isNameOfFunctionDeclaration(location) && !(symbolFlags & SymbolFlags.Accessor)) // name of function declaration + || (location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor) ) { // At constructor keyword of constructor declaration // get the signature from the declaration and write it const functionDeclaration = location.parent as SignatureDeclaration; // Use function declaration to write the signatures only if the symbol corresponding to this declaration - const locationIsSymbolDeclaration = symbol.declarations && find(symbol.declarations, declaration => declaration === (location.kind === SyntaxKind.ConstructorKeyword ? functionDeclaration.parent : functionDeclaration)); + const locationIsSymbolDeclaration = symbol.declarations + && find( + symbol.declarations, + declaration => + declaration + === (location.kind === SyntaxKind.ConstructorKeyword ? functionDeclaration.parent + : functionDeclaration), + ); if (locationIsSymbolDeclaration) { - const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getNonNullableType().getConstructSignatures() : type.getNonNullableType().getCallSignatures(); + const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor + ? type.getNonNullableType().getConstructSignatures() + : type.getNonNullableType().getCallSignatures(); if (!typeChecker.isImplementationOfOverload(functionDeclaration)) { signature = typeChecker.getSignatureFromDeclaration(functionDeclaration); // TODO: GH#18217 } @@ -301,8 +372,9 @@ namespace ts.SymbolDisplay { else { // (function/method) symbol(..signature) addPrefixForAnyFunctionOrVar( - functionDeclaration.kind === SyntaxKind.CallSignature && - !(type.symbol.flags & SymbolFlags.TypeLiteral || type.symbol.flags & SymbolFlags.ObjectLiteral) ? type.symbol : symbol, + functionDeclaration.kind === SyntaxKind.CallSignature + && !(type.symbol.flags & SymbolFlags.TypeLiteral + || type.symbol.flags & SymbolFlags.ObjectLiteral) ? type.symbol : symbol, symbolKind, ); } @@ -346,7 +418,16 @@ namespace ts.SymbolDisplay { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); displayParts.push(spacePart()); - addRange(displayParts, typeToDisplayParts(typeChecker, isConstTypeReference(location.parent) ? typeChecker.getTypeAtLocation(location.parent) : typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration, TypeFormatFlags.InTypeAlias)); + addRange( + displayParts, + typeToDisplayParts( + typeChecker, + isConstTypeReference(location.parent) ? typeChecker.getTypeAtLocation(location.parent) + : typeChecker.getDeclaredTypeOfSymbol(symbol), + enclosingDeclaration, + TypeFormatFlags.InTypeAlias, + ), + ); } if (symbolFlags & SymbolFlags.Enum) { prefixNextMeaning(); @@ -393,10 +474,20 @@ namespace ts.SymbolDisplay { displayParts.push(keywordPart(SyntaxKind.NewKeyword)); displayParts.push(spacePart()); } - else if (declaration.kind !== SyntaxKind.CallSignature && (declaration as SignatureDeclaration).name) { + else if ( + declaration.kind !== SyntaxKind.CallSignature && (declaration as SignatureDeclaration).name + ) { addFullSymbolName(declaration.symbol); } - addRange(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); + addRange( + displayParts, + signatureToDisplayParts( + typeChecker, + signature, + sourceFile, + TypeFormatFlags.WriteTypeArgumentsOfSignature, + ), + ); } else if (declaration.kind === SyntaxKind.TypeAliasDeclaration) { // Type alias type parameter @@ -421,7 +512,13 @@ namespace ts.SymbolDisplay { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); displayParts.push(spacePart()); - displayParts.push(displayPart(getTextOfConstantValue(constantValue), typeof constantValue === "number" ? SymbolDisplayPartKind.numericLiteral : SymbolDisplayPartKind.stringLiteral)); + displayParts.push( + displayPart( + getTextOfConstantValue(constantValue), + typeof constantValue === "number" ? SymbolDisplayPartKind.numericLiteral + : SymbolDisplayPartKind.stringLiteral, + ), + ); } } } @@ -430,12 +527,14 @@ namespace ts.SymbolDisplay { prefixNextMeaning(); if (!hasAddedSymbolInfo) { const resolvedSymbol = typeChecker.getAliasedSymbol(symbol); - if (resolvedSymbol !== symbol && resolvedSymbol.declarations && resolvedSymbol.declarations.length > 0) { + if ( + resolvedSymbol !== symbol && resolvedSymbol.declarations && resolvedSymbol.declarations.length > 0 + ) { const resolvedNode = resolvedSymbol.declarations[0]; const declarationName = getNameOfDeclaration(resolvedNode); if (declarationName) { - const isExternalModuleDeclaration = isModuleWithStringLiteralName(resolvedNode) && - hasSyntacticModifier(resolvedNode, ModifierFlags.Ambient); + const isExternalModuleDeclaration = isModuleWithStringLiteralName(resolvedNode) + && hasSyntacticModifier(resolvedNode, ModifierFlags.Ambient); const shouldUseAliasName = symbol.name !== "default" && !isExternalModuleDeclaration; const resolvedInfo = getSymbolDisplayPartsDocumentationAndSymbolKind( typeChecker, @@ -452,7 +551,10 @@ namespace ts.SymbolDisplay { tagsFromAlias = resolvedInfo.tags; } else { - documentationFromAlias = resolvedSymbol.getContextualDocumentationComment(resolvedNode, typeChecker); + documentationFromAlias = resolvedSymbol.getContextualDocumentationComment( + resolvedNode, + typeChecker, + ); tagsFromAlias = resolvedSymbol.getJsDocTags(typeChecker); } } @@ -468,7 +570,12 @@ namespace ts.SymbolDisplay { case SyntaxKind.ExportAssignment: displayParts.push(keywordPart(SyntaxKind.ExportKeyword)); displayParts.push(spacePart()); - displayParts.push(keywordPart((symbol.declarations[0] as ExportAssignment).isExportEquals ? SyntaxKind.EqualsToken : SyntaxKind.DefaultKeyword)); + displayParts.push( + keywordPart( + (symbol.declarations[0] as ExportAssignment).isExportEquals ? SyntaxKind.EqualsToken + : SyntaxKind.DefaultKeyword, + ), + ); break; case SyntaxKind.ExportSpecifier: displayParts.push(keywordPart(SyntaxKind.ExportKeyword)); @@ -488,11 +595,20 @@ namespace ts.SymbolDisplay { displayParts.push(spacePart()); displayParts.push(keywordPart(SyntaxKind.RequireKeyword)); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); - displayParts.push(displayPart(getTextOfNode(getExternalModuleImportEqualsDeclarationExpression(importEqualsDeclaration)), SymbolDisplayPartKind.stringLiteral)); + displayParts.push( + displayPart( + getTextOfNode( + getExternalModuleImportEqualsDeclarationExpression(importEqualsDeclaration), + ), + SymbolDisplayPartKind.stringLiteral, + ), + ); displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); } else { - const internalAliasSymbol = typeChecker.getSymbolAtLocation(importEqualsDeclaration.moduleReference); + const internalAliasSymbol = typeChecker.getSymbolAtLocation( + importEqualsDeclaration.moduleReference, + ); if (internalAliasSymbol) { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); @@ -516,31 +632,47 @@ namespace ts.SymbolDisplay { } // For properties, variables and local vars: show the type if ( - symbolKind === ScriptElementKind.memberVariableElement || - symbolKind === ScriptElementKind.memberAccessorVariableElement || - symbolKind === ScriptElementKind.memberGetAccessorElement || - symbolKind === ScriptElementKind.memberSetAccessorElement || - symbolKind === ScriptElementKind.jsxAttribute || - symbolFlags & SymbolFlags.Variable || - symbolKind === ScriptElementKind.localVariableElement || - symbolKind === ScriptElementKind.indexSignatureElement || - isThisExpression + symbolKind === ScriptElementKind.memberVariableElement + || symbolKind === ScriptElementKind.memberAccessorVariableElement + || symbolKind === ScriptElementKind.memberGetAccessorElement + || symbolKind === ScriptElementKind.memberSetAccessorElement + || symbolKind === ScriptElementKind.jsxAttribute + || symbolFlags & SymbolFlags.Variable + || symbolKind === ScriptElementKind.localVariableElement + || symbolKind === ScriptElementKind.indexSignatureElement + || isThisExpression ) { displayParts.push(punctuationPart(SyntaxKind.ColonToken)); displayParts.push(spacePart()); // If the type is type parameter, format it specially - if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter && symbolKind !== ScriptElementKind.indexSignatureElement) { + if ( + type.symbol && type.symbol.flags & SymbolFlags.TypeParameter + && symbolKind !== ScriptElementKind.indexSignatureElement + ) { const typeParameterParts = mapToDisplayParts(writer => { - const param = typeChecker.typeParameterToDeclaration(type as TypeParameter, enclosingDeclaration, symbolDisplayNodeBuilderFlags)!; - getPrinter().writeNode(EmitHint.Unspecified, param, getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), writer); + const param = typeChecker.typeParameterToDeclaration( + type as TypeParameter, + enclosingDeclaration, + symbolDisplayNodeBuilderFlags, + )!; + getPrinter().writeNode( + EmitHint.Unspecified, + param, + getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), + writer, + ); }); addRange(displayParts, typeParameterParts); } else { addRange(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration)); } - if ((symbol as TransientSymbol).target && ((symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration) { - const labelDecl = ((symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration!; + if ( + (symbol as TransientSymbol).target + && ((symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration + ) { + const labelDecl = ((symbol as TransientSymbol).target as TransientSymbol) + .tupleLabelDeclaration!; Debug.assertNode(labelDecl.name, isIdentifier); displayParts.push(spacePart()); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); @@ -549,12 +681,12 @@ namespace ts.SymbolDisplay { } } else if ( - symbolFlags & SymbolFlags.Function || - symbolFlags & SymbolFlags.Method || - symbolFlags & SymbolFlags.Constructor || - symbolFlags & SymbolFlags.Signature || - symbolFlags & SymbolFlags.Accessor || - symbolKind === ScriptElementKind.memberFunctionElement + symbolFlags & SymbolFlags.Function + || symbolFlags & SymbolFlags.Method + || symbolFlags & SymbolFlags.Constructor + || symbolFlags & SymbolFlags.Signature + || symbolFlags & SymbolFlags.Accessor + || symbolKind === ScriptElementKind.memberFunctionElement ) { const allSignatures = type.getNonNullableType().getCallSignatures(); if (allSignatures.length) { @@ -577,7 +709,10 @@ namespace ts.SymbolDisplay { // For some special property access expressions like `exports.foo = foo` or `module.exports.foo = foo` // there documentation comments might be attached to the right hand side symbol of their declarations. // The pattern of such special property access is that the parent symbol is the symbol of the file. - if (symbol.parent && symbol.declarations && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile)) { + if ( + symbol.parent && symbol.declarations + && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile) + ) { for (const declaration of symbol.declarations) { if (!declaration.parent || declaration.parent.kind !== SyntaxKind.BinaryExpression) { continue; @@ -597,7 +732,10 @@ namespace ts.SymbolDisplay { } } - if (documentation.length === 0 && isIdentifier(location) && symbol.valueDeclaration && isBindingElement(symbol.valueDeclaration)) { + if ( + documentation.length === 0 && isIdentifier(location) && symbol.valueDeclaration + && isBindingElement(symbol.valueDeclaration) + ) { const declaration = symbol.valueDeclaration; const parent = declaration.parent; if (isIdentifier(declaration.name) && isObjectBindingPattern(parent)) { @@ -680,7 +818,14 @@ namespace ts.SymbolDisplay { fullSymbolDisplayParts.push(punctuationPart(SyntaxKind.CloseBracketToken)); } else { - fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay, enclosingDeclaration || sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing | SymbolFormatFlags.AllowAnyNodeKind); + fullSymbolDisplayParts = symbolToDisplayParts( + typeChecker, + symbolToDisplay, + enclosingDeclaration || sourceFile, + /*meaning*/ undefined, + SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing + | SymbolFormatFlags.AllowAnyNodeKind, + ); } addRange(displayParts, fullSymbolDisplayParts); if (symbol.flags & SymbolFlags.Optional) { @@ -692,7 +837,13 @@ namespace ts.SymbolDisplay { prefixNextMeaning(); if (symbolKind) { pushSymbolKind(symbolKind); - if (symbol && !some(symbol.declarations, d => isArrowFunction(d) || (isFunctionExpression(d) || isClassExpression(d)) && !d.name)) { + if ( + symbol + && !some( + symbol.declarations, + d => isArrowFunction(d) || (isFunctionExpression(d) || isClassExpression(d)) && !d.name, + ) + ) { displayParts.push(spacePart()); addFullSymbolName(symbol); } @@ -716,13 +867,27 @@ namespace ts.SymbolDisplay { } } - function addSignatureDisplayParts(signature: Signature, allSignatures: readonly Signature[], flags = TypeFormatFlags.None) { - addRange(displayParts, signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); + function addSignatureDisplayParts( + signature: Signature, + allSignatures: readonly Signature[], + flags = TypeFormatFlags.None, + ) { + addRange( + displayParts, + signatureToDisplayParts( + typeChecker, + signature, + enclosingDeclaration, + flags | TypeFormatFlags.WriteTypeArgumentsOfSignature, + ), + ); if (allSignatures.length > 1) { displayParts.push(spacePart()); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); displayParts.push(operatorPart(SyntaxKind.PlusToken)); - displayParts.push(displayPart((allSignatures.length - 1).toString(), SymbolDisplayPartKind.numericLiteral)); + displayParts.push( + displayPart((allSignatures.length - 1).toString(), SymbolDisplayPartKind.numericLiteral), + ); displayParts.push(spacePart()); displayParts.push(textPart(allSignatures.length === 2 ? "overload" : "overloads")); displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); @@ -738,8 +903,17 @@ namespace ts.SymbolDisplay { function writeTypeParametersOfSymbol(symbol: Symbol, enclosingDeclaration: Node | undefined) { const typeParameterParts = mapToDisplayParts(writer => { - const params = typeChecker.symbolToTypeParameterDeclarations(symbol, enclosingDeclaration, symbolDisplayNodeBuilderFlags); - getPrinter().writeList(ListFormat.TypeParameters, params, getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), writer); + const params = typeChecker.symbolToTypeParameterDeclarations( + symbol, + enclosingDeclaration, + symbolDisplayNodeBuilderFlags, + ); + getPrinter().writeList( + ListFormat.TypeParameters, + params, + getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), + writer, + ); }); addRange(displayParts, typeParameterParts); } @@ -756,7 +930,10 @@ namespace ts.SymbolDisplay { return true; } - if (declaration.kind !== SyntaxKind.VariableDeclaration && declaration.kind !== SyntaxKind.FunctionDeclaration) { + if ( + declaration.kind !== SyntaxKind.VariableDeclaration + && declaration.kind !== SyntaxKind.FunctionDeclaration + ) { return false; } diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index ee1d33475c830..0d9b011d1ab8f 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -159,11 +159,24 @@ namespace ts.textChanges { readonly text: string; } - function getAdjustedRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd): TextRange { - return { pos: getAdjustedStartPosition(sourceFile, startNode, options), end: getAdjustedEndPosition(sourceFile, endNode, options) }; + function getAdjustedRange( + sourceFile: SourceFile, + startNode: Node, + endNode: Node, + options: ConfigurableStartEnd, + ): TextRange { + return { + pos: getAdjustedStartPosition(sourceFile, startNode, options), + end: getAdjustedEndPosition(sourceFile, endNode, options), + }; } - function getAdjustedStartPosition(sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd, hasTrailingComment = false) { + function getAdjustedStartPosition( + sourceFile: SourceFile, + node: Node, + options: ConfigurableStartEnd, + hasTrailingComment = false, + ) { const { leadingTriviaOption } = options; if (leadingTriviaOption === LeadingTriviaOption.Exclude) { return node.getStart(sourceFile); @@ -201,7 +214,8 @@ namespace ts.textChanges { if (hasTrailingComment) { // Check first for leading comments as if the node is the first import, we want to exclude the trivia; // otherwise we get the trailing comments. - const comment = getLeadingCommentRanges(sourceFile.text, fullStart)?.[0] || getTrailingCommentRanges(sourceFile.text, fullStart)?.[0]; + const comment = getLeadingCommentRanges(sourceFile.text, fullStart)?.[0] + || getTrailingCommentRanges(sourceFile.text, fullStart)?.[0]; if (comment) { return skipTrivia(sourceFile.text, comment.end, /*stopAfterLineBreak*/ true, /*stopAtComments*/ true); } @@ -210,14 +224,21 @@ namespace ts.textChanges { // get start position of the line following the line that contains fullstart position // (but only if the fullstart isn't the very beginning of the file) const nextLineStart = fullStart > 0 ? 1 : 0; - let adjustedStartPosition = getStartPositionOfLine(getLineOfLocalPosition(sourceFile, fullStartLine) + nextLineStart, sourceFile); + let adjustedStartPosition = getStartPositionOfLine( + getLineOfLocalPosition(sourceFile, fullStartLine) + nextLineStart, + sourceFile, + ); // skip whitespaces/newlines adjustedStartPosition = skipWhitespacesAndLineBreaks(sourceFile.text, adjustedStartPosition); return getStartPositionOfLine(getLineOfLocalPosition(sourceFile, adjustedStartPosition), sourceFile); } /** Return the end position of a multiline comment of it is on another line; otherwise returns `undefined`; */ - function getEndPositionOfMultilineTrailingComment(sourceFile: SourceFile, node: Node, options: ConfigurableEnd): number | undefined { + function getEndPositionOfMultilineTrailingComment( + sourceFile: SourceFile, + node: Node, + options: ConfigurableEnd, + ): number | undefined { const { end } = node; const { trailingTriviaOption } = options; if (trailingTriviaOption === TrailingTriviaOption.Include) { @@ -229,7 +250,10 @@ namespace ts.textChanges { for (const comment of comments) { // Single line can break the loop as trivia will only be this line. // Comments on subsequest lines are also ignored. - if (comment.kind === SyntaxKind.SingleLineCommentTrivia || getLineOfLocalPosition(sourceFile, comment.pos) > nodeEndLine) { + if ( + comment.kind === SyntaxKind.SingleLineCommentTrivia + || getLineOfLocalPosition(sourceFile, comment.pos) > nodeEndLine + ) { break; } @@ -238,7 +262,12 @@ namespace ts.textChanges { // then is safe to return the end position. const commentEndLine = getLineOfLocalPosition(sourceFile, comment.end); if (commentEndLine > nodeEndLine) { - return skipTrivia(sourceFile.text, comment.end, /*stopAfterLineBreak*/ true, /*stopAtComments*/ true); + return skipTrivia( + sourceFile.text, + comment.end, + /*stopAfterLineBreak*/ true, + /*stopAtComments*/ true, + ); } } } @@ -254,7 +283,10 @@ namespace ts.textChanges { return end; } if (trailingTriviaOption === TrailingTriviaOption.ExcludeWhitespace) { - const comments = concatenate(getTrailingCommentRanges(sourceFile.text, end), getLeadingCommentRanges(sourceFile.text, end)); + const comments = concatenate( + getTrailingCommentRanges(sourceFile.text, end), + getLeadingCommentRanges(sourceFile.text, end), + ); const realEnd = comments?.[comments.length - 1]?.end; if (realEnd) { return realEnd; @@ -269,7 +301,9 @@ namespace ts.textChanges { const newEnd = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true); - return newEnd !== end && (trailingTriviaOption === TrailingTriviaOption.Include || isLineBreak(sourceFile.text.charCodeAt(newEnd - 1))) + return newEnd !== end + && (trailingTriviaOption === TrailingTriviaOption.Include + || isLineBreak(sourceFile.text.charCodeAt(newEnd - 1))) ? newEnd : end; } @@ -277,8 +311,14 @@ namespace ts.textChanges { /** * Checks if 'candidate' argument is a legal separator in the list that contains 'node' as an element */ - function isSeparator(node: Node, candidate: Node | undefined): candidate is Token { - return !!candidate && !!node.parent && (candidate.kind === SyntaxKind.CommaToken || (candidate.kind === SyntaxKind.SemicolonToken && node.parent.kind === SyntaxKind.ObjectLiteralExpression)); + function isSeparator( + node: Node, + candidate: Node | undefined, + ): candidate is Token { + return !!candidate && !!node.parent + && (candidate.kind === SyntaxKind.CommaToken + || (candidate.kind === SyntaxKind.SemicolonToken + && node.parent.kind === SyntaxKind.ObjectLiteralExpression)); } export interface TextChangesContext { @@ -287,22 +327,45 @@ namespace ts.textChanges { preferences: UserPreferences; } - export type TypeAnnotatable = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature; + export type TypeAnnotatable = + | SignatureDeclaration + | VariableDeclaration + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature; export type ThisTypeAnnotatable = FunctionDeclaration | FunctionExpression; - export function isThisTypeAnnotatable(containingFunction: SignatureDeclaration): containingFunction is ThisTypeAnnotatable { + export function isThisTypeAnnotatable( + containingFunction: SignatureDeclaration, + ): containingFunction is ThisTypeAnnotatable { return isFunctionExpression(containingFunction) || isFunctionDeclaration(containingFunction); } export class ChangeTracker { private readonly changes: Change[] = []; - private readonly newFiles: { readonly oldFile: SourceFile | undefined; readonly fileName: string; readonly statements: readonly (Statement | SyntaxKind.NewLineTrivia)[]; }[] = []; - private readonly classesWithNodesInsertedAtStart = new Map(); // Set implemented as Map - private readonly deletedNodes: { readonly sourceFile: SourceFile; readonly node: Node | NodeArray; }[] = []; + private readonly newFiles: { + readonly oldFile: SourceFile | undefined; + readonly fileName: string; + readonly statements: readonly (Statement | SyntaxKind.NewLineTrivia)[]; + }[] = []; + private readonly classesWithNodesInsertedAtStart = new Map< + number, + { + readonly node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression; + readonly sourceFile: SourceFile; + } + >(); // Set implemented as Map + private readonly deletedNodes: { + readonly sourceFile: SourceFile; + readonly node: Node | NodeArray; + }[] = []; public static fromContext(context: TextChangesContext): ChangeTracker { - return new ChangeTracker(getNewLineOrDefaultFromHost(context.host, context.formatContext.options), context.formatContext); + return new ChangeTracker( + getNewLineOrDefaultFromHost(context.host, context.formatContext.options), + context.formatContext, + ); } public static with(context: TextChangesContext, cb: (tracker: ChangeTracker) => void): FileTextChanges[] { @@ -312,7 +375,10 @@ namespace ts.textChanges { } /** Public for tests only. Other callers should use `ChangeTracker.with`. */ - constructor(private readonly newLineCharacter: string, private readonly formatContext: formatting.FormatContext) {} + constructor( + private readonly newLineCharacter: string, + private readonly formatContext: formatting.FormatContext, + ) {} public pushRaw(sourceFile: SourceFile, change: FileTextChanges) { Debug.assertEqual(sourceFile.fileName, change.fileName); @@ -335,11 +401,20 @@ namespace ts.textChanges { } /** Stop! Consider using `delete` instead, which has logic for deleting nodes from delimited lists. */ - public deleteNode(sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + public deleteNode( + sourceFile: SourceFile, + node: Node, + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, + ): void { this.deleteRange(sourceFile, getAdjustedRange(sourceFile, node, node, options)); } - public deleteNodes(sourceFile: SourceFile, nodes: readonly Node[], options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, hasTrailingComment: boolean): void { + public deleteNodes( + sourceFile: SourceFile, + nodes: readonly Node[], + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, + hasTrailingComment: boolean, + ): void { // When deleting multiple nodes we need to track if the end position is including multiline trailing comments. for (const node of nodes) { const pos = getAdjustedStartPosition(sourceFile, node, options, hasTrailingComment); @@ -352,50 +427,120 @@ namespace ts.textChanges { } public deleteModifier(sourceFile: SourceFile, modifier: Modifier): void { - this.deleteRange(sourceFile, { pos: modifier.getStart(sourceFile), end: skipTrivia(sourceFile.text, modifier.end, /*stopAfterLineBreak*/ true) }); + this.deleteRange(sourceFile, { + pos: modifier.getStart(sourceFile), + end: skipTrivia(sourceFile.text, modifier.end, /*stopAfterLineBreak*/ true), + }); } - public deleteNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + public deleteNodeRange( + sourceFile: SourceFile, + startNode: Node, + endNode: Node, + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, + ): void { const startPosition = getAdjustedStartPosition(sourceFile, startNode, options); const endPosition = getAdjustedEndPosition(sourceFile, endNode, options); this.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); } - public deleteNodeRangeExcludingEnd(sourceFile: SourceFile, startNode: Node, afterEndNode: Node | undefined, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + public deleteNodeRangeExcludingEnd( + sourceFile: SourceFile, + startNode: Node, + afterEndNode: Node | undefined, + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, + ): void { const startPosition = getAdjustedStartPosition(sourceFile, startNode, options); - const endPosition = afterEndNode === undefined ? sourceFile.text.length : getAdjustedStartPosition(sourceFile, afterEndNode, options); + const endPosition = afterEndNode === undefined ? sourceFile.text.length + : getAdjustedStartPosition(sourceFile, afterEndNode, options); this.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); } - public replaceRange(sourceFile: SourceFile, range: TextRange, newNode: Node, options: InsertNodeOptions = {}): void { + public replaceRange( + sourceFile: SourceFile, + range: TextRange, + newNode: Node, + options: InsertNodeOptions = {}, + ): void { this.changes.push({ kind: ChangeKind.ReplaceWithSingleNode, sourceFile, range, options, node: newNode }); } - public replaceNode(sourceFile: SourceFile, oldNode: Node, newNode: Node, options: ChangeNodeOptions = useNonAdjustedPositions): void { + public replaceNode( + sourceFile: SourceFile, + oldNode: Node, + newNode: Node, + options: ChangeNodeOptions = useNonAdjustedPositions, + ): void { this.replaceRange(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, options), newNode, options); } - public replaceNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, newNode: Node, options: ChangeNodeOptions = useNonAdjustedPositions): void { + public replaceNodeRange( + sourceFile: SourceFile, + startNode: Node, + endNode: Node, + newNode: Node, + options: ChangeNodeOptions = useNonAdjustedPositions, + ): void { this.replaceRange(sourceFile, getAdjustedRange(sourceFile, startNode, endNode, options), newNode, options); } - private replaceRangeWithNodes(sourceFile: SourceFile, range: TextRange, newNodes: readonly Node[], options: ReplaceWithMultipleNodesOptions & ConfigurableStartEnd = {}): void { - this.changes.push({ kind: ChangeKind.ReplaceWithMultipleNodes, sourceFile, range, options, nodes: newNodes }); + private replaceRangeWithNodes( + sourceFile: SourceFile, + range: TextRange, + newNodes: readonly Node[], + options: ReplaceWithMultipleNodesOptions & ConfigurableStartEnd = {}, + ): void { + this.changes.push({ + kind: ChangeKind.ReplaceWithMultipleNodes, + sourceFile, + range, + options, + nodes: newNodes, + }); } - public replaceNodeWithNodes(sourceFile: SourceFile, oldNode: Node, newNodes: readonly Node[], options: ChangeNodeOptions = useNonAdjustedPositions): void { - this.replaceRangeWithNodes(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, options), newNodes, options); + public replaceNodeWithNodes( + sourceFile: SourceFile, + oldNode: Node, + newNodes: readonly Node[], + options: ChangeNodeOptions = useNonAdjustedPositions, + ): void { + this.replaceRangeWithNodes( + sourceFile, + getAdjustedRange(sourceFile, oldNode, oldNode, options), + newNodes, + options, + ); } public replaceNodeWithText(sourceFile: SourceFile, oldNode: Node, text: string): void { - this.replaceRangeWithText(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, useNonAdjustedPositions), text); + this.replaceRangeWithText( + sourceFile, + getAdjustedRange(sourceFile, oldNode, oldNode, useNonAdjustedPositions), + text, + ); } - public replaceNodeRangeWithNodes(sourceFile: SourceFile, startNode: Node, endNode: Node, newNodes: readonly Node[], options: ReplaceWithMultipleNodesOptions & ConfigurableStartEnd = useNonAdjustedPositions): void { - this.replaceRangeWithNodes(sourceFile, getAdjustedRange(sourceFile, startNode, endNode, options), newNodes, options); + public replaceNodeRangeWithNodes( + sourceFile: SourceFile, + startNode: Node, + endNode: Node, + newNodes: readonly Node[], + options: ReplaceWithMultipleNodesOptions & ConfigurableStartEnd = useNonAdjustedPositions, + ): void { + this.replaceRangeWithNodes( + sourceFile, + getAdjustedRange(sourceFile, startNode, endNode, options), + newNodes, + options, + ); } - public nodeHasTrailingComment(sourceFile: SourceFile, oldNode: Node, configurableEnd: ConfigurableEnd = useNonAdjustedPositions): boolean { + public nodeHasTrailingComment( + sourceFile: SourceFile, + oldNode: Node, + configurableEnd: ConfigurableEnd = useNonAdjustedPositions, + ): boolean { return !!getEndPositionOfMultilineTrailingComment(sourceFile, oldNode, configurableEnd); } @@ -404,7 +549,11 @@ namespace ts.textChanges { return next && next.kind === SyntaxKind.CommaToken ? next : undefined; } - public replacePropertyAssignment(sourceFile: SourceFile, oldNode: PropertyAssignment, newNode: PropertyAssignment): void { + public replacePropertyAssignment( + sourceFile: SourceFile, + oldNode: PropertyAssignment, + newNode: PropertyAssignment, + ): void { const suffix = this.nextCommaToken(sourceFile, oldNode) ? "" : ("," + this.newLineCharacter); this.replaceNode(sourceFile, oldNode, newNode, { suffix }); } @@ -413,7 +562,12 @@ namespace ts.textChanges { this.replaceRange(sourceFile, createRange(pos), newNode, options); } - private insertNodesAt(sourceFile: SourceFile, pos: number, newNodes: readonly Node[], options: ReplaceWithMultipleNodesOptions = {}): void { + private insertNodesAt( + sourceFile: SourceFile, + pos: number, + newNodes: readonly Node[], + options: ReplaceWithMultipleNodesOptions = {}, + ): void { this.replaceRangeWithNodes(sourceFile, createRange(pos), newNodes, options); } @@ -421,15 +575,24 @@ namespace ts.textChanges { this.insertAtTopOfFile(sourceFile, newNode, blankLineBetween); } - public insertNodesAtTopOfFile(sourceFile: SourceFile, newNodes: readonly Statement[], blankLineBetween: boolean): void { + public insertNodesAtTopOfFile( + sourceFile: SourceFile, + newNodes: readonly Statement[], + blankLineBetween: boolean, + ): void { this.insertAtTopOfFile(sourceFile, newNodes, blankLineBetween); } - private insertAtTopOfFile(sourceFile: SourceFile, insert: Statement | readonly Statement[], blankLineBetween: boolean): void { + private insertAtTopOfFile( + sourceFile: SourceFile, + insert: Statement | readonly Statement[], + blankLineBetween: boolean, + ): void { const pos = getInsertionPositionAtSourceFileTop(sourceFile); const options = { prefix: pos === 0 ? undefined : this.newLineCharacter, - suffix: (isLineBreak(sourceFile.text.charCodeAt(pos)) ? "" : this.newLineCharacter) + (blankLineBetween ? this.newLineCharacter : ""), + suffix: (isLineBreak(sourceFile.text.charCodeAt(pos)) ? "" : this.newLineCharacter) + + (blankLineBetween ? this.newLineCharacter : ""), }; if (isArray(insert)) { this.insertNodesAt(sourceFile, pos, insert, options); @@ -439,7 +602,11 @@ namespace ts.textChanges { } } - public insertFirstParameter(sourceFile: SourceFile, parameters: NodeArray, newParam: ParameterDeclaration): void { + public insertFirstParameter( + sourceFile: SourceFile, + parameters: NodeArray, + newParam: ParameterDeclaration, + ): void { const p0 = firstOrUndefined(parameters); if (p0) { this.insertNodeBefore(sourceFile, p0, newParam); @@ -449,11 +616,27 @@ namespace ts.textChanges { } } - public insertNodeBefore(sourceFile: SourceFile, before: Node, newNode: Node, blankLineBetween = false, options: ConfigurableStartEnd = {}): void { - this.insertNodeAt(sourceFile, getAdjustedStartPosition(sourceFile, before, options), newNode, this.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween)); + public insertNodeBefore( + sourceFile: SourceFile, + before: Node, + newNode: Node, + blankLineBetween = false, + options: ConfigurableStartEnd = {}, + ): void { + this.insertNodeAt( + sourceFile, + getAdjustedStartPosition(sourceFile, before, options), + newNode, + this.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween), + ); } - public insertModifierAt(sourceFile: SourceFile, pos: number, modifier: SyntaxKind, options: InsertNodeOptions = {}): void { + public insertModifierAt( + sourceFile: SourceFile, + pos: number, + modifier: SyntaxKind, + options: InsertNodeOptions = {}, + ): void { this.insertNodeAt(sourceFile, pos, factory.createToken(modifier), options); } @@ -461,7 +644,12 @@ namespace ts.textChanges { return this.insertModifierAt(sourceFile, before.getStart(sourceFile), modifier, { suffix: " " }); } - public insertCommentBeforeLine(sourceFile: SourceFile, lineNumber: number, position: number, commentText: string): void { + public insertCommentBeforeLine( + sourceFile: SourceFile, + lineNumber: number, + position: number, + commentText: string, + ): void { const lineStartPosition = getStartPositionOfLine(lineNumber, sourceFile); const startPosition = getFirstNonSpaceCharacterPosition(sourceFile.text, lineStartPosition); // First try to see if we can put the comment on the previous line. @@ -471,7 +659,9 @@ namespace ts.textChanges { const insertAtLineStart = isValidLocationToAddComment(sourceFile, startPosition); const token = getTouchingToken(sourceFile, insertAtLineStart ? startPosition : position); const indent = sourceFile.text.slice(lineStartPosition, startPosition); - const text = `${insertAtLineStart ? "" : this.newLineCharacter}//${commentText}${this.newLineCharacter}${indent}`; + const text = `${ + insertAtLineStart ? "" : this.newLineCharacter + }//${commentText}${this.newLineCharacter}${indent}`; this.insertText(sourceFile, token.getStart(sourceFile), text); } @@ -491,14 +681,22 @@ namespace ts.textChanges { } private createJSDocText(sourceFile: SourceFile, node: HasJSDoc) { - const comments = flatMap(node.jsDoc, jsDoc => isString(jsDoc.comment) ? factory.createJSDocText(jsDoc.comment) : jsDoc.comment) as JSDocComment[]; + const comments = flatMap( + node.jsDoc, + jsDoc => isString(jsDoc.comment) ? factory.createJSDocText(jsDoc.comment) : jsDoc.comment, + ) as JSDocComment[]; const jsDoc = singleOrUndefined(node.jsDoc); - return jsDoc && positionsAreOnSameLine(jsDoc.pos, jsDoc.end, sourceFile) && length(comments) === 0 ? undefined : - factory.createNodeArray(intersperse(comments, factory.createJSDocText("\n"))); + return jsDoc && positionsAreOnSameLine(jsDoc.pos, jsDoc.end, sourceFile) && length(comments) === 0 + ? undefined + : factory.createNodeArray(intersperse(comments, factory.createJSDocText("\n"))); } public replaceJSDocComment(sourceFile: SourceFile, node: HasJSDoc, tags: readonly JSDocTag[]) { - this.insertJsdocCommentBefore(sourceFile, updateJSDocHost(node), factory.createJSDocComment(this.createJSDocText(sourceFile, node), factory.createNodeArray(tags))); + this.insertJsdocCommentBefore( + sourceFile, + updateJSDocHost(node), + factory.createJSDocComment(this.createJSDocText(sourceFile, node), factory.createNodeArray(tags)), + ); } public addJSDocTags(sourceFile: SourceFile, parent: HasJSDoc, newTags: readonly JSDocTag[]): void { @@ -514,7 +712,11 @@ namespace ts.textChanges { } public filterJSDocTags(sourceFile: SourceFile, parent: HasJSDoc, predicate: (tag: JSDocTag) => boolean): void { - this.replaceJSDocComment(sourceFile, parent, filter(flatMapToMutable(parent.jsDoc, j => j.tags), predicate)); + this.replaceJSDocComment( + sourceFile, + parent, + filter(flatMapToMutable(parent.jsDoc, j => j.tags), predicate), + ); } public replaceRangeWithText(sourceFile: SourceFile, range: TextRange, text: string): void { @@ -537,7 +739,8 @@ namespace ts.textChanges { } } else { - endNode = (node.kind === SyntaxKind.VariableDeclaration ? node.exclamationToken : node.questionToken) ?? node.name; + endNode = (node.kind === SyntaxKind.VariableDeclaration ? node.exclamationToken : node.questionToken) + ?? node.name; } this.insertNodeAt(sourceFile, endNode.end, type, { prefix: ": " }); @@ -551,15 +754,26 @@ namespace ts.textChanges { this.insertNodeAt(sourceFile, start, type, { prefix: "this: ", suffix }); } - public insertTypeParameters(sourceFile: SourceFile, node: SignatureDeclaration, typeParameters: readonly TypeParameterDeclaration[]): void { + public insertTypeParameters( + sourceFile: SourceFile, + node: SignatureDeclaration, + typeParameters: readonly TypeParameterDeclaration[], + ): void { // If no `(`, is an arrow function `x => x`, so use the pos of the first parameter - const start = (findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile) || first(node.parameters)).getStart(sourceFile); + const start = (findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile) || first(node.parameters)) + .getStart(sourceFile); this.insertNodesAt(sourceFile, start, typeParameters, { prefix: "<", suffix: ">", joiner: ", " }); } - private getOptionsForInsertNodeBefore(before: Node, inserted: Node, blankLineBetween: boolean): InsertNodeOptions { + private getOptionsForInsertNodeBefore( + before: Node, + inserted: Node, + blankLineBetween: boolean, + ): InsertNodeOptions { if (isStatement(before) || isClassElement(before)) { - return { suffix: blankLineBetween ? this.newLineCharacter + this.newLineCharacter : this.newLineCharacter }; + return { + suffix: blankLineBetween ? this.newLineCharacter + this.newLineCharacter : this.newLineCharacter, + }; } else if (isVariableDeclaration(before)) { // insert `x = 1, ` into `const x = 1, y = 2; return { suffix: ", " }; @@ -576,7 +790,11 @@ namespace ts.textChanges { return Debug.failBadSyntaxKind(before); // We haven't handled this kind of node yet -- add it } - public insertNodeAtConstructorStart(sourceFile: SourceFile, ctr: ConstructorDeclaration, newStatement: Statement): void { + public insertNodeAtConstructorStart( + sourceFile: SourceFile, + ctr: ConstructorDeclaration, + newStatement: Statement, + ): void { const firstStatement = firstOrUndefined(ctr.body!.statements); if (!firstStatement || !ctr.body!.multiLine) { this.replaceConstructorBody(sourceFile, ctr, [newStatement, ...ctr.body!.statements]); @@ -586,8 +804,15 @@ namespace ts.textChanges { } } - public insertNodeAtConstructorStartAfterSuperCall(sourceFile: SourceFile, ctr: ConstructorDeclaration, newStatement: Statement): void { - const superCallStatement = find(ctr.body!.statements, stmt => isExpressionStatement(stmt) && isSuperCall(stmt.expression)); + public insertNodeAtConstructorStartAfterSuperCall( + sourceFile: SourceFile, + ctr: ConstructorDeclaration, + newStatement: Statement, + ): void { + const superCallStatement = find( + ctr.body!.statements, + stmt => isExpressionStatement(stmt) && isSuperCall(stmt.expression), + ); if (!superCallStatement || !ctr.body!.multiLine) { this.replaceConstructorBody(sourceFile, ctr, [...ctr.body!.statements, newStatement]); } @@ -596,7 +821,11 @@ namespace ts.textChanges { } } - public insertNodeAtConstructorEnd(sourceFile: SourceFile, ctr: ConstructorDeclaration, newStatement: Statement): void { + public insertNodeAtConstructorEnd( + sourceFile: SourceFile, + ctr: ConstructorDeclaration, + newStatement: Statement, + ): void { const lastStatement = lastOrUndefined(ctr.body!.statements); if (!lastStatement || !ctr.body!.multiLine) { this.replaceConstructorBody(sourceFile, ctr, [...ctr.body!.statements, newStatement]); @@ -606,36 +835,62 @@ namespace ts.textChanges { } } - private replaceConstructorBody(sourceFile: SourceFile, ctr: ConstructorDeclaration, statements: readonly Statement[]): void { + private replaceConstructorBody( + sourceFile: SourceFile, + ctr: ConstructorDeclaration, + statements: readonly Statement[], + ): void { this.replaceNode(sourceFile, ctr.body!, factory.createBlock(statements, /*multiLine*/ true)); } public insertNodeAtEndOfScope(sourceFile: SourceFile, scope: Node, newNode: Node): void { const pos = getAdjustedStartPosition(sourceFile, scope.getLastToken()!, {}); this.insertNodeAt(sourceFile, pos, newNode, { - prefix: isLineBreak(sourceFile.text.charCodeAt(scope.getLastToken()!.pos)) ? this.newLineCharacter : this.newLineCharacter + this.newLineCharacter, + prefix: isLineBreak(sourceFile.text.charCodeAt(scope.getLastToken()!.pos)) ? this.newLineCharacter + : this.newLineCharacter + this.newLineCharacter, suffix: this.newLineCharacter, }); } - public insertMemberAtStart(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, newElement: ClassElement | PropertySignature | MethodSignature): void { + public insertMemberAtStart( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + newElement: ClassElement | PropertySignature | MethodSignature, + ): void { this.insertNodeAtStartWorker(sourceFile, node, newElement); } - public insertNodeAtObjectStart(sourceFile: SourceFile, obj: ObjectLiteralExpression, newElement: ObjectLiteralElementLike): void { + public insertNodeAtObjectStart( + sourceFile: SourceFile, + obj: ObjectLiteralExpression, + newElement: ObjectLiteralElementLike, + ): void { this.insertNodeAtStartWorker(sourceFile, obj, newElement); } - private insertNodeAtStartWorker(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, newElement: ClassElement | ObjectLiteralElementLike | PropertySignature | MethodSignature): void { - const indentation = this.guessIndentationFromExistingMembers(sourceFile, node) ?? this.computeIndentationForNewMember(sourceFile, node); - this.insertNodeAt(sourceFile, getMembersOrProperties(node).pos, newElement, this.getInsertNodeAtStartInsertOptions(sourceFile, node, indentation)); + private insertNodeAtStartWorker( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, + newElement: ClassElement | ObjectLiteralElementLike | PropertySignature | MethodSignature, + ): void { + const indentation = this.guessIndentationFromExistingMembers(sourceFile, node) + ?? this.computeIndentationForNewMember(sourceFile, node); + this.insertNodeAt( + sourceFile, + getMembersOrProperties(node).pos, + newElement, + this.getInsertNodeAtStartInsertOptions(sourceFile, node, indentation), + ); } /** * Tries to guess the indentation from the existing members of a class/interface/object. All members must be on * new lines and must share the same indentation. */ - private guessIndentationFromExistingMembers(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode) { + private guessIndentationFromExistingMembers( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, + ) { let indentation: number | undefined; let lastRange: TextRange = node; for (const member of getMembersOrProperties(node)) { @@ -644,7 +899,12 @@ namespace ts.textChanges { return undefined; } const memberStart = member.getStart(sourceFile); - const memberIndentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(memberStart, sourceFile), memberStart, sourceFile, this.formatContext.options); + const memberIndentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn( + getLineStartPositionForPosition(memberStart, sourceFile), + memberStart, + sourceFile, + this.formatContext.options, + ); if (indentation === undefined) { indentation = memberIndentation; } @@ -657,13 +917,25 @@ namespace ts.textChanges { return indentation; } - private computeIndentationForNewMember(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode) { + private computeIndentationForNewMember( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, + ) { const nodeStart = node.getStart(sourceFile); - return formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(nodeStart, sourceFile), nodeStart, sourceFile, this.formatContext.options) + return formatting.SmartIndenter.findFirstNonWhitespaceColumn( + getLineStartPositionForPosition(nodeStart, sourceFile), + nodeStart, + sourceFile, + this.formatContext.options, + ) + (this.formatContext.options.indentSize ?? 4); } - private getInsertNodeAtStartInsertOptions(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, indentation: number): InsertNodeOptions { + private getInsertNodeAtStartInsertOptions( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, + indentation: number, + ): InsertNodeOptions { // Rules: // - Always insert leading newline. // - For object literals: @@ -676,9 +948,13 @@ namespace ts.textChanges { const members = getMembersOrProperties(node); const isEmpty = members.length === 0; - const isFirstInsertion = addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(node), { node, sourceFile }); + const isFirstInsertion = addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(node), { + node, + sourceFile, + }); const insertTrailingComma = isObjectLiteralExpression(node) && (!isJsonSourceFile(sourceFile) || !isEmpty); - const insertLeadingComma = isObjectLiteralExpression(node) && isJsonSourceFile(sourceFile) && isEmpty && !isFirstInsertion; + const insertLeadingComma = isObjectLiteralExpression(node) && isJsonSourceFile(sourceFile) && isEmpty + && !isFirstInsertion; return { indentation, prefix: (insertLeadingComma ? "," : "") + this.newLineCharacter, @@ -687,7 +963,11 @@ namespace ts.textChanges { } public insertNodeAfterComma(sourceFile: SourceFile, after: Node, newNode: Node): void { - const endPosition = this.insertNodeAfterWorker(sourceFile, this.nextCommaToken(sourceFile, after) || after, newNode); + const endPosition = this.insertNodeAfterWorker( + sourceFile, + this.nextCommaToken(sourceFile, after) || after, + newNode, + ); this.insertNodeAt(sourceFile, endPosition, newNode, this.getInsertNodeAfterOptions(sourceFile, after)); } @@ -710,7 +990,11 @@ namespace ts.textChanges { // check if previous statement ends with semicolon // if not - insert semicolon to preserve the code from changing the meaning due to ASI if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) { - this.replaceRange(sourceFile, createRange(after.end), factory.createToken(SyntaxKind.SemicolonToken)); + this.replaceRange( + sourceFile, + createRange(after.end), + factory.createToken(SyntaxKind.SemicolonToken), + ); } } const endPosition = getAdjustedEndPosition(sourceFile, after, {}); @@ -721,7 +1005,8 @@ namespace ts.textChanges { const options = this.getInsertNodeAfterOptionsWorker(after); return { ...options, - prefix: after.end === sourceFile.end && isStatement(after) ? (options.prefix ? `\n${options.prefix}` : "\n") : options.prefix, + prefix: after.end === sourceFile.end && isStatement(after) + ? (options.prefix ? `\n${options.prefix}` : "\n") : options.prefix, }; } @@ -751,14 +1036,21 @@ namespace ts.textChanges { } } - public insertName(sourceFile: SourceFile, node: FunctionExpression | ClassExpression | ArrowFunction, name: string): void { + public insertName( + sourceFile: SourceFile, + node: FunctionExpression | ClassExpression | ArrowFunction, + name: string, + ): void { Debug.assert(!node.name); if (node.kind === SyntaxKind.ArrowFunction) { const arrow = findChildOfKind(node, SyntaxKind.EqualsGreaterThanToken, sourceFile)!; const lparen = findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile); if (lparen) { // `() => {}` --> `function f() {}` - this.insertNodesAt(sourceFile, lparen.getStart(sourceFile), [factory.createToken(SyntaxKind.FunctionKeyword), factory.createIdentifier(name)], { joiner: " " }); + this.insertNodesAt(sourceFile, lparen.getStart(sourceFile), [ + factory.createToken(SyntaxKind.FunctionKeyword), + factory.createIdentifier(name), + ], { joiner: " " }); deleteNode(this, sourceFile, arrow); } else { @@ -770,12 +1062,23 @@ namespace ts.textChanges { if (node.body.kind !== SyntaxKind.Block) { // `() => 0` => `function f() { return 0; }` - this.insertNodesAt(sourceFile, node.body.getStart(sourceFile), [factory.createToken(SyntaxKind.OpenBraceToken), factory.createToken(SyntaxKind.ReturnKeyword)], { joiner: " ", suffix: " " }); - this.insertNodesAt(sourceFile, node.body.end, [factory.createToken(SyntaxKind.SemicolonToken), factory.createToken(SyntaxKind.CloseBraceToken)], { joiner: " " }); + this.insertNodesAt(sourceFile, node.body.getStart(sourceFile), [ + factory.createToken(SyntaxKind.OpenBraceToken), + factory.createToken(SyntaxKind.ReturnKeyword), + ], { joiner: " ", suffix: " " }); + this.insertNodesAt(sourceFile, node.body.end, [ + factory.createToken(SyntaxKind.SemicolonToken), + factory.createToken(SyntaxKind.CloseBraceToken), + ], { joiner: " " }); } } else { - const pos = findChildOfKind(node, node.kind === SyntaxKind.FunctionExpression ? SyntaxKind.FunctionKeyword : SyntaxKind.ClassKeyword, sourceFile)!.end; + const pos = findChildOfKind( + node, + node.kind === SyntaxKind.FunctionExpression ? SyntaxKind.FunctionKeyword + : SyntaxKind.ClassKeyword, + sourceFile, + )!.end; this.insertNodeAt(sourceFile, pos, factory.createIdentifier(name), { prefix: " " }); } } @@ -784,7 +1087,12 @@ namespace ts.textChanges { this.insertText(sourceFile, node.getStart(sourceFile), "export "); } - public insertImportSpecifierAtIndex(sourceFile: SourceFile, importSpecifier: ImportSpecifier, namedImports: NamedImports, index: number) { + public insertImportSpecifierAtIndex( + sourceFile: SourceFile, + importSpecifier: ImportSpecifier, + namedImports: NamedImports, + index: number, + ) { const prevSpecifier = namedImports.elements[index - 1]; if (prevSpecifier) { this.insertNodeInListAfter(sourceFile, prevSpecifier, importSpecifier); @@ -794,7 +1102,11 @@ namespace ts.textChanges { sourceFile, namedImports.elements[0], importSpecifier, - !positionsAreOnSameLine(namedImports.elements[0].getStart(), namedImports.parent.parent.getStart(), sourceFile), + !positionsAreOnSameLine( + namedImports.elements[0].getStart(), + namedImports.parent.parent.getStart(), + sourceFile, + ), ); } } @@ -804,7 +1116,12 @@ namespace ts.textChanges { * i.e. arguments in arguments lists, parameters in parameter lists etc. * Note that separators are part of the node in statements and class elements. */ - public insertNodeInListAfter(sourceFile: SourceFile, after: Node, newNode: Node, containingList = formatting.SmartIndenter.getContainingList(after, sourceFile)): void { + public insertNodeInListAfter( + sourceFile: SourceFile, + after: Node, + newNode: Node, + containingList = formatting.SmartIndenter.getContainingList(after, sourceFile), + ): void { if (!containingList) { Debug.fail("node is not a list element"); return; @@ -839,7 +1156,9 @@ namespace ts.textChanges { const startPos = skipWhitespacesAndLineBreaks(sourceFile.text, nextNode.getFullStart()); // write separator and leading trivia of the next element as suffix - const suffix = `${tokenToString(nextToken.kind)}${sourceFile.text.substring(nextToken.end, startPos)}`; + const suffix = `${tokenToString(nextToken.kind)}${ + sourceFile.text.substring(nextToken.end, startPos) + }`; this.insertNodesAt(sourceFile, startPos, [newNode], { suffix }); } } @@ -863,9 +1182,13 @@ namespace ts.textChanges { else { // element has more than one element, pick separator from the list const tokenBeforeInsertPosition = findPrecedingToken(after.pos, sourceFile); - separator = isSeparator(after, tokenBeforeInsertPosition) ? tokenBeforeInsertPosition.kind : SyntaxKind.CommaToken; + separator = isSeparator(after, tokenBeforeInsertPosition) ? tokenBeforeInsertPosition.kind + : SyntaxKind.CommaToken; // determine if list is multiline by checking lines of after element and element that precedes it. - const afterMinusOneStartLinePosition = getLineStartPositionForPosition(containingList[index - 1].getStart(sourceFile), sourceFile); + const afterMinusOneStartLinePosition = getLineStartPositionForPosition( + containingList[index - 1].getStart(sourceFile), + sourceFile, + ); multilineList = afterMinusOneStartLinePosition !== afterStartLinePosition; } if (hasCommentsBeforeLineBreak(sourceFile.text, after.end)) { @@ -876,17 +1199,32 @@ namespace ts.textChanges { // insert separator immediately following the 'after' node to preserve comments in trailing trivia this.replaceRange(sourceFile, createRange(end), factory.createToken(separator)); // use the same indentation as 'after' item - const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(afterStartLinePosition, afterStart, sourceFile, this.formatContext.options); + const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn( + afterStartLinePosition, + afterStart, + sourceFile, + this.formatContext.options, + ); // insert element before the line break on the line that contains 'after' element - let insertPos = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true, /*stopAtComments*/ false); + let insertPos = skipTrivia( + sourceFile.text, + end, + /*stopAfterLineBreak*/ true, + /*stopAtComments*/ false, + ); // find position before "\n" or "\r\n" while (insertPos !== end && isLineBreak(sourceFile.text.charCodeAt(insertPos - 1))) { insertPos--; } - this.replaceRange(sourceFile, createRange(insertPos), newNode, { indentation, prefix: this.newLineCharacter }); + this.replaceRange(sourceFile, createRange(insertPos), newNode, { + indentation, + prefix: this.newLineCharacter, + }); } else { - this.replaceRange(sourceFile, createRange(end), newNode, { prefix: `${tokenToString(separator)} ` }); + this.replaceRange(sourceFile, createRange(end), newNode, { + prefix: `${tokenToString(separator)} `, + }); } } } @@ -915,7 +1253,11 @@ namespace ts.textChanges { private finishDeleteDeclarations(): void { const deletedNodesInLists = new Set(); // Stores nodes in lists that we already deleted. Used to avoid deleting `, ` twice in `a, b`. for (const { sourceFile, node } of this.deletedNodes) { - if (!this.deletedNodes.some(d => d.sourceFile === sourceFile && rangeContainsRangeExclusive(d.node, node))) { + if ( + !this.deletedNodes.some(d => + d.sourceFile === sourceFile && rangeContainsRangeExclusive(d.node, node) + ) + ) { if (isArray(node)) { this.deleteRange(sourceFile, rangeOfTypeParameters(sourceFile, node)); } @@ -932,7 +1274,10 @@ namespace ts.textChanges { const lastNonDeletedIndex = findLastIndex(list, n => !deletedNodesInLists.has(n), list.length - 2); if (lastNonDeletedIndex !== -1) { - this.deleteRange(sourceFile, { pos: list[lastNonDeletedIndex].end, end: startPositionToDeleteNodeInList(sourceFile, list[lastNonDeletedIndex + 1]) }); + this.deleteRange(sourceFile, { + pos: list[lastNonDeletedIndex].end, + end: startPositionToDeleteNodeInList(sourceFile, list[lastNonDeletedIndex + 1]), + }); } }); } @@ -946,14 +1291,31 @@ namespace ts.textChanges { public getChanges(validate?: ValidateNonFormattedText): FileTextChanges[] { this.finishDeleteDeclarations(); this.finishClassesWithNodesInsertedAtStart(); - const changes = changesToText.getTextChangesFromChanges(this.changes, this.newLineCharacter, this.formatContext, validate); + const changes = changesToText.getTextChangesFromChanges( + this.changes, + this.newLineCharacter, + this.formatContext, + validate, + ); for (const { oldFile, fileName, statements } of this.newFiles) { - changes.push(changesToText.newFileChanges(oldFile, fileName, statements, this.newLineCharacter, this.formatContext)); + changes.push( + changesToText.newFileChanges( + oldFile, + fileName, + statements, + this.newLineCharacter, + this.formatContext, + ), + ); } return changes; } - public createNewFile(oldFile: SourceFile | undefined, fileName: string, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[]): void { + public createNewFile( + oldFile: SourceFile | undefined, + fileName: string, + statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], + ): void { this.newFiles.push({ oldFile, fileName, statements }); } } @@ -962,9 +1324,9 @@ namespace ts.textChanges { if (parent.kind !== SyntaxKind.ArrowFunction) { return parent; } - const jsDocNode = parent.parent.kind === SyntaxKind.PropertyDeclaration ? - parent.parent as HasJSDoc : - parent.parent.parent as HasJSDoc; + const jsDocNode = parent.parent.kind === SyntaxKind.PropertyDeclaration + ? parent.parent as HasJSDoc + : parent.parent.parent as HasJSDoc; jsDocNode.jsDoc = parent.jsDoc; jsDocNode.jsDocCache = parent.jsDocCache; return jsDocNode; @@ -978,47 +1340,96 @@ namespace ts.textChanges { case SyntaxKind.JSDocParameterTag: { const oldParam = oldTag as JSDocParameterTag; const newParam = newTag as JSDocParameterTag; - return isIdentifier(oldParam.name) && isIdentifier(newParam.name) && oldParam.name.escapedText === newParam.name.escapedText - ? factory.createJSDocParameterTag(/*tagName*/ undefined, newParam.name, /*isBracketed*/ false, newParam.typeExpression, newParam.isNameFirst, oldParam.comment) + return isIdentifier(oldParam.name) && isIdentifier(newParam.name) + && oldParam.name.escapedText === newParam.name.escapedText + ? factory.createJSDocParameterTag( + /*tagName*/ undefined, + newParam.name, + /*isBracketed*/ false, + newParam.typeExpression, + newParam.isNameFirst, + oldParam.comment, + ) : undefined; } case SyntaxKind.JSDocReturnTag: - return factory.createJSDocReturnTag(/*tagName*/ undefined, (newTag as JSDocReturnTag).typeExpression, oldTag.comment); + return factory.createJSDocReturnTag( + /*tagName*/ undefined, + (newTag as JSDocReturnTag).typeExpression, + oldTag.comment, + ); case SyntaxKind.JSDocTypeTag: - return factory.createJSDocTypeTag(/*tagName*/ undefined, (newTag as JSDocTypeTag).typeExpression, oldTag.comment); + return factory.createJSDocTypeTag( + /*tagName*/ undefined, + (newTag as JSDocTypeTag).typeExpression, + oldTag.comment, + ); } } // find first non-whitespace position in the leading trivia of the node function startPositionToDeleteNodeInList(sourceFile: SourceFile, node: Node): number { - return skipTrivia(sourceFile.text, getAdjustedStartPosition(sourceFile, node, { leadingTriviaOption: LeadingTriviaOption.IncludeAll }), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); + return skipTrivia( + sourceFile.text, + getAdjustedStartPosition(sourceFile, node, { leadingTriviaOption: LeadingTriviaOption.IncludeAll }), + /*stopAfterLineBreak*/ false, + /*stopAtComments*/ true, + ); } - function getClassOrObjectBraceEnds(cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, sourceFile: SourceFile): [number | undefined, number | undefined] { + function getClassOrObjectBraceEnds( + cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, + sourceFile: SourceFile, + ): [number | undefined, number | undefined] { const open = findChildOfKind(cls, SyntaxKind.OpenBraceToken, sourceFile); const close = findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile); return [open?.end, close?.end]; } - function getMembersOrProperties(node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode): NodeArray { + function getMembersOrProperties( + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, + ): NodeArray { return isObjectLiteralExpression(node) ? node.properties : node.members; } export type ValidateNonFormattedText = (node: Node, text: string) => void; - export function getNewFileText(statements: readonly Statement[], scriptKind: ScriptKind, newLineCharacter: string, formatContext: formatting.FormatContext): string { - return changesToText.newFileChangesWorker(/*oldFile*/ undefined, scriptKind, statements, newLineCharacter, formatContext); + export function getNewFileText( + statements: readonly Statement[], + scriptKind: ScriptKind, + newLineCharacter: string, + formatContext: formatting.FormatContext, + ): string { + return changesToText.newFileChangesWorker( + /*oldFile*/ undefined, + scriptKind, + statements, + newLineCharacter, + formatContext, + ); } namespace changesToText { - export function getTextChangesFromChanges(changes: readonly Change[], newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): FileTextChanges[] { + export function getTextChangesFromChanges( + changes: readonly Change[], + newLineCharacter: string, + formatContext: formatting.FormatContext, + validate: ValidateNonFormattedText | undefined, + ): FileTextChanges[] { return mapDefined(group(changes, c => c.sourceFile.path), changesInFile => { const sourceFile = changesInFile[0].sourceFile; // order changes by start position // If the start position is the same, put the shorter range first, since an empty range (x, x) may precede (x, y) but not vice-versa. - const normalized = stableSort(changesInFile, (a, b) => (a.range.pos - b.range.pos) || (a.range.end - b.range.end)); + const normalized = stableSort( + changesInFile, + (a, b) => (a.range.pos - b.range.pos) || (a.range.end - b.range.end), + ); // verify that change intervals do not overlap, except possibly at end points. for (let i = 0; i < normalized.length - 1; i++) { - Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos, "Changes overlap", () => `${JSON.stringify(normalized[i].range)} and ${JSON.stringify(normalized[i + 1].range)}`); + Debug.assert( + normalized[i].range.end <= normalized[i + 1].range.pos, + "Changes overlap", + () => `${JSON.stringify(normalized[i].range)} and ${JSON.stringify(normalized[i + 1].range)}`, + ); } const textChanges = mapDefined(normalized, c => { @@ -1037,20 +1448,52 @@ namespace ts.textChanges { }); } - export function newFileChanges(oldFile: SourceFile | undefined, fileName: string, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], newLineCharacter: string, formatContext: formatting.FormatContext): FileTextChanges { - const text = newFileChangesWorker(oldFile, getScriptKindFromFileName(fileName), statements, newLineCharacter, formatContext); + export function newFileChanges( + oldFile: SourceFile | undefined, + fileName: string, + statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], + newLineCharacter: string, + formatContext: formatting.FormatContext, + ): FileTextChanges { + const text = newFileChangesWorker( + oldFile, + getScriptKindFromFileName(fileName), + statements, + newLineCharacter, + formatContext, + ); return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)], isNewFile: true }; } - export function newFileChangesWorker(oldFile: SourceFile | undefined, scriptKind: ScriptKind, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], newLineCharacter: string, formatContext: formatting.FormatContext): string { + export function newFileChangesWorker( + oldFile: SourceFile | undefined, + scriptKind: ScriptKind, + statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], + newLineCharacter: string, + formatContext: formatting.FormatContext, + ): string { // TODO: this emits the file, parses it back, then formats it that -- may be a less roundabout way to do this - const nonFormattedText = statements.map(s => s === SyntaxKind.NewLineTrivia ? "" : getNonformattedText(s, oldFile, newLineCharacter).text).join(newLineCharacter); - const sourceFile = createSourceFile("any file name", nonFormattedText, ScriptTarget.ESNext, /*setParentNodes*/ true, scriptKind); + const nonFormattedText = statements.map(s => + s === SyntaxKind.NewLineTrivia ? "" : getNonformattedText(s, oldFile, newLineCharacter).text + ).join(newLineCharacter); + const sourceFile = createSourceFile( + "any file name", + nonFormattedText, + ScriptTarget.ESNext, + /*setParentNodes*/ true, + scriptKind, + ); const changes = formatting.formatDocument(sourceFile, formatContext); return applyChanges(nonFormattedText, changes) + newLineCharacter; } - function computeNewText(change: Change, sourceFile: SourceFile, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string { + function computeNewText( + change: Change, + sourceFile: SourceFile, + newLineCharacter: string, + formatContext: formatting.FormatContext, + validate: ValidateNonFormattedText | undefined, + ): string { if (change.kind === ChangeKind.Remove) { return ""; } @@ -1059,27 +1502,46 @@ namespace ts.textChanges { } const { options = {}, range: { pos } } = change; - const format = (n: Node) => getFormattedTextOfNode(n, sourceFile, pos, options, newLineCharacter, formatContext, validate); + const format = (n: Node) => + getFormattedTextOfNode(n, sourceFile, pos, options, newLineCharacter, formatContext, validate); const text = change.kind === ChangeKind.ReplaceWithMultipleNodes - ? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join(change.options?.joiner || newLineCharacter) + ? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join( + change.options?.joiner || newLineCharacter, + ) : format(change.node); // strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line - const noIndent = (options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text : text.replace(/^\s+/, ""); + const noIndent = + (options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text + : text.replace(/^\s+/, ""); return (options.prefix || "") + noIndent + ((!options.suffix || endsWith(noIndent, options.suffix)) ? "" : options.suffix); } /** Note: this may mutate `nodeIn`. */ - function getFormattedTextOfNode(nodeIn: Node, sourceFile: SourceFile, pos: number, { indentation, prefix, delta }: InsertNodeOptions, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string { + function getFormattedTextOfNode( + nodeIn: Node, + sourceFile: SourceFile, + pos: number, + { indentation, prefix, delta }: InsertNodeOptions, + newLineCharacter: string, + formatContext: formatting.FormatContext, + validate: ValidateNonFormattedText | undefined, + ): string { const { node, text } = getNonformattedText(nodeIn, sourceFile, newLineCharacter); if (validate) validate(node, text); const formatOptions = getFormatCodeSettingsForWriting(formatContext, sourceFile); const initialIndentation = indentation !== undefined ? indentation - : formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, prefix === newLineCharacter || getLineStartPositionForPosition(pos, sourceFile) === pos); + : formatting.SmartIndenter.getIndentation( + pos, + sourceFile, + formatOptions, + prefix === newLineCharacter || getLineStartPositionForPosition(pos, sourceFile) === pos, + ); if (delta === undefined) { - delta = formatting.SmartIndenter.shouldIndentChildNode(formatOptions, nodeIn) ? (formatOptions.indentSize || 0) : 0; + delta = formatting.SmartIndenter.shouldIndentChildNode(formatOptions, nodeIn) + ? (formatOptions.indentSize || 0) : 0; } const file: SourceFileLike = { @@ -1088,12 +1550,23 @@ namespace ts.textChanges { return getLineAndCharacterOfPosition(this, pos); }, }; - const changes = formatting.formatNodeGivenIndentation(node, file, sourceFile.languageVariant, initialIndentation, delta, { ...formatContext, options: formatOptions }); + const changes = formatting.formatNodeGivenIndentation( + node, + file, + sourceFile.languageVariant, + initialIndentation, + delta, + { ...formatContext, options: formatOptions }, + ); return applyChanges(text, changes); } /** Note: output node may be mutated input node. */ - export function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLineCharacter: string): { text: string; node: Node; } { + export function getNonformattedText( + node: Node, + sourceFile: SourceFile | undefined, + newLineCharacter: string, + ): { text: string; node: Node; } { const writer = createWriter(newLineCharacter); const newLine = getNewLineKind(newLineCharacter); createPrinter({ @@ -1129,14 +1602,26 @@ namespace ts.textChanges { }; export function assignPositionsToNode(node: Node): Node { - const visited = visitEachChild(node, assignPositionsToNode, textChangesTransformationContext, assignPositionsToNodeArray, assignPositionsToNode); + const visited = visitEachChild( + node, + assignPositionsToNode, + textChangesTransformationContext, + assignPositionsToNodeArray, + assignPositionsToNode, + ); // create proxy node for non synthesized nodes const newNode = nodeIsSynthesized(visited) ? visited : Object.create(visited) as Node; setTextRangePosEnd(newNode, getPos(node), getEnd(node)); return newNode; } - function assignPositionsToNodeArray(nodes: NodeArray, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number) { + function assignPositionsToNodeArray( + nodes: NodeArray, + visitor: Visitor, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ) { const visited = visitNodes(nodes, visitor, test, start, count); if (!visited) { return visited; @@ -1369,7 +1854,9 @@ namespace ts.textChanges { } if (sourceFile.statements.length) { - if (firstNodeLine === undefined) firstNodeLine = sourceFile.getLineAndCharacterOfPosition(sourceFile.statements[0].getStart()).line; + if (firstNodeLine === undefined) { + firstNodeLine = sourceFile.getLineAndCharacterOfPosition(sourceFile.statements[0].getStart()).line; + } const commentEndLine = sourceFile.getLineAndCharacterOfPosition(range.end).line; if (firstNodeLine < commentEndLine + 2) break; } @@ -1388,7 +1875,10 @@ namespace ts.textChanges { if (isLineBreak(charCode)) { position++; - if (position < text.length && charCode === CharacterCodes.carriageReturn && text.charCodeAt(position) === CharacterCodes.lineFeed) { + if ( + position < text.length && charCode === CharacterCodes.carriageReturn + && text.charCodeAt(position) === CharacterCodes.lineFeed + ) { position++; } } @@ -1397,23 +1887,30 @@ namespace ts.textChanges { } export function isValidLocationToAddComment(sourceFile: SourceFile, position: number) { - return !isInComment(sourceFile, position) && !isInString(sourceFile, position) && !isInTemplateString(sourceFile, position) && !isInJSXText(sourceFile, position); + return !isInComment(sourceFile, position) && !isInString(sourceFile, position) + && !isInTemplateString(sourceFile, position) && !isInJSXText(sourceFile, position); } function needSemicolonBetween(a: Node, b: Node): boolean { - return (isPropertySignature(a) || isPropertyDeclaration(a)) && isClassOrTypeElement(b) && b.name!.kind === SyntaxKind.ComputedPropertyName + return (isPropertySignature(a) || isPropertyDeclaration(a)) && isClassOrTypeElement(b) + && b.name!.kind === SyntaxKind.ComputedPropertyName || isStatementButNotDeclaration(a) && isStatementButNotDeclaration(b); // TODO: only if b would start with a `(` or `[` } namespace deleteDeclaration { - export function deleteDeclaration(changes: ChangeTracker, deletedNodesInLists: Set, sourceFile: SourceFile, node: Node): void { + export function deleteDeclaration( + changes: ChangeTracker, + deletedNodesInLists: Set, + sourceFile: SourceFile, + node: Node, + ): void { switch (node.kind) { case SyntaxKind.Parameter: { const oldFunction = node.parent; if ( - isArrowFunction(oldFunction) && - oldFunction.parameters.length === 1 && - !findChildOfKind(oldFunction, SyntaxKind.OpenParenToken, sourceFile) + isArrowFunction(oldFunction) + && oldFunction.parameters.length === 1 + && !findChildOfKind(oldFunction, SyntaxKind.OpenParenToken, sourceFile) ) { // Lambdas with exactly one parameter are special because, after removal, there // must be an empty parameter list (i.e. `()`) and this won't necessarily be the @@ -1428,16 +1925,19 @@ namespace ts.textChanges { case SyntaxKind.ImportDeclaration: case SyntaxKind.ImportEqualsDeclaration: - const isFirstImport = sourceFile.imports.length && node === first(sourceFile.imports).parent || node === find(sourceFile.statements, isAnyImportSyntax); + const isFirstImport = sourceFile.imports.length && node === first(sourceFile.imports).parent + || node === find(sourceFile.statements, isAnyImportSyntax); // For first import, leave header comment in place, otherwise only delete JSDoc comments deleteNode(changes, sourceFile, node, { - leadingTriviaOption: isFirstImport ? LeadingTriviaOption.Exclude : hasJSDocNodes(node) ? LeadingTriviaOption.JSDoc : LeadingTriviaOption.StartLine, + leadingTriviaOption: isFirstImport ? LeadingTriviaOption.Exclude + : hasJSDocNodes(node) ? LeadingTriviaOption.JSDoc : LeadingTriviaOption.StartLine, }); break; case SyntaxKind.BindingElement: const pattern = (node as BindingElement).parent; - const preserveComma = pattern.kind === SyntaxKind.ArrayBindingPattern && node !== last(pattern.elements); + const preserveComma = pattern.kind === SyntaxKind.ArrayBindingPattern + && node !== last(pattern.elements); if (preserveComma) { deleteNode(changes, sourceFile, node); } @@ -1478,7 +1978,10 @@ namespace ts.textChanges { case SyntaxKind.ClassDeclaration: case SyntaxKind.FunctionDeclaration: - deleteNode(changes, sourceFile, node, { leadingTriviaOption: hasJSDocNodes(node) ? LeadingTriviaOption.JSDoc : LeadingTriviaOption.StartLine }); + deleteNode(changes, sourceFile, node, { + leadingTriviaOption: hasJSDocNodes(node) ? LeadingTriviaOption.JSDoc + : LeadingTriviaOption.StartLine, + }); break; default: @@ -1509,7 +2012,12 @@ namespace ts.textChanges { const nextToken = getTokenAtPosition(sourceFile, importClause.name!.end); if (nextToken && nextToken.kind === SyntaxKind.CommaToken) { // shift first non-whitespace position after comma to the start position of the node - const end = skipTrivia(sourceFile.text, nextToken.end, /*stopAfterLineBreaks*/ false, /*stopAtComments*/ true); + const end = skipTrivia( + sourceFile.text, + nextToken.end, + /*stopAfterLineBreaks*/ false, + /*stopAtComments*/ true, + ); changes.deleteRange(sourceFile, { pos: start, end }); } else { @@ -1535,12 +2043,21 @@ namespace ts.textChanges { } } - function deleteVariableDeclaration(changes: ChangeTracker, deletedNodesInLists: Set, sourceFile: SourceFile, node: VariableDeclaration): void { + function deleteVariableDeclaration( + changes: ChangeTracker, + deletedNodesInLists: Set, + sourceFile: SourceFile, + node: VariableDeclaration, + ): void { const { parent } = node; if (parent.kind === SyntaxKind.CatchClause) { // TODO: There's currently no unused diagnostic for this, could be a suggestion - changes.deleteNodeRange(sourceFile, findChildOfKind(parent, SyntaxKind.OpenParenToken, sourceFile)!, findChildOfKind(parent, SyntaxKind.CloseParenToken, sourceFile)!); + changes.deleteNodeRange( + sourceFile, + findChildOfKind(parent, SyntaxKind.OpenParenToken, sourceFile)!, + findChildOfKind(parent, SyntaxKind.CloseParenToken, sourceFile)!, + ); return; } @@ -1561,7 +2078,10 @@ namespace ts.textChanges { break; case SyntaxKind.VariableStatement: - deleteNode(changes, sourceFile, gp, { leadingTriviaOption: hasJSDocNodes(gp) ? LeadingTriviaOption.JSDoc : LeadingTriviaOption.StartLine }); + deleteNode(changes, sourceFile, gp, { + leadingTriviaOption: hasJSDocNodes(gp) ? LeadingTriviaOption.JSDoc + : LeadingTriviaOption.StartLine, + }); break; default: @@ -1572,13 +2092,23 @@ namespace ts.textChanges { /** Warning: This deletes comments too. See `copyComments` in `convertFunctionToEs6Class`. */ // Exported for tests only! (TODO: improve tests to not need this) - export function deleteNode(changes: ChangeTracker, sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + export function deleteNode( + changes: ChangeTracker, + sourceFile: SourceFile, + node: Node, + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, + ): void { const startPosition = getAdjustedStartPosition(sourceFile, node, options); const endPosition = getAdjustedEndPosition(sourceFile, node, options); changes.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); } - function deleteNodeInList(changes: ChangeTracker, deletedNodesInLists: Set, sourceFile: SourceFile, node: Node): void { + function deleteNodeInList( + changes: ChangeTracker, + deletedNodesInLists: Set, + sourceFile: SourceFile, + node: Node, + ): void { const containingList = Debug.checkDefined(formatting.SmartIndenter.getContainingList(node, sourceFile)); const index = indexOfNode(containingList, node); Debug.assert(index !== -1); @@ -1593,7 +2123,8 @@ namespace ts.textChanges { deletedNodesInLists.add(node); changes.deleteRange(sourceFile, { pos: startPositionToDeleteNodeInList(sourceFile, node), - end: index === containingList.length - 1 ? getAdjustedEndPosition(sourceFile, node, {}) : startPositionToDeleteNodeInList(sourceFile, containingList[index + 1]), + end: index === containingList.length - 1 ? getAdjustedEndPosition(sourceFile, node, {}) + : startPositionToDeleteNodeInList(sourceFile, containingList[index + 1]), }); } } diff --git a/src/services/transform.ts b/src/services/transform.ts index c471a4951ef9f..dcec164310660 100644 --- a/src/services/transform.ts +++ b/src/services/transform.ts @@ -5,11 +5,23 @@ namespace ts { * @param transformers An array of `TransformerFactory` callbacks used to process the transformation. * @param compilerOptions Optional compiler options. */ - export function transform(source: T | T[], transformers: TransformerFactory[], compilerOptions?: CompilerOptions) { + export function transform( + source: T | T[], + transformers: TransformerFactory[], + compilerOptions?: CompilerOptions, + ) { const diagnostics: DiagnosticWithLocation[] = []; compilerOptions = fixupCompilerOptions(compilerOptions!, diagnostics); // TODO: GH#18217 const nodes = isArray(source) ? source : [source]; - const result = transformNodes(/*resolver*/ undefined, /*emitHost*/ undefined, factory, compilerOptions, nodes, transformers, /*allowDtsFiles*/ true); + const result = transformNodes( + /*resolver*/ undefined, + /*emitHost*/ undefined, + factory, + compilerOptions, + nodes, + transformers, + /*allowDtsFiles*/ true, + ); result.diagnostics = concatenate(result.diagnostics, diagnostics); return result; } diff --git a/src/services/transpile.ts b/src/services/transpile.ts index 8a19c82055bbb..5eef65bda8a6c 100644 --- a/src/services/transpile.ts +++ b/src/services/transpile.ts @@ -26,7 +26,8 @@ namespace ts { export function transpileModule(input: string, transpileOptions: TranspileOptions): TranspileOutput { const diagnostics: Diagnostic[] = []; - const options: CompilerOptions = transpileOptions.compilerOptions ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : {}; + const options: CompilerOptions = transpileOptions.compilerOptions + ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : {}; // mix in default options const defaultOptions = getDefaultCompilerOptions(); @@ -72,13 +73,19 @@ namespace ts { }; // if jsx is specified then treat file as .tsx - const inputFileName = transpileOptions.fileName || (transpileOptions.compilerOptions && transpileOptions.compilerOptions.jsx ? "module.tsx" : "module.ts"); + const inputFileName = transpileOptions.fileName + || (transpileOptions.compilerOptions && transpileOptions.compilerOptions.jsx ? "module.tsx" : "module.ts"); const sourceFile = createSourceFile( inputFileName, input, { languageVersion: getEmitScriptTarget(options), - impliedNodeFormat: getImpliedNodeFormatForFile(toPath(inputFileName, "", compilerHost.getCanonicalFileName), /*cache*/ undefined, compilerHost, options), + impliedNodeFormat: getImpliedNodeFormatForFile( + toPath(inputFileName, "", compilerHost.getCanonicalFileName), + /*cache*/ undefined, + compilerHost, + options, + ), setExternalModuleIndicator: getSetExternalModuleIndicator(options), }, ); @@ -101,7 +108,13 @@ namespace ts { addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics()); } // Emit - program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ undefined, transpileOptions.transformers); + program.emit( + /*targetSourceFile*/ undefined, + /*writeFile*/ undefined, + /*cancellationToken*/ undefined, + /*emitOnlyDtsFiles*/ undefined, + transpileOptions.transformers, + ); if (outputText === undefined) return Debug.fail("Output generation failed"); @@ -111,8 +124,19 @@ namespace ts { /* * This is a shortcut function for transpileModule - it accepts transpileOptions as parameters and returns only outputText part of the result. */ - export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string { - const output = transpileModule(input, { compilerOptions, fileName, reportDiagnostics: !!diagnostics, moduleName }); + export function transpile( + input: string, + compilerOptions?: CompilerOptions, + fileName?: string, + diagnostics?: Diagnostic[], + moduleName?: string, + ): string { + const output = transpileModule(input, { + compilerOptions, + fileName, + reportDiagnostics: !!diagnostics, + moduleName, + }); // addRange correctly handles cases when wither 'from' or 'to' argument is missing addRange(diagnostics, output.diagnostics); return output.outputText; @@ -124,8 +148,11 @@ namespace ts { /*@internal*/ export function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions { // Lazily create this value to fix module loading errors. - commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || - filter(optionDeclarations, o => typeof o.type === "object" && !forEachEntry(o.type, v => typeof v !== "number")) as CommandLineOptionOfCustomType[]; + commandLineOptionsStringToEnum = commandLineOptionsStringToEnum + || filter( + optionDeclarations, + o => typeof o.type === "object" && !forEachEntry(o.type, v => typeof v !== "number"), + ) as CommandLineOptionOfCustomType[]; options = cloneCompilerOptions(options); diff --git a/src/services/types.ts b/src/services/types.ts index c88d0e3a02347..02266288fe759 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -23,7 +23,10 @@ namespace ts { /* @internal */ getLastToken(sourceFile?: SourceFileLike): Node | undefined; // eslint-disable-line @typescript-eslint/unified-signatures // See ts.forEachChild for documentation. - forEachChild(cbNode: (node: Node) => T | undefined, cbNodeArray?: (nodes: NodeArray) => T | undefined): T | undefined; + forEachChild( + cbNode: (node: Node) => T | undefined, + cbNodeArray?: (nodes: NodeArray) => T | undefined, + ): T | undefined; } export interface Identifier { @@ -42,7 +45,10 @@ namespace ts { getDeclarations(): Declaration[] | undefined; getDocumentationComment(typeChecker: TypeChecker | undefined): SymbolDisplayPart[]; /* @internal */ - getContextualDocumentationComment(context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[]; + getContextualDocumentationComment( + context: Node | undefined, + checker: TypeChecker | undefined, + ): SymbolDisplayPart[]; getJsDocTags(checker?: TypeChecker): JSDocTagInfo[]; /* @internal */ getContextualJsDocTags(context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[]; @@ -261,7 +267,13 @@ namespace ts { * LS host can optionally implement these methods to support completions for module specifiers. * Without these methods, only completions for ambient modules will be provided. */ - readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory?( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; realpath?(path: string): string; /* @@ -283,9 +295,26 @@ namespace ts { * * If this is implemented, `getResolvedModuleWithFailedLookupLocationsFromCache` should be too. */ - resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[]; - getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined; - resolveTypeReferenceDirectives?(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; + resolveModuleNames?( + moduleNames: string[], + containingFile: string, + reusedNames: string[] | undefined, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingSourceFile?: SourceFile, + ): (ResolvedModule | undefined)[]; + getResolvedModuleWithFailedLookupLocationsFromCache?( + modulename: string, + containingFile: string, + resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext, + ): ResolvedModuleWithFailedLookupLocations | undefined; + resolveTypeReferenceDirectives?( + typeDirectiveNames: string[] | FileReference[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingFileMode?: SourceFile["impliedNodeFormat"] | undefined, + ): (ResolvedTypeReferenceDirective | undefined)[]; /* @internal */ hasInvalidatedResolutions?: HasInvalidatedResolutions; /* @internal */ hasChangedAutomaticTypeDirectiveNames?: HasChangedAutomaticTypeDirectiveNames; /* @internal */ getGlobalTypingsCacheLocation?(): string | undefined; @@ -308,9 +337,15 @@ namespace ts { installPackage?(options: InstallPackageOptions): Promise; writeFile?(fileName: string, content: string): void; - /* @internal */ getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined; + /* @internal */ getDocumentPositionMapper?( + generatedFileName: string, + sourceFileName?: string, + ): DocumentPositionMapper | undefined; /* @internal */ getSourceFileLike?(fileName: string): SourceFileLike | undefined; - /* @internal */ getPackageJsonsVisibleToFile?(fileName: string, rootDir?: string): readonly ProjectPackageJsonInfo[]; + /* @internal */ getPackageJsonsVisibleToFile?( + fileName: string, + rootDir?: string, + ): readonly ProjectPackageJsonInfo[]; /* @internal */ getNearestAncestorDirectoryWithPackageJson?(fileName: string): string | undefined; /* @internal */ getPackageJsonsForAutoImport?(rootDir?: string): readonly ProjectPackageJsonInfo[]; /* @internal */ getCachedExportInfoMap?(): ExportInfoMap; @@ -320,7 +355,11 @@ namespace ts { /* @internal */ getPackageJsonAutoImportProvider?(): Program | undefined; /* @internal */ sendPerformanceEvent?(kind: PerformanceEvent["kind"], durationMs: number): void; getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; - /* @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; + /* @internal */ onReleaseParsedCommandLine?( + configFileName: string, + oldResolvedRef: ResolvedProjectReference | undefined, + optionOptions: CompilerOptions, + ): void; /* @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache; } @@ -397,11 +436,19 @@ namespace ts { /** @deprecated Use getEncodedSyntacticClassifications instead. */ getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; - getSyntacticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; + getSyntacticClassifications( + fileName: string, + span: TextSpan, + format: SemanticClassificationFormat, + ): ClassifiedSpan[] | ClassifiedSpan2020[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; - getSemanticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; + getSemanticClassifications( + fileName: string, + span: TextSpan, + format: SemanticClassificationFormat, + ): ClassifiedSpan[] | ClassifiedSpan2020[]; /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; @@ -415,7 +462,11 @@ namespace ts { * @param format Which format to use, defaults to "original" * @returns a number array encoded as triples of [start, length, ClassificationType, ...]. */ - getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications; + getEncodedSemanticClassifications( + fileName: string, + span: TextSpan, + format?: SemanticClassificationFormat, + ): Classifications; /** * Gets completion entries at a particular position in a file. @@ -426,7 +477,12 @@ namespace ts { * of code actions can be returned with the completions. * @param formattingSettings settings needed for calling formatting functions. */ - getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined, formattingSettings?: FormatCodeSettings): WithMetadata | undefined; + getCompletionsAtPosition( + fileName: string, + position: number, + options: GetCompletionsAtPositionOptions | undefined, + formattingSettings?: FormatCodeSettings, + ): WithMetadata | undefined; /** * Gets the extended details for a completion entry retrieved from `getCompletionsAtPosition`. @@ -449,7 +505,12 @@ namespace ts { data: CompletionEntryData | undefined, ): CompletionEntryDetails | undefined; - getCompletionEntrySymbol(fileName: string, position: number, name: string, source: string | undefined): Symbol | undefined; + getCompletionEntrySymbol( + fileName: string, + position: number, + name: string, + source: string | undefined, + ): Symbol | undefined; /** * Gets semantic information about the identifier at a particular position in a @@ -464,22 +525,42 @@ namespace ts { getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan | undefined; - getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined; + getSignatureHelpItems( + fileName: string, + position: number, + options: SignatureHelpItemsOptions | undefined, + ): SignatureHelpItems | undefined; getRenameInfo(fileName: string, position: number, preferences: UserPreferences): RenameInfo; /** @deprecated Use the signature with `UserPreferences` instead. */ getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo; - findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): readonly RenameLocation[] | undefined; + findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + providePrefixAndSuffixTextForRename?: boolean, + ): readonly RenameLocation[] | undefined; getSmartSelectionRange(fileName: string, position: number): SelectionRange; /*@internal*/ // eslint-disable-next-line @typescript-eslint/unified-signatures - getDefinitionAtPosition(fileName: string, position: number, searchOtherFilesOnly: false, stopAtAlias: boolean): readonly DefinitionInfo[] | undefined; + getDefinitionAtPosition( + fileName: string, + position: number, + searchOtherFilesOnly: false, + stopAtAlias: boolean, + ): readonly DefinitionInfo[] | undefined; /*@internal*/ // eslint-disable-next-line @typescript-eslint/unified-signatures - getDefinitionAtPosition(fileName: string, position: number, searchOtherFilesOnly: boolean, stopAtAlias: false): readonly DefinitionInfo[] | undefined; + getDefinitionAtPosition( + fileName: string, + position: number, + searchOtherFilesOnly: boolean, + stopAtAlias: false, + ): readonly DefinitionInfo[] | undefined; getDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined; getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined; getTypeDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined; @@ -487,13 +568,22 @@ namespace ts { getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined; findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined; - getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined; + getDocumentHighlights( + fileName: string, + position: number, + filesToSearch: string[], + ): DocumentHighlights[] | undefined; getFileReferences(fileName: string): ReferenceEntry[]; /** @deprecated */ getOccurrencesAtPosition(fileName: string, position: number): readonly ReferenceEntry[] | undefined; - getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[]; + getNavigateToItems( + searchValue: string, + maxResultCount?: number, + fileName?: string, + excludeDtsFiles?: boolean, + ): NavigateToItem[]; getNavigationBarItems(fileName: string): NavigationBarItem[]; getNavigationTree(fileName: string): NavigationTree; @@ -508,11 +598,25 @@ namespace ts { getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[]; getIndentationAtPosition(fileName: string, position: number, options: EditorOptions | EditorSettings): number; - getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[]; + getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[]; getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[]; - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[]; + getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[]; - getDocCommentTemplateAtPosition(fileName: string, position: number, options?: DocCommentTemplateOptions): TextInsertion | undefined; + getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: DocCommentTemplateOptions, + ): TextInsertion | undefined; isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; /** @@ -529,23 +633,69 @@ namespace ts { /** @internal */ clearSourceMapperCache(): void; - getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[]; - getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions; - - applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise; - applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise; - applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise; + getCodeFixesAtPosition( + fileName: string, + start: number, + end: number, + errorCodes: readonly number[], + formatOptions: FormatCodeSettings, + preferences: UserPreferences, + ): readonly CodeFixAction[]; + getCombinedCodeFix( + scope: CombinedCodeFixScope, + fixId: {}, + formatOptions: FormatCodeSettings, + preferences: UserPreferences, + ): CombinedCodeActions; + + applyCodeActionCommand( + action: CodeActionCommand, + formatSettings?: FormatCodeSettings, + ): Promise; + applyCodeActionCommand( + action: CodeActionCommand[], + formatSettings?: FormatCodeSettings, + ): Promise; + applyCodeActionCommand( + action: CodeActionCommand | CodeActionCommand[], + formatSettings?: FormatCodeSettings, + ): Promise; /** @deprecated `fileName` will be ignored */ applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise; /** @deprecated `fileName` will be ignored */ applyCodeActionCommand(fileName: string, action: CodeActionCommand[]): Promise; /** @deprecated `fileName` will be ignored */ - applyCodeActionCommand(fileName: string, action: CodeActionCommand | CodeActionCommand[]): Promise; + applyCodeActionCommand( + fileName: string, + action: CodeActionCommand | CodeActionCommand[], + ): Promise; - getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string): ApplicableRefactorInfo[]; - getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined; - organizeImports(args: OrganizeImportsArgs, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[]; - getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[]; + getApplicableRefactors( + fileName: string, + positionOrRange: number | TextRange, + preferences: UserPreferences | undefined, + triggerReason?: RefactorTriggerReason, + kind?: string, + ): ApplicableRefactorInfo[]; + getEditsForRefactor( + fileName: string, + formatOptions: FormatCodeSettings, + positionOrRange: number | TextRange, + refactorName: string, + actionName: string, + preferences: UserPreferences | undefined, + ): RefactorEditInfo | undefined; + organizeImports( + args: OrganizeImportsArgs, + formatOptions: FormatCodeSettings, + preferences: UserPreferences | undefined, + ): readonly FileTextChanges[]; + getEditsForFileRename( + oldFilePath: string, + newFilePath: string, + formatOptions: FormatCodeSettings, + preferences: UserPreferences | undefined, + ): readonly FileTextChanges[]; getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean): EmitOutput; @@ -558,7 +708,10 @@ namespace ts { /// Returns true if a suitable symbol was found in the project. /// May set isDefinition properties in `referencedSymbols` to false. /// May add elements to `knownSymbolSpans`. - /* @internal */ updateIsDefinitionOfReferencedSymbols(referencedSymbols: readonly ReferencedSymbol[], knownSymbolSpans: Set): boolean; + /* @internal */ updateIsDefinitionOfReferencedSymbols( + referencedSymbols: readonly ReferencedSymbol[], + knownSymbolSpans: Set, + ): boolean; toggleLineComment(fileName: string, textRange: TextRange): TextChange[]; toggleMultilineComment(fileName: string, textRange: TextRange): TextChange[]; @@ -1413,8 +1566,16 @@ namespace ts { * subsume the classification. * @deprecated Use getLexicalClassifications instead. */ - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; - getEncodedLexicalClassifications(text: string, endOfLineState: EndOfLineState, syntacticClassifierAbsent: boolean): Classifications; + getClassificationsForLine( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent: boolean, + ): ClassificationResult; + getEncodedLexicalClassifications( + text: string, + endOfLineState: EndOfLineState, + syntacticClassifierAbsent: boolean, + ): Classifications; } export const enum ScriptElementKind { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index aaace852f0358..0a975e72a8aad 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -2,7 +2,9 @@ // Don't expose that we use this // Based on lib.es6.d.ts interface PromiseConstructor { - new (executor: (resolve: (value?: T | PromiseLike) => void, reject: (reason?: any) => void) => void): Promise; + new ( + executor: (resolve: (value?: T | PromiseLike) => void, reject: (reason?: any) => void) => void, + ): Promise; reject(reason: any): Promise; all(values: (T | PromiseLike)[]): Promise; } @@ -54,7 +56,8 @@ namespace ts { case SyntaxKind.JSDocTypedefTag: // If it has no name node, it shares the name with the value declaration below it. - return (node as JSDocTypedefTag).name === undefined ? SemanticMeaning.Value | SemanticMeaning.Type : SemanticMeaning.Type; + return (node as JSDocTypedefTag).name === undefined ? SemanticMeaning.Value | SemanticMeaning.Type + : SemanticMeaning.Type; case SyntaxKind.EnumMember: case SyntaxKind.ClassDeclaration: @@ -110,7 +113,9 @@ namespace ts { else if (isDeclarationName(node)) { return getMeaningFromDeclaration(parent); } - else if (isEntityName(node) && findAncestor(node, or(isJSDocNameReference, isJSDocLinkLike, isJSDocMemberName))) { + else if ( + isEntityName(node) && findAncestor(node, or(isJSDocNameReference, isJSDocLinkLike, isJSDocMemberName)) + ) { return SemanticMeaning.All; } else if (isTypeReference(node)) { @@ -136,8 +141,10 @@ namespace ts { // import a = |b|; // Namespace // import a = |b.c|; // Value, type, namespace // import a = |b.c|.d; // Namespace - const name = node.kind === SyntaxKind.QualifiedName ? node : isQualifiedName(node.parent) && node.parent.right === node ? node.parent : undefined; - return name && name.parent.kind === SyntaxKind.ImportEqualsDeclaration ? SemanticMeaning.All : SemanticMeaning.Namespace; + const name = node.kind === SyntaxKind.QualifiedName ? node + : isQualifiedName(node.parent) && node.parent.right === node ? node.parent : undefined; + return name && name.parent.kind === SyntaxKind.ImportEqualsDeclaration ? SemanticMeaning.All + : SemanticMeaning.Namespace; } export function isInRightSideOfInternalImportEqualsDeclaration(node: Node) { @@ -176,10 +183,15 @@ namespace ts { isLastClause = (root as PropertyAccessExpression).name === node; } - if (!isLastClause && root.parent.kind === SyntaxKind.ExpressionWithTypeArguments && root.parent.parent.kind === SyntaxKind.HeritageClause) { + if ( + !isLastClause && root.parent.kind === SyntaxKind.ExpressionWithTypeArguments + && root.parent.parent.kind === SyntaxKind.HeritageClause + ) { const decl = root.parent.parent.parent; - return (decl.kind === SyntaxKind.ClassDeclaration && (root.parent.parent as HeritageClause).token === SyntaxKind.ImplementsKeyword) || - (decl.kind === SyntaxKind.InterfaceDeclaration && (root.parent.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword); + return (decl.kind === SyntaxKind.ClassDeclaration + && (root.parent.parent as HeritageClause).token === SyntaxKind.ImplementsKeyword) + || (decl.kind === SyntaxKind.InterfaceDeclaration + && (root.parent.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword); } return false; @@ -209,28 +221,88 @@ namespace ts { return false; } - export function isCallExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isCallExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions); + export function isCallExpressionTarget( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, + ): boolean { + return isCalleeWorker( + node, + isCallExpression, + selectExpressionOfCallOrNewExpressionOrDecorator, + includeElementAccess, + skipPastOuterExpressions, + ); } - export function isNewExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions); + export function isNewExpressionTarget( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, + ): boolean { + return isCalleeWorker( + node, + isNewExpression, + selectExpressionOfCallOrNewExpressionOrDecorator, + includeElementAccess, + skipPastOuterExpressions, + ); } - export function isCallOrNewExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isCallOrNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions); + export function isCallOrNewExpressionTarget( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, + ): boolean { + return isCalleeWorker( + node, + isCallOrNewExpression, + selectExpressionOfCallOrNewExpressionOrDecorator, + includeElementAccess, + skipPastOuterExpressions, + ); } - export function isTaggedTemplateTag(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isTaggedTemplateExpression, selectTagOfTaggedTemplateExpression, includeElementAccess, skipPastOuterExpressions); + export function isTaggedTemplateTag( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, + ): boolean { + return isCalleeWorker( + node, + isTaggedTemplateExpression, + selectTagOfTaggedTemplateExpression, + includeElementAccess, + skipPastOuterExpressions, + ); } - export function isDecoratorTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isDecorator, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions); + export function isDecoratorTarget( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, + ): boolean { + return isCalleeWorker( + node, + isDecorator, + selectExpressionOfCallOrNewExpressionOrDecorator, + includeElementAccess, + skipPastOuterExpressions, + ); } - export function isJsxOpeningLikeElementTagName(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isJsxOpeningLikeElement, selectTagNameOfJsxOpeningLikeElement, includeElementAccess, skipPastOuterExpressions); + export function isJsxOpeningLikeElementTagName( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, + ): boolean { + return isCalleeWorker( + node, + isJsxOpeningLikeElement, + selectTagNameOfJsxOpeningLikeElement, + includeElementAccess, + skipPastOuterExpressions, + ); } function selectExpressionOfCallOrNewExpressionOrDecorator(node: CallExpression | NewExpression | Decorator) { @@ -245,7 +317,15 @@ namespace ts { return node.tagName; } - function isCalleeWorker(node: Node, pred: (node: Node) => node is T, calleeSelector: (node: T) => Expression, includeElementAccess: boolean, skipPastOuterExpressions: boolean) { + function isCalleeWorker< + T extends CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement, + >( + node: Node, + pred: (node: Node) => node is T, + calleeSelector: (node: T) => Expression, + includeElementAccess: boolean, + skipPastOuterExpressions: boolean, + ) { let target = includeElementAccess ? climbPastPropertyOrElementAccess(node) : climbPastPropertyAccess(node); if (skipPastOuterExpressions) { target = skipOuterExpressions(target); @@ -263,7 +343,10 @@ namespace ts { export function getTargetLabel(referenceNode: Node, labelName: string): Identifier | undefined { while (referenceNode) { - if (referenceNode.kind === SyntaxKind.LabeledStatement && (referenceNode as LabeledStatement).label.escapedText === labelName) { + if ( + referenceNode.kind === SyntaxKind.LabeledStatement + && (referenceNode as LabeledStatement).label.escapedText === labelName + ) { return (referenceNode as LabeledStatement).label; } referenceNode = referenceNode.parent; @@ -315,7 +398,9 @@ namespace ts { return isIdentifier(node) && tryCast(node.parent, isFunctionLike)?.name === node; } - export function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: StringLiteral | NumericLiteral | NoSubstitutionTemplateLiteral): boolean { + export function isLiteralNameOfPropertyDeclarationOrIndexAccess( + node: StringLiteral | NumericLiteral | NoSubstitutionTemplateLiteral, + ): boolean { switch (node.parent.kind) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -339,8 +424,8 @@ namespace ts { } export function isExpressionOfExternalModuleImportEqualsDeclaration(node: Node) { - return isExternalModuleImportEqualsDeclaration(node.parent.parent) && - getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node; + return isExternalModuleImportEqualsDeclaration(node.parent.parent) + && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node; } export function getContainerNode(node: Node): Declaration | undefined { @@ -376,7 +461,8 @@ namespace ts { export function getNodeKind(node: Node): ScriptElementKind { switch (node.kind) { case SyntaxKind.SourceFile: - return isExternalModule(node as SourceFile) ? ScriptElementKind.moduleElement : ScriptElementKind.scriptElement; + return isExternalModule(node as SourceFile) ? ScriptElementKind.moduleElement + : ScriptElementKind.scriptElement; case SyntaxKind.ModuleDeclaration: return ScriptElementKind.moduleElement; case SyntaxKind.ClassDeclaration: @@ -407,7 +493,8 @@ namespace ts { return ScriptElementKind.memberFunctionElement; case SyntaxKind.PropertyAssignment: const { initializer } = node as PropertyAssignment; - return isFunctionLike(initializer) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement; + return isFunctionLike(initializer) ? ScriptElementKind.memberFunctionElement + : ScriptElementKind.memberVariableElement; case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.ShorthandPropertyAssignment: @@ -427,7 +514,8 @@ namespace ts { case SyntaxKind.EnumMember: return ScriptElementKind.enumMemberElement; case SyntaxKind.Parameter: - return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; + return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) + ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: @@ -448,12 +536,14 @@ namespace ts { const rightKind = getNodeKind(right); return rightKind === ScriptElementKind.unknown ? ScriptElementKind.constElement : rightKind; case AssignmentDeclarationKind.PrototypeProperty: - return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement; + return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement + : ScriptElementKind.memberVariableElement; case AssignmentDeclarationKind.ThisProperty: return ScriptElementKind.memberVariableElement; // property case AssignmentDeclarationKind.Property: // static method / property - return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement; + return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement + : ScriptElementKind.memberVariableElement; case AssignmentDeclarationKind.Prototype: return ScriptElementKind.localClassElement; default: { @@ -620,8 +710,8 @@ namespace ts { return isCompletedNode((n as IfStatement).thenStatement, sourceFile); case SyntaxKind.ExpressionStatement: - return isCompletedNode((n as ExpressionStatement).expression, sourceFile) || - hasChildOfKind(n, SyntaxKind.SemicolonToken, sourceFile); + return isCompletedNode((n as ExpressionStatement).expression, sourceFile) + || hasChildOfKind(n, SyntaxKind.SemicolonToken, sourceFile); case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.ArrayBindingPattern: @@ -661,7 +751,8 @@ namespace ts { case SyntaxKind.VoidExpression: case SyntaxKind.YieldExpression: case SyntaxKind.SpreadElement: - const unaryWordExpression = n as (TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadElement); + const unaryWordExpression = + n as (TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadElement); return isCompletedNode(unaryWordExpression.expression, sourceFile); case SyntaxKind.TaggedTemplateExpression: @@ -730,7 +821,11 @@ namespace ts { return !!findChildOfKind(n, kind, sourceFile); } - export function findChildOfKind(n: Node, kind: T["kind"], sourceFile: SourceFileLike): T | undefined { + export function findChildOfKind( + n: Node, + kind: T["kind"], + sourceFile: SourceFileLike, + ): T | undefined { return find(n.getChildren(sourceFile), (c): c is T => c.kind === kind); } @@ -739,7 +834,10 @@ namespace ts { // be parented by the container of the SyntaxList, not the SyntaxList itself. // In order to find the list item index, we first need to locate SyntaxList itself and then search // for the position of the relevant node (or comma). - const syntaxList = find(node.parent.getChildren(), (c): c is SyntaxList => isSyntaxList(c) && rangeContainsRange(c, node)); + const syntaxList = find( + node.parent.getChildren(), + (c): c is SyntaxList => isSyntaxList(c) && rangeContainsRange(c, node), + ); // Either we didn't find an appropriate list, or the list must contain us. Debug.assert(!syntaxList || contains(syntaxList.getChildren(), node)); return syntaxList; @@ -802,7 +900,10 @@ namespace ts { return lastTypeNode; } - export function getContextualTypeFromParentOrAncestorTypeNode(node: Expression, checker: TypeChecker): Type | undefined { + export function getContextualTypeFromParentOrAncestorTypeNode( + node: Expression, + checker: TypeChecker, + ): Type | undefined { if (node.flags & (NodeFlags.JSDoc & ~NodeFlags.JavaScriptFile)) return undefined; const contextualType = getContextualTypeFromParent(node, checker); @@ -919,16 +1020,18 @@ namespace ts { // NOTE: If the node is a modifier, we don't adjust its location if it is the `default` modifier as that is handled // specially by `getSymbolAtLocation`. if ( - isModifier(node) && (forRename || node.kind !== SyntaxKind.DefaultKeyword) ? canHaveModifiers(parent) && contains(parent.modifiers, node) : - node.kind === SyntaxKind.ClassKeyword ? isClassDeclaration(parent) || isClassExpression(node) : - node.kind === SyntaxKind.FunctionKeyword ? isFunctionDeclaration(parent) || isFunctionExpression(node) : - node.kind === SyntaxKind.InterfaceKeyword ? isInterfaceDeclaration(parent) : - node.kind === SyntaxKind.EnumKeyword ? isEnumDeclaration(parent) : - node.kind === SyntaxKind.TypeKeyword ? isTypeAliasDeclaration(parent) : - node.kind === SyntaxKind.NamespaceKeyword || node.kind === SyntaxKind.ModuleKeyword ? isModuleDeclaration(parent) : - node.kind === SyntaxKind.ImportKeyword ? isImportEqualsDeclaration(parent) : - node.kind === SyntaxKind.GetKeyword ? isGetAccessorDeclaration(parent) : - node.kind === SyntaxKind.SetKeyword && isSetAccessorDeclaration(parent) + isModifier(node) && (forRename || node.kind !== SyntaxKind.DefaultKeyword) + ? canHaveModifiers(parent) && contains(parent.modifiers, node) + : node.kind === SyntaxKind.ClassKeyword ? isClassDeclaration(parent) || isClassExpression(node) + : node.kind === SyntaxKind.FunctionKeyword ? isFunctionDeclaration(parent) || isFunctionExpression(node) + : node.kind === SyntaxKind.InterfaceKeyword ? isInterfaceDeclaration(parent) + : node.kind === SyntaxKind.EnumKeyword ? isEnumDeclaration(parent) + : node.kind === SyntaxKind.TypeKeyword ? isTypeAliasDeclaration(parent) + : node.kind === SyntaxKind.NamespaceKeyword || node.kind === SyntaxKind.ModuleKeyword + ? isModuleDeclaration(parent) + : node.kind === SyntaxKind.ImportKeyword ? isImportEqualsDeclaration(parent) + : node.kind === SyntaxKind.GetKeyword ? isGetAccessorDeclaration(parent) + : node.kind === SyntaxKind.SetKeyword && isSetAccessorDeclaration(parent) ) { const location = getAdjustedLocationForDeclaration(parent, forRename); if (location) { @@ -937,8 +1040,9 @@ namespace ts { } // /**/ [|name|] ... if ( - (node.kind === SyntaxKind.VarKeyword || node.kind === SyntaxKind.ConstKeyword || node.kind === SyntaxKind.LetKeyword) && - isVariableDeclarationList(parent) && parent.declarations.length === 1 + (node.kind === SyntaxKind.VarKeyword || node.kind === SyntaxKind.ConstKeyword + || node.kind === SyntaxKind.LetKeyword) + && isVariableDeclarationList(parent) && parent.declarations.length === 1 ) { const decl = parent.declarations[0]; if (isIdentifier(decl.name)) { @@ -973,10 +1077,10 @@ namespace ts { // export * /**/as [|name|] ... if (node.kind === SyntaxKind.AsKeyword) { if ( - isImportSpecifier(parent) && parent.propertyName || - isExportSpecifier(parent) && parent.propertyName || - isNamespaceImport(parent) || - isNamespaceExport(parent) + isImportSpecifier(parent) && parent.propertyName + || isExportSpecifier(parent) && parent.propertyName + || isNamespaceImport(parent) + || isNamespaceExport(parent) ) { return parent.name; } @@ -1019,7 +1123,10 @@ namespace ts { } // import ... /**/from "[|module|]"; // export ... /**/from "[|module|]"; - if (node.kind === SyntaxKind.FromKeyword && (isImportDeclaration(parent) || isExportDeclaration(parent)) && parent.moduleSpecifier) { + if ( + node.kind === SyntaxKind.FromKeyword && (isImportDeclaration(parent) || isExportDeclaration(parent)) + && parent.moduleSpecifier + ) { return parent.moduleSpecifier; } // class ... /**/extends [|name|] ... @@ -1027,7 +1134,10 @@ namespace ts { // class ... /**/implements name1, name2 ... // interface ... /**/extends [|name|] ... // interface ... /**/extends name1, name2 ... - if ((node.kind === SyntaxKind.ExtendsKeyword || node.kind === SyntaxKind.ImplementsKeyword) && isHeritageClause(parent) && parent.token === node.kind) { + if ( + (node.kind === SyntaxKind.ExtendsKeyword || node.kind === SyntaxKind.ImplementsKeyword) + && isHeritageClause(parent) && parent.token === node.kind + ) { const location = getAdjustedLocationForHeritageClause(parent); if (location) { return location; @@ -1048,20 +1158,24 @@ namespace ts { return parent.typeParameter.name; } // { [ [|K|] /**/in keyof T]: ... } - if (node.kind === SyntaxKind.InKeyword && isTypeParameterDeclaration(parent) && isMappedTypeNode(parent.parent)) { + if ( + node.kind === SyntaxKind.InKeyword && isTypeParameterDeclaration(parent) && isMappedTypeNode(parent.parent) + ) { return parent.name; } // /**/keyof [|T|] if ( - node.kind === SyntaxKind.KeyOfKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.KeyOfKeyword && - isTypeReferenceNode(parent.type) + node.kind === SyntaxKind.KeyOfKeyword && isTypeOperatorNode(parent) + && parent.operator === SyntaxKind.KeyOfKeyword + && isTypeReferenceNode(parent.type) ) { return parent.type.typeName; } // /**/readonly [|name|][] if ( - node.kind === SyntaxKind.ReadonlyKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.ReadonlyKeyword && - isArrayTypeNode(parent.type) && isTypeReferenceNode(parent.type.elementType) + node.kind === SyntaxKind.ReadonlyKeyword && isTypeOperatorNode(parent) + && parent.operator === SyntaxKind.ReadonlyKeyword + && isArrayTypeNode(parent.type) && isTypeReferenceNode(parent.type.elementType) ) { return parent.type.elementType.typeName; } @@ -1077,12 +1191,12 @@ namespace ts { // /**/yield obj.[|name|] // /**/delete obj.[|name|] if ( - node.kind === SyntaxKind.NewKeyword && isNewExpression(parent) || - node.kind === SyntaxKind.VoidKeyword && isVoidExpression(parent) || - node.kind === SyntaxKind.TypeOfKeyword && isTypeOfExpression(parent) || - node.kind === SyntaxKind.AwaitKeyword && isAwaitExpression(parent) || - node.kind === SyntaxKind.YieldKeyword && isYieldExpression(parent) || - node.kind === SyntaxKind.DeleteKeyword && isDeleteExpression(parent) + node.kind === SyntaxKind.NewKeyword && isNewExpression(parent) + || node.kind === SyntaxKind.VoidKeyword && isVoidExpression(parent) + || node.kind === SyntaxKind.TypeOfKeyword && isTypeOfExpression(parent) + || node.kind === SyntaxKind.AwaitKeyword && isAwaitExpression(parent) + || node.kind === SyntaxKind.YieldKeyword && isYieldExpression(parent) + || node.kind === SyntaxKind.DeleteKeyword && isDeleteExpression(parent) ) { if (parent.expression) { return skipOuterExpressions(parent.expression); @@ -1090,7 +1204,10 @@ namespace ts { } // left /**/in [|name|] // left /**/instanceof [|name|] - if ((node.kind === SyntaxKind.InKeyword || node.kind === SyntaxKind.InstanceOfKeyword) && isBinaryExpression(parent) && parent.operatorToken === node) { + if ( + (node.kind === SyntaxKind.InKeyword || node.kind === SyntaxKind.InstanceOfKeyword) + && isBinaryExpression(parent) && parent.operatorToken === node + ) { return skipOuterExpressions(parent.right); } // left /**/as [|name|] @@ -1100,8 +1217,8 @@ namespace ts { // for (... /**/in [|name|]) // for (... /**/of [|name|]) if ( - node.kind === SyntaxKind.InKeyword && isForInStatement(parent) || - node.kind === SyntaxKind.OfKeyword && isForOfStatement(parent) + node.kind === SyntaxKind.InKeyword && isForInStatement(parent) + || node.kind === SyntaxKind.OfKeyword && isForOfStatement(parent) ) { return skipOuterExpressions(parent.expression); } @@ -1129,24 +1246,50 @@ namespace ts { * position >= start and (position < end or (position === end && token is literal or keyword or identifier)) */ export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node { - return getTouchingToken(sourceFile, position, n => isPropertyNameLiteral(n) || isKeyword(n.kind) || isPrivateIdentifier(n)); + return getTouchingToken( + sourceFile, + position, + n => isPropertyNameLiteral(n) || isKeyword(n.kind) || isPrivateIdentifier(n), + ); } /** * Returns the token if position is in [start, end). * If position === end, returns the preceding token if includeItemAtEndPosition(previousToken) === true */ - export function getTouchingToken(sourceFile: SourceFile, position: number, includePrecedingTokenAtEndPosition?: (n: Node) => boolean): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includePrecedingTokenAtEndPosition, /*includeEndPosition*/ false); + export function getTouchingToken( + sourceFile: SourceFile, + position: number, + includePrecedingTokenAtEndPosition?: (n: Node) => boolean, + ): Node { + return getTokenAtPositionWorker( + sourceFile, + position, + /*allowPositionInLeadingTrivia*/ false, + includePrecedingTokenAtEndPosition, + /*includeEndPosition*/ false, + ); } /** Returns a token if position is in [start-of-leading-trivia, end) */ export function getTokenAtPosition(sourceFile: SourceFile, position: number): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, /*includeEndPosition*/ false); + return getTokenAtPositionWorker( + sourceFile, + position, + /*allowPositionInLeadingTrivia*/ true, + /*includePrecedingTokenAtEndPosition*/ undefined, + /*includeEndPosition*/ false, + ); } /** Get the token whose text contains the position */ - function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includePrecedingTokenAtEndPosition: ((n: Node) => boolean) | undefined, includeEndPosition: boolean): Node { + function getTokenAtPositionWorker( + sourceFile: SourceFile, + position: number, + allowPositionInLeadingTrivia: boolean, + includePrecedingTokenAtEndPosition: ((n: Node) => boolean) | undefined, + includeEndPosition: boolean, + ): Node { let current: Node = sourceFile; let foundToken: Node | undefined; outer: @@ -1183,7 +1326,8 @@ namespace ts { return Comparison.LessThan; } - const start = allowPositionInLeadingTrivia ? children[middle].getFullStart() : children[middle].getStart(sourceFile, /*includeJsDoc*/ true); + const start = allowPositionInLeadingTrivia ? children[middle].getFullStart() + : children[middle].getStart(sourceFile, /*includeJsDoc*/ true); if (start > position) { return Comparison.GreaterThan; } @@ -1200,7 +1344,10 @@ namespace ts { } // this complex condition makes us left-recur around a zero-length node when includePrecedingTokenAtEndPosition is set, rather than right-recur on it - if (includePrecedingTokenAtEndPosition && start === position && children[middle - 1] && children[middle - 1].getEnd() === position && nodeContainsPosition(children[middle - 1])) { + if ( + includePrecedingTokenAtEndPosition && start === position && children[middle - 1] + && children[middle - 1].getEnd() === position && nodeContainsPosition(children[middle - 1]) + ) { return Comparison.GreaterThan; } return Comparison.LessThan; @@ -1222,12 +1369,15 @@ namespace ts { if (end < position) { return false; } - start ??= allowPositionInLeadingTrivia ? node.getFullStart() : node.getStart(sourceFile, /*includeJsDoc*/ true); + start ??= allowPositionInLeadingTrivia ? node.getFullStart() + : node.getStart(sourceFile, /*includeJsDoc*/ true); if (start > position) { // If this child begins after position, then all subsequent children will as well. return false; } - if (position < end || (position === end && (node.kind === SyntaxKind.EndOfFileToken || includeEndPosition))) { + if ( + position < end || (position === end && (node.kind === SyntaxKind.EndOfFileToken || includeEndPosition)) + ) { return true; } else if (includePrecedingTokenAtEndPosition && end === position) { @@ -1266,7 +1416,9 @@ namespace ts { // Ideally, getTokenAtPosition should return a token. However, it is currently // broken, so we do a check to make sure the result was indeed a token. const tokenAtPosition = getTokenAtPosition(file, position); - if (isToken(tokenAtPosition) && position > tokenAtPosition.getStart(file) && position < tokenAtPosition.getEnd()) { + if ( + isToken(tokenAtPosition) && position > tokenAtPosition.getStart(file) && position < tokenAtPosition.getEnd() + ) { return tokenAtPosition; } @@ -1284,9 +1436,9 @@ namespace ts { return firstDefined(n.getChildren(sourceFile), child => { const shouldDiveInChildNode = // previous token is enclosed somewhere in the child - (child.pos <= previousToken.pos && child.end > previousToken.end) || + (child.pos <= previousToken.pos && child.end > previousToken.end) // previous token ends exactly at the beginning of child - (child.pos === previousToken.end); + || (child.pos === previousToken.end); return shouldDiveInChildNode && nodeHasTokens(child, sourceFile) ? find(child) : undefined; }); } @@ -1296,9 +1448,24 @@ namespace ts { * Finds the rightmost token satisfying `token.end <= position`, * excluding `JsxText` tokens containing only whitespace. */ - export function findPrecedingToken(position: number, sourceFile: SourceFileLike, startNode: Node, excludeJsdoc?: boolean): Node | undefined; - export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, excludeJsdoc?: boolean): Node | undefined; - export function findPrecedingToken(position: number, sourceFile: SourceFileLike, startNode?: Node, excludeJsdoc?: boolean): Node | undefined { + export function findPrecedingToken( + position: number, + sourceFile: SourceFileLike, + startNode: Node, + excludeJsdoc?: boolean, + ): Node | undefined; + export function findPrecedingToken( + position: number, + sourceFile: SourceFile, + startNode?: Node, + excludeJsdoc?: boolean, + ): Node | undefined; + export function findPrecedingToken( + position: number, + sourceFile: SourceFileLike, + startNode?: Node, + excludeJsdoc?: boolean, + ): Node | undefined { const result = find((startNode || sourceFile) as Node); Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result))); return result; @@ -1332,13 +1499,18 @@ namespace ts { // 2) `position` is within the same span: we recurse on `child`. if (position < child.end) { const start = child.getStart(sourceFile, /*includeJsDoc*/ !excludeJsdoc); - const lookInPreviousChild = (start >= position) || // cursor in the leading trivia - !nodeHasTokens(child, sourceFile) || - isWhiteSpaceOnlyJsxText(child); + const lookInPreviousChild = (start >= position) // cursor in the leading trivia + || !nodeHasTokens(child, sourceFile) + || isWhiteSpaceOnlyJsxText(child); if (lookInPreviousChild) { // actual start of the node is past the position - previous token should be at the end of previous child - const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i, sourceFile, n.kind); + const candidate = findRightmostChildNodeWithTokens( + children, + /*exclusiveStartPosition*/ i, + sourceFile, + n.kind, + ); return candidate && findRightmostToken(candidate, sourceFile); } else { @@ -1348,13 +1520,21 @@ namespace ts { } } - Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || n.kind === SyntaxKind.EndOfFileToken || isJSDocCommentContainingNode(n)); + Debug.assert( + startNode !== undefined || n.kind === SyntaxKind.SourceFile || n.kind === SyntaxKind.EndOfFileToken + || isJSDocCommentContainingNode(n), + ); // Here we know that none of child token nodes embrace the position, // the only known case is when position is at the end of the file. // Try to find the rightmost token in the file without filtering. // Namely we are skipping the check: 'position < node.end' - const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile, n.kind); + const candidate = findRightmostChildNodeWithTokens( + children, + /*exclusiveStartPosition*/ children.length, + sourceFile, + n.kind, + ); return candidate && findRightmostToken(candidate, sourceFile); } } @@ -1373,20 +1553,32 @@ namespace ts { return n; } - const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile, n.kind); + const candidate = findRightmostChildNodeWithTokens( + children, + /*exclusiveStartPosition*/ children.length, + sourceFile, + n.kind, + ); return candidate && findRightmostToken(candidate, sourceFile); } /** * Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens. */ - function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number, sourceFile: SourceFileLike, parentKind: SyntaxKind): Node | undefined { + function findRightmostChildNodeWithTokens( + children: Node[], + exclusiveStartPosition: number, + sourceFile: SourceFileLike, + parentKind: SyntaxKind, + ): Node | undefined { for (let i = exclusiveStartPosition - 1; i >= 0; i--) { const child = children[i]; if (isWhiteSpaceOnlyJsxText(child)) { if (i === 0 && (parentKind === SyntaxKind.JsxText || parentKind === SyntaxKind.JsxSelfClosingElement)) { - Debug.fail("`JsxText` tokens should not be the first child of `JsxElement | JsxSelfClosingElement`"); + Debug.fail( + "`JsxText` tokens should not be the first child of `JsxElement | JsxSelfClosingElement`", + ); } } else if (nodeHasTokens(children[i], sourceFile)) { @@ -1395,7 +1587,11 @@ namespace ts { } } - export function isInString(sourceFile: SourceFile, position: number, previousToken = findPrecedingToken(position, sourceFile)): boolean { + export function isInString( + sourceFile: SourceFile, + position: number, + previousToken = findPrecedingToken(position, sourceFile), + ): boolean { if (previousToken && isStringTextContainingNode(previousToken)) { const start = previousToken.getStart(sourceFile); const end = previousToken.getEnd(); @@ -1469,10 +1665,16 @@ namespace ts { if (isJsxText(token)) { return true; } - if (token.kind === SyntaxKind.OpenBraceToken && isJsxExpression(token.parent) && isJsxElement(token.parent.parent)) { + if ( + token.kind === SyntaxKind.OpenBraceToken && isJsxExpression(token.parent) + && isJsxElement(token.parent.parent) + ) { return true; } - if (token.kind === SyntaxKind.LessThanToken && isJsxOpeningLikeElement(token.parent) && isJsxElement(token.parent.parent)) { + if ( + token.kind === SyntaxKind.LessThanToken && isJsxOpeningLikeElement(token.parent) + && isJsxElement(token.parent.parent) + ) { return true; } return false; @@ -1509,7 +1711,11 @@ namespace ts { return isInsideJsxElementTraversal(getTokenAtPosition(sourceFile, position)); } - export function findPrecedingMatchingToken(token: Node, matchingTokenKind: SyntaxKind.OpenBraceToken | SyntaxKind.OpenParenToken | SyntaxKind.OpenBracketToken, sourceFile: SourceFile) { + export function findPrecedingMatchingToken( + token: Node, + matchingTokenKind: SyntaxKind.OpenBraceToken | SyntaxKind.OpenParenToken | SyntaxKind.OpenBracketToken, + sourceFile: SourceFile, + ) { const closeTokenText = tokenToString(token.kind)!; const matchingTokenText = tokenToString(matchingTokenKind)!; const tokenFullStart = token.getFullStart(); @@ -1549,26 +1755,32 @@ namespace ts { } export function removeOptionality(type: Type, isOptionalExpression: boolean, isOptionalChain: boolean) { - return isOptionalExpression ? type.getNonNullableType() : - isOptionalChain ? type.getNonOptionalType() : - type; + return isOptionalExpression ? type.getNonNullableType() + : isOptionalChain ? type.getNonOptionalType() + : type; } export function isPossiblyTypeArgumentPosition(token: Node, sourceFile: SourceFile, checker: TypeChecker): boolean { const info = getPossibleTypeArgumentsInfo(token, sourceFile); - return info !== undefined && (isPartOfTypeNode(info.called) || - getPossibleGenericSignatures(info.called, info.nTypeArguments, checker).length !== 0 || - isPossiblyTypeArgumentPosition(info.called, sourceFile, checker)); + return info !== undefined && (isPartOfTypeNode(info.called) + || getPossibleGenericSignatures(info.called, info.nTypeArguments, checker).length !== 0 + || isPossiblyTypeArgumentPosition(info.called, sourceFile, checker)); } - export function getPossibleGenericSignatures(called: Expression, typeArgumentCount: number, checker: TypeChecker): readonly Signature[] { + export function getPossibleGenericSignatures( + called: Expression, + typeArgumentCount: number, + checker: TypeChecker, + ): readonly Signature[] { let type = checker.getTypeAtLocation(called); if (isOptionalChain(called.parent)) { type = removeOptionality(type, isOptionalChainRoot(called.parent), /*isOptionalChain*/ true); } const signatures = isNewExpression(called.parent) ? type.getConstructSignatures() : type.getCallSignatures(); - return signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= typeArgumentCount); + return signatures.filter(candidate => + !!candidate.typeParameters && candidate.typeParameters.length >= typeArgumentCount + ); } export interface PossibleTypeArgumentInfo { @@ -1581,7 +1793,10 @@ namespace ts { } // Get info for an expression like `f <` that may be the start of type arguments. - export function getPossibleTypeArgumentsInfo(tokenIn: Node | undefined, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined { + export function getPossibleTypeArgumentsInfo( + tokenIn: Node | undefined, + sourceFile: SourceFile, + ): PossibleTypeArgumentInfo | undefined { // This is a rare case, but one that saves on a _lot_ of work if true - if the source file has _no_ `<` character, // then there obviously can't be any type arguments - no expensive brace-matching backwards scanning required @@ -1689,8 +1904,17 @@ namespace ts { * @param tokenAtPosition Must equal `getTokenAtPosition(sourceFile, position)` * @param predicate Additional predicate to test on the comment range. */ - export function isInComment(sourceFile: SourceFile, position: number, tokenAtPosition?: Node): CommentRange | undefined { - return formatting.getRangeOfEnclosingComment(sourceFile, position, /*precedingToken*/ undefined, tokenAtPosition); + export function isInComment( + sourceFile: SourceFile, + position: number, + tokenAtPosition?: Node, + ): CommentRange | undefined { + return formatting.getRangeOfEnclosingComment( + sourceFile, + position, + /*precedingToken*/ undefined, + tokenAtPosition, + ); } export function hasDocComment(sourceFile: SourceFile, position: number): boolean { @@ -1713,7 +1937,9 @@ namespace ts { if (flags & ModifierFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); if (flags & ModifierFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier); if (flags & ModifierFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); - if (flags & ModifierFlags.Static || isClassStaticBlockDeclaration(node)) result.push(ScriptElementKindModifier.staticModifier); + if (flags & ModifierFlags.Static || isClassStaticBlockDeclaration(node)) { + result.push(ScriptElementKindModifier.staticModifier); + } if (flags & ModifierFlags.Abstract) result.push(ScriptElementKindModifier.abstractModifier); if (flags & ModifierFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); if (flags & ModifierFlags.Deprecated) result.push(ScriptElementKindModifier.deprecatedModifier); @@ -1728,7 +1954,10 @@ namespace ts { return (node as CallExpression).typeArguments; } - if (isFunctionLike(node) || node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.InterfaceDeclaration) { + if ( + isFunctionLike(node) || node.kind === SyntaxKind.ClassDeclaration + || node.kind === SyntaxKind.InterfaceDeclaration + ) { return (node as FunctionLikeDeclaration).typeParameters; } @@ -1754,9 +1983,14 @@ namespace ts { return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation; } - export function isInsideTemplateLiteral(node: TemplateLiteralToken, position: number, sourceFile: SourceFile): boolean { + export function isInsideTemplateLiteral( + node: TemplateLiteralToken, + position: number, + sourceFile: SourceFile, + ): boolean { return isTemplateLiteralKind(node.kind) - && (node.getStart(sourceFile) < position && position < node.end) || (!!node.isUnterminated && position === node.end); + && (node.getStart(sourceFile) < position && position < node.end) + || (!!node.isUnterminated && position === node.end); } export function isAccessibilityModifier(kind: SyntaxKind) { @@ -1778,15 +2012,15 @@ namespace ts { export function isArrayLiteralOrObjectLiteralDestructuringPattern(node: Node) { if ( - node.kind === SyntaxKind.ArrayLiteralExpression || - node.kind === SyntaxKind.ObjectLiteralExpression + node.kind === SyntaxKind.ArrayLiteralExpression + || node.kind === SyntaxKind.ObjectLiteralExpression ) { // [a,b,c] from: // [a, b, c] = someExpression; if ( - node.parent.kind === SyntaxKind.BinaryExpression && - (node.parent as BinaryExpression).left === node && - (node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + node.parent.kind === SyntaxKind.BinaryExpression + && (node.parent as BinaryExpression).left === node + && (node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken ) { return true; } @@ -1794,8 +2028,8 @@ namespace ts { // [a, b, c] from: // for([a, b, c] of expression) if ( - node.parent.kind === SyntaxKind.ForOfStatement && - (node.parent as ForOfStatement).initializer === node + node.parent.kind === SyntaxKind.ForOfStatement + && (node.parent as ForOfStatement).initializer === node ) { return true; } @@ -1804,7 +2038,11 @@ namespace ts { // [x, [a, b, c] ] = someExpression // or // {x, a: {a, b, c} } = someExpression - if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent)) { + if ( + isArrayLiteralOrObjectLiteralDestructuringPattern( + node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent, + ) + ) { return true; } } @@ -1822,7 +2060,9 @@ namespace ts { function isInReferenceCommentWorker(sourceFile: SourceFile, position: number, shouldBeReference: boolean): boolean { const range = isInComment(sourceFile, position, /*tokenAtPosition*/ undefined); - return !!range && shouldBeReference === tripleSlashDirectivePrefixRegex.test(sourceFile.text.substring(range.pos, range.end)); + return !!range + && shouldBeReference + === tripleSlashDirectivePrefixRegex.test(sourceFile.text.substring(range.pos, range.end)); } export function getReplacementSpanForContextToken(contextToken: Node | undefined) { @@ -1902,7 +2142,8 @@ namespace ts { /** True if the symbol is for an external module, as opposed to a namespace. */ export function isExternalModuleSymbol(moduleSymbol: Symbol): boolean { - return !!(moduleSymbol.flags & SymbolFlags.Module) && moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote; + return !!(moduleSymbol.flags & SymbolFlags.Module) + && moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote; } /** Returns `true` the first time it encounters a node and `false` afterwards. */ @@ -1939,16 +2180,25 @@ namespace ts { } export function programContainsModules(program: Program): boolean { - return program.getSourceFiles().some(s => !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) && !!(s.externalModuleIndicator || s.commonJsModuleIndicator)); + return program.getSourceFiles().some(s => + !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) + && !!(s.externalModuleIndicator || s.commonJsModuleIndicator) + ); } export function programContainsEsModules(program: Program): boolean { - return program.getSourceFiles().some(s => !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) && !!s.externalModuleIndicator); + return program.getSourceFiles().some(s => + !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) && !!s.externalModuleIndicator + ); } export function compilerOptionsIndicateEsModules(compilerOptions: CompilerOptions): boolean { - return !!compilerOptions.module || getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 || !!compilerOptions.noEmit; + return !!compilerOptions.module || getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 + || !!compilerOptions.noEmit; } - export function createModuleSpecifierResolutionHost(program: Program, host: LanguageServiceHost): ModuleSpecifierResolutionHost { + export function createModuleSpecifierResolutionHost( + program: Program, + host: LanguageServiceHost, + ): ModuleSpecifierResolutionHost { // Mix in `getSymlinkCache` from Program when host doesn't have it // in order for non-Project hosts to have a symlinks cache. return { @@ -1963,12 +2213,18 @@ namespace ts { redirectTargetsMap: program.redirectTargetsMap, getProjectReferenceRedirect: fileName => program.getProjectReferenceRedirect(fileName), isSourceOfProjectReferenceRedirect: fileName => program.isSourceOfProjectReferenceRedirect(fileName), - getNearestAncestorDirectoryWithPackageJson: maybeBind(host, host.getNearestAncestorDirectoryWithPackageJson), + getNearestAncestorDirectoryWithPackageJson: maybeBind( + host, + host.getNearestAncestorDirectoryWithPackageJson, + ), getFileIncludeReasons: () => program.getFileIncludeReasons(), }; } - export function getModuleSpecifierResolverHost(program: Program, host: LanguageServiceHost): SymbolTracker["moduleResolverHost"] { + export function getModuleSpecifierResolverHost( + program: Program, + host: LanguageServiceHost, + ): SymbolTracker["moduleResolverHost"] { return { ...createModuleSpecifierResolutionHost(program, host), getCommonSourceDirectory: () => program.getCommonSourceDirectory(), @@ -1980,18 +2236,35 @@ namespace ts { } export function moduleResolutionUsesNodeModules(moduleResolution: ModuleResolutionKind): boolean { - return moduleResolution === ModuleResolutionKind.NodeJs || moduleResolution >= ModuleResolutionKind.Node16 && moduleResolution <= ModuleResolutionKind.NodeNext; - } - - export function makeImportIfNecessary(defaultImport: Identifier | undefined, namedImports: readonly ImportSpecifier[] | undefined, moduleSpecifier: string, quotePreference: QuotePreference): ImportDeclaration | undefined { - return defaultImport || namedImports && namedImports.length ? makeImport(defaultImport, namedImports, moduleSpecifier, quotePreference) : undefined; - } - - export function makeImport(defaultImport: Identifier | undefined, namedImports: readonly ImportSpecifier[] | undefined, moduleSpecifier: string | Expression, quotePreference: QuotePreference, isTypeOnly?: boolean): ImportDeclaration { + return moduleResolution === ModuleResolutionKind.NodeJs + || moduleResolution >= ModuleResolutionKind.Node16 && moduleResolution <= ModuleResolutionKind.NodeNext; + } + + export function makeImportIfNecessary( + defaultImport: Identifier | undefined, + namedImports: readonly ImportSpecifier[] | undefined, + moduleSpecifier: string, + quotePreference: QuotePreference, + ): ImportDeclaration | undefined { + return defaultImport || namedImports && namedImports.length + ? makeImport(defaultImport, namedImports, moduleSpecifier, quotePreference) : undefined; + } + + export function makeImport( + defaultImport: Identifier | undefined, + namedImports: readonly ImportSpecifier[] | undefined, + moduleSpecifier: string | Expression, + quotePreference: QuotePreference, + isTypeOnly?: boolean, + ): ImportDeclaration { return factory.createImportDeclaration( /*modifiers*/ undefined, defaultImport || namedImports - ? factory.createImportClause(!!isTypeOnly, defaultImport, namedImports && namedImports.length ? factory.createNamedImports(namedImports) : undefined) + ? factory.createImportClause( + !!isTypeOnly, + defaultImport, + namedImports && namedImports.length ? factory.createNamedImports(namedImports) : undefined, + ) : undefined, typeof moduleSpecifier === "string" ? makeStringLiteral(moduleSpecifier, quotePreference) : moduleSpecifier, /*assertClause*/ undefined, @@ -2017,9 +2290,10 @@ namespace ts { } else { // ignore synthetic import added when importHelpers: true - const firstModuleSpecifier = sourceFile.imports && - find(sourceFile.imports, n => isStringLiteral(n) && !nodeIsSynthesized(n.parent)) as StringLiteral; - return firstModuleSpecifier ? quotePreferenceFromString(firstModuleSpecifier, sourceFile) : QuotePreference.Double; + const firstModuleSpecifier = sourceFile.imports + && find(sourceFile.imports, n => isStringLiteral(n) && !nodeIsSynthesized(n.parent)) as StringLiteral; + return firstModuleSpecifier ? quotePreferenceFromString(firstModuleSpecifier, sourceFile) + : QuotePreference.Double; } } @@ -2052,23 +2326,29 @@ namespace ts { export function isModuleSpecifierLike(node: Node): node is StringLiteralLike { return isStringLiteralLike(node) && ( - isExternalModuleReference(node.parent) || - isImportDeclaration(node.parent) || - isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false) && node.parent.arguments[0] === node || - isImportCall(node.parent) && node.parent.arguments[0] === node + isExternalModuleReference(node.parent) + || isImportDeclaration(node.parent) + || isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false) + && node.parent.arguments[0] === node + || isImportCall(node.parent) && node.parent.arguments[0] === node ); } export type ObjectBindingElementWithoutPropertyName = BindingElement & { name: Identifier; }; - export function isObjectBindingElementWithoutPropertyName(bindingElement: Node): bindingElement is ObjectBindingElementWithoutPropertyName { - return isBindingElement(bindingElement) && - isObjectBindingPattern(bindingElement.parent) && - isIdentifier(bindingElement.name) && - !bindingElement.propertyName; + export function isObjectBindingElementWithoutPropertyName( + bindingElement: Node, + ): bindingElement is ObjectBindingElementWithoutPropertyName { + return isBindingElement(bindingElement) + && isObjectBindingPattern(bindingElement.parent) + && isIdentifier(bindingElement.name) + && !bindingElement.propertyName; } - export function getPropertySymbolFromBindingElement(checker: TypeChecker, bindingElement: ObjectBindingElementWithoutPropertyName): Symbol | undefined { + export function getPropertySymbolFromBindingElement( + checker: TypeChecker, + bindingElement: ObjectBindingElementWithoutPropertyName, + ): Symbol | undefined { const typeOfPattern = checker.getTypeAtLocation(bindingElement.parent); return typeOfPattern && checker.getPropertyOfType(typeOfPattern, bindingElement.name.text); } @@ -2086,30 +2366,46 @@ namespace ts { } function spanContainsNode(span: TextSpan, node: Node, file: SourceFile): boolean { - return textSpanContainsPosition(span, node.getStart(file)) && - node.getEnd() <= textSpanEnd(span); + return textSpanContainsPosition(span, node.getStart(file)) + && node.getEnd() <= textSpanEnd(span); } export function findModifier(node: Node, kind: Modifier["kind"]): Modifier | undefined { return canHaveModifiers(node) ? find(node.modifiers, (m): m is Modifier => m.kind === kind) : undefined; } - export function insertImports(changes: textChanges.ChangeTracker, sourceFile: SourceFile, imports: AnyImportOrRequireStatement | readonly AnyImportOrRequireStatement[], blankLineBetween: boolean): void { + export function insertImports( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + imports: AnyImportOrRequireStatement | readonly AnyImportOrRequireStatement[], + blankLineBetween: boolean, + ): void { const decl = isArray(imports) ? imports[0] : imports; - const importKindPredicate: (node: Node) => node is AnyImportOrRequireStatement = decl.kind === SyntaxKind.VariableStatement ? isRequireVariableStatement : isAnyImportSyntax; + const importKindPredicate: (node: Node) => node is AnyImportOrRequireStatement = + decl.kind === SyntaxKind.VariableStatement ? isRequireVariableStatement : isAnyImportSyntax; const existingImportStatements = filter(sourceFile.statements, importKindPredicate); - const sortedNewImports = isArray(imports) ? stableSort(imports, OrganizeImports.compareImportsOrRequireStatements) : [imports]; + const sortedNewImports = isArray(imports) + ? stableSort(imports, OrganizeImports.compareImportsOrRequireStatements) : [imports]; if (!existingImportStatements.length) { changes.insertNodesAtTopOfFile(sourceFile, sortedNewImports, blankLineBetween); } else if (existingImportStatements && OrganizeImports.importsAreSorted(existingImportStatements)) { for (const newImport of sortedNewImports) { - const insertionIndex = OrganizeImports.getImportDeclarationInsertionIndex(existingImportStatements, newImport); + const insertionIndex = OrganizeImports.getImportDeclarationInsertionIndex( + existingImportStatements, + newImport, + ); if (insertionIndex === 0) { // If the first import is top-of-file, insert after the leading comment which is likely the header. - const options = existingImportStatements[0] === sourceFile.statements[0] ? - { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude } : {}; - changes.insertNodeBefore(sourceFile, existingImportStatements[0], newImport, /*blankLineBetween*/ false, options); + const options = existingImportStatements[0] === sourceFile.statements[0] + ? { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude } : {}; + changes.insertNodeBefore( + sourceFile, + existingImportStatements[0], + newImport, + /*blankLineBetween*/ false, + options, + ); } else { const prevImport = existingImportStatements[insertionIndex - 1]; @@ -2128,7 +2424,10 @@ namespace ts { } } - export function getTypeKeywordOfTypeOnlyImport(importClause: ImportClause, sourceFile: SourceFile): Token { + export function getTypeKeywordOfTypeOnlyImport( + importClause: ImportClause, + sourceFile: SourceFile, + ): Token { Debug.assert(importClause.isTypeOnly); return cast(importClause.getChildAt(0, sourceFile), isTypeKeywordToken); } @@ -2145,7 +2444,10 @@ namespace ts { * returns a truthy value, then returns that value. * If no such value is found, the callback is applied to each element of array and undefined is returned. */ - export function forEachUnique(array: readonly T[] | undefined, callback: (element: T, index: number) => U): U | undefined { + export function forEachUnique( + array: readonly T[] | undefined, + callback: (element: T, index: number) => U, + ): U | undefined { if (array) { for (let i = 0; i < array.length; i++) { if (array.indexOf(array[i]) === i) { @@ -2169,16 +2471,28 @@ namespace ts { return true; } - export function getMappedLocation(location: DocumentPosition, sourceMapper: SourceMapper, fileExists: ((path: string) => boolean) | undefined): DocumentPosition | undefined { + export function getMappedLocation( + location: DocumentPosition, + sourceMapper: SourceMapper, + fileExists: ((path: string) => boolean) | undefined, + ): DocumentPosition | undefined { const mapsTo = sourceMapper.tryGetSourcePosition(location); return mapsTo && (!fileExists || fileExists(normalizePath(mapsTo.fileName)) ? mapsTo : undefined); } - export function getMappedDocumentSpan(documentSpan: DocumentSpan, sourceMapper: SourceMapper, fileExists?: (path: string) => boolean): DocumentSpan | undefined { + export function getMappedDocumentSpan( + documentSpan: DocumentSpan, + sourceMapper: SourceMapper, + fileExists?: (path: string) => boolean, + ): DocumentSpan | undefined { const { fileName, textSpan } = documentSpan; const newPosition = getMappedLocation({ fileName, pos: textSpan.start }, sourceMapper, fileExists); if (!newPosition) return undefined; - const newEndPosition = getMappedLocation({ fileName, pos: textSpan.start + textSpan.length }, sourceMapper, fileExists); + const newEndPosition = getMappedLocation( + { fileName, pos: textSpan.start + textSpan.length }, + sourceMapper, + fileExists, + ); const newLength = newEndPosition ? newEndPosition.pos - newPosition.pos : textSpan.length; // This shouldn't happen @@ -2195,7 +2509,11 @@ namespace ts { }; } - export function getMappedContextSpan(documentSpan: DocumentSpan, sourceMapper: SourceMapper, fileExists?: (path: string) => boolean): TextSpan | undefined { + export function getMappedContextSpan( + documentSpan: DocumentSpan, + sourceMapper: SourceMapper, + fileExists?: (path: string) => boolean, + ): TextSpan | undefined { const contextSpanStart = documentSpan.contextSpan && getMappedLocation( { fileName: documentSpan.fileName, pos: documentSpan.contextSpan.start }, sourceMapper, @@ -2206,9 +2524,9 @@ namespace ts { sourceMapper, fileExists, ); - return contextSpanStart && contextSpanEnd ? - { start: contextSpanStart.pos, length: contextSpanEnd.pos - contextSpanStart.pos } : - undefined; + return contextSpanStart && contextSpanEnd + ? { start: contextSpanStart.pos, length: contextSpanEnd.pos - contextSpanStart.pos } + : undefined; } // #endregion @@ -2217,7 +2535,11 @@ namespace ts { // #region export function isFirstDeclarationOfSymbolParameter(symbol: Symbol) { const declaration = symbol.declarations ? firstOrUndefined(symbol.declarations) : undefined; - return !!findAncestor(declaration, n => isParameter(n) ? true : isBindingElement(n) || isObjectBindingPattern(n) || isArrayBindingPattern(n) ? false : "quit"); + return !!findAncestor( + declaration, + n => isParameter(n) ? true + : isBindingElement(n) || isObjectBindingPattern(n) || isArrayBindingPattern(n) ? false : "quit", + ); } const displayPartWriter = getDisplayPartWriter(); @@ -2324,7 +2646,8 @@ namespace ts { const flags = symbol.flags; if (flags & SymbolFlags.Variable) { - return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName; + return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName + : SymbolDisplayPartKind.localName; } if (flags & SymbolFlags.Property) return SymbolDisplayPartKind.propertyName; if (flags & SymbolFlags.GetAccessor) return SymbolDisplayPartKind.propertyName; @@ -2410,7 +2733,10 @@ namespace ts { return displayPart(text, SymbolDisplayPartKind.link); } - export function buildLinkParts(link: JSDocLink | JSDocLinkCode | JSDocLinkPlain, checker?: TypeChecker): SymbolDisplayPart[] { + export function buildLinkParts( + link: JSDocLink | JSDocLinkCode | JSDocLinkPlain, + checker?: TypeChecker, + ): SymbolDisplayPart[] { const prefix = isJSDocLink(link) ? "link" : isJSDocLinkCode(link) ? "linkcode" : "linkplain"; @@ -2466,16 +2792,18 @@ namespace ts { * The default is CRLF. */ export function getNewLineOrDefaultFromHost(host: FormattingHost, formatSettings?: FormatCodeSettings) { - return formatSettings?.newLineCharacter || - host.getNewLine?.() || - carriageReturnLineFeed; + return formatSettings?.newLineCharacter + || host.getNewLine?.() + || carriageReturnLineFeed; } export function lineBreakPart() { return displayPart("\n", SymbolDisplayPartKind.lineBreak); } - export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] { + export function mapToDisplayParts( + writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void, + ): SymbolDisplayPart[] { try { writeDisplayParts(displayPartWriter); return displayPartWriter.displayParts(); @@ -2485,20 +2813,48 @@ namespace ts { } } - export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.None): SymbolDisplayPart[] { + export function typeToDisplayParts( + typechecker: TypeChecker, + type: Type, + enclosingDeclaration?: Node, + flags: TypeFormatFlags = TypeFormatFlags.None, + ): SymbolDisplayPart[] { return mapToDisplayParts(writer => { - typechecker.writeType(type, enclosingDeclaration, flags | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer); + typechecker.writeType( + type, + enclosingDeclaration, + flags | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, + writer, + ); }); } - export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.None): SymbolDisplayPart[] { + export function symbolToDisplayParts( + typeChecker: TypeChecker, + symbol: Symbol, + enclosingDeclaration?: Node, + meaning?: SymbolFlags, + flags: SymbolFormatFlags = SymbolFormatFlags.None, + ): SymbolDisplayPart[] { return mapToDisplayParts(writer => { - typeChecker.writeSymbol(symbol, enclosingDeclaration, meaning, flags | SymbolFormatFlags.UseAliasDefinedOutsideCurrentScope, writer); + typeChecker.writeSymbol( + symbol, + enclosingDeclaration, + meaning, + flags | SymbolFormatFlags.UseAliasDefinedOutsideCurrentScope, + writer, + ); }); } - export function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.None): SymbolDisplayPart[] { - flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers; + export function signatureToDisplayParts( + typechecker: TypeChecker, + signature: Signature, + enclosingDeclaration?: Node, + flags: TypeFormatFlags = TypeFormatFlags.None, + ): SymbolDisplayPart[] { + flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.MultilineObjectLiterals + | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers; return mapToDisplayParts(writer => { typechecker.writeSignature(signature, enclosingDeclaration, flags, /*signatureKind*/ undefined, writer); }); @@ -2513,7 +2869,8 @@ namespace ts { } export function isImportOrExportSpecifierName(location: Node): location is Identifier { - return !!location.parent && isImportOrExportSpecifier(location.parent) && location.parent.propertyName === location; + return !!location.parent && isImportOrExportSpecifier(location.parent) + && location.parent.propertyName === location; } export function getScriptKind(fileName: string, host: LanguageServiceHost): ScriptKind { @@ -2601,9 +2958,11 @@ namespace ts { if (visited === node) { // This only happens for leaf nodes - internal nodes always see their children change. - const clone = isStringLiteral(node) ? setOriginalNode(factory.createStringLiteralFromNode(node), node) as Node as T : - isNumericLiteral(node) ? setOriginalNode(factory.createNumericLiteral(node.text, node.numericLiteralFlags), node) as Node as T : - factory.cloneNode(node); + const clone = isStringLiteral(node) + ? setOriginalNode(factory.createStringLiteralFromNode(node), node) as Node as T + : isNumericLiteral(node) + ? setOriginalNode(factory.createNumericLiteral(node.text, node.numericLiteralFlags), node) as Node as T + : factory.cloneNode(node); return setTextRange(clone, node); } @@ -2614,10 +2973,23 @@ namespace ts { return visited; } - export function getSynthesizedDeepClones(nodes: NodeArray, includeTrivia?: boolean): NodeArray; - export function getSynthesizedDeepClones(nodes: NodeArray | undefined, includeTrivia?: boolean): NodeArray | undefined; - export function getSynthesizedDeepClones(nodes: NodeArray | undefined, includeTrivia = true): NodeArray | undefined { - return nodes && factory.createNodeArray(nodes.map(n => getSynthesizedDeepClone(n, includeTrivia)), nodes.hasTrailingComma); + export function getSynthesizedDeepClones( + nodes: NodeArray, + includeTrivia?: boolean, + ): NodeArray; + export function getSynthesizedDeepClones( + nodes: NodeArray | undefined, + includeTrivia?: boolean, + ): NodeArray | undefined; + export function getSynthesizedDeepClones( + nodes: NodeArray | undefined, + includeTrivia = true, + ): NodeArray | undefined { + return nodes + && factory.createNodeArray( + nodes.map(n => getSynthesizedDeepClone(n, includeTrivia)), + nodes.hasTrailingComma, + ); } export function getSynthesizedDeepClonesWithReplacements( @@ -2625,7 +2997,10 @@ namespace ts { includeTrivia: boolean, replaceNode: (node: Node) => Node | undefined, ): NodeArray { - return factory.createNodeArray(nodes.map(n => getSynthesizedDeepCloneWithReplacements(n, includeTrivia, replaceNode)), nodes.hasTrailingComma); + return factory.createNodeArray( + nodes.map(n => getSynthesizedDeepCloneWithReplacements(n, includeTrivia, replaceNode)), + nodes.hasTrailingComma, + ); } /** @@ -2694,7 +3069,12 @@ namespace ts { * to be on the reference, rather than the declaration, because it's closer to where the * user was before extracting it. */ - export function getRenameLocation(edits: readonly FileTextChanges[], renameFilename: string, name: string, preferLastLocation: boolean): number { + export function getRenameLocation( + edits: readonly FileTextChanges[], + renameFilename: string, + name: string, + preferLastLocation: boolean, + ): number { let delta = 0; let lastPos = -1; for (const { fileName, textChanges } of edits) { @@ -2720,12 +3100,38 @@ namespace ts { return lastPos; } - export function copyLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { - forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment)); + export function copyLeadingComments( + sourceNode: Node, + targetNode: Node, + sourceFile: SourceFile, + commentKind?: CommentKind, + hasTrailingNewLine?: boolean, + ) { + forEachLeadingCommentRange( + sourceFile.text, + sourceNode.pos, + getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment), + ); } - export function copyTrailingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { - forEachTrailingCommentRange(sourceFile.text, sourceNode.end, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticTrailingComment)); + export function copyTrailingComments( + sourceNode: Node, + targetNode: Node, + sourceFile: SourceFile, + commentKind?: CommentKind, + hasTrailingNewLine?: boolean, + ) { + forEachTrailingCommentRange( + sourceFile.text, + sourceNode.end, + getAddCommentsFunction( + targetNode, + sourceFile, + commentKind, + hasTrailingNewLine, + addSyntheticTrailingComment, + ), + ); } /** @@ -2735,11 +3141,27 @@ namespace ts { * `function foo(\* not leading comment for a *\ a: string) {}` * The comment refers to `a` but belongs to the `(` token, but we might want to copy it. */ - export function copyTrailingAsLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { - forEachTrailingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment)); + export function copyTrailingAsLeadingComments( + sourceNode: Node, + targetNode: Node, + sourceFile: SourceFile, + commentKind?: CommentKind, + hasTrailingNewLine?: boolean, + ) { + forEachTrailingCommentRange( + sourceFile.text, + sourceNode.pos, + getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment), + ); } - function getAddCommentsFunction(targetNode: Node, sourceFile: SourceFile, commentKind: CommentKind | undefined, hasTrailingNewLine: boolean | undefined, cb: (node: Node, kind: CommentKind, text: string, hasTrailingNewLine?: boolean) => void) { + function getAddCommentsFunction( + targetNode: Node, + sourceFile: SourceFile, + commentKind: CommentKind | undefined, + hasTrailingNewLine: boolean | undefined, + cb: (node: Node, kind: CommentKind, text: string, hasTrailingNewLine?: boolean) => void, + ) { return (pos: number, end: number, kind: CommentKind, htnl: boolean) => { if (kind === SyntaxKind.MultiLineCommentTrivia) { // Remove leading /* @@ -2751,7 +3173,12 @@ namespace ts { // Remove leading // pos += 2; } - cb(targetNode, commentKind || kind, sourceFile.text.slice(pos, end), hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl); + cb( + targetNode, + commentKind || kind, + sourceFile.text.slice(pos, end), + hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl, + ); }; } @@ -2783,7 +3210,8 @@ namespace ts { : checker.getContextualType(node); } case SyntaxKind.CaseClause: - return (parent as CaseClause).expression === node ? getSwitchedType(parent as CaseClause, checker) : undefined; + return (parent as CaseClause).expression === node ? getSwitchedType(parent as CaseClause, checker) + : undefined; default: return checker.getContextualType(node); } @@ -2793,7 +3221,8 @@ namespace ts { // Editors can pass in undefined or empty string - we want to infer the preference in those cases. const quotePreference = getQuotePreference(sourceFile, preferences); const quoted = JSON.stringify(text); - return quotePreference === QuotePreference.Single ? `'${stripQuotes(quoted).replace(/'/g, "\\'").replace(/\\"/g, '"')}'` : quoted; + return quotePreference === QuotePreference.Single + ? `'${stripQuotes(quoted).replace(/'/g, "\\'").replace(/\\"/g, '"')}'` : quoted; } export function isEqualityOperatorKind(kind: SyntaxKind): kind is EqualityOperator { @@ -2808,7 +3237,9 @@ namespace ts { } } - export function isStringLiteralOrTemplate(node: Node): node is StringLiteralLike | TemplateExpression | TaggedTemplateExpression { + export function isStringLiteralOrTemplate( + node: Node, + ): node is StringLiteralLike | TemplateExpression | TaggedTemplateExpression { switch (node.kind) { case SyntaxKind.StringLiteral: case SyntaxKind.NoSubstitutionTemplateLiteral: @@ -2830,13 +3261,24 @@ namespace ts { export const ANONYMOUS = "anonymous function"; - export function getTypeNodeIfAccessible(type: Type, enclosingScope: Node, program: Program, host: LanguageServiceHost): TypeNode | undefined { + export function getTypeNodeIfAccessible( + type: Type, + enclosingScope: Node, + program: Program, + host: LanguageServiceHost, + ): TypeNode | undefined { const checker = program.getTypeChecker(); let typeIsAccessible = true; const notAccessible = () => typeIsAccessible = false; const res = checker.typeToTypeNode(type, enclosingScope, NodeBuilderFlags.NoTruncation, { trackSymbol: (symbol, declaration, meaning) => { - typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible; + typeIsAccessible = typeIsAccessible + && checker.isSymbolAccessible( + symbol, + declaration, + meaning, + /*shouldComputeAliasToMarkVisible*/ false, + ).accessibility === SymbolAccessibility.Accessible; return !typeIsAccessible; }, reportInaccessibleThisError: notAccessible, @@ -2966,8 +3408,12 @@ namespace ts { withSemicolon++; } else if (lastToken && lastToken.kind !== SyntaxKind.CommaToken) { - const lastTokenLine = getLineAndCharacterOfPosition(sourceFile, lastToken.getStart(sourceFile)).line; - const nextTokenLine = getLineAndCharacterOfPosition(sourceFile, getSpanOfTokenAtPosition(sourceFile, lastToken.end).start).line; + const lastTokenLine = + getLineAndCharacterOfPosition(sourceFile, lastToken.getStart(sourceFile)).line; + const nextTokenLine = getLineAndCharacterOfPosition( + sourceFile, + getSpanOfTokenAtPosition(sourceFile, lastToken.end).start, + ).line; // Avoid counting missing semicolon in single-line objects: // `function f(p: { x: string /*no semicolon here is insignificant*/ }) {` if (lastTokenLine !== nextTokenLine) { @@ -2993,11 +3439,20 @@ namespace ts { return withSemicolon / withoutSemicolon > 1 / nStatementsToObserve; } - export function tryGetDirectories(host: Pick, directoryName: string): string[] { + export function tryGetDirectories( + host: Pick, + directoryName: string, + ): string[] { return tryIOAndConsumeErrors(host, host.getDirectories, directoryName) || []; } - export function tryReadDirectory(host: Pick, path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[]): readonly string[] { + export function tryReadDirectory( + host: Pick, + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + ): readonly string[] { return tryIOAndConsumeErrors(host, host.readDirectory, path, extensions, exclude, include) || emptyArray; } @@ -3022,7 +3477,11 @@ namespace ts { return tryAndIgnoreErrors(() => toApply && toApply.apply(host, args)); } - export function findPackageJsons(startDirectory: string, host: Pick, stopDirectory?: string): string[] { + export function findPackageJsons( + startDirectory: string, + host: Pick, + stopDirectory?: string, + ): string[] { const paths: string[] = []; forEachAncestorDirectory(startDirectory, ancestor => { if (ancestor === stopDirectory) { @@ -3048,7 +3507,10 @@ namespace ts { return packageJson; } - export function getPackageJsonsVisibleToFile(fileName: string, host: LanguageServiceHost): readonly ProjectPackageJsonInfo[] { + export function getPackageJsonsVisibleToFile( + fileName: string, + host: LanguageServiceHost, + ): readonly ProjectPackageJsonInfo[] { if (!host.fileExists) { return []; } @@ -3067,7 +3529,10 @@ namespace ts { return packageJsons; } - export function createPackageJsonInfo(fileName: string, host: { readFile?(fileName: string): string | undefined; }): ProjectPackageJsonInfo | undefined { + export function createPackageJsonInfo( + fileName: string, + host: { readFile?(fileName: string): string | undefined; }, + ): ProjectPackageJsonInfo | undefined { if (!host.readFile) { return undefined; } @@ -3121,8 +3586,14 @@ namespace ts { } export interface PackageJsonImportFilter { - allowsImportingAmbientModule: (moduleSymbol: Symbol, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost) => boolean; - allowsImportingSourceFile: (sourceFile: SourceFile, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost) => boolean; + allowsImportingAmbientModule: ( + moduleSymbol: Symbol, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ) => boolean; + allowsImportingSourceFile: ( + sourceFile: SourceFile, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ) => boolean; /** * Use for a specific module specifier that has already been resolved. * Use `allowsImportingAmbientModule` or `allowsImportingSourceFile` to resolve @@ -3131,9 +3602,14 @@ namespace ts { allowsImportingSpecifier: (moduleSpecifier: string) => boolean; } - export function createPackageJsonImportFilter(fromFile: SourceFile, preferences: UserPreferences, host: LanguageServiceHost): PackageJsonImportFilter { + export function createPackageJsonImportFilter( + fromFile: SourceFile, + preferences: UserPreferences, + host: LanguageServiceHost, + ): PackageJsonImportFilter { const packageJsons = ( - (host.getPackageJsonsVisibleToFile && host.getPackageJsonsVisibleToFile(fromFile.fileName)) || getPackageJsonsVisibleToFile(fromFile.fileName, host) + (host.getPackageJsonsVisibleToFile && host.getPackageJsonsVisibleToFile(fromFile.fileName)) + || getPackageJsonsVisibleToFile(fromFile.fileName, host) ).filter(p => p.parseable); let usesNodeCoreModules: boolean | undefined; @@ -3149,13 +3625,19 @@ namespace ts { return false; } - function allowsImportingAmbientModule(moduleSymbol: Symbol, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost): boolean { + function allowsImportingAmbientModule( + moduleSymbol: Symbol, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ): boolean { if (!packageJsons.length || !moduleSymbol.valueDeclaration) { return true; } const declaringSourceFile = moduleSymbol.valueDeclaration.getSourceFile(); - const declaringNodeModuleName = getNodeModulesPackageNameFromFileName(declaringSourceFile.fileName, moduleSpecifierResolutionHost); + const declaringNodeModuleName = getNodeModulesPackageNameFromFileName( + declaringSourceFile.fileName, + moduleSpecifierResolutionHost, + ); if (typeof declaringNodeModuleName === "undefined") { return true; } @@ -3169,12 +3651,18 @@ namespace ts { || moduleSpecifierIsCoveredByPackageJson(declaredModuleSpecifier); } - function allowsImportingSourceFile(sourceFile: SourceFile, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost): boolean { + function allowsImportingSourceFile( + sourceFile: SourceFile, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ): boolean { if (!packageJsons.length) { return true; } - const moduleSpecifier = getNodeModulesPackageNameFromFileName(sourceFile.fileName, moduleSpecifierResolutionHost); + const moduleSpecifier = getNodeModulesPackageNameFromFileName( + sourceFile.fileName, + moduleSpecifierResolutionHost, + ); if (!moduleSpecifier) { return true; } @@ -3208,7 +3696,10 @@ namespace ts { return false; } - function getNodeModulesPackageNameFromFileName(importedFileName: string, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost): string | undefined { + function getNodeModulesPackageNameFromFileName( + importedFileName: string, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ): string | undefined { if (!stringContains(importedFileName, "node_modules")) { return undefined; } @@ -3261,17 +3752,27 @@ namespace ts { return diagnostic.file !== undefined && diagnostic.start !== undefined && diagnostic.length !== undefined; } - export function findDiagnosticForNode(node: Node, sortedFileDiagnostics: readonly Diagnostic[]): DiagnosticWithLocation | undefined { + export function findDiagnosticForNode( + node: Node, + sortedFileDiagnostics: readonly Diagnostic[], + ): DiagnosticWithLocation | undefined { const span: Partial = createTextSpanFromNode(node); const index = binarySearchKey(sortedFileDiagnostics, span, identity, compareTextSpans); if (index >= 0) { const diagnostic = sortedFileDiagnostics[index]; - Debug.assertEqual(diagnostic.file, node.getSourceFile(), "Diagnostics proided to 'findDiagnosticForNode' must be from a single SourceFile"); + Debug.assertEqual( + diagnostic.file, + node.getSourceFile(), + "Diagnostics proided to 'findDiagnosticForNode' must be from a single SourceFile", + ); return cast(diagnostic, isDiagnosticWithLocation); } } - export function getDiagnosticsWithinSpan(span: TextSpan, sortedFileDiagnostics: readonly Diagnostic[]): readonly DiagnosticWithLocation[] { + export function getDiagnosticsWithinSpan( + span: TextSpan, + sortedFileDiagnostics: readonly Diagnostic[], + ): readonly DiagnosticWithLocation[] { let index = binarySearchKey(sortedFileDiagnostics, span.start, diag => diag.start, compareValues); if (index < 0) { index = ~index; @@ -3322,11 +3823,27 @@ namespace ts { * to the provided value itself. */ export function mapOneOrMany(valueOrArray: T | readonly T[], f: (x: T, i: number) => U): U | U[]; - export function mapOneOrMany(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U): U | U[] | undefined; - export function mapOneOrMany(valueOrArray: T | readonly T[], f: (x: T, i: number) => U, resultSelector: (x: U[]) => U): U; - export function mapOneOrMany(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U, resultSelector: (x: U[]) => U): U | undefined; - export function mapOneOrMany(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U, resultSelector: (x: U[]) => U | U[] = identity): U | U[] | undefined { - return valueOrArray ? isArray(valueOrArray) ? resultSelector(map(valueOrArray, f)) : f(valueOrArray, 0) : undefined; + export function mapOneOrMany( + valueOrArray: T | readonly T[] | undefined, + f: (x: T, i: number) => U, + ): U | U[] | undefined; + export function mapOneOrMany( + valueOrArray: T | readonly T[], + f: (x: T, i: number) => U, + resultSelector: (x: U[]) => U, + ): U; + export function mapOneOrMany( + valueOrArray: T | readonly T[] | undefined, + f: (x: T, i: number) => U, + resultSelector: (x: U[]) => U, + ): U | undefined; + export function mapOneOrMany( + valueOrArray: T | readonly T[] | undefined, + f: (x: T, i: number) => U, + resultSelector: (x: U[]) => U | U[] = identity, + ): U | U[] | undefined { + return valueOrArray ? isArray(valueOrArray) ? resultSelector(map(valueOrArray, f)) : f(valueOrArray, 0) + : undefined; } /** @@ -3336,45 +3853,70 @@ namespace ts { return isArray(valueOrArray) ? first(valueOrArray) : valueOrArray; } - export function getNamesForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget | undefined): string | [lowercase: string, capitalized: string] { + export function getNamesForExportedSymbol( + symbol: Symbol, + scriptTarget: ScriptTarget | undefined, + ): string | [lowercase: string, capitalized: string] { if (needsNameFromDeclaration(symbol)) { const fromDeclaration = getDefaultLikeExportNameFromDeclaration(symbol); if (fromDeclaration) return fromDeclaration; - const fileNameCase = codefix.moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget, /*preferCapitalized*/ false); - const capitalized = codefix.moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget, /*preferCapitalized*/ true); + const fileNameCase = codefix.moduleSymbolToValidIdentifier( + getSymbolParentOrFail(symbol), + scriptTarget, + /*preferCapitalized*/ false, + ); + const capitalized = codefix.moduleSymbolToValidIdentifier( + getSymbolParentOrFail(symbol), + scriptTarget, + /*preferCapitalized*/ true, + ); if (fileNameCase === capitalized) return fileNameCase; return [fileNameCase, capitalized]; } return symbol.name; } - export function getNameForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget | undefined, preferCapitalized?: boolean) { + export function getNameForExportedSymbol( + symbol: Symbol, + scriptTarget: ScriptTarget | undefined, + preferCapitalized?: boolean, + ) { if (needsNameFromDeclaration(symbol)) { // Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase. return getDefaultLikeExportNameFromDeclaration(symbol) - || codefix.moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget, !!preferCapitalized); + || codefix.moduleSymbolToValidIdentifier( + getSymbolParentOrFail(symbol), + scriptTarget, + !!preferCapitalized, + ); } return symbol.name; } function needsNameFromDeclaration(symbol: Symbol) { - return !(symbol.flags & SymbolFlags.Transient) && (symbol.escapedName === InternalSymbolName.ExportEquals || symbol.escapedName === InternalSymbolName.Default); + return !(symbol.flags & SymbolFlags.Transient) + && (symbol.escapedName === InternalSymbolName.ExportEquals + || symbol.escapedName === InternalSymbolName.Default); } function getDefaultLikeExportNameFromDeclaration(symbol: Symbol) { - return firstDefined(symbol.declarations, d => isExportAssignment(d) ? tryCast(skipOuterExpressions(d.expression), isIdentifier)?.text : undefined); + return firstDefined( + symbol.declarations, + d => isExportAssignment(d) ? tryCast(skipOuterExpressions(d.expression), isIdentifier)?.text : undefined, + ); } function getSymbolParentOrFail(symbol: Symbol) { return Debug.checkDefined( symbol.parent, - `Symbol parent was undefined. Flags: ${Debug.formatSymbolFlags(symbol.flags)}. ` + - `Declarations: ${ + `Symbol parent was undefined. Flags: ${Debug.formatSymbolFlags(symbol.flags)}. ` + + `Declarations: ${ symbol.declarations?.map(d => { const kind = Debug.formatSyntaxKind(d.kind); const inJS = isInJSFile(d); const { expression } = d as any; - return (inJS ? "[JS]" : "") + kind + (expression ? ` (expression: ${Debug.formatSyntaxKind(expression.kind)})` : ""); + return (inJS ? "[JS]" : "") + kind + + (expression ? ` (expression: ${Debug.formatSyntaxKind(expression.kind)})` : ""); }).join(", ") }.`, ); @@ -3444,7 +3986,11 @@ namespace ts { return newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed; } - export type DiagnosticAndArguments = DiagnosticMessage | [DiagnosticMessage, string] | [DiagnosticMessage, string, string]; + export type DiagnosticAndArguments = DiagnosticMessage | [DiagnosticMessage, string] | [ + DiagnosticMessage, + string, + string, + ]; export function diagnosticToString(diag: DiagnosticAndArguments): string { return isArray(diag) ? formatStringFromArgs(getLocaleSpecificMessage(diag[0]), diag.slice(1) as readonly string[]) @@ -3454,9 +4000,14 @@ namespace ts { /** * Get format code settings for a code writing context (e.g. when formatting text changes or completions code). */ - export function getFormatCodeSettingsForWriting({ options }: formatting.FormatContext, sourceFile: SourceFile): FormatCodeSettings { - const shouldAutoDetectSemicolonPreference = !options.semicolons || options.semicolons === SemicolonPreference.Ignore; - const shouldRemoveSemicolons = options.semicolons === SemicolonPreference.Remove || shouldAutoDetectSemicolonPreference && !probablyUsesSemicolons(sourceFile); + export function getFormatCodeSettingsForWriting( + { options }: formatting.FormatContext, + sourceFile: SourceFile, + ): FormatCodeSettings { + const shouldAutoDetectSemicolonPreference = !options.semicolons + || options.semicolons === SemicolonPreference.Ignore; + const shouldRemoveSemicolons = options.semicolons === SemicolonPreference.Remove + || shouldAutoDetectSemicolonPreference && !probablyUsesSemicolons(sourceFile); return { ...options, semicolons: shouldRemoveSemicolons ? SemicolonPreference.Remove : SemicolonPreference.Ignore, diff --git a/src/testRunner/compilerRunner.ts b/src/testRunner/compilerRunner.ts index 084c867951d17..338af6e5ca235 100644 --- a/src/testRunner/compilerRunner.ts +++ b/src/testRunner/compilerRunner.ts @@ -40,7 +40,9 @@ namespace Harness { public enumerateTestFiles() { // see also: `enumerateTestFiles` in tests/webTestServer.ts - return this.enumerateFiles(this.basePath, /\.tsx?$/, { recursive: true }).map(CompilerTest.getConfigurations); + return this.enumerateFiles(this.basePath, /\.tsx?$/, { recursive: true }).map( + CompilerTest.getConfigurations, + ); } public initializeTests() { @@ -53,7 +55,10 @@ namespace Harness { const files = this.tests.length > 0 ? this.tests : IO.enumerateTestFiles(this); files.forEach(test => { const file = typeof test === "string" ? test : test.file; - this.checkTestCodeOutput(vpath.normalizeSeparators(file), typeof test === "string" ? CompilerTest.getConfigurations(test) : test); + this.checkTestCodeOutput( + vpath.normalizeSeparators(file), + typeof test === "string" ? CompilerTest.getConfigurations(test) : test, + ); }); }); } @@ -80,7 +85,8 @@ namespace Harness { before(() => { let payload; if (test && test.content) { - const rootDir = test.file.indexOf("conformance") === -1 ? "tests/cases/compiler/" : ts.getDirectoryPath(test.file) + "/"; + const rootDir = test.file.indexOf("conformance") === -1 ? "tests/cases/compiler/" + : ts.getDirectoryPath(test.file) + "/"; payload = TestCaseParser.makeUnitsFromTest(test.content, test.file, rootDir); } compilerTest = new CompilerTest(fileName, payload, configuration); @@ -160,7 +166,11 @@ namespace Harness { // equivalent to other files on the file system not directly passed to the compiler (ie things that are referenced by other files) private otherFiles: Compiler.TestFile[]; - constructor(fileName: string, testCaseContent?: TestCaseParser.TestCaseContent, configurationOverrides?: TestCaseParser.CompilerSettings) { + constructor( + fileName: string, + testCaseContent?: TestCaseParser.TestCaseContent, + configurationOverrides?: TestCaseParser.CompilerSettings, + ) { this.fileName = fileName; this.justName = vpath.basename(fileName); this.configuredName = this.justName; @@ -182,14 +192,18 @@ namespace Harness { } } - const rootDir = fileName.indexOf("conformance") === -1 ? "tests/cases/compiler/" : ts.getDirectoryPath(fileName) + "/"; + const rootDir = fileName.indexOf("conformance") === -1 ? "tests/cases/compiler/" + : ts.getDirectoryPath(fileName) + "/"; if (testCaseContent === undefined) { testCaseContent = TestCaseParser.makeUnitsFromTest(IO.readFile(fileName)!, fileName, rootDir); } if (configurationOverrides) { - testCaseContent = { ...testCaseContent, settings: { ...testCaseContent.settings, ...configurationOverrides } }; + testCaseContent = { + ...testCaseContent, + settings: { ...testCaseContent.settings, ...configurationOverrides }, + }; } const units = testCaseContent.testUnitData; @@ -197,11 +211,25 @@ namespace Harness { let tsConfigOptions: ts.CompilerOptions | undefined; this.tsConfigFiles = []; if (testCaseContent.tsConfig) { - assert.equal(testCaseContent.tsConfig.fileNames.length, 0, `list of files in tsconfig is not currently supported`); - assert.equal(testCaseContent.tsConfig.raw.exclude, undefined, `exclude in tsconfig is not currently supported`); + assert.equal( + testCaseContent.tsConfig.fileNames.length, + 0, + `list of files in tsconfig is not currently supported`, + ); + assert.equal( + testCaseContent.tsConfig.raw.exclude, + undefined, + `exclude in tsconfig is not currently supported`, + ); tsConfigOptions = ts.cloneCompilerOptions(testCaseContent.tsConfig.options); - this.tsConfigFiles.push(this.createHarnessTestFile(testCaseContent.tsConfigFileUnitData!, rootDir, ts.combinePaths(rootDir, tsConfigOptions.configFilePath))); + this.tsConfigFiles.push( + this.createHarnessTestFile( + testCaseContent.tsConfigFileUnitData!, + rootDir, + ts.combinePaths(rootDir, tsConfigOptions.configFilePath), + ), + ); } else { const baseUrl = this.harnessSettings.baseUrl; @@ -218,7 +246,10 @@ namespace Harness { this.toBeCompiled = []; this.otherFiles = []; - if (testCaseContent.settings.noImplicitReferences || /require\(/.test(this.lastUnit.content) || /reference\spath/.test(this.lastUnit.content)) { + if ( + testCaseContent.settings.noImplicitReferences || /require\(/.test(this.lastUnit.content) + || /reference\spath/.test(this.lastUnit.content) + ) { this.toBeCompiled.push(this.createHarnessTestFile(this.lastUnit, rootDir)); units.forEach(unit => { if (unit.name !== this.lastUnit.name) { @@ -269,17 +300,21 @@ namespace Harness { public verifyModuleResolution() { if (this.options.traceResolution) { - Baseline.runBaseline(this.configuredName.replace(/\.tsx?$/, ".trace.json"), JSON.stringify(this.result.traces.map(Utils.sanitizeTraceResolutionLogEntry), undefined, 4)); + Baseline.runBaseline( + this.configuredName.replace(/\.tsx?$/, ".trace.json"), + JSON.stringify(this.result.traces.map(Utils.sanitizeTraceResolutionLogEntry), undefined, 4), + ); } } public verifySourceMapRecord() { if (this.options.sourceMap || this.options.inlineSourceMap || this.options.declarationMap) { const record = Utils.removeTestPathPrefixes(this.result.getSourceMapRecord()!); - const baseline = (this.options.noEmitOnError && this.result.diagnostics.length !== 0) || record === undefined - // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. - ? null // eslint-disable-line no-null/no-null - : record; + const baseline = + (this.options.noEmitOnError && this.result.diagnostics.length !== 0) || record === undefined + // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. + ? null // eslint-disable-line no-null/no-null + : record; Baseline.runBaseline(this.configuredName.replace(/\.tsx?$/, ".sourcemap.txt"), baseline); } } @@ -313,8 +348,8 @@ namespace Harness { return; } - const noTypesAndSymbols = this.harnessSettings.noTypesAndSymbols && - this.harnessSettings.noTypesAndSymbols.toLowerCase() === "true"; + const noTypesAndSymbols = this.harnessSettings.noTypesAndSymbols + && this.harnessSettings.noTypesAndSymbols.toLowerCase() === "true"; if (noTypesAndSymbols) { return; } @@ -322,7 +357,9 @@ namespace Harness { Compiler.doTypeAndSymbolBaseline( this.configuredName, this.result.program!, - this.toBeCompiled.concat(this.otherFiles).filter(file => !!this.result.program!.getSourceFile(file.unitName)), + this.toBeCompiled.concat(this.otherFiles).filter(file => + !!this.result.program!.getSourceFile(file.unitName) + ), /*opts*/ undefined, /*multifile*/ undefined, /*skipTypeBaselines*/ undefined, @@ -337,8 +374,16 @@ namespace Harness { return pathStart ? path.replace(pathStart, "/") : path; } - private createHarnessTestFile(lastUnit: TestCaseParser.TestUnitData, rootDir: string, unitName?: string): Compiler.TestFile { - return { unitName: unitName || this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content, fileOptions: lastUnit.fileOptions }; + private createHarnessTestFile( + lastUnit: TestCaseParser.TestUnitData, + rootDir: string, + unitName?: string, + ): Compiler.TestFile { + return { + unitName: unitName || this.makeUnitName(lastUnit.name, rootDir), + content: lastUnit.content, + fileOptions: lastUnit.fileOptions, + }; } } } diff --git a/src/testRunner/externalCompileRunner.ts b/src/testRunner/externalCompileRunner.ts index e25e29c0419ca..c0de6a7cf993b 100644 --- a/src/testRunner/externalCompileRunner.ts +++ b/src/testRunner/externalCompileRunner.ts @@ -52,18 +52,60 @@ namespace Harness { const stdio = isWorker ? "pipe" : "inherit"; let types: string[] | undefined; if (fs.existsSync(path.join(cwd, "test.json"))) { - const config = JSON.parse(fs.readFileSync(path.join(cwd, "test.json"), { encoding: "utf8" })) as UserConfig; + const config = JSON.parse( + fs.readFileSync(path.join(cwd, "test.json"), { encoding: "utf8" }), + ) as UserConfig; ts.Debug.assert(!!config.types, "Bad format from test.json: Types field must be present."); - ts.Debug.assert(!!config.cloneUrl, "Bad format from test.json: cloneUrl field must be present."); + ts.Debug.assert( + !!config.cloneUrl, + "Bad format from test.json: cloneUrl field must be present.", + ); const submoduleDir = path.join(cwd, directoryName); if (!fs.existsSync(submoduleDir)) { - exec("git", ["--work-tree", submoduleDir, "clone", "-b", config.branch || "master", config.cloneUrl, path.join(submoduleDir, ".git")], { cwd }); + exec("git", [ + "--work-tree", + submoduleDir, + "clone", + "-b", + config.branch || "master", + config.cloneUrl, + path.join(submoduleDir, ".git"), + ], { cwd }); } else { - exec("git", ["--git-dir", path.join(submoduleDir, ".git"), "--work-tree", submoduleDir, "checkout", config.branch || "master"], { cwd: submoduleDir }); - exec("git", ["--git-dir", path.join(submoduleDir, ".git"), "--work-tree", submoduleDir, "reset", "HEAD", "--hard"], { cwd: submoduleDir }); - exec("git", ["--git-dir", path.join(submoduleDir, ".git"), "--work-tree", submoduleDir, "clean", "-f"], { cwd: submoduleDir }); - exec("git", ["--git-dir", path.join(submoduleDir, ".git"), "--work-tree", submoduleDir, "pull", "-f"], { cwd: submoduleDir }); + exec("git", [ + "--git-dir", + path.join(submoduleDir, ".git"), + "--work-tree", + submoduleDir, + "checkout", + config.branch || "master", + ], { cwd: submoduleDir }); + exec("git", [ + "--git-dir", + path.join(submoduleDir, ".git"), + "--work-tree", + submoduleDir, + "reset", + "HEAD", + "--hard", + ], { cwd: submoduleDir }); + exec("git", [ + "--git-dir", + path.join(submoduleDir, ".git"), + "--work-tree", + submoduleDir, + "clean", + "-f", + ], { cwd: submoduleDir }); + exec("git", [ + "--git-dir", + path.join(submoduleDir, ".git"), + "--work-tree", + submoduleDir, + "pull", + "-f", + ], { cwd: submoduleDir }); } types = config.types; @@ -80,23 +122,47 @@ namespace Harness { if (fs.existsSync(path.join(cwd, "node_modules"))) { del.sync(path.join(cwd, "node_modules"), { force: true }); } - exec("npm", ["i", "--ignore-scripts", ...(isV7OrLater ? ["--legacy-peer-deps"] : [])], { cwd, timeout: timeout / 2 }); // NPM shouldn't take the entire timeout - if it takes a long time, it should be terminated and we should log the failure + exec("npm", ["i", "--ignore-scripts", ...(isV7OrLater ? ["--legacy-peer-deps"] : [])], { + cwd, + timeout: timeout / 2, + }); // NPM shouldn't take the entire timeout - if it takes a long time, it should be terminated and we should log the failure } const args = [path.join(IO.getWorkspaceRoot(), "built/local/tsc.js")]; if (types) { args.push("--types", types.join(",")); // Also actually install those types (for, eg, the js projects which need node) if (types.length) { - exec("npm", ["i", ...types.map(t => `@types/${t}`), "--no-save", "--ignore-scripts", ...(isV7OrLater ? ["--legacy-peer-deps"] : [])], { cwd: originalCwd, timeout: timeout / 2 }); // NPM shouldn't take the entire timeout - if it takes a long time, it should be terminated and we should log the failure + exec("npm", [ + "i", + ...types.map(t => `@types/${t}`), + "--no-save", + "--ignore-scripts", + ...(isV7OrLater ? ["--legacy-peer-deps"] : []), + ], { cwd: originalCwd, timeout: timeout / 2 }); // NPM shouldn't take the entire timeout - if it takes a long time, it should be terminated and we should log the failure } } args.push("--noEmit"); - Baseline.runBaseline(`${cls.kind()}/${directoryName}.log`, cls.report(cp.spawnSync(`node`, args, { cwd, timeout, shell: true }))); - - function exec(command: string, args: string[], options: { cwd: string; timeout?: number; stdio?: import("child_process").StdioOptions; }): string | undefined { - const res = cp.spawnSync(isWorker ? `${command} 2>&1` : command, args, { shell: true, stdio, ...options }); + Baseline.runBaseline( + `${cls.kind()}/${directoryName}.log`, + cls.report(cp.spawnSync(`node`, args, { cwd, timeout, shell: true })), + ); + + function exec( + command: string, + args: string[], + options: { cwd: string; timeout?: number; stdio?: import("child_process").StdioOptions; }, + ): string | undefined { + const res = cp.spawnSync(isWorker ? `${command} 2>&1` : command, args, { + shell: true, + stdio, + ...options, + }); if (res.status !== 0) { - throw new Error(`${command} ${args.join(" ")} for ${directoryName} failed: ${res.stdout && res.stdout.toString()}`); + throw new Error( + `${command} ${args.join(" ")} for ${directoryName} failed: ${ + res.stdout && res.stdout.toString() + }`, + ); } return options.stdio === "pipe" ? res.stdout.toString("utf8") : undefined; } @@ -112,7 +178,8 @@ namespace Harness { } report(result: ExecResult) { // eslint-disable-next-line no-null/no-null - return result.status === 0 && !result.stdout.length && !result.stderr.length ? null : `Exit Code: ${result.status} + return result.status === 0 && !result.stdout.length && !result.stderr.length ? null + : `Exit Code: ${result.status} Standard output: ${sortErrors(stripAbsoluteImportPaths(result.stdout.toString().replace(/\r\n/g, "\n")))} @@ -145,7 +212,12 @@ ${stripAbsoluteImportPaths(result.stderr.toString().replace(/\r\n/g, "\n"))}`; const imageName = `tstest/${directory}`; cls.exec("docker", ["build", "--no-cache", ".", "-t", imageName], { cwd }); // --no-cache so the latest version of the repos referenced is always fetched const cp: typeof import("child_process") = require("child_process"); - Baseline.runBaseline(`${cls.kind()}/${directory}.log`, cls.report(cp.spawnSync(`docker`, ["run", imageName], { cwd, timeout: cls.timeout, shell: true }))); + Baseline.runBaseline( + `${cls.kind()}/${directory}.log`, + cls.report( + cp.spawnSync(`docker`, ["run", imageName], { cwd, timeout: cls.timeout, shell: true }), + ), + ); }); } }); @@ -155,14 +227,22 @@ ${stripAbsoluteImportPaths(result.stderr.toString().replace(/\r\n/g, "\n"))}`; private exec(command: string, args: string[], options: { cwd: string; }): void { const cp: typeof import("child_process") = require("child_process"); const stdio = isWorker ? "pipe" : "inherit"; - const res = cp.spawnSync(isWorker ? `${command} 2>&1` : command, args, { timeout: this.timeout, shell: true, stdio, ...options }); + const res = cp.spawnSync(isWorker ? `${command} 2>&1` : command, args, { + timeout: this.timeout, + shell: true, + stdio, + ...options, + }); if (res.status !== 0) { - throw new Error(`${command} ${args.join(" ")} for ${options.cwd} failed: ${res.stdout && res.stdout.toString()}`); + throw new Error( + `${command} ${args.join(" ")} for ${options.cwd} failed: ${res.stdout && res.stdout.toString()}`, + ); } } report(result: ExecResult) { // eslint-disable-next-line no-null/no-null - return result.status === 0 && !result.stdout.length && !result.stderr.length ? null : `Exit Code: ${result.status} + return result.status === 0 && !result.stdout.length && !result.stderr.length ? null + : `Exit Code: ${result.status} Standard output: ${sanitizeDockerfileOutput(result.stdout.toString())} @@ -268,11 +348,11 @@ ${sanitizeDockerfileOutput(result.stderr.toString())}`; } const [, errorFileA, lineNumberStringA, columnNumberStringA, remainderA] = matchA; const [, errorFileB, lineNumberStringB, columnNumberStringB, remainderB] = matchB; - return ts.comparePathsCaseSensitive(errorFileA, errorFileB) || - ts.compareValues(parseInt(lineNumberStringA), parseInt(lineNumberStringB)) || - ts.compareValues(parseInt(columnNumberStringA), parseInt(columnNumberStringB)) || - ts.compareStringsCaseSensitive(remainderA, remainderB) || - ts.compareStringsCaseSensitive(a.slice(1).join("\n"), b.slice(1).join("\n")); + return ts.comparePathsCaseSensitive(errorFileA, errorFileB) + || ts.compareValues(parseInt(lineNumberStringA), parseInt(lineNumberStringB)) + || ts.compareValues(parseInt(columnNumberStringA), parseInt(columnNumberStringB)) + || ts.compareStringsCaseSensitive(remainderA, remainderB) + || ts.compareStringsCaseSensitive(a.slice(1).join("\n"), b.slice(1).join("\n")); } export class DefinitelyTypedRunner extends ExternalCompileRunnerBase { diff --git a/src/testRunner/parallel/host.ts b/src/testRunner/parallel/host.ts index 47d9c010d7bda..e40b79d99cc0a 100644 --- a/src/testRunner/parallel/host.ts +++ b/src/testRunner/parallel/host.ts @@ -14,7 +14,9 @@ namespace Harness.Parallel.Host { const { statSync } = require("fs") as typeof import("fs"); // NOTE: paths for module and types for FailedTestReporter _do not_ line up due to our use of --outFile for run.js - const FailedTestReporter = require(Utils.findUpFile("scripts/failed-tests.cjs")) as typeof import("../../../scripts/failed-tests.cjs"); + const FailedTestReporter = require( + Utils.findUpFile("scripts/failed-tests.cjs"), + ) as typeof import("../../../scripts/failed-tests.cjs"); const perfdataFileNameFragment = ".parallelperf"; const perfData = readSavedPerfData(configOption); @@ -111,7 +113,13 @@ namespace Harness.Parallel.Host { this._enabled = false; } } - update(index: number, percentComplete: number, color: string, title: string | undefined, titleColor?: string) { + update( + index: number, + percentComplete: number, + color: string, + title: string | undefined, + titleColor?: string, + ) { percentComplete = minMax(percentComplete, 0, 1); const progressBar = this._progressBars[index] || (this._progressBars[index] = {}); @@ -187,7 +195,10 @@ namespace Harness.Parallel.Host { } function startDelayed(perfData: { [testHash: string]: number; } | undefined, totalCost: number) { - console.log(`Discovered ${tasks.length} unittest suites` + (newTasks.length ? ` and ${newTasks.length} new suites.` : ".")); + console.log( + `Discovered ${tasks.length} unittest suites` + + (newTasks.length ? ` and ${newTasks.length} new suites.` : "."), + ); console.log("Discovering runner-based tests..."); const discoverStart = +(new Date()); for (const runner of runners) { @@ -201,7 +212,9 @@ namespace Harness.Parallel.Host { catch { // May be a directory try { - size = IO.listFiles(path.join(runner.workingDirectory, file), /.*/g, { recursive: true }).reduce((acc, elem) => acc + statSync(elem).size, 0); + size = IO.listFiles(path.join(runner.workingDirectory, file), /.*/g, { + recursive: true, + }).reduce((acc, elem) => acc + statSync(elem).size, 0); } catch { // Unknown test kind, just return 0 and let the historical analysis take over after one run @@ -250,7 +263,13 @@ namespace Harness.Parallel.Host { let closedWorkers = 0; for (let i = 0; i < workerCount; i++) { // TODO: Just send the config over the IPC channel or in the command line arguments - const config: TestConfig = { light: lightMode, listenForWork: true, runUnitTests: Harness.runUnitTests, stackTraceLimit: Harness.stackTraceLimit, timeout: globalTimeout }; // eslint-disable-line @typescript-eslint/no-unnecessary-qualifier + const config: TestConfig = { + light: lightMode, + listenForWork: true, + runUnitTests: Harness.runUnitTests, + stackTraceLimit: Harness.stackTraceLimit, + timeout: globalTimeout, + }; // eslint-disable-line @typescript-eslint/no-unnecessary-qualifier const configPath = ts.combinePaths(taskConfigsFolder, `task-config${i}.json`); IO.writeFile(configPath, JSON.stringify(config)); const worker: Worker = { @@ -267,7 +286,12 @@ namespace Harness.Parallel.Host { worker.process.stdout!.on("data", appendOutput); const killChild = (timeout: TaskTimeout) => { worker.process.kill(); - console.error(`Worker exceeded ${timeout.duration}ms timeout ${worker.currentTasks && worker.currentTasks.length ? `while running test '${worker.currentTasks[0].file}'.` : `during test setup.`}`); + console.error( + `Worker exceeded ${timeout.duration}ms timeout ${ + worker.currentTasks && worker.currentTasks.length + ? `while running test '${worker.currentTasks[0].file}'.` : `during test setup.` + }`, + ); return process.exit(2); }; worker.process.on("error", err => { @@ -285,9 +309,13 @@ namespace Harness.Parallel.Host { worker.process.on("message", (data: ParallelClientMessage) => { switch (data.type) { case "error": { - console.error(`Test worker encountered unexpected error${data.payload.name ? ` during the execution of test ${data.payload.name}` : ""} and was forced to close: + console.error( + `Test worker encountered unexpected error${ + data.payload.name ? ` during the execution of test ${data.payload.name}` : "" + } and was forced to close: Message: ${data.payload.error} - Stack: ${data.payload.stack}`); + Stack: ${data.payload.stack}`, + ); return process.exit(2); } case "timeout": { @@ -319,14 +347,19 @@ namespace Harness.Parallel.Host { passingResults = passingResults.concat(data.payload.passes); passingFiles++; } - newPerfData[hashName(data.payload.task.runner, data.payload.task.file)] = data.payload.duration; + newPerfData[hashName(data.payload.task.runner, data.payload.task.file)] = + data.payload.duration; const progress = (failingFiles + passingFiles) / totalFiles; if (progress >= nextProgress) { while (nextProgress < progress) { nextProgress += progressUpdateInterval; } - updateProgress(progress, errorResults.length ? `${errorResults.length} failing` : `${totalPassing} passing`, errorResults.length ? "fail" : undefined); + updateProgress( + progress, + errorResults.length ? `${errorResults.length} failing` : `${totalPassing} passing`, + errorResults.length ? "fail" : undefined, + ); } if (data.type === "result") { @@ -361,14 +394,18 @@ namespace Harness.Parallel.Host { // It's only really worth doing an initial batching if there are a ton of files to go through (and they have estimates) if (totalFiles > 1000 && batchSize > 0) { console.log("Batching initial test lists..."); - const batches: { runner: TestRunnerKind | "unittest"; file: string; size: number; }[][] = new Array(batchCount); + const batches: { runner: TestRunnerKind | "unittest"; file: string; size: number; }[][] = new Array( + batchCount, + ); const doneBatching = new Array(batchCount); let scheduledTotal = 0; batcher: while (true) { for (let i = 0; i < batchCount; i++) { if (tasks.length <= workerCount) { // Keep a small reserve even in the suboptimally packed case - console.log(`Suboptimal packing detected: no tests remain to be stolen. Reduce packing fraction from ${packfraction} to fix.`); + console.log( + `Suboptimal packing detected: no tests remain to be stolen. Reduce packing fraction from ${packfraction} to fix.`, + ); break batcher; } if (doneBatching[i]) { @@ -398,7 +435,11 @@ namespace Harness.Parallel.Host { console.log(`${prefix}. Unprofiled tests including ${unknownValue} will be run first.`); } else { - console.log(`${prefix} with approximate total ${perfData ? "time" : "file sizes"} of ${perfData ? ms(batchSize) : `${Math.floor(batchSize)} bytes`} in each group. (${(scheduledTotal / totalCost * 100).toFixed(1)}% of total tests batched)`); + console.log( + `${prefix} with approximate total ${perfData ? "time" : "file sizes"} of ${ + perfData ? ms(batchSize) : `${Math.floor(batchSize)} bytes` + } in each group. (${(scheduledTotal / totalCost * 100).toFixed(1)}% of total tests batched)`, + ); } for (const worker of workers) { const payload = batches.pop(); @@ -432,12 +473,15 @@ namespace Harness.Parallel.Host { const summaryColor = isPartitionFail ? "fail" : "green"; const summarySymbol = isPartitionFail ? Base.symbols.err : Base.symbols.ok; - const summaryTests = (isPartitionFail ? totalPassing + "/" + (errorResults.length + totalPassing) : totalPassing) + " passing"; + const summaryTests = + (isPartitionFail ? totalPassing + "/" + (errorResults.length + totalPassing) : totalPassing) + + " passing"; const summaryDuration = "(" + ms(duration) + ")"; const savedUseColors = Base.useColors; Base.useColors = !noColors; - const summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + color("light", summaryDuration); + const summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + + color("light", summaryDuration); Base.useColors = savedUseColors; updateProgress(1, summary); @@ -522,7 +566,11 @@ namespace Harness.Parallel.Host { function replayTest(runner: Mocha.Runner, test: RemoteTest) { runner.emit("test", test); if (test.isFailed()) { - runner.emit("fail", test, "error" in test.info ? rebuildError(test.info) : new Error("Unknown error")); // eslint-disable-line local/no-in-operator + runner.emit( + "fail", + test, + "error" in test.info ? rebuildError(test.info) : new Error("Unknown error"), + ); // eslint-disable-line local/no-in-operator } else { runner.emit("pass", test); diff --git a/src/testRunner/parallel/shared.ts b/src/testRunner/parallel/shared.ts index 913f3bfd5c67a..600ab5ac7572a 100644 --- a/src/testRunner/parallel/shared.ts +++ b/src/testRunner/parallel/shared.ts @@ -71,7 +71,11 @@ namespace Harness.Parallel { payload: TaskTimeout; } - export type ParallelClientMessage = ParallelErrorMessage | ParallelResultMessage | ParallelBatchProgressMessage | ParallelTimeoutChangeMessage; + export type ParallelClientMessage = + | ParallelErrorMessage + | ParallelResultMessage + | ParallelBatchProgressMessage + | ParallelTimeoutChangeMessage; export function shimNoopTestInterface(global: Mocha.MochaGlobals) { global.before = ts.noop; diff --git a/src/testRunner/parallel/worker.ts b/src/testRunner/parallel/worker.ts index a08b7a01e3645..fcdc309691c14 100644 --- a/src/testRunner/parallel/worker.ts +++ b/src/testRunner/parallel/worker.ts @@ -98,16 +98,28 @@ namespace Harness.Parallel.Worker { */ function shimTestInterface(rootSuite: Mocha.Suite, context: Mocha.MochaGlobals) { const suites = [rootSuite]; - context.before = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => suites[0].beforeAll(title as string, fn); - context.after = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => suites[0].afterAll(title as string, fn); - context.beforeEach = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => suites[0].beforeEach(title as string, fn); - context.afterEach = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => suites[0].afterEach(title as string, fn); - context.describe = context.context = ((title: string, fn: (this: Mocha.Suite) => void) => addSuite(title, fn)) as Mocha.SuiteFunction; - context.describe.skip = context.xdescribe = context.xcontext = (title: string) => addSuite(title, /*fn*/ undefined); + context.before = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + suites[0].beforeAll(title as string, fn); + context.after = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + suites[0].afterAll(title as string, fn); + context.beforeEach = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + suites[0].beforeEach(title as string, fn); + context.afterEach = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + suites[0].afterEach(title as string, fn); + context.describe = + context.context = + ((title: string, fn: (this: Mocha.Suite) => void) => addSuite(title, fn)) as Mocha.SuiteFunction; + context.describe.skip = context.xdescribe = context.xcontext = (title: string) => + addSuite(title, /*fn*/ undefined); context.describe.only = (title: string, fn?: (this: Mocha.Suite) => void) => addSuite(title, fn); - context.it = context.specify = ((title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => addTest(title, fn)) as Mocha.TestFunction; - context.it.skip = context.xit = context.xspecify = (title: string | Mocha.Func | Mocha.AsyncFunc) => addTest(typeof title === "function" ? title.name : title, /*fn*/ undefined); - context.it.only = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => addTest(title, fn); + context.it = + context.specify = + ((title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + addTest(title, fn)) as Mocha.TestFunction; + context.it.skip = context.xit = context.xspecify = (title: string | Mocha.Func | Mocha.AsyncFunc) => + addTest(typeof title === "function" ? title.name : title, /*fn*/ undefined); + context.it.only = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + addTest(title, fn); function addSuite(title: string, fn: ((this: Mocha.Suite) => void) | undefined): Mocha.Suite { const suite = new Suite(title, suites[0].ctx); @@ -121,7 +133,10 @@ namespace Harness.Parallel.Worker { return suite; } - function addTest(title: string | Mocha.Func | Mocha.AsyncFunc, fn: Mocha.Func | Mocha.AsyncFunc | undefined): Mocha.Test { + function addTest( + title: string | Mocha.Func | Mocha.AsyncFunc, + fn: Mocha.Func | Mocha.AsyncFunc | undefined, + ): Mocha.Test { if (typeof title === "function") { fn = title; title = fn.name; @@ -165,7 +180,9 @@ namespace Harness.Parallel.Worker { let suite = unitTestSuiteMap.get(task.file); const test = unitTestTestMap.get(task.file); if (!suite && !test) { - throw new Error(`Unit test with name "${task.file}" was asked to be run, but such a test does not exist!`); + throw new Error( + `Unit test with name "${task.file}" was asked to be run, but such a test does not exist!`, + ); } const root = new Suite("", new Mocha.Context()); diff --git a/src/testRunner/projectsRunner.ts b/src/testRunner/projectsRunner.ts index 004be47a324b5..29a3a59c95124 100644 --- a/src/testRunner/projectsRunner.ts +++ b/src/testRunner/projectsRunner.ts @@ -54,21 +54,29 @@ namespace project { private runProjectTestCase(testCaseFileName: string) { for (const { name, payload } of ProjectTestCase.getConfigurations(testCaseFileName)) { - describe("Compiling project for " + payload.testCase.scenario + ": testcase " + testCaseFileName + (name ? ` (${name})` : ``), () => { - let projectTestCase: ProjectTestCase | undefined; - before(() => { - projectTestCase = new ProjectTestCase(testCaseFileName, payload); - }); - it(`Correct module resolution tracing for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifyResolution()); - it(`Correct errors for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifyDiagnostics()); - it(`Correct JS output for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifyJavaScriptOutput()); - // NOTE: This check was commented out in previous code. Leaving this here to eventually be restored if needed. - // it(`Correct sourcemap content for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifySourceMapRecord()); - it(`Correct declarations for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifyDeclarations()); - after(() => { - projectTestCase = undefined; - }); - }); + describe( + "Compiling project for " + payload.testCase.scenario + ": testcase " + testCaseFileName + + (name ? ` (${name})` : ``), + () => { + let projectTestCase: ProjectTestCase | undefined; + before(() => { + projectTestCase = new ProjectTestCase(testCaseFileName, payload); + }); + it(`Correct module resolution tracing for ${testCaseFileName}`, () => + projectTestCase && projectTestCase.verifyResolution()); + it(`Correct errors for ${testCaseFileName}`, () => + projectTestCase && projectTestCase.verifyDiagnostics()); + it(`Correct JS output for ${testCaseFileName}`, () => + projectTestCase && projectTestCase.verifyJavaScriptOutput()); + // NOTE: This check was commented out in previous code. Leaving this here to eventually be restored if needed. + // it(`Correct sourcemap content for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifySourceMapRecord()); + it(`Correct declarations for ${testCaseFileName}`, () => + projectTestCase && projectTestCase.verifyDeclarations()); + after(() => { + projectTestCase = undefined; + }); + }, + ); } } } @@ -77,13 +85,20 @@ namespace project { private _testCase: ProjectRunnerTestCase & ts.CompilerOptions; private _projectParseConfigHost: ProjectParseConfigHost | undefined; - constructor(sys: fakes.System | vfs.FileSystem, compilerOptions: ts.CompilerOptions, _testCaseJustName: string, testCase: ProjectRunnerTestCase & ts.CompilerOptions, _moduleKind: ts.ModuleKind) { + constructor( + sys: fakes.System | vfs.FileSystem, + compilerOptions: ts.CompilerOptions, + _testCaseJustName: string, + testCase: ProjectRunnerTestCase & ts.CompilerOptions, + _moduleKind: ts.ModuleKind, + ) { super(sys, compilerOptions); this._testCase = testCase; } public get parseConfigHost(): fakes.ParseConfigHost { - return this._projectParseConfigHost || (this._projectParseConfigHost = new ProjectParseConfigHost(this.sys, this._testCase)); + return this._projectParseConfigHost + || (this._projectParseConfigHost = new ProjectParseConfigHost(this.sys, this._testCase)); } public getDefaultLibFileName(_options: ts.CompilerOptions) { @@ -99,7 +114,13 @@ namespace project { this._testCase = testCase; } - public readDirectory(path: string, extensions: string[], excludes: string[], includes: string[], depth: number): string[] { + public readDirectory( + path: string, + extensions: string[], + excludes: string[], + includes: string[], + depth: number, + ): string[] { const result = super.readDirectory(path, extensions, excludes, includes, depth); const projectRoot = vpath.resolve(vfs.srcFolder, this._testCase.projectRoot); return result.map(item => @@ -141,7 +162,10 @@ namespace project { if (this.compilerOptions.project) { // Parse project configFileName = ts.normalizePath(ts.combinePaths(this.compilerOptions.project, "tsconfig.json")); - assert(!inputFiles || inputFiles.length === 0, "cannot specify input files and project option together"); + assert( + !inputFiles || inputFiles.length === 0, + "cannot specify input files and project option together", + ); } else if (!inputFiles || inputFiles.length === 0) { configFileName = ts.findConfigFile("", path => this.sys.fileExists(path)); @@ -153,14 +177,31 @@ namespace project { const result = ts.readJsonConfigFile(configFileName, path => this.sys.readFile(path)); configFileSourceFiles.push(result); const configParseHost = new ProjectParseConfigHost(this.sys, this.testCase); - const configParseResult = ts.parseJsonSourceFileConfigFileContent(result, configParseHost, ts.getDirectoryPath(configFileName), this.compilerOptions); + const configParseResult = ts.parseJsonSourceFileConfigFileContent( + result, + configParseHost, + ts.getDirectoryPath(configFileName), + this.compilerOptions, + ); inputFiles = configParseResult.fileNames; this.compilerOptions = configParseResult.options; errors = [...result.parseDiagnostics, ...configParseResult.errors]; } - const compilerHost = new ProjectCompilerHost(this.sys, this.compilerOptions, this.testCaseJustName, this.testCase, moduleKind); - const projectCompilerResult = this.compileProjectFiles(moduleKind, configFileSourceFiles, () => inputFiles, compilerHost, this.compilerOptions); + const compilerHost = new ProjectCompilerHost( + this.sys, + this.compilerOptions, + this.testCaseJustName, + this.testCase, + moduleKind, + ); + const projectCompilerResult = this.compileProjectFiles( + moduleKind, + configFileSourceFiles, + () => inputFiles, + compilerHost, + this.compilerOptions, + ); this.compilerResult = { configFileSourceFiles, @@ -192,11 +233,18 @@ namespace project { testCase = JSON.parse(testFileText!) as ProjectRunnerTestCase & ts.CompilerOptions; } catch (e) { - throw assert(false, "Testcase: " + testCaseFileName + " does not contain valid json format: " + e.message); + throw assert( + false, + "Testcase: " + testCaseFileName + " does not contain valid json format: " + e.message, + ); } const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false); - fs.mountSync(vpath.resolve(Harness.IO.getWorkspaceRoot(), "tests"), vpath.combine(vfs.srcFolder, "tests"), vfs.createResolver(Harness.IO)); + fs.mountSync( + vpath.resolve(Harness.IO.getWorkspaceRoot(), "tests"), + vpath.combine(vfs.srcFolder, "tests"), + vfs.createResolver(Harness.IO), + ); fs.mkdirpSync(vpath.combine(vfs.srcFolder, testCase.projectRoot)); fs.chdir(vpath.combine(vfs.srcFolder, testCase.projectRoot)); fs.makeReadonly(); @@ -210,25 +258,39 @@ namespace project { public verifyResolution() { const cwd = this.vfs.cwd(); const ignoreCase = this.vfs.ignoreCase; - const resolutionInfo: ProjectRunnerTestCaseResolutionInfo & ts.CompilerOptions = JSON.parse(JSON.stringify(this.testCase)); + const resolutionInfo: ProjectRunnerTestCaseResolutionInfo & ts.CompilerOptions = JSON.parse( + JSON.stringify(this.testCase), + ); resolutionInfo.resolvedInputFiles = this.compilerResult.program!.getSourceFiles() .map(({ fileName: input }) => - vpath.beneath(vfs.builtFolder, input, this.vfs.ignoreCase) || vpath.beneath(vfs.testLibFolder, input, this.vfs.ignoreCase) ? Utils.removeTestPathPrefixes(input) : - vpath.isAbsolute(input) ? vpath.relative(cwd, input, ignoreCase) : - input + vpath.beneath(vfs.builtFolder, input, this.vfs.ignoreCase) + || vpath.beneath(vfs.testLibFolder, input, this.vfs.ignoreCase) + ? Utils.removeTestPathPrefixes(input) + : vpath.isAbsolute(input) ? vpath.relative(cwd, input, ignoreCase) + : input ); resolutionInfo.emittedFiles = this.compilerResult.outputFiles! .map(output => output.meta.get("fileName") || output.file) - .map(output => Utils.removeTestPathPrefixes(vpath.isAbsolute(output) ? vpath.relative(cwd, output, ignoreCase) : output)); + .map(output => + Utils.removeTestPathPrefixes( + vpath.isAbsolute(output) ? vpath.relative(cwd, output, ignoreCase) : output, + ) + ); const content = JSON.stringify(resolutionInfo, undefined, " "); - Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".json", content); + Harness.Baseline.runBaseline( + this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".json", + content, + ); } public verifyDiagnostics() { if (this.compilerResult.errors.length) { - Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".errors.txt", getErrorsBaseline(this.compilerResult)); + Harness.Baseline.runBaseline( + this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".errors.txt", + getErrorsBaseline(this.compilerResult), + ); } } @@ -241,7 +303,8 @@ namespace project { // convert file name to rooted name // if filename is not rooted - concat it with project root and then expand project root relative to current directory const fileName = output.meta.get("fileName") || output.file; - const diskFileName = vpath.isAbsolute(fileName) ? fileName : vpath.resolve(this.vfs.cwd(), fileName); + const diskFileName = vpath.isAbsolute(fileName) ? fileName + : vpath.resolve(this.vfs.cwd(), fileName); // compute file name relative to current directory (expanded project root) let diskRelativeName = vpath.relative(this.vfs.cwd(), diskFileName, this.vfs.ignoreCase); @@ -249,12 +312,20 @@ namespace project { // If the generated output file resides in the parent folder or is rooted path, // we need to instead create files that can live in the project reference folder // but make sure extension of these files matches with the fileName the compiler asked to write - diskRelativeName = `diskFile${nonSubfolderDiskFiles}${vpath.extname(fileName, [".js.map", ".js", ".d.ts"], this.vfs.ignoreCase)}`; + diskRelativeName = `diskFile${nonSubfolderDiskFiles}${ + vpath.extname(fileName, [".js.map", ".js", ".d.ts"], this.vfs.ignoreCase) + }`; nonSubfolderDiskFiles++; } - const content = Utils.removeTestPathPrefixes(output.text, /*retainTrailingDirectorySeparator*/ true); - Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + diskRelativeName, content as string | null); // TODO: GH#18217 + const content = Utils.removeTestPathPrefixes( + output.text, + /*retainTrailingDirectorySeparator*/ true, + ); + Harness.Baseline.runBaseline( + this.getBaselineFolder(this.compilerResult.moduleKind) + diskRelativeName, + content as string | null, + ); // TODO: GH#18217 } catch (e) { errs.push(e); @@ -281,7 +352,11 @@ namespace project { if (!this.compilerResult.errors.length && this.testCase.declaration) { const dTsCompileResult = this.compileDeclarations(this.compilerResult); if (dTsCompileResult && dTsCompileResult.errors.length) { - Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".dts.errors.txt", getErrorsBaseline(dTsCompileResult)); + Harness.Baseline.runBaseline( + this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + + ".dts.errors.txt", + getErrorsBaseline(dTsCompileResult), + ); } } } @@ -314,7 +389,13 @@ namespace project { return url; } - private compileProjectFiles(moduleKind: ts.ModuleKind, configFileSourceFiles: readonly ts.SourceFile[], getInputFiles: () => readonly string[], compilerHost: ts.CompilerHost, compilerOptions: ts.CompilerOptions): CompileProjectFilesResult { + private compileProjectFiles( + moduleKind: ts.ModuleKind, + configFileSourceFiles: readonly ts.SourceFile[], + getInputFiles: () => readonly string[], + compilerHost: ts.CompilerHost, + compilerOptions: ts.CompilerOptions, + ): CompileProjectFilesResult { const program = ts.createProgram(getInputFiles(), compilerOptions, compilerHost); const errors = ts.getPreEmitDiagnostics(program); @@ -358,9 +439,14 @@ namespace project { else if (!(compilerOptions.outFile || compilerOptions.out)) { let emitOutputFilePathWithoutExtension: string | undefined; if (compilerOptions.outDir) { - let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, compilerResult.program!.getCurrentDirectory()); + let sourceFilePath = ts.getNormalizedAbsolutePath( + sourceFile.fileName, + compilerResult.program!.getCurrentDirectory(), + ); sourceFilePath = sourceFilePath.replace(compilerResult.program!.getCommonSourceDirectory(), ""); - emitOutputFilePathWithoutExtension = ts.removeFileExtension(ts.combinePaths(compilerOptions.outDir, sourceFilePath)); + emitOutputFilePathWithoutExtension = ts.removeFileExtension( + ts.combinePaths(compilerOptions.outDir, sourceFilePath), + ); } else { emitOutputFilePathWithoutExtension = ts.removeFileExtension(sourceFile.fileName); @@ -374,7 +460,8 @@ namespace project { } } else { - const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out!) + ts.Extension.Dts; + const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out!) + + ts.Extension.Dts; const outputDtsFile = findOutputDtsFile(outputDtsFileName)!; if (!ts.contains(allInputFiles, outputDtsFile)) { allInputFiles.unshift(outputDtsFile); @@ -389,18 +476,33 @@ namespace project { }); // Dont allow config files since we are compiling existing source options - const compilerHost = new ProjectCompilerHost(_vfs, compilerResult.compilerOptions!, this.testCaseJustName, this.testCase, compilerResult.moduleKind); - return this.compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, () => rootFiles, compilerHost, compilerResult.compilerOptions!); + const compilerHost = new ProjectCompilerHost( + _vfs, + compilerResult.compilerOptions!, + this.testCaseJustName, + this.testCase, + compilerResult.moduleKind, + ); + return this.compileProjectFiles( + compilerResult.moduleKind, + compilerResult.configFileSourceFiles, + () => rootFiles, + compilerHost, + compilerResult.compilerOptions!, + ); function findOutputDtsFile(fileName: string) { - return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.meta.get("fileName") === fileName ? outputFile : undefined); + return ts.forEach( + compilerResult.outputFiles, + outputFile => outputFile.meta.get("fileName") === fileName ? outputFile : undefined, + ); } } } function moduleNameToString(moduleKind: ts.ModuleKind) { - return moduleKind === ts.ModuleKind.AMD ? "amd" : - moduleKind === ts.ModuleKind.CommonJS ? "node" : "none"; + return moduleKind === ts.ModuleKind.AMD ? "amd" + : moduleKind === ts.ModuleKind.CommonJS ? "node" : "none"; } function getErrorsBaseline(compilerResult: CompileProjectFilesResult) { @@ -414,9 +516,9 @@ namespace project { } const inputFiles = inputSourceFiles.map(sourceFile => ({ - unitName: ts.isRootedDiskPath(sourceFile.fileName) ? - Harness.RunnerBase.removeFullPaths(sourceFile.fileName) : - sourceFile.fileName, + unitName: ts.isRootedDiskPath(sourceFile.fileName) + ? Harness.RunnerBase.removeFullPaths(sourceFile.fileName) + : sourceFile.fileName, content: sourceFile.text, })); diff --git a/src/testRunner/rwcRunner.ts b/src/testRunner/rwcRunner.ts index 2a71db4df08eb..d6e104f9b8faa 100644 --- a/src/testRunner/rwcRunner.ts +++ b/src/testRunner/rwcRunner.ts @@ -51,7 +51,11 @@ namespace RWC { this.timeout(800_000); // Allow long timeouts for RWC compilations let opts!: ts.ParsedCommandLine; - const ioLog: Playback.IoLog = Playback.newStyleLogIntoOldStyleLog(JSON.parse(Harness.IO.readFile(`internal/cases/rwc/${jsonPath}/test.json`)!), Harness.IO, `internal/cases/rwc/${baseName}`); + const ioLog: Playback.IoLog = Playback.newStyleLogIntoOldStyleLog( + JSON.parse(Harness.IO.readFile(`internal/cases/rwc/${jsonPath}/test.json`)!), + Harness.IO, + `internal/cases/rwc/${baseName}`, + ); currentDirectory = ioLog.currentDirectory; useCustomLibraryFile = !!ioLog.useCustomLibraryFile; runWithIOLog(ioLog, () => { @@ -69,14 +73,21 @@ namespace RWC { if (tsconfigFile) { const tsconfigFileContents = getHarnessCompilerInputUnit(tsconfigFile.path); tsconfigFiles.push({ unitName: tsconfigFile.path, content: tsconfigFileContents.content }); - const parsedTsconfigFileContents = ts.parseJsonText(tsconfigFile.path, tsconfigFileContents.content); + const parsedTsconfigFileContents = ts.parseJsonText( + tsconfigFile.path, + tsconfigFileContents.content, + ); const configParseHost: ts.ParseConfigHost = { useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(), fileExists: Harness.IO.fileExists, readDirectory: Harness.IO.readDirectory, readFile: Harness.IO.readFile, }; - const configParseResult = ts.parseJsonSourceFileConfigFileContent(parsedTsconfigFileContents, configParseHost, ts.getDirectoryPath(tsconfigFile.path)); + const configParseResult = ts.parseJsonSourceFileConfigFileContent( + parsedTsconfigFileContents, + configParseHost, + ts.getDirectoryPath(tsconfigFile.path), + ); fileNames = configParseResult.fileNames; opts.options = ts.extend(opts.options, configParseResult.options); ts.setConfigFileInOptions(opts.options, configParseResult.options.configFile); @@ -101,7 +112,10 @@ namespace RWC { uniqueNames.set(unitName, true); otherFiles.push(getHarnessCompilerInputUnit(fileRead.path)); } - else if (!opts.options.noLib && Harness.isDefaultLibraryFile(fileRead.path) && !uniqueNames.has(unitName) && useCustomLibraryFile) { + else if ( + !opts.options.noLib && Harness.isDefaultLibraryFile(fileRead.path) + && !uniqueNames.has(unitName) && useCustomLibraryFile + ) { // If useCustomLibraryFile is true, we will use lib.d.ts from json object // otherwise use the lib.d.ts from built/local // Majority of RWC code will be using built/local/lib.d.ts instead of @@ -196,9 +210,16 @@ namespace RWC { return null; // eslint-disable-line no-null/no-null } // Do not include the library in the baselines to avoid noise - const baselineFiles = tsconfigFiles.concat(inputFiles, otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName)); - const errors = compilerResult.diagnostics.filter(e => !e.file || !Harness.isDefaultLibraryFile(e.file.fileName)); - return Harness.Compiler.iterateErrorBaseline(baselineFiles, errors, { caseSensitive, currentDirectory }); + const baselineFiles = tsconfigFiles.concat(inputFiles, otherFiles).filter(f => + !Harness.isDefaultLibraryFile(f.unitName) + ); + const errors = compilerResult.diagnostics.filter(e => + !e.file || !Harness.isDefaultLibraryFile(e.file.fileName) + ); + return Harness.Compiler.iterateErrorBaseline(baselineFiles, errors, { + caseSensitive, + currentDirectory, + }); }, baselineOpts); }); @@ -224,7 +245,14 @@ namespace RWC { compilerResult = undefined!; const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declContext, links)!; - return Harness.Compiler.iterateErrorBaseline(tsconfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.diagnostics, { caseSensitive, currentDirectory }); + return Harness.Compiler.iterateErrorBaseline( + tsconfigFiles.concat( + declFileCompilationResult.declInputFiles, + declFileCompilationResult.declOtherFiles, + ), + declFileCompilationResult.declResult.diagnostics, + { caseSensitive, currentDirectory }, + ); }, baselineOpts); } }); diff --git a/src/testRunner/test262Runner.ts b/src/testRunner/test262Runner.ts index 274b89da1317f..dea2c657e97b5 100644 --- a/src/testRunner/test262Runner.ts +++ b/src/testRunner/test262Runner.ts @@ -63,25 +63,44 @@ namespace Harness { }); it("has the expected emitted code", () => { - const files = Array.from(testState.compilerResult.js.values()).filter(f => f.file !== Test262BaselineRunner.helpersFilePath); - Baseline.runBaseline(testState.filename + ".output.js", Compiler.collateOutputs(files), Test262BaselineRunner.baselineOptions); + const files = Array.from(testState.compilerResult.js.values()).filter(f => + f.file !== Test262BaselineRunner.helpersFilePath + ); + Baseline.runBaseline( + testState.filename + ".output.js", + Compiler.collateOutputs(files), + Test262BaselineRunner.baselineOptions, + ); }); it("has the expected errors", () => { const errors = testState.compilerResult.diagnostics; // eslint-disable-next-line no-null/no-null - const baseline = errors.length === 0 ? null : Compiler.getErrorBaseline(testState.inputFiles, errors); - Baseline.runBaseline(testState.filename + ".errors.txt", baseline, Test262BaselineRunner.baselineOptions); + const baseline = errors.length === 0 ? null + : Compiler.getErrorBaseline(testState.inputFiles, errors); + Baseline.runBaseline( + testState.filename + ".errors.txt", + baseline, + Test262BaselineRunner.baselineOptions, + ); }); it("satisfies invariants", () => { - const sourceFile = testState.compilerResult.program!.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); + const sourceFile = testState.compilerResult.program!.getSourceFile( + Test262BaselineRunner.getTestFilePath(testState.filename), + ); Utils.assertInvariants(sourceFile, /*parent:*/ undefined); }); it("has the expected AST", () => { - const sourceFile = testState.compilerResult.program!.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename))!; - Baseline.runBaseline(testState.filename + ".AST.txt", Utils.sourceFileToJSON(sourceFile), Test262BaselineRunner.baselineOptions); + const sourceFile = testState.compilerResult.program!.getSourceFile( + Test262BaselineRunner.getTestFilePath(testState.filename), + )!; + Baseline.runBaseline( + testState.filename + ".AST.txt", + Utils.sourceFileToJSON(sourceFile), + Test262BaselineRunner.baselineOptions, + ); }); }); } @@ -92,7 +111,12 @@ namespace Harness { public enumerateTestFiles() { // see also: `enumerateTestFiles` in tests/webTestServer.ts - return ts.map(this.enumerateFiles(Test262BaselineRunner.basePath, Test262BaselineRunner.testFileExtensionRegex, { recursive: true }), ts.normalizePath); + return ts.map( + this.enumerateFiles(Test262BaselineRunner.basePath, Test262BaselineRunner.testFileExtensionRegex, { + recursive: true, + }), + ts.normalizePath, + ); } public initializeTests() { diff --git a/src/testRunner/unittests/asserts.ts b/src/testRunner/unittests/asserts.ts index 81d6686f56ced..c7d6056c1d2bd 100644 --- a/src/testRunner/unittests/asserts.ts +++ b/src/testRunner/unittests/asserts.ts @@ -1,9 +1,22 @@ namespace ts { describe("unittests:: assert", () => { it("deepEqual", () => { - assert.throws(() => assert.deepEqual(factory.createNodeArray([factory.createIdentifier("A")]), factory.createNodeArray([factory.createIdentifier("B")]))); - assert.throws(() => assert.deepEqual(factory.createNodeArray([], /*hasTrailingComma*/ true), factory.createNodeArray([], /*hasTrailingComma*/ false))); - assert.deepEqual(factory.createNodeArray([factory.createIdentifier("A")], /*hasTrailingComma*/ true), factory.createNodeArray([factory.createIdentifier("A")], /*hasTrailingComma*/ true)); + assert.throws(() => + assert.deepEqual( + factory.createNodeArray([factory.createIdentifier("A")]), + factory.createNodeArray([factory.createIdentifier("B")]), + ) + ); + assert.throws(() => + assert.deepEqual( + factory.createNodeArray([], /*hasTrailingComma*/ true), + factory.createNodeArray([], /*hasTrailingComma*/ false), + ) + ); + assert.deepEqual( + factory.createNodeArray([factory.createIdentifier("A")], /*hasTrailingComma*/ true), + factory.createNodeArray([factory.createIdentifier("A")], /*hasTrailingComma*/ true), + ); }); it("assertNever on string has correct error", () => { assert.throws(() => Debug.assertNever("hi" as never), 'Debug Failure. Illegal value: "hi"'); diff --git a/src/testRunner/unittests/builder.ts b/src/testRunner/unittests/builder.ts index ca92636ba50ba..5908f1044dd7b 100644 --- a/src/testRunner/unittests/builder.ts +++ b/src/testRunner/unittests/builder.ts @@ -85,7 +85,9 @@ namespace ts { }; } - function makeAssertChangesWithCancellationToken(getProgram: () => Program): (fileNames: readonly string[], cancelAfterEmitLength?: number) => void { + function makeAssertChangesWithCancellationToken( + getProgram: () => Program, + ): (fileNames: readonly string[], cancelAfterEmitLength?: number) => void { const host: BuilderProgramHost = { useCaseSensitiveFileNames: returnTrue }; let builderProgram: EmitAndSemanticDiagnosticsBuilderProgram | undefined; let cancel = false; @@ -110,7 +112,9 @@ namespace ts { cancel = true; } } - while (builderProgram.emitNextAffectedFile(fileName => outputFileNames.push(fileName), cancellationToken)); + while ( + builderProgram.emitNextAffectedFile(fileName => outputFileNames.push(fileName), cancellationToken) + ); } catch (e) { assert.isFalse(operationWasCancelled); @@ -123,7 +127,11 @@ namespace ts { }; } - function updateProgramFile(program: ProgramWithSourceTexts, fileName: string, fileContent: string): ProgramWithSourceTexts { + function updateProgramFile( + program: ProgramWithSourceTexts, + fileName: string, + fileContent: string, + ): ProgramWithSourceTexts { return updateProgram(program, program.getRootFileNames(), program.getCompilerOptions(), files => { updateProgramText(files, fileName, fileContent); }); diff --git a/src/testRunner/unittests/config/commandLineParsing.ts b/src/testRunner/unittests/config/commandLineParsing.ts index 31d63539610cc..64ae462dbcfc6 100644 --- a/src/testRunner/unittests/config/commandLineParsing.ts +++ b/src/testRunner/unittests/config/commandLineParsing.ts @@ -1,10 +1,17 @@ namespace ts { describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => { - function assertParseResult(subScenario: string, commandLine: string[], workerDiagnostic?: () => ParseCommandLineWorkerDiagnostics) { + function assertParseResult( + subScenario: string, + commandLine: string[], + workerDiagnostic?: () => ParseCommandLineWorkerDiagnostics, + ) { it(subScenario, () => { const baseline: string[] = []; baseline.push(commandLine.join(" ")); - const parsed = parseCommandLineWorker(workerDiagnostic?.() || compilerOptionsDidYouMeanDiagnostics, commandLine); + const parsed = parseCommandLineWorker( + workerDiagnostic?.() || compilerOptionsDidYouMeanDiagnostics, + commandLine, + ); baseline.push("CompilerOptions::"); baseline.push(JSON.stringify(parsed.options, /*replacer*/ undefined, " ")); baseline.push("WatchOptions::"); @@ -17,7 +24,10 @@ namespace ts { getCanonicalFileName: identity, getNewLine: () => "\n", })); - Harness.Baseline.runBaseline(`config/commandLineParsing/parseCommandLine/${subScenario}.js`, baseline.join("\n")); + Harness.Baseline.runBaseline( + `config/commandLineParsing/parseCommandLine/${subScenario}.js`, + baseline.join("\n"), + ); }); } @@ -46,17 +56,45 @@ namespace ts { // This test is an error because the empty string is falsey assertParseResult("Parse empty string of --lib", ["0.ts", "--lib", ""]); // 0.ts --lib - assertParseResult("Parse immediately following command line argument of --lib", ["0.ts", "--lib", "--sourcemap"]); + assertParseResult("Parse immediately following command line argument of --lib", [ + "0.ts", + "--lib", + "--sourcemap", + ]); // --lib es5, es7 0.ts assertParseResult("Parse --lib option with extra comma", ["--lib", "es5,", "es7", "0.ts"]); // --lib es5, es7 0.ts assertParseResult("Parse --lib option with trailing white-space", ["--lib", "es5, ", "es7", "0.ts"]); // --lib es5,es2015.symbol.wellknown --target es5 0.ts - assertParseResult("Parse multiple compiler flags with input files at the end", ["--lib", "es5,es2015.symbol.wellknown", "--target", "es5", "0.ts"]); + assertParseResult("Parse multiple compiler flags with input files at the end", [ + "--lib", + "es5,es2015.symbol.wellknown", + "--target", + "es5", + "0.ts", + ]); // --module commonjs --target es5 0.ts --lib es5,es2015.symbol.wellknown - assertParseResult("Parse multiple compiler flags with input files in the middle", ["--module", "commonjs", "--target", "es5", "0.ts", "--lib", "es5,es2015.symbol.wellknown"]); + assertParseResult("Parse multiple compiler flags with input files in the middle", [ + "--module", + "commonjs", + "--target", + "es5", + "0.ts", + "--lib", + "es5,es2015.symbol.wellknown", + ]); // --module commonjs --target es5 --lib es5 0.ts --library es2015.array,es2015.symbol.wellknown - assertParseResult("Parse multiple library compiler flags ", ["--module", "commonjs", "--target", "es5", "--lib", "es5", "0.ts", "--lib", "es2015.core, es2015.symbol.wellknown "]); + assertParseResult("Parse multiple library compiler flags ", [ + "--module", + "commonjs", + "--target", + "es5", + "--lib", + "es5", + "0.ts", + "--lib", + "es2015.core, es2015.symbol.wellknown ", + ]); assertParseResult("Parse explicit boolean flag value", ["--strictNullChecks", "false", "0.ts"]); assertParseResult("Parse non boolean argument after boolean flag", ["--noImplicitAny", "t", "0.ts"]); assertParseResult("Parse implicit boolean flag value", ["--strictNullChecks"]); @@ -176,7 +214,13 @@ namespace ts { }); }); - assertParseResult("allows tsconfig only option to be set to null", ["--composite", "null", "-tsBuildInfoFile", "null", "0.ts"]); + assertParseResult("allows tsconfig only option to be set to null", [ + "--composite", + "null", + "-tsBuildInfoFile", + "null", + "0.ts", + ]); describe("Watch options", () => { assertParseResult("parse --watchFile", ["--watchFile", "UseFsEvents", "0.ts"]); @@ -209,15 +253,33 @@ namespace ts { getCanonicalFileName: identity, getNewLine: () => "\n", })); - Harness.Baseline.runBaseline(`config/commandLineParsing/parseBuildOptions/${subScenario}.js`, baseline.join("\n")); + Harness.Baseline.runBaseline( + `config/commandLineParsing/parseBuildOptions/${subScenario}.js`, + baseline.join("\n"), + ); }); } assertParseResult("parse build without any options ", []); assertParseResult("Parse multiple options", ["--verbose", "--force", "tests"]); assertParseResult("Parse option with invalid option", ["--verbose", "--invalidOption"]); - assertParseResult("Parse multiple flags with input projects at the end", ["--force", "--verbose", "src", "tests"]); - assertParseResult("Parse multiple flags with input projects in the middle", ["--force", "src", "tests", "--verbose"]); - assertParseResult("Parse multiple flags with input projects in the beginning", ["src", "tests", "--force", "--verbose"]); + assertParseResult("Parse multiple flags with input projects at the end", [ + "--force", + "--verbose", + "src", + "tests", + ]); + assertParseResult("Parse multiple flags with input projects in the middle", [ + "--force", + "src", + "tests", + "--verbose", + ]); + assertParseResult("Parse multiple flags with input projects in the beginning", [ + "src", + "tests", + "--force", + "--verbose", + ]); assertParseResult("parse build with --incremental", ["--incremental", "tests"]); assertParseResult("parse build with --locale en-us", ["--locale", "en-us", "src"]); assertParseResult("parse build with --tsBuildInfoFile", ["--tsBuildInfoFile", "build.tsbuildinfo", "tests"]); diff --git a/src/testRunner/unittests/config/configurationExtension.ts b/src/testRunner/unittests/config/configurationExtension.ts index 274044eea8494..8bc0d8d3e4994 100644 --- a/src/testRunner/unittests/config/configurationExtension.ts +++ b/src/testRunner/unittests/config/configurationExtension.ts @@ -190,13 +190,20 @@ namespace ts { } const caseInsensitiveBasePath = "c:/dev/"; - const caseInsensitiveHost = new fakes.ParseConfigHost(createFileSystem(/*ignoreCase*/ true, caseInsensitiveBasePath, "c:/")); + const caseInsensitiveHost = new fakes.ParseConfigHost( + createFileSystem(/*ignoreCase*/ true, caseInsensitiveBasePath, "c:/"), + ); const caseSensitiveBasePath = "/dev/"; - const caseSensitiveHost = new fakes.ParseConfigHost(createFileSystem(/*ignoreCase*/ false, caseSensitiveBasePath, "/")); + const caseSensitiveHost = new fakes.ParseConfigHost( + createFileSystem(/*ignoreCase*/ false, caseSensitiveBasePath, "/"), + ); function verifyDiagnostics(actual: Diagnostic[], expected: { code: number; messageText: string; }[]) { - assert.isTrue(expected.length === actual.length, `Expected error: ${JSON.stringify(expected)}. Actual error: ${JSON.stringify(actual)}.`); + assert.isTrue( + expected.length === actual.length, + `Expected error: ${JSON.stringify(expected)}. Actual error: ${JSON.stringify(actual)}.`, + ); for (let i = 0; i < actual.length; i++) { const actualError = actual[i]; const expectedError = expected[i]; @@ -219,7 +226,13 @@ namespace ts { function getParseCommandLineJsonSourceFile(entry: string) { const jsonSourceFile = readJsonConfigFile(entry, name => host.readFile(name)); - assert(jsonSourceFile.endOfFileToken && !jsonSourceFile.parseDiagnostics.length, flattenDiagnosticMessageText(jsonSourceFile.parseDiagnostics[0] && jsonSourceFile.parseDiagnostics[0].messageText, "\n")); + assert( + jsonSourceFile.endOfFileToken && !jsonSourceFile.parseDiagnostics.length, + flattenDiagnosticMessageText( + jsonSourceFile.parseDiagnostics[0] && jsonSourceFile.parseDiagnostics[0].messageText, + "\n", + ), + ); return { jsonSourceFile, parsed: parseJsonSourceFileConfigFileContent(jsonSourceFile, host, basePath, {}, entry), @@ -230,21 +243,31 @@ namespace ts { expected.configFilePath = entry; it(name, () => { const parsed = getParseCommandLine(entry); - assert(!parsed.errors.length, flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n")); + assert( + !parsed.errors.length, + flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n"), + ); assert.deepEqual(parsed.options, expected); assert.deepEqual(parsed.fileNames, expectedFiles); }); it(name + " with jsonSourceFile", () => { const { parsed, jsonSourceFile } = getParseCommandLineJsonSourceFile(entry); - assert(!parsed.errors.length, flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n")); + assert( + !parsed.errors.length, + flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n"), + ); assert.deepEqual(parsed.options, expected); assert.equal(parsed.options.configFile, jsonSourceFile); assert.deepEqual(parsed.fileNames, expectedFiles); }); } - function testFailure(name: string, entry: string, expectedDiagnostics: { code: number; messageText: string; }[]) { + function testFailure( + name: string, + entry: string, + expectedDiagnostics: { code: number; messageText: string; }[], + ) { it(name, () => { const parsed = getParseCommandLine(entry); verifyDiagnostics(parsed.errors, expectedDiagnostics); @@ -266,19 +289,30 @@ namespace ts { combinePaths(basePath, "supplemental.ts"), ]); - testSuccess("can resolve an extension with a base extension that overrides options", "tsconfig.nostrictnull.json", { - allowJs: true, - noImplicitAny: true, - strictNullChecks: false, - }, [ - combinePaths(basePath, "main.ts"), - combinePaths(basePath, "supplemental.ts"), - ]); + testSuccess( + "can resolve an extension with a base extension that overrides options", + "tsconfig.nostrictnull.json", + { + allowJs: true, + noImplicitAny: true, + strictNullChecks: false, + }, + [ + combinePaths(basePath, "main.ts"), + combinePaths(basePath, "supplemental.ts"), + ], + ); testFailure("can report errors on circular imports", "circular.json", [ { code: 18000, - messageText: `Circularity detected while resolving configuration: ${[combinePaths(basePath, "circular.json"), combinePaths(basePath, "circular2.json"), combinePaths(basePath, "circular.json")].join(" -> ")}`, + messageText: `Circularity detected while resolving configuration: ${ + [ + combinePaths(basePath, "circular.json"), + combinePaths(basePath, "circular2.json"), + combinePaths(basePath, "circular.json"), + ].join(" -> ") + }`, }, ]); @@ -325,14 +359,48 @@ namespace ts { ]); describe("finding extended configs from node_modules", () => { - testSuccess("can lookup via tsconfig field", "tsconfig.extendsBox.json", { strict: true }, [combinePaths(basePath, "main.ts")]); - testSuccess("can lookup via package-relative path", "tsconfig.extendsStrict.json", { strict: true }, [combinePaths(basePath, "main.ts")]); - testSuccess("can lookup via non-redirected-to package-relative path", "tsconfig.extendsUnStrict.json", { strict: false }, [combinePaths(basePath, "main.ts")]); - testSuccess("can lookup via package-relative path with extension", "tsconfig.extendsStrictExtension.json", { strict: true }, [combinePaths(basePath, "main.ts")]); - testSuccess("can lookup via an implicit tsconfig", "tsconfig.extendsBoxImplied.json", { strict: true }, [combinePaths(basePath, "main.ts")]); - testSuccess("can lookup via an implicit tsconfig in a package-relative directory", "tsconfig.extendsBoxImpliedUnstrict.json", { strict: false }, [combinePaths(basePath, "main.ts")]); - testSuccess("can lookup via an implicit tsconfig in a package-relative directory with name", "tsconfig.extendsBoxImpliedUnstrictExtension.json", { strict: false }, [combinePaths(basePath, "main.ts")]); - testSuccess("can lookup via an implicit tsconfig in a package-relative directory with extension", "tsconfig.extendsBoxImpliedPath.json", { strict: true }, [combinePaths(basePath, "main.ts")]); + testSuccess("can lookup via tsconfig field", "tsconfig.extendsBox.json", { strict: true }, [ + combinePaths(basePath, "main.ts"), + ]); + testSuccess( + "can lookup via package-relative path", + "tsconfig.extendsStrict.json", + { strict: true }, + [combinePaths(basePath, "main.ts")], + ); + testSuccess( + "can lookup via non-redirected-to package-relative path", + "tsconfig.extendsUnStrict.json", + { strict: false }, + [combinePaths(basePath, "main.ts")], + ); + testSuccess( + "can lookup via package-relative path with extension", + "tsconfig.extendsStrictExtension.json", + { strict: true }, + [combinePaths(basePath, "main.ts")], + ); + testSuccess("can lookup via an implicit tsconfig", "tsconfig.extendsBoxImplied.json", { + strict: true, + }, [combinePaths(basePath, "main.ts")]); + testSuccess( + "can lookup via an implicit tsconfig in a package-relative directory", + "tsconfig.extendsBoxImpliedUnstrict.json", + { strict: false }, + [combinePaths(basePath, "main.ts")], + ); + testSuccess( + "can lookup via an implicit tsconfig in a package-relative directory with name", + "tsconfig.extendsBoxImpliedUnstrictExtension.json", + { strict: false }, + [combinePaths(basePath, "main.ts")], + ); + testSuccess( + "can lookup via an implicit tsconfig in a package-relative directory with extension", + "tsconfig.extendsBoxImpliedPath.json", + { strict: true }, + [combinePaths(basePath, "main.ts")], + ); }); it("adds extendedSourceFiles only once", () => { diff --git a/src/testRunner/unittests/config/convertCompilerOptionsFromJson.ts b/src/testRunner/unittests/config/convertCompilerOptionsFromJson.ts index 6adb6fc135586..1165cbac9e6d9 100644 --- a/src/testRunner/unittests/config/convertCompilerOptionsFromJson.ts +++ b/src/testRunner/unittests/config/convertCompilerOptionsFromJson.ts @@ -18,35 +18,68 @@ namespace ts { type ExpectedResult = ExpectedResultWithParsingSuccess | ExpectedResultWithParsingFailure; - function isExpectedResultWithParsingFailure(expectedResult: ExpectedResult): expectedResult is ExpectedResultWithParsingFailure { + function isExpectedResultWithParsingFailure( + expectedResult: ExpectedResult, + ): expectedResult is ExpectedResultWithParsingFailure { return !!(expectedResult as ExpectedResultWithParsingFailure).hasParseErrors; } - function assertCompilerOptions(json: any, configFileName: string, expectedResult: ExpectedResultWithParsingSuccess) { + function assertCompilerOptions( + json: any, + configFileName: string, + expectedResult: ExpectedResultWithParsingSuccess, + ) { assertCompilerOptionsWithJson(json, configFileName, expectedResult); assertCompilerOptionsWithJsonNode(json, configFileName, expectedResult); } - function assertCompilerOptionsWithJson(json: any, configFileName: string, expectedResult: ExpectedResultWithParsingSuccess) { - const { options: actualCompilerOptions, errors: actualErrors } = convertCompilerOptionsFromJson(json.compilerOptions, "/apath/", configFileName); + function assertCompilerOptionsWithJson( + json: any, + configFileName: string, + expectedResult: ExpectedResultWithParsingSuccess, + ) { + const { options: actualCompilerOptions, errors: actualErrors } = convertCompilerOptionsFromJson( + json.compilerOptions, + "/apath/", + configFileName, + ); const parsedCompilerOptions = JSON.stringify(actualCompilerOptions); - const expectedCompilerOptions = JSON.stringify({ ...expectedResult.compilerOptions, configFilePath: configFileName }); + const expectedCompilerOptions = JSON.stringify({ + ...expectedResult.compilerOptions, + configFilePath: configFileName, + }); assert.equal(parsedCompilerOptions, expectedCompilerOptions); verifyErrors(actualErrors, expectedResult.errors, /*ignoreLocation*/ true); } - function assertCompilerOptionsWithJsonNode(json: any, configFileName: string, expectedResult: ExpectedResultWithParsingSuccess) { + function assertCompilerOptionsWithJsonNode( + json: any, + configFileName: string, + expectedResult: ExpectedResultWithParsingSuccess, + ) { assertCompilerOptionsWithJsonText(JSON.stringify(json), configFileName, expectedResult); } - function assertCompilerOptionsWithJsonText(fileText: string, configFileName: string, expectedResult: ExpectedResult) { + function assertCompilerOptionsWithJsonText( + fileText: string, + configFileName: string, + expectedResult: ExpectedResult, + ) { const result = parseJsonText(configFileName, fileText); assert(!!result.endOfFileToken); assert.equal(!!result.parseDiagnostics.length, isExpectedResultWithParsingFailure(expectedResult)); - const host: ParseConfigHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ false, { cwd: "/apath/" })); - const { options: actualCompilerOptions, errors: actualParseErrors } = parseJsonSourceFileConfigFileContent(result, host, "/apath/", /*existingOptions*/ undefined, configFileName); + const host: ParseConfigHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ false, { cwd: "/apath/" }), + ); + const { options: actualCompilerOptions, errors: actualParseErrors } = parseJsonSourceFileConfigFileContent( + result, + host, + "/apath/", + /*existingOptions*/ undefined, + configFileName, + ); expectedResult.compilerOptions.configFilePath = configFileName; const parsedCompilerOptions = JSON.stringify(actualCompilerOptions); @@ -55,18 +88,47 @@ namespace ts { assert.equal(actualCompilerOptions.configFile, result); if (!isExpectedResultWithParsingFailure(expectedResult)) { - verifyErrors(actualParseErrors.filter(error => error.code !== Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code), expectedResult.errors); + verifyErrors( + actualParseErrors.filter(error => + error.code + !== Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2 + .code + ), + expectedResult.errors, + ); } } - function verifyErrors(actualErrors: Diagnostic[], expectedErrors: readonly Diagnostic[], ignoreLocation?: boolean) { - assert.isTrue(expectedErrors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedErrors.map(getDiagnosticString), undefined, " ")}. Actual error: ${JSON.stringify(actualErrors.map(getDiagnosticString), undefined, " ")}.`); + function verifyErrors( + actualErrors: Diagnostic[], + expectedErrors: readonly Diagnostic[], + ignoreLocation?: boolean, + ) { + assert.isTrue( + expectedErrors.length === actualErrors.length, + `Expected error: ${ + JSON.stringify(expectedErrors.map(getDiagnosticString), undefined, " ") + }. Actual error: ${JSON.stringify(actualErrors.map(getDiagnosticString), undefined, " ")}.`, + ); for (let i = 0; i < actualErrors.length; i++) { const actualError = actualErrors[i]; const expectedError = expectedErrors[i]; - assert.equal(actualError.code, expectedError.code, `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${JSON.stringify(actualError.code)}.`); - assert.equal(actualError.category, expectedError.category, `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${JSON.stringify(actualError.category)}.`); + assert.equal( + actualError.code, + expectedError.code, + `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${ + JSON.stringify(actualError.code) + }.`, + ); + assert.equal( + actualError.category, + expectedError.category, + `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${ + JSON.stringify(actualError.category) + }.`, + ); if (!ignoreLocation) { assert(actualError.file); assert.isDefined(actualError.start); @@ -188,7 +250,8 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'es2022', 'esnext'.", + messageText: + "Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'es2022', 'esnext'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, }], @@ -244,7 +307,8 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext'.", + messageText: + "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, }], @@ -303,7 +367,8 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.bigint', 'esnext.string', 'esnext.promise'.", + messageText: + "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.bigint', 'esnext.string', 'esnext.promise'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, }], @@ -335,7 +400,8 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise'.", + messageText: + "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, }], @@ -367,7 +433,8 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise'.", + messageText: + "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, }], @@ -399,7 +466,8 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise'.", + messageText: + "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, }], @@ -766,7 +834,8 @@ namespace ts { compilerOptions: {}, errors: [{ ...Diagnostics._0_should_be_set_inside_the_compilerOptions_object_of_the_config_json_file, - messageText: "'module' should be set inside the 'compilerOptions' object of the config json file.", + messageText: + "'module' should be set inside the 'compilerOptions' object of the config json file.", file: undefined, start: 0, length: 0, diff --git a/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts b/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts index b5f3c2f749b72..42c0638bb5e2c 100644 --- a/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts +++ b/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts @@ -17,12 +17,29 @@ namespace ts { function verifyErrors(actualErrors: Diagnostic[], expectedResult: ExpectedResult, hasLocation?: boolean) { const expectedErrors = expectedResult.errors; - assert.isTrue(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`); + assert.isTrue( + expectedResult.errors.length === actualErrors.length, + `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${ + JSON.stringify(actualErrors) + }.`, + ); for (let i = 0; i < actualErrors.length; i++) { const actualError = actualErrors[i]; const expectedError = expectedErrors[i]; - assert.equal(actualError.code, expectedError.code, `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${JSON.stringify(actualError.code)}.`); - assert.equal(actualError.category, expectedError.category, `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${JSON.stringify(actualError.category)}.`); + assert.equal( + actualError.code, + expectedError.code, + `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${ + JSON.stringify(actualError.code) + }.`, + ); + assert.equal( + actualError.category, + expectedError.category, + `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${ + JSON.stringify(actualError.category) + }.`, + ); if (hasLocation) { assert(actualError.file); assert(actualError.start); @@ -33,7 +50,11 @@ namespace ts { function assertTypeAcquisitionWithJson(json: any, configFileName: string, expectedResult: ExpectedResult) { const jsonOptions = json.typeAcquisition || json.typingOptions; - const { options: actualTypeAcquisition, errors: actualErrors } = convertTypeAcquisitionFromJson(jsonOptions, "/apath/", configFileName); + const { options: actualTypeAcquisition, errors: actualErrors } = convertTypeAcquisitionFromJson( + jsonOptions, + "/apath/", + configFileName, + ); verifyAcquisition(actualTypeAcquisition, expectedResult); verifyErrors(actualErrors, expectedResult); } @@ -43,11 +64,27 @@ namespace ts { const result = parseJsonText(configFileName, fileText); assert(!result.parseDiagnostics.length); assert(!!result.endOfFileToken); - const host: ParseConfigHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ false, { cwd: "/apath/" })); - const { typeAcquisition: actualTypeAcquisition, errors: actualParseErrors } = parseJsonSourceFileConfigFileContent(result, host, "/apath/", /*existingOptions*/ undefined, configFileName); + const host: ParseConfigHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ false, { cwd: "/apath/" }), + ); + const { typeAcquisition: actualTypeAcquisition, errors: actualParseErrors } = + parseJsonSourceFileConfigFileContent( + result, + host, + "/apath/", + /*existingOptions*/ undefined, + configFileName, + ); verifyAcquisition(actualTypeAcquisition, expectedResult); - const actualErrors = filter(actualParseErrors, error => error.code !== Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code); + const actualErrors = filter( + actualParseErrors, + error => + error.code + !== Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2 + .code, + ); verifyErrors(actualErrors, expectedResult, /*hasLocation*/ true); } diff --git a/src/testRunner/unittests/config/initializeTSConfig.ts b/src/testRunner/unittests/config/initializeTSConfig.ts index d92c906f46180..a0aad43204e3f 100644 --- a/src/testRunner/unittests/config/initializeTSConfig.ts +++ b/src/testRunner/unittests/config/initializeTSConfig.ts @@ -14,21 +14,53 @@ namespace ts { initTSConfigCorrectly("Default initialized TSConfig", ["--init"]); - initTSConfigCorrectly("Initialized TSConfig with files options", ["--init", "file0.st", "file1.ts", "file2.ts"]); + initTSConfigCorrectly("Initialized TSConfig with files options", [ + "--init", + "file0.st", + "file1.ts", + "file2.ts", + ]); - initTSConfigCorrectly("Initialized TSConfig with boolean value compiler options", ["--init", "--noUnusedLocals"]); + initTSConfigCorrectly("Initialized TSConfig with boolean value compiler options", [ + "--init", + "--noUnusedLocals", + ]); - initTSConfigCorrectly("Initialized TSConfig with enum value compiler options", ["--init", "--target", "es5", "--jsx", "react"]); + initTSConfigCorrectly("Initialized TSConfig with enum value compiler options", [ + "--init", + "--target", + "es5", + "--jsx", + "react", + ]); initTSConfigCorrectly("Initialized TSConfig with list compiler options", ["--init", "--types", "jquery,mocha"]); - initTSConfigCorrectly("Initialized TSConfig with list compiler options with enum value", ["--init", "--lib", "es5,es2015.core"]); + initTSConfigCorrectly("Initialized TSConfig with list compiler options with enum value", [ + "--init", + "--lib", + "es5,es2015.core", + ]); - initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option", ["--init", "--someNonExistOption"]); + initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option", [ + "--init", + "--someNonExistOption", + ]); - initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option value", ["--init", "--lib", "nonExistLib,es5,es2015.promise"]); + initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option value", [ + "--init", + "--lib", + "nonExistLib,es5,es2015.promise", + ]); - initTSConfigCorrectly("Initialized TSConfig with advanced options", ["--init", "--declaration", "--declarationDir", "lib", "--skipLibCheck", "--noErrorTruncation"]); + initTSConfigCorrectly("Initialized TSConfig with advanced options", [ + "--init", + "--declaration", + "--declarationDir", + "lib", + "--skipLibCheck", + "--noErrorTruncation", + ]); initTSConfigCorrectly("Initialized TSConfig with --help", ["--init", "--help"]); diff --git a/src/testRunner/unittests/config/matchFiles.ts b/src/testRunner/unittests/config/matchFiles.ts index e559c4c1f0173..822d0277d0fc6 100644 --- a/src/testRunner/unittests/config/matchFiles.ts +++ b/src/testRunner/unittests/config/matchFiles.ts @@ -141,11 +141,26 @@ namespace ts { assert.deepEqual(actual.errors, expected.errors); } - function validateMatches(expected: ParsedCommandLine, json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[]) { + function validateMatches( + expected: ParsedCommandLine, + json: any, + host: ParseConfigHost, + basePath: string, + existingOptions?: CompilerOptions, + configFileName?: string, + resolutionStack?: Path[], + ) { { const jsonText = JSON.stringify(json); const result = parseJsonText(caseInsensitiveTsconfigPath, jsonText); - const actual = parseJsonSourceFileConfigFileContent(result, host, basePath, existingOptions, configFileName, resolutionStack); + const actual = parseJsonSourceFileConfigFileContent( + result, + host, + basePath, + existingOptions, + configFileName, + resolutionStack, + ); for (const error of expected.errors) { if (error.file) { error.file = result; @@ -154,7 +169,14 @@ namespace ts { assertParsed(actual, expected); } { - const actual = parseJsonConfigFileContent(json, host, basePath, existingOptions, configFileName, resolutionStack); + const actual = parseJsonConfigFileContent( + json, + host, + basePath, + existingOptions, + configFileName, + resolutionStack, + ); expected.errors = expected.errors.map((error): Diagnostic => ({ category: error.category, code: error.code, @@ -169,7 +191,13 @@ namespace ts { } } - function createDiagnosticForConfigFile(json: any, start: number, length: number, diagnosticMessage: DiagnosticMessage, arg0: string) { + function createDiagnosticForConfigFile( + json: any, + start: number, + length: number, + diagnosticMessage: DiagnosticMessage, + arg0: string, + ) { const text = JSON.stringify(json); const file = { fileName: caseInsensitiveTsconfigPath, @@ -286,12 +314,25 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]"), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + "[]", + ), ], fileNames: [], wildcardDirectories: {}, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); it("with missing files are excluded", () => { const json = { @@ -303,12 +344,25 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]"), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + "[]", + ), ], fileNames: [], wildcardDirectories: {}, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); it("with literal excludes", () => { const json = { @@ -637,14 +691,27 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]"), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + "[]", + ), ], fileNames: [], wildcardDirectories: { "c:/dev": WatchDirectoryFlags.Recursive, }, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); it("always include literal files", () => { const json = { @@ -830,14 +897,27 @@ namespace ts { allowJs: false, }, errors: [ - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]"), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + "[]", + ), ], fileNames: [], wildcardDirectories: { "c:/dev/js": WatchDirectoryFlags.None, }, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); it("include .js files when allowJs=true", () => { const json = { @@ -944,12 +1024,25 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), JSON.stringify(json.exclude)), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + JSON.stringify(json.exclude), + ), ], fileNames: [], wildcardDirectories: {}, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); it("include files with .. in their name", () => { const json = { @@ -1174,13 +1267,33 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createDiagnosticForConfigFile(json, 12, 4, Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**"), - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]"), + createDiagnosticForConfigFile( + json, + 12, + 4, + Diagnostics + .File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, + "**", + ), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + "[]", + ), ], fileNames: [], wildcardDirectories: {}, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); it("in excludes", () => { const json = { @@ -1194,12 +1307,25 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), JSON.stringify(json.exclude)), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + JSON.stringify(json.exclude), + ), ], fileNames: [], wildcardDirectories: {}, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); }); describe("with multiple recursive directory patterns", () => { @@ -1223,7 +1349,14 @@ namespace ts { "c:/dev": WatchDirectoryFlags.Recursive, }, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); it("in excludes", () => { const json = { @@ -1259,13 +1392,33 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createDiagnosticForConfigFile(json, 12, 9, Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/../*"), - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]"), + createDiagnosticForConfigFile( + json, + 12, + 9, + Diagnostics + .File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, + "**/../*", + ), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + "[]", + ), ], fileNames: [], wildcardDirectories: {}, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); it("in includes after a subdirectory", () => { @@ -1277,13 +1430,33 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createDiagnosticForConfigFile(json, 12, 11, Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/../*"), - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]"), + createDiagnosticForConfigFile( + json, + 12, + 11, + Diagnostics + .File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, + "**/y/../*", + ), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + "[]", + ), ], fileNames: [], wildcardDirectories: {}, }; - validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); it("in excludes immediately after", () => { @@ -1298,7 +1471,14 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createDiagnosticForConfigFile(json, 34, 7, Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/.."), + createDiagnosticForConfigFile( + json, + 34, + 7, + Diagnostics + .File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, + "**/..", + ), ], fileNames: [ "c:/dev/a.ts", @@ -1325,7 +1505,14 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createDiagnosticForConfigFile(json, 34, 9, Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/.."), + createDiagnosticForConfigFile( + json, + 34, + 9, + Diagnostics + .File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, + "**/y/..", + ), ], fileNames: [ "c:/dev/a.ts", @@ -1454,12 +1641,25 @@ namespace ts { const expected: ParsedCommandLine = { options: {}, errors: [ - createCompilerDiagnostic(Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, caseInsensitiveTsconfigPath, JSON.stringify(json.include), JSON.stringify(json.exclude)), + createCompilerDiagnostic( + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, + caseInsensitiveTsconfigPath, + JSON.stringify(json.include), + JSON.stringify(json.exclude), + ), ], fileNames: [], wildcardDirectories: {}, }; - validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); + validateMatches( + expected, + json, + caseInsensitiveDottedFoldersHost, + caseInsensitiveBasePath, + /*existingOptions*/ undefined, + caseInsensitiveTsconfigPath, + ); }); }); }); @@ -1535,8 +1735,18 @@ namespace ts { }; } const json = {}; - validateMatches(getExpected(caseSensitiveBasePath), json, caseSensitiveOrderingDiffersWithCaseHost, caseSensitiveBasePath); - validateMatches(getExpected(caseInsensitiveBasePath), json, caseInsensitiveOrderingDiffersWithCaseHost, caseInsensitiveBasePath); + validateMatches( + getExpected(caseSensitiveBasePath), + json, + caseSensitiveOrderingDiffersWithCaseHost, + caseSensitiveBasePath, + ); + validateMatches( + getExpected(caseInsensitiveBasePath), + json, + caseInsensitiveOrderingDiffersWithCaseHost, + caseInsensitiveBasePath, + ); }); it("when recursive symlinked directories are present", () => { diff --git a/src/testRunner/unittests/config/projectReferences.ts b/src/testRunner/unittests/config/projectReferences.ts index 60961a244d8a1..267d3096edd44 100644 --- a/src/testRunner/unittests/config/projectReferences.ts +++ b/src/testRunner/unittests/config/projectReferences.ts @@ -13,14 +13,19 @@ namespace ts { function assertHasError(message: string, errors: readonly Diagnostic[], diag: DiagnosticMessage) { if (!errors.some(e => e.code === diag.code)) { - const errorString = errors.map(e => ` ${e.file ? e.file.fileName : "[global]"}: ${e.messageText}`).join("\r\n"); + const errorString = errors.map(e => ` ${e.file ? e.file.fileName : "[global]"}: ${e.messageText}`).join( + "\r\n", + ); assert(false, `${message}: Did not find any diagnostic for ${diag.message} in:\r\n${errorString}`); } } function assertNoErrors(message: string, errors: readonly Diagnostic[]) { if (errors && errors.length > 0) { - assert(false, `${message}: Expected no errors, but found:\r\n${errors.map(e => ` ${e.messageText}`).join("\r\n")}`); + assert( + false, + `${message}: Expected no errors, but found:\r\n${errors.map(e => ` ${e.messageText}`).join("\r\n")}`, + ); } } @@ -42,7 +47,11 @@ namespace ts { return names.map((n, i) => `import * as mod_${i} from ${n}`).join("\r\n"); } - function testProjectReferences(spec: TestSpecification, entryPointConfigFileName: string, checkResult: (prog: Program, host: fakes.CompilerHost) => void) { + function testProjectReferences( + spec: TestSpecification, + entryPointConfigFileName: string, + checkResult: (prog: Program, host: fakes.CompilerHost) => void, + ) { const files = new Map(); for (const key in spec) { const sp = spec[key]; @@ -85,7 +94,13 @@ namespace ts { // We shouldn't have any errors about invalid tsconfig files in these tests assert(config && !error, flattenDiagnosticMessageText(error && error.messageText, "\n")); - const file = parseJsonConfigFileContent(config, parseConfigHostFromCompilerHostLike(host), getDirectoryPath(entryPointConfigFileName), {}, entryPointConfigFileName); + const file = parseJsonConfigFileContent( + config, + parseConfigHostFromCompilerHostLike(host), + getDirectoryPath(entryPointConfigFileName), + {}, + entryPointConfigFileName, + ); file.options.configFilePath = entryPointConfigFileName; const prog = createProgram({ rootNames: file.fileNames, @@ -132,7 +147,11 @@ namespace ts { testProjectReferences(spec, "/primary/tsconfig.json", program => { const errs = program.getOptionsDiagnostics(); - assertHasError("Reports an error about the wrong decl setting", errs, Diagnostics.Composite_projects_may_not_disable_declaration_emit); + assertHasError( + "Reports an error about the wrong decl setting", + errs, + Diagnostics.Composite_projects_may_not_disable_declaration_emit, + ); }); }); @@ -155,7 +174,11 @@ namespace ts { }; testProjectReferences(spec, "/reference/tsconfig.json", program => { const errs = program.getOptionsDiagnostics(); - assertHasError("Reports an error about 'composite' not being set", errs, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true); + assertHasError( + "Reports an error about 'composite' not being set", + errs, + Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, + ); }); }); @@ -194,7 +217,12 @@ namespace ts { testProjectReferences(spec, "/primary/tsconfig.json", program => { const errs = program.getSemanticDiagnostics(program.getSourceFile("/primary/a.ts")); - assertHasError("Reports an error about b.ts not being in the list", errs, Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern); + assertHasError( + "Reports an error about b.ts not being in the list", + errs, + Diagnostics + .File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, + ); }); }); @@ -223,7 +251,11 @@ namespace ts { }; testProjectReferences(spec, "/primary/tsconfig.json", program => { const errs = program.getOptionsDiagnostics(); - assertHasError("Reports an error about outFile not being set", errs, Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set); + assertHasError( + "Reports an error about outFile not being set", + errs, + Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, + ); }); }); @@ -240,7 +272,11 @@ namespace ts { }; testProjectReferences(spec, "/primary/tsconfig.json", program => { const errs = program.getOptionsDiagnostics(); - assertHasError("Reports an error about outFile being missing", errs, Diagnostics.Output_file_0_from_project_1_does_not_exist); + assertHasError( + "Reports an error about outFile being missing", + errs, + Diagnostics.Output_file_0_from_project_1_does_not_exist, + ); }); }); }); @@ -263,7 +299,11 @@ namespace ts { }; testProjectReferences(spec, "/beta/tsconfig.json", program => { assertNoErrors("File setup should be correct", program.getOptionsDiagnostics()); - assertHasError("Found a type error", program.getSemanticDiagnostics(), Diagnostics.Module_0_has_no_exported_member_1); + assertHasError( + "Found a type error", + program.getSemanticDiagnostics(), + Diagnostics.Module_0_has_no_exported_member_1, + ); }); }); }); @@ -281,7 +321,11 @@ namespace ts { }, }; testProjectReferences(spec, "/beta/tsconfig.json", program => { - assertHasError("Issues a useful error", program.getSemanticDiagnostics(), Diagnostics.Output_file_0_has_not_been_built_from_source_file_1); + assertHasError( + "Issues a useful error", + program.getSemanticDiagnostics(), + Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, + ); }); }); @@ -303,7 +347,11 @@ namespace ts { }, }; testProjectReferences(spec, "/beta/tsconfig.json", program => { - assertHasError("Issues a useful error", program.getSemanticDiagnostics(), Diagnostics.Output_file_0_has_not_been_built_from_source_file_1); + assertHasError( + "Issues a useful error", + program.getSemanticDiagnostics(), + Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, + ); }); }); }); @@ -325,7 +373,11 @@ namespace ts { }; testProjectReferences(spec, "/alpha/tsconfig.json", (program, host) => { program.emit(); - assert.deepEqual(host.outputs.map(e => e.file).sort(), ["/alpha/bin/src/a.d.ts", "/alpha/bin/src/a.js", "/alpha/bin/tsconfig.tsbuildinfo"]); + assert.deepEqual(host.outputs.map(e => e.file).sort(), [ + "/alpha/bin/src/a.d.ts", + "/alpha/bin/src/a.js", + "/alpha/bin/tsconfig.tsbuildinfo", + ]); }); }); }); @@ -344,8 +396,17 @@ namespace ts { }; testProjectReferences(spec, "/alpha/tsconfig.json", program => { const semanticDiagnostics = program.getSemanticDiagnostics(program.getSourceFile("/alpha/src/a.ts")); - assertHasError("Issues an error about the rootDir", semanticDiagnostics, Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files); - assertHasError("Issues an error about the fileList", semanticDiagnostics, Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern); + assertHasError( + "Issues an error about the rootDir", + semanticDiagnostics, + Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, + ); + assertHasError( + "Issues an error about the fileList", + semanticDiagnostics, + Diagnostics + .File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, + ); }); }); }); diff --git a/src/testRunner/unittests/config/showConfig.ts b/src/testRunner/unittests/config/showConfig.ts index b398864302834..721c6c8b3185d 100644 --- a/src/testRunner/unittests/config/showConfig.ts +++ b/src/testRunner/unittests/config/showConfig.ts @@ -9,7 +9,9 @@ namespace ts { const configPath = combinePaths(cwd, "tsconfig.json"); const configContents = configJson ? JSON.stringify(configJson) : undefined; const configParseHost: ParseConfigFileHost = { - fileExists: path => comparePaths(getNormalizedAbsolutePath(path, cwd), configPath) === Comparison.EqualTo ? true : false, + fileExists: path => + comparePaths(getNormalizedAbsolutePath(path, cwd), configPath) === Comparison.EqualTo ? true + : false, getCurrentDirectory() { return cwd; }, @@ -20,11 +22,17 @@ namespace ts { readDirectory() { return []; }, - readFile: path => comparePaths(getNormalizedAbsolutePath(path, cwd), configPath) === Comparison.EqualTo ? configContents : undefined, + readFile: path => + comparePaths(getNormalizedAbsolutePath(path, cwd), configPath) === Comparison.EqualTo + ? configContents : undefined, }; let commandLine = parseCommandLine(commandLinesArgs); if (commandLine.options.project) { - const result = getParsedCommandLineOfConfigFile(commandLine.options.project, commandLine.options, configParseHost); + const result = getParsedCommandLineOfConfigFile( + commandLine.options.project, + commandLine.options, + configParseHost, + ); if (result) { commandLine = result; } @@ -41,19 +49,43 @@ namespace ts { showTSConfigCorrectly("Show TSConfig with files options", ["--showConfig", "file0.ts", "file1.ts", "file2.ts"]); - showTSConfigCorrectly("Show TSConfig with boolean value compiler options", ["--showConfig", "--noUnusedLocals"]); + showTSConfigCorrectly("Show TSConfig with boolean value compiler options", [ + "--showConfig", + "--noUnusedLocals", + ]); - showTSConfigCorrectly("Show TSConfig with enum value compiler options", ["--showConfig", "--target", "es5", "--jsx", "react"]); + showTSConfigCorrectly("Show TSConfig with enum value compiler options", [ + "--showConfig", + "--target", + "es5", + "--jsx", + "react", + ]); showTSConfigCorrectly("Show TSConfig with list compiler options", ["--showConfig", "--types", "jquery,mocha"]); - showTSConfigCorrectly("Show TSConfig with list compiler options with enum value", ["--showConfig", "--lib", "es5,es2015.core"]); + showTSConfigCorrectly("Show TSConfig with list compiler options with enum value", [ + "--showConfig", + "--lib", + "es5,es2015.core", + ]); showTSConfigCorrectly("Show TSConfig with incorrect compiler option", ["--showConfig", "--someNonExistOption"]); - showTSConfigCorrectly("Show TSConfig with incorrect compiler option value", ["--showConfig", "--lib", "nonExistLib,es5,es2015.promise"]); - - showTSConfigCorrectly("Show TSConfig with advanced options", ["--showConfig", "--declaration", "--declarationDir", "lib", "--skipLibCheck", "--noErrorTruncation"]); + showTSConfigCorrectly("Show TSConfig with incorrect compiler option value", [ + "--showConfig", + "--lib", + "nonExistLib,es5,es2015.promise", + ]); + + showTSConfigCorrectly("Show TSConfig with advanced options", [ + "--showConfig", + "--declaration", + "--declarationDir", + "lib", + "--skipLibCheck", + "--noErrorTruncation", + ]); showTSConfigCorrectly("Show TSConfig with compileOnSave and more", ["-p", "tsconfig.json"], { compilerOptions: { @@ -187,8 +219,8 @@ namespace ts { } } - const configObject = optionValue && - (isCompilerOptions ? { compilerOptions: optionValue } : { watchOptions: optionValue }); + const configObject = optionValue + && (isCompilerOptions ? { compilerOptions: optionValue } : { watchOptions: optionValue }); showTSConfigCorrectly(`Shows tsconfig for single option/${option.name}`, args, configObject); } }); diff --git a/src/testRunner/unittests/config/tsconfigParsing.ts b/src/testRunner/unittests/config/tsconfigParsing.ts index 91930f151b47a..4032ba5dc00de 100644 --- a/src/testRunner/unittests/config/tsconfigParsing.ts +++ b/src/testRunner/unittests/config/tsconfigParsing.ts @@ -10,35 +10,69 @@ namespace ts { const parsed = parseConfigFileTextToJson("/apath/tsconfig.json", jsonText); const parsedCommand = parseJsonConfigFileContent(parsed.config, sys, "tests/cases/unittests"); assert.isTrue( - parsedCommand.errors && parsedCommand.errors.length === 1 && - parsedCommand.errors[0].code === Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code, + parsedCommand.errors && parsedCommand.errors.length === 1 + && parsedCommand.errors[0].code + === Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code, ); } { const parsed = parseJsonText("/apath/tsconfig.json", jsonText); const parsedCommand = parseJsonSourceFileConfigFileContent(parsed, sys, "tests/cases/unittests"); assert.isTrue( - parsedCommand.errors && parsedCommand.errors.length === 1 && - parsedCommand.errors[0].code === Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code, + parsedCommand.errors && parsedCommand.errors.length === 1 + && parsedCommand.errors[0].code + === Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code, ); } } - function getParsedCommandJson(jsonText: string, configFileName: string, basePath: string, allFileList: string[]) { + function getParsedCommandJson( + jsonText: string, + configFileName: string, + basePath: string, + allFileList: string[], + ) { const parsed = parseConfigFileTextToJson(configFileName, jsonText); const files = allFileList.reduce((files, value) => (files[value] = "", files), {} as vfs.FileSet); - const host: ParseConfigHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ false, { cwd: basePath, files: { "/": {}, ...files } })); - return parseJsonConfigFileContent(parsed.config, host, basePath, /*existingOptions*/ undefined, configFileName); + const host: ParseConfigHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ false, { cwd: basePath, files: { "/": {}, ...files } }), + ); + return parseJsonConfigFileContent( + parsed.config, + host, + basePath, + /*existingOptions*/ undefined, + configFileName, + ); } - function getParsedCommandJsonNode(jsonText: string, configFileName: string, basePath: string, allFileList: string[]) { + function getParsedCommandJsonNode( + jsonText: string, + configFileName: string, + basePath: string, + allFileList: string[], + ) { const parsed = parseJsonText(configFileName, jsonText); const files = allFileList.reduce((files, value) => (files[value] = "", files), {} as vfs.FileSet); - const host: ParseConfigHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ false, { cwd: basePath, files: { "/": {}, ...files } })); - return parseJsonSourceFileConfigFileContent(parsed, host, basePath, /*existingOptions*/ undefined, configFileName); + const host: ParseConfigHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ false, { cwd: basePath, files: { "/": {}, ...files } }), + ); + return parseJsonSourceFileConfigFileContent( + parsed, + host, + basePath, + /*existingOptions*/ undefined, + configFileName, + ); } - function assertParseFileList(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedFileList: string[]) { + function assertParseFileList( + jsonText: string, + configFileName: string, + basePath: string, + allFileList: string[], + expectedFileList: string[], + ) { { const parsed = getParsedCommandJson(jsonText, configFileName, basePath, allFileList); assert.isTrue(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort())); @@ -49,32 +83,67 @@ namespace ts { } } - function assertParseFileDiagnostics(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedDiagnosticCode: number, noLocation?: boolean) { + function assertParseFileDiagnostics( + jsonText: string, + configFileName: string, + basePath: string, + allFileList: string[], + expectedDiagnosticCode: number, + noLocation?: boolean, + ) { { const parsed = getParsedCommandJson(jsonText, configFileName, basePath, allFileList); assert.isTrue(parsed.errors.length >= 0); - assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`); + assert.isTrue( + parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, + `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`, + ); } { const parsed = getParsedCommandJsonNode(jsonText, configFileName, basePath, allFileList); assert.isTrue(parsed.errors.length >= 0); - assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`); + assert.isTrue( + parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, + `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`, + ); if (!noLocation) { - assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode && e.file && e.start && e.length).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)} with location information`); + assert.isTrue( + parsed.errors.filter(e => e.code === expectedDiagnosticCode && e.file && e.start && e.length) + .length > 0, + `Expected error code ${expectedDiagnosticCode} to be in ${ + JSON.stringify(parsed.errors) + } with location information`, + ); } } } - function assertParseFileDiagnosticsExclusion(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedExcludedDiagnosticCode: number) { + function assertParseFileDiagnosticsExclusion( + jsonText: string, + configFileName: string, + basePath: string, + allFileList: string[], + expectedExcludedDiagnosticCode: number, + ) { { const parsed = getParsedCommandJson(jsonText, configFileName, basePath, allFileList); assert.isTrue(parsed.errors.length >= 0); - assert.isTrue(parsed.errors.findIndex(e => e.code === expectedExcludedDiagnosticCode) === -1, `Expected error code ${expectedExcludedDiagnosticCode} to not be in ${JSON.stringify(parsed.errors)}`); + assert.isTrue( + parsed.errors.findIndex(e => e.code === expectedExcludedDiagnosticCode) === -1, + `Expected error code ${expectedExcludedDiagnosticCode} to not be in ${ + JSON.stringify(parsed.errors) + }`, + ); } { const parsed = getParsedCommandJsonNode(jsonText, configFileName, basePath, allFileList); assert.isTrue(parsed.errors.length >= 0); - assert.isTrue(parsed.errors.findIndex(e => e.code === expectedExcludedDiagnosticCode) === -1, `Expected error code ${expectedExcludedDiagnosticCode} to not be in ${JSON.stringify(parsed.errors)}`); + assert.isTrue( + parsed.errors.findIndex(e => e.code === expectedExcludedDiagnosticCode) === -1, + `Expected error code ${expectedExcludedDiagnosticCode} to not be in ${ + JSON.stringify(parsed.errors) + }`, + ); } } @@ -303,7 +372,13 @@ namespace ts { const content = `{ "files": [] }`; - assertParseFileDiagnostics(content, "/apath/tsconfig.json", "tests/cases/unittests", ["/apath/a.ts"], Diagnostics.The_files_list_in_config_file_0_is_empty.code); + assertParseFileDiagnostics( + content, + "/apath/tsconfig.json", + "tests/cases/unittests", + ["/apath/a.ts"], + Diagnostics.The_files_list_in_config_file_0_is_empty.code, + ); }); it("generates errors for empty files list when no references are provided", () => { @@ -311,7 +386,13 @@ namespace ts { "files": [], "references": [] }`; - assertParseFileDiagnostics(content, "/apath/tsconfig.json", "tests/cases/unittests", ["/apath/a.ts"], Diagnostics.The_files_list_in_config_file_0_is_empty.code); + assertParseFileDiagnostics( + content, + "/apath/tsconfig.json", + "tests/cases/unittests", + ["/apath/a.ts"], + Diagnostics.The_files_list_in_config_file_0_is_empty.code, + ); }); it("does not generate errors for empty files list when one or more references are provided", () => { @@ -319,13 +400,23 @@ namespace ts { "files": [], "references": [{ "path": "/apath" }] }`; - assertParseFileDiagnosticsExclusion(content, "/apath/tsconfig.json", "tests/cases/unittests", ["/apath/a.ts"], Diagnostics.The_files_list_in_config_file_0_is_empty.code); + assertParseFileDiagnosticsExclusion(content, "/apath/tsconfig.json", "tests/cases/unittests", [ + "/apath/a.ts", + ], Diagnostics.The_files_list_in_config_file_0_is_empty.code); }); it("generates errors for directory with no .ts files", () => { const content = `{ }`; - assertParseFileDiagnostics(content, "/apath/tsconfig.json", "tests/cases/unittests", ["/apath/a.js"], Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code, /*noLocation*/ true); + assertParseFileDiagnostics( + content, + "/apath/tsconfig.json", + "tests/cases/unittests", + ["/apath/a.js"], + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code, + /*noLocation*/ true, + ); }); it("generates errors for empty directory", () => { @@ -334,14 +425,30 @@ namespace ts { "allowJs": true } }`; - assertParseFileDiagnostics(content, "/apath/tsconfig.json", "tests/cases/unittests", [], Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code, /*noLocation*/ true); + assertParseFileDiagnostics( + content, + "/apath/tsconfig.json", + "tests/cases/unittests", + [], + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code, + /*noLocation*/ true, + ); }); it("generates errors for empty include", () => { const content = `{ "include": [] }`; - assertParseFileDiagnostics(content, "/apath/tsconfig.json", "tests/cases/unittests", ["/apath/a.ts"], Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code, /*noLocation*/ true); + assertParseFileDiagnostics( + content, + "/apath/tsconfig.json", + "tests/cases/unittests", + ["/apath/a.ts"], + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code, + /*noLocation*/ true, + ); }); it("generates errors for includes with outDir", () => { @@ -351,7 +458,15 @@ namespace ts { }, "include": ["**/*"] }`; - assertParseFileDiagnostics(content, "/apath/tsconfig.json", "tests/cases/unittests", ["/apath/a.ts"], Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code, /*noLocation*/ true); + assertParseFileDiagnostics( + content, + "/apath/tsconfig.json", + "tests/cases/unittests", + ["/apath/a.ts"], + Diagnostics + .No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code, + /*noLocation*/ true, + ); }); it("generates errors for when invalid comment type present in tsconfig", () => { @@ -362,7 +477,9 @@ namespace ts { ] } }`; - const parsed = getParsedCommandJsonNode(jsonText, "/apath/tsconfig.json", "tests/cases/unittests", ["/apath/a.ts"]); + const parsed = getParsedCommandJsonNode(jsonText, "/apath/tsconfig.json", "tests/cases/unittests", [ + "/apath/a.ts", + ]); assert.isTrue(parsed.errors.length >= 0); }); diff --git a/src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts b/src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts index 3abbadc0d9e7d..50bf5914c2de3 100644 --- a/src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts +++ b/src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts @@ -11,7 +11,11 @@ namespace ts { ), ); } - function getParsedCommandJson(json: object, additionalFiles?: vfs.FileSet, existingWatchOptions?: WatchOptions) { + function getParsedCommandJson( + json: object, + additionalFiles?: vfs.FileSet, + existingWatchOptions?: WatchOptions, + ) { return parseJsonConfigFileContent( json, createParseConfigHost(additionalFiles), @@ -25,7 +29,11 @@ namespace ts { ); } - function getParsedCommandJsonNode(json: object, additionalFiles?: vfs.FileSet, existingWatchOptions?: WatchOptions) { + function getParsedCommandJsonNode( + json: object, + additionalFiles?: vfs.FileSet, + existingWatchOptions?: WatchOptions, + ) { const parsed = parseJsonText("tsconfig.json", JSON.stringify(json)); return parseJsonSourceFileConfigFileContent( parsed, @@ -51,7 +59,11 @@ namespace ts { it("with json api", () => { const baseline: string[] = []; for (const { json, additionalFiles, existingWatchOptions } of scenario()) { - addToBaseLine(baseline, json, getParsedCommandJson(json, additionalFiles, existingWatchOptions)); + addToBaseLine( + baseline, + json, + getParsedCommandJson(json, additionalFiles, existingWatchOptions), + ); } runBaseline(`${subScenario} with json api`, baseline); }); @@ -59,7 +71,11 @@ namespace ts { it("with json source file api", () => { const baseline: string[] = []; for (const { json, additionalFiles, existingWatchOptions } of scenario()) { - addToBaseLine(baseline, json, getParsedCommandJsonNode(json, additionalFiles, existingWatchOptions)); + addToBaseLine( + baseline, + json, + getParsedCommandJsonNode(json, additionalFiles, existingWatchOptions), + ); } runBaseline(`${subScenario} with jsonSourceFile api`, baseline); }); @@ -76,7 +92,10 @@ namespace ts { })); } function runBaseline(subScenario: string, baseline: readonly string[]) { - Harness.Baseline.runBaseline(`config/tsconfigParsingWatchOptions/${subScenario}.js`, baseline.join("\n")); + Harness.Baseline.runBaseline( + `config/tsconfigParsingWatchOptions/${subScenario}.js`, + baseline.join("\n"), + ); } } diff --git a/src/testRunner/unittests/convertToBase64.ts b/src/testRunner/unittests/convertToBase64.ts index d534bf207d9c6..2173e0d8812ad 100644 --- a/src/testRunner/unittests/convertToBase64.ts +++ b/src/testRunner/unittests/convertToBase64.ts @@ -3,12 +3,18 @@ namespace ts { function runTest(input: string): void { const actual = convertToBase64(input); const expected = sys.base64encode!(input); - assert.equal(actual, expected, "Encoded string using convertToBase64 does not match buffer.toString('base64')"); + assert.equal( + actual, + expected, + "Encoded string using convertToBase64 does not match buffer.toString('base64')", + ); } if (Buffer) { it("Converts ASCII charaters correctly", () => { - runTest(" !\"#$ %&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"); + runTest( + " !\"#$ %&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", + ); }); it("Converts escape sequences correctly", () => { diff --git a/src/testRunner/unittests/customTransforms.ts b/src/testRunner/unittests/customTransforms.ts index e70b41fcb51e2..4b40f20bb5d04 100644 --- a/src/testRunner/unittests/customTransforms.ts +++ b/src/testRunner/unittests/customTransforms.ts @@ -1,6 +1,11 @@ namespace ts { describe("unittests:: customTransforms", () => { - function emitsCorrectly(name: string, sources: { file: string; text: string; }[], customTransformers: CustomTransformers, options: CompilerOptions = {}) { + function emitsCorrectly( + name: string, + sources: { file: string; text: string; }[], + customTransformers: CustomTransformers, + options: CompilerOptions = {}, + ) { it(name, () => { const roots = sources.map(source => createSourceFile(source.file, source.text, ScriptTarget.ES2015)); const fileMap = arrayToMap(roots, file => file.fileName); @@ -18,8 +23,18 @@ namespace ts { writeFile: (fileName, text) => outputs.set(fileName, text), }; - const program = createProgram(arrayFrom(fileMap.keys()), { newLine: NewLineKind.LineFeed, ...options }, host); - program.emit(/*targetSourceFile*/ undefined, host.writeFile, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ false, customTransformers); + const program = createProgram( + arrayFrom(fileMap.keys()), + { newLine: NewLineKind.LineFeed, ...options }, + host, + ); + program.emit( + /*targetSourceFile*/ undefined, + host.writeFile, + /*cancellationToken*/ undefined, + /*emitOnlyDtsFiles*/ false, + customTransformers, + ); let content = ""; for (const [file, text] of arrayFrom(outputs.entries())) { if (content) content += "\n\n"; @@ -52,7 +67,12 @@ namespace ts { } } function visitFunction(node: FunctionDeclaration) { - addSyntheticLeadingComment(node, SyntaxKind.MultiLineCommentTrivia, "@before", /*hasTrailingNewLine*/ true); + addSyntheticLeadingComment( + node, + SyntaxKind.MultiLineCommentTrivia, + "@before", + /*hasTrailingNewLine*/ true, + ); return node; } }; @@ -89,7 +109,9 @@ namespace ts { before: [ context => node => visitNode(node, function visitor(node: Node): Node { - if (isStringLiteral(node) && node.text === "change") return factory.createStringLiteral("changed"); + if (isStringLiteral(node) && node.text === "change") { + return factory.createStringLiteral("changed"); + } return visitEachChild(node, visitor, context); }), ], @@ -122,7 +144,8 @@ namespace ts { text, fileName: "another.html", lineMap, - getLineAndCharacterOfPosition: pos => computeLineAndCharacterOfPosition(lineMap, pos), + getLineAndCharacterOfPosition: pos => + computeLineAndCharacterOfPosition(lineMap, pos), }, }); return node; @@ -157,7 +180,8 @@ namespace ts { }); return { transformSourceFile, - transformBundle: node => factory.createBundle(map(node.sourceFiles, transformSourceFile), node.prepends), + transformBundle: node => + factory.createBundle(map(node.sourceFiles, transformSourceFile), node.prepends), }; }, ], diff --git a/src/testRunner/unittests/factory.ts b/src/testRunner/unittests/factory.ts index 87fe967b0ba6e..951be5ea782ba 100644 --- a/src/testRunner/unittests/factory.ts +++ b/src/testRunner/unittests/factory.ts @@ -1,7 +1,11 @@ namespace ts { describe("unittests:: FactoryAPI", () => { function assertSyntaxKind(node: Node, expected: SyntaxKind) { - assert.strictEqual(node.kind, expected, `Actual: ${Debug.formatSyntaxKind(node.kind)} Expected: ${Debug.formatSyntaxKind(expected)}`); + assert.strictEqual( + node.kind, + expected, + `Actual: ${Debug.formatSyntaxKind(node.kind)} Expected: ${Debug.formatSyntaxKind(expected)}`, + ); } describe("factory.createExportAssignment", () => { it("parenthesizes default export if necessary", () => { @@ -14,19 +18,58 @@ namespace ts { assertSyntaxKind(node.expression, SyntaxKind.ParenthesizedExpression); } - const clazz = factory.createClassExpression(/*modifiers*/ undefined, "C", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [ - factory.createPropertyDeclaration([factory.createToken(SyntaxKind.StaticKeyword)], "prop", /*questionOrExclamationToken*/ undefined, /*type*/ undefined, factory.createStringLiteral("1")), - ]); + const clazz = factory.createClassExpression( + /*modifiers*/ undefined, + "C", + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [ + factory.createPropertyDeclaration( + [factory.createToken(SyntaxKind.StaticKeyword)], + "prop", + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + factory.createStringLiteral("1"), + ), + ], + ); checkExpression(clazz); checkExpression(factory.createPropertyAccessExpression(clazz, "prop")); - const func = factory.createFunctionExpression(/*modifiers*/ undefined, /*asteriskToken*/ undefined, "fn", /*typeParameters*/ undefined, /*parameters*/ undefined, /*type*/ undefined, factory.createBlock([])); + const func = factory.createFunctionExpression( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + "fn", + /*typeParameters*/ undefined, + /*parameters*/ undefined, + /*type*/ undefined, + factory.createBlock([]), + ); checkExpression(func); - checkExpression(factory.createCallExpression(func, /*typeArguments*/ undefined, /*argumentsArray*/ undefined)); - checkExpression(factory.createTaggedTemplateExpression(func, /*typeArguments*/ undefined, factory.createNoSubstitutionTemplateLiteral(""))); + checkExpression( + factory.createCallExpression(func, /*typeArguments*/ undefined, /*argumentsArray*/ undefined), + ); + checkExpression( + factory.createTaggedTemplateExpression( + func, + /*typeArguments*/ undefined, + factory.createNoSubstitutionTemplateLiteral(""), + ), + ); - checkExpression(factory.createBinaryExpression(factory.createStringLiteral("a"), SyntaxKind.CommaToken, factory.createStringLiteral("b"))); - checkExpression(factory.createCommaListExpression([factory.createStringLiteral("a"), factory.createStringLiteral("b")])); + checkExpression( + factory.createBinaryExpression( + factory.createStringLiteral("a"), + SyntaxKind.CommaToken, + factory.createStringLiteral("b"), + ), + ); + checkExpression( + factory.createCommaListExpression([ + factory.createStringLiteral("a"), + factory.createStringLiteral("b"), + ]), + ); }); }); @@ -46,10 +89,30 @@ namespace ts { checkBody(factory.createObjectLiteralExpression()); checkBody(factory.createPropertyAccessExpression(factory.createObjectLiteralExpression(), "prop")); - checkBody(factory.createAsExpression(factory.createPropertyAccessExpression(factory.createObjectLiteralExpression(), "prop"), factory.createTypeReferenceNode("T", /*typeArguments*/ undefined))); - checkBody(factory.createNonNullExpression(factory.createPropertyAccessExpression(factory.createObjectLiteralExpression(), "prop"))); - checkBody(factory.createCommaListExpression([factory.createStringLiteral("a"), factory.createStringLiteral("b")])); - checkBody(factory.createBinaryExpression(factory.createStringLiteral("a"), SyntaxKind.CommaToken, factory.createStringLiteral("b"))); + checkBody( + factory.createAsExpression( + factory.createPropertyAccessExpression(factory.createObjectLiteralExpression(), "prop"), + factory.createTypeReferenceNode("T", /*typeArguments*/ undefined), + ), + ); + checkBody( + factory.createNonNullExpression( + factory.createPropertyAccessExpression(factory.createObjectLiteralExpression(), "prop"), + ), + ); + checkBody( + factory.createCommaListExpression([ + factory.createStringLiteral("a"), + factory.createStringLiteral("b"), + ]), + ); + checkBody( + factory.createBinaryExpression( + factory.createStringLiteral("a"), + SyntaxKind.CommaToken, + factory.createStringLiteral("b"), + ), + ); }); }); @@ -66,7 +129,10 @@ namespace ts { ); function checkRhs(operator: BinaryOperator, expectParens: boolean) { const node = factory.createBinaryExpression(lhs, operator, rhs); - assertSyntaxKind(node.right, expectParens ? SyntaxKind.ParenthesizedExpression : SyntaxKind.ArrowFunction); + assertSyntaxKind( + node.right, + expectParens ? SyntaxKind.ParenthesizedExpression : SyntaxKind.ArrowFunction, + ); } checkRhs(SyntaxKind.CommaToken, /*expectParens*/ false); diff --git a/src/testRunner/unittests/incrementalParser.ts b/src/testRunner/unittests/incrementalParser.ts index b8418760f177b..4a1464ced8a5a 100644 --- a/src/testRunner/unittests/incrementalParser.ts +++ b/src/testRunner/unittests/incrementalParser.ts @@ -1,21 +1,43 @@ namespace ts { - function withChange(text: IScriptSnapshot, start: number, length: number, newText: string): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { + function withChange( + text: IScriptSnapshot, + start: number, + length: number, + newText: string, + ): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { const contents = getSnapshotText(text); const newContents = contents.substr(0, start) + newText + contents.substring(start + length); - return { text: ScriptSnapshot.fromString(newContents), textChangeRange: createTextChangeRange(createTextSpan(start, length), newText.length) }; + return { + text: ScriptSnapshot.fromString(newContents), + textChangeRange: createTextChangeRange(createTextSpan(start, length), newText.length), + }; } - function withInsert(text: IScriptSnapshot, start: number, newText: string): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { + function withInsert( + text: IScriptSnapshot, + start: number, + newText: string, + ): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { return withChange(text, start, 0, newText); } - function withDelete(text: IScriptSnapshot, start: number, length: number): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { + function withDelete( + text: IScriptSnapshot, + start: number, + length: number, + ): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { return withChange(text, start, length, ""); } function createTree(text: IScriptSnapshot, version: string) { - return createLanguageServiceSourceFile(/*fileName:*/ "", text, ScriptTarget.Latest, version, /*setNodeParents:*/ true); + return createLanguageServiceSourceFile( + /*fileName:*/ "", + text, + ScriptTarget.Latest, + version, + /*setNodeParents:*/ true, + ); } function assertSameDiagnostics(file1: SourceFile, file2: SourceFile) { @@ -42,7 +64,13 @@ namespace ts { // be a good thing. If it decreases, that's not great (less reusability), but that may be // unavoidable. If it does decrease an investigation should be done to make sure that things // are still ok and we're still appropriately reusing most of the tree. - function compareTrees(oldText: IScriptSnapshot, newText: IScriptSnapshot, textChangeRange: TextChangeRange, expectedReusedElements: number, oldTree?: SourceFile) { + function compareTrees( + oldText: IScriptSnapshot, + newText: IScriptSnapshot, + textChangeRange: TextChangeRange, + expectedReusedElements: number, + oldTree?: SourceFile, + ) { oldTree = oldTree || createTree(oldText, /*version:*/ "."); Utils.assertInvariants(oldTree, /*parent:*/ undefined); @@ -51,7 +79,12 @@ namespace ts { Utils.assertInvariants(newTree, /*parent:*/ undefined); // Create a tree for the new text, in an incremental fashion. - const incrementalNewTree = updateLanguageServiceSourceFile(oldTree, newText, oldTree.version + ".", textChangeRange); + const incrementalNewTree = updateLanguageServiceSourceFile( + oldTree, + newText, + oldTree.version + ".", + textChangeRange, + ); Utils.assertInvariants(incrementalNewTree, /*parent:*/ undefined); // We should get the same tree when doign a full or incremental parse. @@ -68,7 +101,11 @@ namespace ts { if (expectedReusedElements !== -1) { const actualReusedCount = reusedElements(oldTree, incrementalNewTree); - assert.equal(actualReusedCount, expectedReusedElements, actualReusedCount + " !== " + expectedReusedElements); + assert.equal( + actualReusedCount, + expectedReusedElements, + actualReusedCount + " !== " + expectedReusedElements, + ); } return { oldTree, newTree, incrementalNewTree }; @@ -98,7 +135,8 @@ namespace ts { for (let i = 0; i < repeat; i++) { const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withDelete(oldText, index, 1); - const newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree).incrementalNewTree; + const newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree) + .incrementalNewTree; source = getSnapshotText(newTextAndChange.text); oldTree = newTree; @@ -111,7 +149,8 @@ namespace ts { for (let i = 0; i < repeat; i++) { const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withInsert(oldText, index + i, toInsert.charAt(i)); - const newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree).incrementalNewTree; + const newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree) + .incrementalNewTree; source = getSnapshotText(newTextAndChange.text); oldTree = newTree; @@ -120,13 +159,13 @@ namespace ts { describe("unittests:: Incremental Parser", () => { it("Inserting into method", () => { - const source = "class C {\r\n" + - " public foo1() { }\r\n" + - " public foo2() {\r\n" + - " return 1;\r\n" + - " }\r\n" + - " public foo3() { }\r\n" + - "}"; + const source = "class C {\r\n" + + " public foo1() { }\r\n" + + " public foo2() {\r\n" + + " return 1;\r\n" + + " }\r\n" + + " public foo3() { }\r\n" + + "}"; const oldText = ScriptSnapshot.fromString(source); const semicolonIndex = source.indexOf(";"); @@ -136,13 +175,13 @@ namespace ts { }); it("Deleting from method", () => { - const source = "class C {\r\n" + - " public foo1() { }\r\n" + - " public foo2() {\r\n" + - " return 1 + 1;\r\n" + - " }\r\n" + - " public foo3() { }\r\n" + - "}"; + const source = "class C {\r\n" + + " public foo1() { }\r\n" + + " public foo2() {\r\n" + + " return 1 + 1;\r\n" + + " }\r\n" + + " public foo3() { }\r\n" + + "}"; const index = source.indexOf("+ 1"); const oldText = ScriptSnapshot.fromString(source); @@ -211,11 +250,11 @@ namespace ts { it("Parameter 1", () => { // Should be able to reuse all the parameters. - const source = "class C {\r\n" + - " public foo2(a, b, c, d) {\r\n" + - " return 1;\r\n" + - " }\r\n" + - "}"; + const source = "class C {\r\n" + + " public foo2(a, b, c, d) {\r\n" + + " return 1;\r\n" + + " }\r\n" + + "}"; const semicolonIndex = source.indexOf(";"); const oldText = ScriptSnapshot.fromString(source); @@ -285,7 +324,8 @@ namespace ts { }); it("Strict mode 5", () => { - const source = "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; + const source = + "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; const index = source.indexOf("b"); const oldText = ScriptSnapshot.fromString(source); @@ -295,7 +335,8 @@ namespace ts { }); it("Strict mode 6", () => { - const source = "'use strict';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; + const source = + "'use strict';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; const index = source.indexOf("s"); const oldText = ScriptSnapshot.fromString(source); @@ -305,7 +346,8 @@ namespace ts { }); it("Strict mode 7", () => { - const source = "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; + const source = + "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; const index = source.indexOf("f"); const oldText = ScriptSnapshot.fromString(source); @@ -517,7 +559,8 @@ namespace ts { }); it("Delete semicolon", () => { - const source = "export class Foo {\r\n}\r\n\r\nexport var foo = new Foo();\r\n\r\n export function test(foo: Foo) {\r\n return true;\r\n }\r\n"; + const source = + "export class Foo {\r\n}\r\n\r\nexport var foo = new Foo();\r\n\r\n export function test(foo: Foo) {\r\n return true;\r\n }\r\n"; const oldText = ScriptSnapshot.fromString(source); const index = source.lastIndexOf(";"); @@ -723,7 +766,8 @@ module m3 { }\ }); it("Moving index signatures from class to interface", () => { - const source = "class C { public [a: number]: string; public [a: number]: string; public [a: number]: string }"; + const source = + "class C { public [a: number]: string; public [a: number]: string; public [a: number]: string }"; const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 0, "class".length, "interface"); @@ -732,7 +776,8 @@ module m3 { }\ }); it("Moving index signatures from class to interface in strict mode", () => { - const source = '"use strict"; class C { public [a: number]: string; public [a: number]: string; public [a: number]: string }'; + const source = + '"use strict"; class C { public [a: number]: string; public [a: number]: string; public [a: number]: string }'; const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 14, "class".length, "interface"); @@ -741,7 +786,8 @@ module m3 { }\ }); it("Moving index signatures from interface to class", () => { - const source = "interface C { public [a: number]: string; public [a: number]: string; public [a: number]: string }"; + const source = + "interface C { public [a: number]: string; public [a: number]: string; public [a: number]: string }"; const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 0, "interface".length, "class"); @@ -750,7 +796,8 @@ module m3 { }\ }); it("Moving index signatures from interface to class in strict mode", () => { - const source = '"use strict"; interface C { public [a: number]: string; public [a: number]: string; public [a: number]: string }'; + const source = + '"use strict"; interface C { public [a: number]: string; public [a: number]: string; public [a: number]: string }'; const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 14, "interface".length, "class"); @@ -789,7 +836,12 @@ module m3 { }\ const source = `class Greeter { constructor(element: HTMLElement) { } }`; const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 15, 0, "\n"); - const { oldTree, incrementalNewTree } = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + const { oldTree, incrementalNewTree } = compareTrees( + oldText, + newTextAndChange.text, + newTextAndChange.textChangeRange, + -1, + ); bindSourceFile(oldTree, {}); bindSourceFile(incrementalNewTree, {}); assert.equal(oldTree.transformFlags, incrementalNewTree.transformFlags); @@ -805,22 +857,22 @@ module m3 { }\ }); it("Type after incomplete enum 1", () => { - const source = "function foo() {\r\n" + - " function getOccurrencesAtPosition() {\r\n" + - " switch (node) {\r\n" + - " enum \r\n" + - " }\r\n" + - " \r\n" + - " return undefined;\r\n" + - " \r\n" + - " function keywordToReferenceEntry() {\r\n" + - " }\r\n" + - " }\r\n" + - " \r\n" + - " return {\r\n" + - " getEmitOutput: (fileName): Bar => null,\r\n" + - " };\r\n" + - " }"; + const source = "function foo() {\r\n" + + " function getOccurrencesAtPosition() {\r\n" + + " switch (node) {\r\n" + + " enum \r\n" + + " }\r\n" + + " \r\n" + + " return undefined;\r\n" + + " \r\n" + + " function keywordToReferenceEntry() {\r\n" + + " }\r\n" + + " }\r\n" + + " \r\n" + + " return {\r\n" + + " getEmitOutput: (fileName): Bar => null,\r\n" + + " };\r\n" + + " }"; const index = source.indexOf("enum ") + "enum ".length; insertCode(source, index, "Fo"); @@ -861,12 +913,23 @@ module m3 { }\ verifyScenario("when changing text that adds another comment", verifyChangeDirectiveType); verifyScenario("when changing text that keeps the comment but adds more nodes", verifyReuseChange); - function verifyCommentDirectives(oldText: IScriptSnapshot, newTextAndChange: { text: IScriptSnapshot; textChangeRange: TextChangeRange; }) { - const { incrementalNewTree, newTree } = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + function verifyCommentDirectives( + oldText: IScriptSnapshot, + newTextAndChange: { text: IScriptSnapshot; textChangeRange: TextChangeRange; }, + ) { + const { incrementalNewTree, newTree } = compareTrees( + oldText, + newTextAndChange.text, + newTextAndChange.textChangeRange, + -1, + ); assert.deepEqual(incrementalNewTree.commentDirectives, newTree.commentDirectives); } - function verifyScenario(scenario: string, verifyChange: (atIndex: number, singleIgnore?: true) => void) { + function verifyScenario( + scenario: string, + verifyChange: (atIndex: number, singleIgnore?: true) => void, + ) { it(`${scenario} - 0`, () => { verifyChange(0); }); @@ -904,14 +967,20 @@ module m3 { }\ function verifyDelete(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex); - const oldText = ScriptSnapshot.fromString(textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore)); + const oldText = ScriptSnapshot.fromString( + textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore), + ); const newTextAndChange = withDelete(oldText, index, tsIgnoreComment.length); verifyCommentDirectives(oldText, newTextAndChange); } function verifyInsert(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex); - const source = textWithIgnoreCommentFrom(textWithIgnoreComment.slice(0, index) + textWithIgnoreComment.slice(index + tsIgnoreComment.length), singleIgnore); + const source = textWithIgnoreCommentFrom( + textWithIgnoreComment.slice(0, index) + + textWithIgnoreComment.slice(index + tsIgnoreComment.length), + singleIgnore, + ); const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withInsert(oldText, index, tsIgnoreComment); verifyCommentDirectives(oldText, newTextAndChange); @@ -919,14 +988,19 @@ module m3 { }\ function verifyChangeToBlah(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex) + tsIgnoreComment.indexOf("@"); - const oldText = ScriptSnapshot.fromString(textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore)); + const oldText = ScriptSnapshot.fromString( + textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore), + ); const newTextAndChange = withChange(oldText, index, 1, "blah "); verifyCommentDirectives(oldText, newTextAndChange); } function verifyChangeBackToDirective(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex) + tsIgnoreComment.indexOf("@"); - const source = textWithIgnoreCommentFrom(textWithIgnoreComment.slice(0, index) + "blah " + textWithIgnoreComment.slice(index + 1), singleIgnore); + const source = textWithIgnoreCommentFrom( + textWithIgnoreComment.slice(0, index) + "blah " + textWithIgnoreComment.slice(index + 1), + singleIgnore, + ); const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, index, "blah ".length, "@"); verifyCommentDirectives(oldText, newTextAndChange); @@ -935,7 +1009,10 @@ module m3 { }\ function verifyDeletingBlah(atIndex: number, singleIgnore?: true) { const tsIgnoreIndex = getIndexOfTsIgnoreComment(atIndex); const index = tsIgnoreIndex + tsIgnoreComment.indexOf("@"); - const source = textWithIgnoreCommentFrom(textWithIgnoreComment.slice(0, index) + "blah " + textWithIgnoreComment.slice(index + 1), singleIgnore); + const source = textWithIgnoreCommentFrom( + textWithIgnoreComment.slice(0, index) + "blah " + textWithIgnoreComment.slice(index + 1), + singleIgnore, + ); const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withDelete(oldText, tsIgnoreIndex, tsIgnoreComment.length + "blah".length); verifyCommentDirectives(oldText, newTextAndChange); @@ -943,7 +1020,9 @@ module m3 { }\ function verifyChangeDirectiveType(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex) + tsIgnoreComment.indexOf("ignore"); - const oldText = ScriptSnapshot.fromString(textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore)); + const oldText = ScriptSnapshot.fromString( + textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore), + ); const newTextAndChange = withChange(oldText, index, "ignore".length, "expect-error"); verifyCommentDirectives(oldText, newTextAndChange); } diff --git a/src/testRunner/unittests/jsDocParsing.ts b/src/testRunner/unittests/jsDocParsing.ts index c69281abad4b8..6ee11f5fb3ee9 100644 --- a/src/testRunner/unittests/jsDocParsing.ts +++ b/src/testRunner/unittests/jsDocParsing.ts @@ -4,9 +4,15 @@ namespace ts { function parsesCorrectly(name: string, content: string) { it(name, () => { const typeAndDiagnostics = parseJSDocTypeExpressionForTests(content); - assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0, "no errors issued"); - - Harness.Baseline.runBaseline("JSDocParsing/TypeExpressions.parsesCorrectly." + name + ".json", Utils.sourceFileToJSON(typeAndDiagnostics!.jsDocTypeExpression.type)); + assert.isTrue( + typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0, + "no errors issued", + ); + + Harness.Baseline.runBaseline( + "JSDocParsing/TypeExpressions.parsesCorrectly." + name + ".json", + Utils.sourceFileToJSON(typeAndDiagnostics!.jsDocTypeExpression.type), + ); }); } @@ -95,7 +101,14 @@ namespace ts { Debug.fail("Comment has at least one diagnostic: " + comment.diagnostics[0].messageText); } - Harness.Baseline.runBaseline("JSDocParsing/DocComments.parsesCorrectly." + name + ".json", JSON.stringify(comment.jsDoc, (_, v) => v && v.pos !== undefined ? JSON.parse(Utils.sourceFileToJSON(v)) : v, 4)); + Harness.Baseline.runBaseline( + "JSDocParsing/DocComments.parsesCorrectly." + name + ".json", + JSON.stringify( + comment.jsDoc, + (_, v) => v && v.pos !== undefined ? JSON.parse(Utils.sourceFileToJSON(v)) : v, + 4, + ), + ); }); } @@ -434,7 +447,12 @@ oh.no }); describe("getFirstToken", () => { it("gets jsdoc", () => { - const root = createSourceFile("foo.ts", "/** comment */var a = true;", ScriptTarget.ES5, /*setParentNodes*/ true); + const root = createSourceFile( + "foo.ts", + "/** comment */var a = true;", + ScriptTarget.ES5, + /*setParentNodes*/ true, + ); assert.isDefined(root); assert.equal(root.kind, SyntaxKind.SourceFile); const first = root.getFirstToken(); @@ -444,7 +462,12 @@ oh.no }); describe("getLastToken", () => { it("gets jsdoc", () => { - const root = createSourceFile("foo.ts", "var a = true;/** comment */", ScriptTarget.ES5, /*setParentNodes*/ true); + const root = createSourceFile( + "foo.ts", + "var a = true;/** comment */", + ScriptTarget.ES5, + /*setParentNodes*/ true, + ); assert.isDefined(root); const last = root.getLastToken(); assert.isDefined(last); @@ -453,7 +476,12 @@ oh.no }); describe("getStart", () => { it("runs when node with JSDoc but no parent pointers", () => { - const root = createSourceFile("foo.ts", "/** */var a = true;", ScriptTarget.ES5, /*setParentNodes*/ false); + const root = createSourceFile( + "foo.ts", + "/** */var a = true;", + ScriptTarget.ES5, + /*setParentNodes*/ false, + ); root.statements[0].getStart(root, /*includeJsdocComment*/ true); }); }); diff --git a/src/testRunner/unittests/moduleResolution.ts b/src/testRunner/unittests/moduleResolution.ts index 2957ba3b7411c..1bcd1e1845147 100644 --- a/src/testRunner/unittests/moduleResolution.ts +++ b/src/testRunner/unittests/moduleResolution.ts @@ -1,5 +1,8 @@ namespace ts { - export function checkResolvedModule(actual: ResolvedModuleFull | undefined, expected: ResolvedModuleFull | undefined): boolean { + export function checkResolvedModule( + actual: ResolvedModuleFull | undefined, + expected: ResolvedModuleFull | undefined, + ): boolean { if (!expected) { if (actual) { assert.fail(actual, expected, "expected resolved module to be undefined"); @@ -12,19 +15,39 @@ namespace ts { return false; } - assert.isTrue(actual.resolvedFileName === expected.resolvedFileName, `'resolvedFileName': expected '${actual.resolvedFileName}' to be equal to '${expected.resolvedFileName}'`); - assert.isTrue(actual.extension === expected.extension, `'ext': expected '${actual.extension}' to be equal to '${expected.extension}'`); - assert.isTrue(actual.isExternalLibraryImport === expected.isExternalLibraryImport, `'isExternalLibraryImport': expected '${actual.isExternalLibraryImport}' to be equal to '${expected.isExternalLibraryImport}'`); + assert.isTrue( + actual.resolvedFileName === expected.resolvedFileName, + `'resolvedFileName': expected '${actual.resolvedFileName}' to be equal to '${expected.resolvedFileName}'`, + ); + assert.isTrue( + actual.extension === expected.extension, + `'ext': expected '${actual.extension}' to be equal to '${expected.extension}'`, + ); + assert.isTrue( + actual.isExternalLibraryImport === expected.isExternalLibraryImport, + `'isExternalLibraryImport': expected '${actual.isExternalLibraryImport}' to be equal to '${expected.isExternalLibraryImport}'`, + ); return true; } - export function checkResolvedModuleWithFailedLookupLocations(actual: ResolvedModuleWithFailedLookupLocations, expectedResolvedModule: ResolvedModuleFull, expectedFailedLookupLocations: string[]): void { + export function checkResolvedModuleWithFailedLookupLocations( + actual: ResolvedModuleWithFailedLookupLocations, + expectedResolvedModule: ResolvedModuleFull, + expectedFailedLookupLocations: string[], + ): void { assert.isTrue(actual.resolvedModule !== undefined, "module should be resolved"); checkResolvedModule(actual.resolvedModule, expectedResolvedModule); - assert.deepEqual(actual.failedLookupLocations, expectedFailedLookupLocations, `Failed lookup locations should match - expected has ${expectedFailedLookupLocations.length}, actual has ${actual.failedLookupLocations.length}`); + assert.deepEqual( + actual.failedLookupLocations, + expectedFailedLookupLocations, + `Failed lookup locations should match - expected has ${expectedFailedLookupLocations.length}, actual has ${actual.failedLookupLocations.length}`, + ); } - export function createResolvedModule(resolvedFileName: string, isExternalLibraryImport = false): ResolvedModuleFull { + export function createResolvedModule( + resolvedFileName: string, + isExternalLibraryImport = false, + ): ResolvedModuleFull { return { resolvedFileName, extension: extensionFromPath(resolvedFileName), isExternalLibraryImport }; } @@ -63,7 +86,10 @@ namespace ts { realpath, directoryExists: path => directories.has(path), fileExists: path => { - assert.isTrue(directories.has(getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`); + assert.isTrue( + directories.has(getDirectoryPath(path)), + `'fileExists' '${path}' request in non-existing directory`, + ); return map.has(path); }, useCaseSensitiveFileNames: true, @@ -83,7 +109,14 @@ namespace ts { describe("unittests:: moduleResolution:: Node module resolution - relative paths", () => { // node module resolution does _not_ implicitly append these extensions to an extensionless path (though will still attempt to load them if explicitly) - const nonImplicitExtensions = [Extension.Mts, Extension.Dmts, Extension.Mjs, Extension.Cts, Extension.Dcts, Extension.Cjs]; + const nonImplicitExtensions = [ + Extension.Mts, + Extension.Dmts, + Extension.Mjs, + Extension.Cts, + Extension.Dcts, + Extension.Cjs, + ]; const autoExtensions = filter(supportedTSExtensionsFlat, e => nonImplicitExtensions.indexOf(e) === -1); function testLoadAsFile(containingFileName: string, moduleFileNameNoExt: string, moduleName: string): void { for (const ext of autoExtensions) { @@ -94,7 +127,12 @@ namespace ts { function test(ext: string, hasDirectoryExists: boolean) { const containingFile = { name: containingFileName }; const moduleFile = { name: moduleFileNameNoExt + ext }; - const resolution = nodeModuleNameResolver(moduleName, containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile)); + const resolution = nodeModuleNameResolver( + moduleName, + containingFile.name, + {}, + createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile), + ); checkResolvedModule(resolution.resolvedModule, createResolvedModule(moduleFile.name)); const failedLookupLocations: string[] = []; @@ -104,7 +142,10 @@ namespace ts { break; } else { - failedLookupLocations.push(normalizePath(getRootLength(moduleName) === 0 ? combinePaths(dir, moduleName) : moduleName) + e); + failedLookupLocations.push( + normalizePath(getRootLength(moduleName) === 0 ? combinePaths(dir, moduleName) : moduleName) + + e, + ); } } @@ -128,7 +169,13 @@ namespace ts { testLoadAsFile("c:/foo/bar/baz.ts", "c:/foo", "c:/foo"); }); - function testLoadingFromPackageJson(containingFileName: string, packageJsonFileName: string, fieldRef: string, moduleFileName: string, moduleName: string): void { + function testLoadingFromPackageJson( + containingFileName: string, + packageJsonFileName: string, + fieldRef: string, + moduleFileName: string, + moduleName: string, + ): void { test(/*hasDirectoryExists*/ false); test(/*hasDirectoryExists*/ true); @@ -136,7 +183,12 @@ namespace ts { const containingFile = { name: containingFileName }; const packageJson = { name: packageJsonFileName, content: JSON.stringify({ typings: fieldRef }) }; const moduleFile = { name: moduleFileName }; - const resolution = nodeModuleNameResolver(moduleName, containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, moduleFile)); + const resolution = nodeModuleNameResolver( + moduleName, + containingFile.name, + {}, + createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, moduleFile), + ); checkResolvedModule(resolution.resolvedModule, createResolvedModule(moduleFile.name)); // expect three failed lookup location - attempt to load module as file with all supported extensions assert.equal(resolution.failedLookupLocations.length, supportedTSExtensions[0].length); @@ -145,7 +197,13 @@ namespace ts { } it("module name as directory - load from 'typings'", () => { - testLoadingFromPackageJson("/a/b/c/d.ts", "/a/b/c/bar/package.json", "c/d/e.d.ts", "/a/b/c/bar/c/d/e.d.ts", "./bar"); + testLoadingFromPackageJson( + "/a/b/c/d.ts", + "/a/b/c/bar/package.json", + "c/d/e.d.ts", + "/a/b/c/bar/c/d/e.d.ts", + "./bar", + ); testLoadingFromPackageJson("/a/b/c/d.ts", "/a/bar/package.json", "e.d.ts", "/a/bar/e.d.ts", "../../bar"); testLoadingFromPackageJson("/a/b/c/d.ts", "/bar/package.json", "e.d.ts", "/bar/e.d.ts", "/bar"); testLoadingFromPackageJson("c:/a/b/c/d.ts", "c:/bar/package.json", "e.d.ts", "c:/bar/e.d.ts", "c:/bar"); @@ -163,9 +221,17 @@ namespace ts { const indexPath = "/node_modules/b/index.d.ts"; const indexFile = { name: indexPath }; - const resolution = nodeModuleNameResolver("b", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, moduleFile, indexFile)); + const resolution = nodeModuleNameResolver( + "b", + containingFile.name, + {}, + createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, moduleFile, indexFile), + ); - checkResolvedModule(resolution.resolvedModule, createResolvedModule(indexPath, /*isExternalLibraryImport*/ true)); + checkResolvedModule( + resolution.resolvedModule, + createResolvedModule(indexPath, /*isExternalLibraryImport*/ true), + ); } } @@ -184,7 +250,12 @@ namespace ts { const containingFile = { name: "/a/b/c.ts" }; const packageJson = { name: "/a/b/foo/package.json", content: JSON.stringify({ main: "/c/d" }) }; const indexFile = { name: "/a/b/foo/index.d.ts" }; - const resolution = nodeModuleNameResolver("./foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, indexFile)); + const resolution = nodeModuleNameResolver( + "./foo", + containingFile.name, + {}, + createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, indexFile), + ); checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(indexFile.name), [ "/a/b/foo.ts", "/a/b/foo.tsx", @@ -305,37 +376,46 @@ namespace ts { function test(hasDirectoryExists: boolean) { const containingFile = { name: "/a/b/c/d/e.ts" }; const moduleFile = { name: "/a/b/node_modules/foo.ts" }; - const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile)); - checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), [ - "/a/b/c/d/node_modules/foo/package.json", - "/a/b/c/d/node_modules/foo.ts", - "/a/b/c/d/node_modules/foo.tsx", - "/a/b/c/d/node_modules/foo.d.ts", - - "/a/b/c/d/node_modules/foo/index.ts", - "/a/b/c/d/node_modules/foo/index.tsx", - "/a/b/c/d/node_modules/foo/index.d.ts", - - "/a/b/c/d/node_modules/@types/foo/package.json", - "/a/b/c/d/node_modules/@types/foo.d.ts", - - "/a/b/c/d/node_modules/@types/foo/index.d.ts", - - "/a/b/c/node_modules/foo/package.json", - "/a/b/c/node_modules/foo.ts", - "/a/b/c/node_modules/foo.tsx", - "/a/b/c/node_modules/foo.d.ts", - - "/a/b/c/node_modules/foo/index.ts", - "/a/b/c/node_modules/foo/index.tsx", - "/a/b/c/node_modules/foo/index.d.ts", - - "/a/b/c/node_modules/@types/foo/package.json", - "/a/b/c/node_modules/@types/foo.d.ts", - - "/a/b/c/node_modules/@types/foo/index.d.ts", - "/a/b/node_modules/foo/package.json", - ]); + const resolution = nodeModuleNameResolver( + "foo", + containingFile.name, + {}, + createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile), + ); + checkResolvedModuleWithFailedLookupLocations( + resolution, + createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), + [ + "/a/b/c/d/node_modules/foo/package.json", + "/a/b/c/d/node_modules/foo.ts", + "/a/b/c/d/node_modules/foo.tsx", + "/a/b/c/d/node_modules/foo.d.ts", + + "/a/b/c/d/node_modules/foo/index.ts", + "/a/b/c/d/node_modules/foo/index.tsx", + "/a/b/c/d/node_modules/foo/index.d.ts", + + "/a/b/c/d/node_modules/@types/foo/package.json", + "/a/b/c/d/node_modules/@types/foo.d.ts", + + "/a/b/c/d/node_modules/@types/foo/index.d.ts", + + "/a/b/c/node_modules/foo/package.json", + "/a/b/c/node_modules/foo.ts", + "/a/b/c/node_modules/foo.tsx", + "/a/b/c/node_modules/foo.d.ts", + + "/a/b/c/node_modules/foo/index.ts", + "/a/b/c/node_modules/foo/index.tsx", + "/a/b/c/node_modules/foo/index.d.ts", + + "/a/b/c/node_modules/@types/foo/package.json", + "/a/b/c/node_modules/@types/foo.d.ts", + + "/a/b/c/node_modules/@types/foo/index.d.ts", + "/a/b/node_modules/foo/package.json", + ], + ); } }); @@ -346,8 +426,16 @@ namespace ts { function test(hasDirectoryExists: boolean) { const containingFile = { name: "/a/b/c/d/e.ts" }; const moduleFile = { name: "/a/b/node_modules/foo.d.ts" }; - const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile)); - checkResolvedModule(resolution.resolvedModule, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true)); + const resolution = nodeModuleNameResolver( + "foo", + containingFile.name, + {}, + createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile), + ); + checkResolvedModule( + resolution.resolvedModule, + createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), + ); } }); @@ -358,58 +446,67 @@ namespace ts { function test(hasDirectoryExists: boolean) { const containingFile: File = { name: "/a/node_modules/b/c/node_modules/d/e.ts" }; const moduleFile: File = { name: "/a/node_modules/foo/index.d.ts" }; - const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile)); - checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), [ - "/a/node_modules/b/c/node_modules/d/node_modules/foo/package.json", - "/a/node_modules/b/c/node_modules/d/node_modules/foo.ts", - "/a/node_modules/b/c/node_modules/d/node_modules/foo.tsx", - "/a/node_modules/b/c/node_modules/d/node_modules/foo.d.ts", + const resolution = nodeModuleNameResolver( + "foo", + containingFile.name, + {}, + createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile), + ); + checkResolvedModuleWithFailedLookupLocations( + resolution, + createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), + [ + "/a/node_modules/b/c/node_modules/d/node_modules/foo/package.json", + "/a/node_modules/b/c/node_modules/d/node_modules/foo.ts", + "/a/node_modules/b/c/node_modules/d/node_modules/foo.tsx", + "/a/node_modules/b/c/node_modules/d/node_modules/foo.d.ts", - "/a/node_modules/b/c/node_modules/d/node_modules/foo/index.ts", - "/a/node_modules/b/c/node_modules/d/node_modules/foo/index.tsx", - "/a/node_modules/b/c/node_modules/d/node_modules/foo/index.d.ts", + "/a/node_modules/b/c/node_modules/d/node_modules/foo/index.ts", + "/a/node_modules/b/c/node_modules/d/node_modules/foo/index.tsx", + "/a/node_modules/b/c/node_modules/d/node_modules/foo/index.d.ts", - "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo/package.json", - "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo.d.ts", + "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo/package.json", + "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo.d.ts", - "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo/index.d.ts", + "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo/index.d.ts", - "/a/node_modules/b/c/node_modules/foo/package.json", - "/a/node_modules/b/c/node_modules/foo.ts", - "/a/node_modules/b/c/node_modules/foo.tsx", - "/a/node_modules/b/c/node_modules/foo.d.ts", + "/a/node_modules/b/c/node_modules/foo/package.json", + "/a/node_modules/b/c/node_modules/foo.ts", + "/a/node_modules/b/c/node_modules/foo.tsx", + "/a/node_modules/b/c/node_modules/foo.d.ts", - "/a/node_modules/b/c/node_modules/foo/index.ts", - "/a/node_modules/b/c/node_modules/foo/index.tsx", - "/a/node_modules/b/c/node_modules/foo/index.d.ts", + "/a/node_modules/b/c/node_modules/foo/index.ts", + "/a/node_modules/b/c/node_modules/foo/index.tsx", + "/a/node_modules/b/c/node_modules/foo/index.d.ts", - "/a/node_modules/b/c/node_modules/@types/foo/package.json", - "/a/node_modules/b/c/node_modules/@types/foo.d.ts", + "/a/node_modules/b/c/node_modules/@types/foo/package.json", + "/a/node_modules/b/c/node_modules/@types/foo.d.ts", - "/a/node_modules/b/c/node_modules/@types/foo/index.d.ts", + "/a/node_modules/b/c/node_modules/@types/foo/index.d.ts", - "/a/node_modules/b/node_modules/foo/package.json", - "/a/node_modules/b/node_modules/foo.ts", - "/a/node_modules/b/node_modules/foo.tsx", - "/a/node_modules/b/node_modules/foo.d.ts", + "/a/node_modules/b/node_modules/foo/package.json", + "/a/node_modules/b/node_modules/foo.ts", + "/a/node_modules/b/node_modules/foo.tsx", + "/a/node_modules/b/node_modules/foo.d.ts", - "/a/node_modules/b/node_modules/foo/index.ts", - "/a/node_modules/b/node_modules/foo/index.tsx", - "/a/node_modules/b/node_modules/foo/index.d.ts", + "/a/node_modules/b/node_modules/foo/index.ts", + "/a/node_modules/b/node_modules/foo/index.tsx", + "/a/node_modules/b/node_modules/foo/index.d.ts", - "/a/node_modules/b/node_modules/@types/foo/package.json", - "/a/node_modules/b/node_modules/@types/foo.d.ts", + "/a/node_modules/b/node_modules/@types/foo/package.json", + "/a/node_modules/b/node_modules/@types/foo.d.ts", - "/a/node_modules/b/node_modules/@types/foo/index.d.ts", + "/a/node_modules/b/node_modules/@types/foo/index.d.ts", - "/a/node_modules/foo/package.json", - "/a/node_modules/foo.ts", - "/a/node_modules/foo.tsx", - "/a/node_modules/foo.d.ts", + "/a/node_modules/foo/package.json", + "/a/node_modules/foo.ts", + "/a/node_modules/foo.tsx", + "/a/node_modules/foo.d.ts", - "/a/node_modules/foo/index.ts", - "/a/node_modules/foo/index.tsx", - ]); + "/a/node_modules/foo/index.ts", + "/a/node_modules/foo/index.tsx", + ], + ); } }); @@ -422,11 +519,17 @@ namespace ts { const host = createModuleResolutionHost( /*hasDirectoryExists*/ true, { name: realFileName, symlinks: [symlinkFileName] }, - { name: "/app/node_modules/linked/package.json", content: '{"version": "0.0.0", "main": "./index"}' }, + { + name: "/app/node_modules/linked/package.json", + content: '{"version": "0.0.0", "main": "./index"}', + }, ); const resolution = nodeModuleNameResolver("linked", "/app/app.ts", { preserveSymlinks }, host); const resolvedFileName = preserveSymlinks ? symlinkFileName : realFileName; - checkResolvedModule(resolution.resolvedModule, createResolvedModule(resolvedFileName, /*isExternalLibraryImport*/ true)); + checkResolvedModule( + resolution.resolvedModule, + createResolvedModule(resolvedFileName, /*isExternalLibraryImport*/ true), + ); }); } @@ -445,10 +548,16 @@ namespace ts { const compilerOptions: CompilerOptions = { moduleResolution: ModuleResolutionKind.NodeJs }; const cache = createModuleResolutionCache("/", f => f); let resolution = resolveModuleName("a", "/sub/dir/foo.ts", compilerOptions, host, cache); - checkResolvedModule(resolution.resolvedModule, createResolvedModule("/modules/a.ts", /*isExternalLibraryImport*/ true)); + checkResolvedModule( + resolution.resolvedModule, + createResolvedModule("/modules/a.ts", /*isExternalLibraryImport*/ true), + ); resolution = resolveModuleName("a", "/sub/foo.ts", compilerOptions, host, cache); - checkResolvedModule(resolution.resolvedModule, createResolvedModule("/modules/a.ts", /*isExternalLibraryImport*/ true)); + checkResolvedModule( + resolution.resolvedModule, + createResolvedModule("/modules/a.ts", /*isExternalLibraryImport*/ true), + ); resolution = resolveModuleName("a", "/foo.ts", compilerOptions, host, cache); assert.isUndefined(resolution.resolvedModule, "lookup in parent directory doesn't hit the cache"); @@ -466,14 +575,23 @@ namespace ts { checkResolution(resolveModuleName("linked", "/app/lib/main.ts", compilerOptions, host, cache)); function checkResolution(resolution: ResolvedModuleWithFailedLookupLocations) { - checkResolvedModule(resolution.resolvedModule, createResolvedModule("/linked/index.d.ts", /*isExternalLibraryImport*/ true)); + checkResolvedModule( + resolution.resolvedModule, + createResolvedModule("/linked/index.d.ts", /*isExternalLibraryImport*/ true), + ); assert.strictEqual(resolution.resolvedModule!.originalPath, "/app/node_modules/linked/index.d.ts"); } }); }); describe("unittests:: moduleResolution:: Relative imports", () => { - function test(files: ESMap, currentDirectory: string, rootFiles: string[], expectedFilesCount: number, relativeNamesToCheck: string[]) { + function test( + files: ESMap, + currentDirectory: string, + rootFiles: string[], + expectedFilesCount: number, + relativeNamesToCheck: string[], + ) { const options: CompilerOptions = { module: ModuleKind.CommonJS }; const host: CompilerHost = { getSourceFile: (fileName: string, languageVersion: ScriptTarget) => { @@ -499,13 +617,28 @@ namespace ts { assert.equal(program.getSourceFiles().length, expectedFilesCount); const syntacticDiagnostics = program.getSyntacticDiagnostics(); - assert.equal(syntacticDiagnostics.length, 0, `expect no syntactic diagnostics, got: ${JSON.stringify(Harness.Compiler.minimalDiagnosticsToString(syntacticDiagnostics))}`); + assert.equal( + syntacticDiagnostics.length, + 0, + `expect no syntactic diagnostics, got: ${ + JSON.stringify(Harness.Compiler.minimalDiagnosticsToString(syntacticDiagnostics)) + }`, + ); const semanticDiagnostics = program.getSemanticDiagnostics(); - assert.equal(semanticDiagnostics.length, 0, `expect no semantic diagnostics, got: ${JSON.stringify(Harness.Compiler.minimalDiagnosticsToString(semanticDiagnostics))}`); + assert.equal( + semanticDiagnostics.length, + 0, + `expect no semantic diagnostics, got: ${ + JSON.stringify(Harness.Compiler.minimalDiagnosticsToString(semanticDiagnostics)) + }`, + ); // try to get file using a relative name for (const relativeFileName of relativeNamesToCheck) { - assert.isTrue(program.getSourceFile(relativeFileName) !== undefined, `expected to get file by relative name, got undefined`); + assert.isTrue( + program.getSourceFile(relativeFileName) !== undefined, + `expected to get file by relative name, got undefined`, + ); } } @@ -590,7 +723,10 @@ export = C; readFile: notImplemented, }; const program = createProgram(rootFiles, options, host); - const diagnostics = sortAndDeduplicateDiagnostics([...program.getSemanticDiagnostics(), ...program.getOptionsDiagnostics()]); + const diagnostics = sortAndDeduplicateDiagnostics([ + ...program.getSemanticDiagnostics(), + ...program.getOptionsDiagnostics(), + ]); assert.deepEqual(diagnostics, sortAndDeduplicateDiagnostics(expectedDiagnostics(program))); } @@ -634,8 +770,13 @@ export = C; Diagnostics.The_file_is_in_the_program_because_Colon, emptyArray, [ - tscWatch.getDiagnosticMessageChain(Diagnostics.Referenced_via_0_from_file_1, ["D.ts", "c.ts"]), - tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation), + tscWatch.getDiagnosticMessageChain(Diagnostics.Referenced_via_0_from_file_1, [ + "D.ts", + "c.ts", + ]), + tscWatch.getDiagnosticMessageChain( + Diagnostics.Root_file_specified_for_compilation, + ), ], ), ], @@ -671,8 +812,13 @@ export = C; Diagnostics.The_file_is_in_the_program_because_Colon, emptyArray, [ - tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"D"`, "c.ts"]), - tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation), + tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [ + `"D"`, + "c.ts", + ]), + tscWatch.getDiagnosticMessageChain( + Diagnostics.Root_file_specified_for_compilation, + ), ], ), ], @@ -708,8 +854,13 @@ export = C; Diagnostics.The_file_is_in_the_program_because_Colon, emptyArray, [ - tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./ModuleB"`, "moduleA.ts"]), - tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation), + tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [ + `"./ModuleB"`, + "moduleA.ts", + ]), + tscWatch.getDiagnosticMessageChain( + Diagnostics.Root_file_specified_for_compilation, + ), ], ), ], @@ -746,8 +897,13 @@ export = C; Diagnostics.The_file_is_in_the_program_because_Colon, emptyArray, [ - tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"D"`, "c.ts"]), - tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation), + tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [ + `"D"`, + "c.ts", + ]), + tscWatch.getDiagnosticMessageChain( + Diagnostics.Root_file_specified_for_compilation, + ), ], ), ], @@ -793,12 +949,22 @@ export = C; reportsUnnecessary: undefined, reportsDeprecated: undefined, }; - const importHereInA = tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./ModuleC"`, "moduleA.ts"]); - const importHereInB = tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./moduleC"`, "moduleB.ts"]); + const importHereInA = tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [ + `"./ModuleC"`, + "moduleA.ts", + ]); + const importHereInB = tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [ + `"./moduleC"`, + "moduleB.ts", + ]); const details = [tscWatch.getDiagnosticMessageChain( Diagnostics.The_file_is_in_the_program_because_Colon, emptyArray, - [importHereInA, importHereInB, tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation)], + [ + importHereInA, + importHereInB, + tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation), + ], )]; return [ { @@ -862,8 +1028,14 @@ import b = require("./moduleB"); Diagnostics.The_file_is_in_the_program_because_Colon, emptyArray, [ - tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./ModuleC"`, "/a/B/c/moduleA.ts"]), - tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./moduleC"`, "/a/B/c/moduleB.ts"]), + tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [ + `"./ModuleC"`, + "/a/B/c/moduleA.ts", + ]), + tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [ + `"./moduleC"`, + "/a/B/c/moduleB.ts", + ]), ], ), ], @@ -959,7 +1131,10 @@ import b = require("./moduleB"); const main: File = { name: "/root/a/b/main.ts" }; const m1: File = { name: "/root/m1.ts" }; // load file as module const m2: File = { name: "/root/m2/index.d.ts" }; // load folder as module - const m3: File = { name: "/root/m3/package.json", content: JSON.stringify({ typings: "dist/typings.d.ts" }) }; + const m3: File = { + name: "/root/m3/package.json", + content: JSON.stringify({ typings: "dist/typings.d.ts" }), + }; const m3Typings: File = { name: "/root/m3/dist/typings.d.ts" }; const m4: File = { name: "/root/node_modules/m4.ts" }; // fallback to node @@ -973,7 +1148,10 @@ import b = require("./moduleB"); function check(name: string, caller: File, expected: File, isExternalLibraryImport = false) { const result = resolveModuleName(name, caller.name, options, host); - checkResolvedModule(result.resolvedModule, createResolvedModule(expected.name, isExternalLibraryImport)); + checkResolvedModule( + result.resolvedModule, + createResolvedModule(expected.name, isExternalLibraryImport), + ); } } }); @@ -987,7 +1165,11 @@ import b = require("./moduleB"); const m1: File = { name: "/root/x/m1.ts" }; // load from base url const m2: File = { name: "/m2.ts" }; // fallback to classic - const options: CompilerOptions = { moduleResolution: ModuleResolutionKind.Classic, baseUrl: "/root/x", jsx: JsxEmit.React }; + const options: CompilerOptions = { + moduleResolution: ModuleResolutionKind.Classic, + baseUrl: "/root/x", + jsx: JsxEmit.React, + }; const host = createModuleResolutionHost(hasDirectoryExists, main, m1, m2); check("m1", main, m1); @@ -1010,11 +1192,23 @@ import b = require("./moduleB"); const file1: File = { name: "/root/folder1/file1.ts" }; const file2: File = { name: "/root/generated/folder1/file2.ts" }; // load remapped file as module const file3: File = { name: "/root/generated/folder2/file3/index.d.ts" }; // load folder a module - const file4Typings: File = { name: "/root/generated/folder2/file4/package.json", content: JSON.stringify({ typings: "dist/types.d.ts" }) }; + const file4Typings: File = { + name: "/root/generated/folder2/file4/package.json", + content: JSON.stringify({ typings: "dist/types.d.ts" }), + }; const file4: File = { name: "/root/generated/folder2/file4/dist/types.d.ts" }; // load file pointed by typings const file5: File = { name: "/root/someanotherfolder/file5/index.d.ts" }; // load remapped module from folder const file6: File = { name: "/root/node_modules/file6.ts" }; // fallback to node - const host = createModuleResolutionHost(hasDirectoryExists, file1, file2, file3, file4, file4Typings, file5, file6); + const host = createModuleResolutionHost( + hasDirectoryExists, + file1, + file2, + file3, + file4, + file4Typings, + file5, + file6, + ); const options: CompilerOptions = { moduleResolution: ModuleResolutionKind.NodeJs, @@ -1144,9 +1338,18 @@ import b = require("./moduleB"); // success on /root/node_modules/file6.ts ], /*isExternalLibraryImport*/ true); - function check(name: string, expected: File, expectedFailedLookups: string[], isExternalLibraryImport = false) { + function check( + name: string, + expected: File, + expectedFailedLookups: string[], + isExternalLibraryImport = false, + ) { const result = resolveModuleName(name, main.name, options, host); - checkResolvedModuleWithFailedLookupLocations(result, createResolvedModule(expected.name, isExternalLibraryImport), expectedFailedLookups); + checkResolvedModuleWithFailedLookupLocations( + result, + createResolvedModule(expected.name, isExternalLibraryImport), + expectedFailedLookups, + ); } } }); @@ -1209,7 +1412,11 @@ import b = require("./moduleB"); function check(name: string, expected: File, expectedFailedLookups: string[]) { const result = resolveModuleName(name, main.name, options, host); - checkResolvedModuleWithFailedLookupLocations(result, createResolvedModule(expected.name), expectedFailedLookups); + checkResolvedModuleWithFailedLookupLocations( + result, + createResolvedModule(expected.name), + expectedFailedLookups, + ); } } }); @@ -1282,7 +1489,11 @@ import b = require("./moduleB"); function check(name: string, container: File, expected: File, expectedFailedLookups: string[]) { const result = resolveModuleName(name, container.name, options, host); - checkResolvedModuleWithFailedLookupLocations(result, createResolvedModule(expected.name), expectedFailedLookups); + checkResolvedModuleWithFailedLookupLocations( + result, + createResolvedModule(expected.name), + expectedFailedLookups, + ); } } }); @@ -1336,7 +1547,11 @@ import b = require("./moduleB"); function check(name: string, container: File, expected: File, expectedFailedLookups: string[]) { const result = resolveModuleName(name, container.name, options, host); - checkResolvedModuleWithFailedLookupLocations(result, createResolvedModule(expected.name), expectedFailedLookups); + checkResolvedModuleWithFailedLookupLocations( + result, + createResolvedModule(expected.name), + expectedFailedLookups, + ); } } }); @@ -1347,7 +1562,10 @@ import b = require("./moduleB"); function test(hasDirectoryExists: boolean) { const app: File = { name: "/root/src/app.ts" }; - const libsPackage: File = { name: "/root/src/libs/guid/package.json", content: JSON.stringify({ typings: "dist/guid.d.ts" }) }; + const libsPackage: File = { + name: "/root/src/libs/guid/package.json", + content: JSON.stringify({ typings: "dist/guid.d.ts" }), + }; const libsTypings: File = { name: "/root/src/libs/guid/dist/guid.d.ts" }; const host = createModuleResolutionHost(hasDirectoryExists, app, libsPackage, libsTypings); const options: CompilerOptions = { @@ -1376,22 +1594,65 @@ import b = require("./moduleB"); directoryExists: _ => false, }; - const result = resolveModuleName("someName", "/a/b/c/d", { moduleResolution: ModuleResolutionKind.NodeJs }, host); + const result = resolveModuleName( + "someName", + "/a/b/c/d", + { moduleResolution: ModuleResolutionKind.NodeJs }, + host, + ); assert(!result.resolvedModule); }); }); describe("unittests:: moduleResolution:: Type reference directive resolution: ", () => { - function testWorker(hasDirectoryExists: boolean, typesRoot: string | undefined, typeDirective: string, primary: boolean, initialFile: File, targetFile: File, ...otherFiles: File[]) { - const host = createModuleResolutionHost(hasDirectoryExists, ...[initialFile, targetFile].concat(...otherFiles)); - const result = resolveTypeReferenceDirective(typeDirective, initialFile.name, typesRoot ? { typeRoots: [typesRoot] } : {}, host); - assert(result.resolvedTypeReferenceDirective!.resolvedFileName !== undefined, "expected type directive to be resolved"); - assert.equal(result.resolvedTypeReferenceDirective!.resolvedFileName, targetFile.name, "unexpected result of type reference resolution"); + function testWorker( + hasDirectoryExists: boolean, + typesRoot: string | undefined, + typeDirective: string, + primary: boolean, + initialFile: File, + targetFile: File, + ...otherFiles: File[] + ) { + const host = createModuleResolutionHost( + hasDirectoryExists, + ...[initialFile, targetFile].concat(...otherFiles), + ); + const result = resolveTypeReferenceDirective( + typeDirective, + initialFile.name, + typesRoot ? { typeRoots: [typesRoot] } : {}, + host, + ); + assert( + result.resolvedTypeReferenceDirective!.resolvedFileName !== undefined, + "expected type directive to be resolved", + ); + assert.equal( + result.resolvedTypeReferenceDirective!.resolvedFileName, + targetFile.name, + "unexpected result of type reference resolution", + ); assert.equal(result.resolvedTypeReferenceDirective!.primary, primary, "unexpected 'primary' value"); } - function test(typesRoot: string, typeDirective: string, primary: boolean, initialFile: File, targetFile: File, ...otherFiles: File[]) { - testWorker(/*hasDirectoryExists*/ false, typesRoot, typeDirective, primary, initialFile, targetFile, ...otherFiles); + function test( + typesRoot: string, + typeDirective: string, + primary: boolean, + initialFile: File, + targetFile: File, + ...otherFiles: File[] + ) { + testWorker( + /*hasDirectoryExists*/ false, + typesRoot, + typeDirective, + primary, + initialFile, + targetFile, + ...otherFiles, + ); } it("Can be resolved from primary location", () => { @@ -1403,7 +1664,10 @@ import b = require("./moduleB"); { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/src/types/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/src/types/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) }; + const packageFile = { + name: "/root/src/types/lib/package.json", + content: JSON.stringify({ types: "typings/lib.d.ts" }), + }; test(/*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", /*primary*/ true, f1, f2, packageFile); } { @@ -1414,8 +1678,18 @@ import b = require("./moduleB"); { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/src/node_modules/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/src/node_modules/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) }; - test(/*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", /*primary*/ false, f1, f2, packageFile); + const packageFile = { + name: "/root/src/node_modules/lib/package.json", + content: JSON.stringify({ types: "typings/lib.d.ts" }), + }; + test( + /*typesRoot*/ "/root/src/types", + /* typeDirective */ "lib", + /*primary*/ false, + f1, + f2, + packageFile, + ); } { const f1 = { name: "/root/src/app.ts" }; @@ -1425,8 +1699,18 @@ import b = require("./moduleB"); { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/src/node_modules/@types/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/src/node_modules/@types/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) }; - test(/*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", /*primary*/ false, f1, f2, packageFile); + const packageFile = { + name: "/root/src/node_modules/@types/lib/package.json", + content: JSON.stringify({ types: "typings/lib.d.ts" }), + }; + test( + /*typesRoot*/ "/root/src/types", + /* typeDirective */ "lib", + /*primary*/ false, + f1, + f2, + packageFile, + ); } }); it("Can be resolved from secondary location", () => { @@ -1443,8 +1727,18 @@ import b = require("./moduleB"); { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/node_modules/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/node_modules/lib/package.json", content: JSON.stringify({ typings: "typings/lib.d.ts" }) }; - test(/*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", /*primary*/ false, f1, f2, packageFile); + const packageFile = { + name: "/root/node_modules/lib/package.json", + content: JSON.stringify({ typings: "typings/lib.d.ts" }), + }; + test( + /*typesRoot*/ "/root/src/types", + /* typeDirective */ "lib", + /*primary*/ false, + f1, + f2, + packageFile, + ); } { const f1 = { name: "/root/src/app.ts" }; @@ -1454,8 +1748,18 @@ import b = require("./moduleB"); { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/node_modules/@types/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/node_modules/@types/lib/package.json", content: JSON.stringify({ typings: "typings/lib.d.ts" }) }; - test(/*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", /*primary*/ false, f1, f2, packageFile); + const packageFile = { + name: "/root/node_modules/@types/lib/package.json", + content: JSON.stringify({ typings: "typings/lib.d.ts" }), + }; + test( + /*typesRoot*/ "/root/src/types", + /* typeDirective */ "lib", + /*primary*/ false, + f1, + f2, + packageFile, + ); } }); it("Primary resolution overrides secondary resolutions", () => { @@ -1474,7 +1778,10 @@ import b = require("./moduleB"); const files = [f1, f2, f3, f4]; const names = map(files, f => f.name); - const sourceFiles = arrayToMap(map(files, f => createSourceFile(f.name, f.content, ScriptTarget.ES2015)), f => f.fileName); + const sourceFiles = arrayToMap( + map(files, f => createSourceFile(f.name, f.content, ScriptTarget.ES2015)), + f => f.fileName, + ); const compilerHost: CompilerHost = { fileExists: fileName => sourceFiles.has(fileName), getSourceFile: fileName => sourceFiles.get(fileName), @@ -1565,10 +1872,24 @@ import b = require("./moduleB"); const initialFile = { name: "/root/src/background/app.ts" }; const targetFile = { name: "/root/src/typedefs/filesystem.d.ts" }; it("when host doesnt have directoryExists", () => { - testWorker(/*hasDirectoryExists*/ false, /*typesRoot*/ undefined, /*typeDirective*/ "../typedefs/filesystem", /*primary*/ false, initialFile, targetFile); + testWorker( + /*hasDirectoryExists*/ false, + /*typesRoot*/ undefined, + /*typeDirective*/ "../typedefs/filesystem", + /*primary*/ false, + initialFile, + targetFile, + ); }); it("when host has directoryExists", () => { - testWorker(/*hasDirectoryExists*/ true, /*typesRoot*/ undefined, /*typeDirective*/ "../typedefs/filesystem", /*primary*/ false, initialFile, targetFile); + testWorker( + /*hasDirectoryExists*/ true, + /*typesRoot*/ undefined, + /*typeDirective*/ "../typedefs/filesystem", + /*primary*/ false, + initialFile, + targetFile, + ); }); }); }); diff --git a/src/testRunner/unittests/parsePseudoBigInt.ts b/src/testRunner/unittests/parsePseudoBigInt.ts index a568f5dda7229..4de376e79fdf1 100644 --- a/src/testRunner/unittests/parsePseudoBigInt.ts +++ b/src/testRunner/unittests/parsePseudoBigInt.ts @@ -54,7 +54,9 @@ namespace ts { "123456789012345678901234567890", ); assert.equal( - parsePseudoBigInt("0b1100011101110100100001111111101101100001101110011111000001110111001001110001111110000101011010010n"), + parsePseudoBigInt( + "0b1100011101110100100001111111101101100001101110011111000001110111001001110001111110000101011010010n", + ), "123456789012345678901234567890", ); assert.equal( diff --git a/src/testRunner/unittests/paths.ts b/src/testRunner/unittests/paths.ts index 6ae85065b6112..b16b0ff4574b0 100644 --- a/src/testRunner/unittests/paths.ts +++ b/src/testRunner/unittests/paths.ts @@ -283,11 +283,23 @@ describe("unittests:: core paths", () => { assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/", "file:///a", /*ignoreCase*/ false), ""); assert.strictEqual(ts.getRelativePathFromDirectory("file:///a", "file:///", /*ignoreCase*/ false), ".."); assert.strictEqual(ts.getRelativePathFromDirectory("file:///a", "file:///b", /*ignoreCase*/ false), "../b"); - assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/b", "file:///b", /*ignoreCase*/ false), "../../b"); - assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/b/c", "file:///b", /*ignoreCase*/ false), "../../../b"); - assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/b/c", "file:///b/c", /*ignoreCase*/ false), "../../../b/c"); + assert.strictEqual( + ts.getRelativePathFromDirectory("file:///a/b", "file:///b", /*ignoreCase*/ false), + "../../b", + ); + assert.strictEqual( + ts.getRelativePathFromDirectory("file:///a/b/c", "file:///b", /*ignoreCase*/ false), + "../../../b", + ); + assert.strictEqual( + ts.getRelativePathFromDirectory("file:///a/b/c", "file:///b/c", /*ignoreCase*/ false), + "../../../b/c", + ); assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/b/c", "file:///a/b", /*ignoreCase*/ false), ".."); - assert.strictEqual(ts.getRelativePathFromDirectory("file:///c:", "file:///d:", /*ignoreCase*/ false), "file:///d:/"); + assert.strictEqual( + ts.getRelativePathFromDirectory("file:///c:", "file:///d:", /*ignoreCase*/ false), + "file:///d:/", + ); }); it("toFileNameLowerCase", () => { assert.strictEqual( diff --git a/src/testRunner/unittests/printer.ts b/src/testRunner/unittests/printer.ts index 1eb9a7c377c0e..8771c6b70e6b7 100644 --- a/src/testRunner/unittests/printer.ts +++ b/src/testRunner/unittests/printer.ts @@ -1,9 +1,16 @@ namespace ts { describe("unittests:: PrinterAPI", () => { function makePrintsCorrectly(prefix: string) { - return function printsCorrectly(name: string, options: PrinterOptions, printCallback: (printer: Printer) => string) { + return function printsCorrectly( + name: string, + options: PrinterOptions, + printCallback: (printer: Printer) => string, + ) { it(name, () => { - Harness.Baseline.runBaseline(`printerApi/${prefix}.${name}.js`, printCallback(createPrinter({ newLine: NewLineKind.CarriageReturnLineFeed, ...options }))); + Harness.Baseline.runBaseline( + `printerApi/${prefix}.${name}.js`, + printCallback(createPrinter({ newLine: NewLineKind.CarriageReturnLineFeed, ...options })), + ); }); }; } @@ -60,13 +67,33 @@ namespace ts { // https://github.com/microsoft/TypeScript/issues/14948 // eslint-disable-next-line no-template-curly-in-string - printsCorrectly("templateLiteral", {}, printer => printer.printFile(createSourceFile("source.ts", "let greeting = `Hi ${name}, how are you?`;", ScriptTarget.ES2017))); + printsCorrectly( + "templateLiteral", + {}, + printer => + printer.printFile( + createSourceFile( + "source.ts", + "let greeting = `Hi ${name}, how are you?`;", + ScriptTarget.ES2017, + ), + ), + ); // https://github.com/microsoft/TypeScript/issues/18071 - printsCorrectly("regularExpressionLiteral", {}, printer => printer.printFile(createSourceFile("source.ts", "let regex = /abc/;", ScriptTarget.ES2017))); + printsCorrectly( + "regularExpressionLiteral", + {}, + printer => printer.printFile(createSourceFile("source.ts", "let regex = /abc/;", ScriptTarget.ES2017)), + ); // https://github.com/microsoft/TypeScript/issues/22239 - printsCorrectly("importStatementRemoveComments", { removeComments: true }, printer => printer.printFile(createSourceFile("source.ts", "import {foo} from 'foo';", ScriptTarget.ESNext))); + printsCorrectly( + "importStatementRemoveComments", + { removeComments: true }, + printer => + printer.printFile(createSourceFile("source.ts", "import {foo} from 'foo';", ScriptTarget.ESNext)), + ); printsCorrectly("classHeritageClauses", {}, printer => printer.printFile(createSourceFile( "source.ts", @@ -117,7 +144,8 @@ namespace ts { const host = new fakes.CompilerHost( new vfs.FileSystem(true, { files: { - "/test.d.ts": `/// \n/// \n/// map.has(k) ? k : undefined)); @@ -26,10 +31,10 @@ namespace ts { const referenceFile = new documents.TextDocument( referenceFileName, - '/// \n' + // Absolute - '/// \n' + // Relative - '/// \n' + // Unqualified - '/// \n', // No extension + '/// \n' // Absolute + + '/// \n' // Relative + + '/// \n' // Unqualified + + '/// \n', // No extension ); const testCompilerHost = new fakes.CompilerHost( @@ -60,7 +65,11 @@ namespace ts { }); it("handles a mix of present and missing root files", () => { - const program = createProgram(["./nonexistent0.ts", emptyFileRelativePath, "./nonexistent1.ts"], options, testCompilerHost); + const program = createProgram( + ["./nonexistent0.ts", emptyFileRelativePath, "./nonexistent1.ts"], + options, + testCompilerHost, + ); const missing = program.getMissingFilePaths(); verifyMissingFilePaths(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]); }); @@ -107,7 +116,11 @@ namespace ts { }`; const host: CompilerHost = { - getSourceFile: (fileName: string, languageVersion: ScriptTarget, _onError?: (message: string) => void) => { + getSourceFile: ( + fileName: string, + languageVersion: ScriptTarget, + _onError?: (message: string) => void, + ) => { return fileName === "test.ts" ? createSourceFile(fileName, testSource, languageVersion) : undefined; }, getDefaultLibFileName: () => "", @@ -131,7 +144,10 @@ namespace ts { const program = createProgram(["test.ts"], { module: ModuleKind.ES2015 }, host); assert(program.getSourceFiles().length === 1, "expected 'getSourceFiles' length to be 1"); assert(program.getMissingFilePaths().length === 0, "expected 'getMissingFilePaths' length to be 0"); - assert((program.getFileProcessingDiagnostics()?.length || 0) === 0, "expected 'getFileProcessingDiagnostics' length to be 0"); + assert( + (program.getFileProcessingDiagnostics()?.length || 0) === 0, + "expected 'getFileProcessingDiagnostics' length to be 0", + ); }); }); @@ -142,29 +158,57 @@ namespace ts { const bar = new documents.TextDocument("/node_modules/bar/index.d.ts", 'import * as foo from "foo";'); const fooPackageJsonText = '{ "name": "foo", "version": "1.2.3" }'; const fooIndexText = "export const x: number;"; - const barFooPackage = new documents.TextDocument("/node_modules/bar/node_modules/foo/package.json", fooPackageJsonText); - const barFooIndex = new documents.TextDocument("/node_modules/bar/node_modules/foo/index.d.ts", fooIndexText); + const barFooPackage = new documents.TextDocument( + "/node_modules/bar/node_modules/foo/package.json", + fooPackageJsonText, + ); + const barFooIndex = new documents.TextDocument( + "/node_modules/bar/node_modules/foo/index.d.ts", + fooIndexText, + ); const fooPackage = new documents.TextDocument("/node_modules/foo/package.json", fooPackageJsonText); const fooIndex = new documents.TextDocument("/node_modules/foo/index.d.ts", fooIndexText); - const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [a, bar, barFooPackage, barFooIndex, fooPackage, fooIndex], cwd: "/" }); - const program = createProgram(["/a.ts"], emptyOptions, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed })); + const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { + documents: [a, bar, barFooPackage, barFooIndex, fooPackage, fooIndex], + cwd: "/", + }); + const program = createProgram( + ["/a.ts"], + emptyOptions, + new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }), + ); assertIsExternal(program, [a, bar, barFooIndex, fooIndex], f => f !== a); }); it('works on `/// `', () => { const a = new documents.TextDocument("/a.ts", '/// '); const fooIndex = new documents.TextDocument("/node_modules/foo/index.d.ts", "declare const foo: number;"); - const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [a, fooIndex], cwd: "/" }); - const program = createProgram(["/a.ts"], emptyOptions, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed })); + const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { + documents: [a, fooIndex], + cwd: "/", + }); + const program = createProgram( + ["/a.ts"], + emptyOptions, + new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }), + ); assertIsExternal(program, [a, fooIndex], f => f !== a); }); - function assertIsExternal(program: Program, files: readonly documents.TextDocument[], isExternalExpected: (file: documents.TextDocument) => boolean): void { + function assertIsExternal( + program: Program, + files: readonly documents.TextDocument[], + isExternalExpected: (file: documents.TextDocument) => boolean, + ): void { for (const file of files) { const actual = program.isSourceFileFromExternalLibrary(program.getSourceFile(file.file)!); const expected = isExternalExpected(file); - assert.equal(actual, expected, `Expected ${file.file} isSourceFileFromExternalLibrary to be ${expected}, got ${actual}`); + assert.equal( + actual, + expected, + `Expected ${file.file} isSourceFileFromExternalLibrary to be ${expected}, got ${actual}`, + ); } } }); @@ -175,7 +219,11 @@ namespace ts { const pkg = new documents.TextDocument("/package.json", '{"version": "1.0.0"}'); const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [main, pkg], cwd: "/" }); - const program = createProgram(["/main.ts"], { resolveJsonModule: true }, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed })); + const program = createProgram( + ["/main.ts"], + { resolveJsonModule: true }, + new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }), + ); const json = program.getSourceFile("/package.json")!; assert.equal(json.scriptKind, ScriptKind.JSON); @@ -192,10 +240,16 @@ namespace ts { const main = new documents.TextDocument("/main.ts", "0 as const"); const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [main], cwd: "/" }); - const program = createProgram(["/main.ts"], {}, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed })); + const program = createProgram( + ["/main.ts"], + {}, + new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }), + ); const typeChecker = program.getTypeChecker(); const sourceFile = program.getSourceFile("main.ts")!; - typeChecker.getTypeAtLocation(((sourceFile.statements[0] as ExpressionStatement).expression as AsExpression).type); + typeChecker.getTypeAtLocation( + ((sourceFile.statements[0] as ExpressionStatement).expression as AsExpression).type, + ); const diag = program.getSemanticDiagnostics(); assert.isEmpty(diag); }); @@ -204,7 +258,11 @@ namespace ts { const mod = new documents.TextDocument("/module.d.ts", "declare const foo: any;"); const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [main, mod], cwd: "/" }); - const program = createProgram(["/main.ts"], {}, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed })); + const program = createProgram( + ["/main.ts"], + {}, + new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }), + ); const sourceFile = program.getSourceFile("main.ts")!; const typeChecker = program.getTypeChecker(); diff --git a/src/testRunner/unittests/publicApi.ts b/src/testRunner/unittests/publicApi.ts index 85157da7e0aba..af282996f101d 100644 --- a/src/testRunner/unittests/publicApi.ts +++ b/src/testRunner/unittests/publicApi.ts @@ -24,7 +24,10 @@ describe("unittests:: Public APIs", () => { }; const host = new fakes.CompilerHost(sys, options); const result = compiler.compileFiles(host, [`${vfs.srcFolder}/${fileName}`], options); - assert(!result.diagnostics || !result.diagnostics.length, Harness.Compiler.minimalDiagnosticsToString(result.diagnostics, /*pretty*/ true)); + assert( + !result.diagnostics || !result.diagnostics.length, + Harness.Compiler.minimalDiagnosticsToString(result.diagnostics, /*pretty*/ true), + ); }); } @@ -54,7 +57,10 @@ describe("unittests:: Public APIs:: token to string", () => { describe("unittests:: Public APIs:: createPrivateIdentifier", () => { it("throws when name doesn't start with #", () => { - assert.throw(() => ts.factory.createPrivateIdentifier("not"), "Debug Failure. First character of private identifier must be #: not"); + assert.throw( + () => ts.factory.createPrivateIdentifier("not"), + "Debug Failure. First character of private identifier must be #: not", + ); }); }); @@ -68,7 +74,12 @@ describe("unittests:: Public APIs:: JSDoc newlines", () => { */ function test() {}`; - const testSourceFile = ts.createSourceFile(testFilePath, testFileText, ts.ScriptTarget.Latest, /*setParentNodes*/ true); + const testSourceFile = ts.createSourceFile( + testFilePath, + testFileText, + ts.ScriptTarget.Latest, + /*setParentNodes*/ true, + ); const funcDec = testSourceFile.statements.find(ts.isFunctionDeclaration)!; const tags = ts.getJSDocTags(funcDec); assert.isDefined(tags[0].comment); @@ -154,7 +165,8 @@ describe("unittests:: Public APIs:: getTypeAtLocation", () => { const checker = program.getTypeChecker(); const file = program.getSourceFile("/file.ts")!; - const [declaration] = (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations; + const [declaration] = + (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations; assert.equal(checker.getTypeAtLocation(declaration.initializer!).flags, ts.TypeFlags.Object); }); @@ -175,7 +187,8 @@ describe("unittests:: Public APIs:: getTypeAtLocation", () => { const checker = program.getTypeChecker(); const file = program.getSourceFile("/file.ts")!; - const [declaration] = (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations; + const [declaration] = + (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations; assert.equal(checker.getTypeAtLocation(declaration).flags, ts.TypeFlags.Any); }); }); @@ -192,11 +205,19 @@ describe("unittests:: Public APIs:: validateLocaleAndSetLanguage", () => { getExecutingFilePath: () => "/tsc.js", resolvePath: ts.identity, fileExists: fileName => { - assert.isTrue(expectedToReadFile, `Locale : ${locale} ${expectedToReadFile ? "should" : "should not"} check if ${fileName} exists.`); + assert.isTrue( + expectedToReadFile, + `Locale : ${locale} ${ + expectedToReadFile ? "should" : "should not" + } check if ${fileName} exists.`, + ); return expectedToReadFile; }, readFile: fileName => { - assert.isTrue(expectedToReadFile, `Locale : ${locale} ${expectedToReadFile ? "should" : "should not"} read ${fileName}.`); + assert.isTrue( + expectedToReadFile, + `Locale : ${locale} ${expectedToReadFile ? "should" : "should not"} read ${fileName}.`, + ); // Throw error here so that actual change to localized diagnostics messages doesnt take place throw new Error("cannot read file"); }, diff --git a/src/testRunner/unittests/reuseProgramStructure.ts b/src/testRunner/unittests/reuseProgramStructure.ts index a2f34aa736b34..9d2d1a86bdcbd 100644 --- a/src/testRunner/unittests/reuseProgramStructure.ts +++ b/src/testRunner/unittests/reuseProgramStructure.ts @@ -28,7 +28,13 @@ namespace ts { export class SourceText implements IScriptSnapshot { private fullText: string | undefined; - constructor(private references: string, private importsAndExports: string, private program: string, private changedPart: ChangedPart = 0, private version = 0) { + constructor( + private references: string, + private importsAndExports: string, + private program: string, + private changedPart: ChangedPart = 0, + private version = 0, + ) { } static New(references: string, importsAndExports: string, program: string): SourceText { @@ -44,15 +50,33 @@ namespace ts { public updateReferences(newReferences: string): SourceText { Debug.assert(newReferences !== undefined); - return new SourceText(newReferences + newLine, this.importsAndExports, this.program, this.changedPart | ChangedPart.references, this.version + 1); + return new SourceText( + newReferences + newLine, + this.importsAndExports, + this.program, + this.changedPart | ChangedPart.references, + this.version + 1, + ); } public updateImportsAndExports(newImportsAndExports: string): SourceText { Debug.assert(newImportsAndExports !== undefined); - return new SourceText(this.references, newImportsAndExports + newLine, this.program, this.changedPart | ChangedPart.importsAndExports, this.version + 1); + return new SourceText( + this.references, + newImportsAndExports + newLine, + this.program, + this.changedPart | ChangedPart.importsAndExports, + this.version + 1, + ); } public updateProgram(newProgram: string): SourceText { Debug.assert(newProgram !== undefined); - return new SourceText(this.references, this.importsAndExports, newProgram, this.changedPart | ChangedPart.program, this.version + 1); + return new SourceText( + this.references, + this.importsAndExports, + newProgram, + this.changedPart | ChangedPart.program, + this.version + 1, + ); } public getFullText() { @@ -81,7 +105,10 @@ namespace ts { newLength = this.importsAndExports.length; break; case ChangedPart.program: - oldSpan = createTextSpan(oldText.references.length + oldText.importsAndExports.length, oldText.program.length); + oldSpan = createTextSpan( + oldText.references.length + oldText.importsAndExports.length, + oldText.program.length, + ); newLength = this.program.length; break; default: @@ -99,7 +126,12 @@ namespace ts { return file; } - export function createTestCompilerHost(texts: readonly NamedSourceText[], target: ScriptTarget, oldProgram?: ProgramWithSourceTexts, useGetSourceFileByPath?: boolean) { + export function createTestCompilerHost( + texts: readonly NamedSourceText[], + target: ScriptTarget, + oldProgram?: ProgramWithSourceTexts, + useGetSourceFileByPath?: boolean, + ) { const files = arrayToMap(texts, t => t.name, t => { if (oldProgram) { let oldFile = oldProgram.getSourceFile(t.name) as SourceFileWithText; @@ -133,13 +165,21 @@ namespace ts { }, }; if (useGetSourceFileByPath) { - const filesByPath = mapEntries(files, (fileName, file) => [toPath(fileName, "", getCanonicalFileName), file]); + const filesByPath = mapEntries( + files, + (fileName, file) => [toPath(fileName, "", getCanonicalFileName), file], + ); result.getSourceFileByPath = (_fileName, path) => filesByPath.get(path); } return result; } - export function newProgram(texts: NamedSourceText[], rootNames: string[], options: CompilerOptions, useGetSourceFileByPath?: boolean): ProgramWithSourceTexts { + export function newProgram( + texts: NamedSourceText[], + rootNames: string[], + options: CompilerOptions, + useGetSourceFileByPath?: boolean, + ): ProgramWithSourceTexts { const host = createTestCompilerHost(texts, options.target!, /*oldProgram*/ undefined, useGetSourceFileByPath); const program = createProgram(rootNames, options, host) as ProgramWithSourceTexts; program.sourceTexts = texts; @@ -147,7 +187,14 @@ namespace ts { return program; } - export function updateProgram(oldProgram: ProgramWithSourceTexts, rootNames: readonly string[], options: CompilerOptions, updater: (files: NamedSourceText[]) => void, newTexts?: NamedSourceText[], useGetSourceFileByPath?: boolean) { + export function updateProgram( + oldProgram: ProgramWithSourceTexts, + rootNames: readonly string[], + options: CompilerOptions, + updater: (files: NamedSourceText[]) => void, + newTexts?: NamedSourceText[], + useGetSourceFileByPath?: boolean, + ) { if (!newTexts) { newTexts = oldProgram.sourceTexts!.slice(0); } @@ -164,13 +211,31 @@ namespace ts { file.text = file.text.updateProgram(newProgramText); } - function checkResolvedTypeDirective(actual: ResolvedTypeReferenceDirective, expected: ResolvedTypeReferenceDirective) { - assert.equal(actual.resolvedFileName, expected.resolvedFileName, `'resolvedFileName': expected '${actual.resolvedFileName}' to be equal to '${expected.resolvedFileName}'`); - assert.equal(actual.primary, expected.primary, `'primary': expected '${actual.primary}' to be equal to '${expected.primary}'`); + function checkResolvedTypeDirective( + actual: ResolvedTypeReferenceDirective, + expected: ResolvedTypeReferenceDirective, + ) { + assert.equal( + actual.resolvedFileName, + expected.resolvedFileName, + `'resolvedFileName': expected '${actual.resolvedFileName}' to be equal to '${expected.resolvedFileName}'`, + ); + assert.equal( + actual.primary, + expected.primary, + `'primary': expected '${actual.primary}' to be equal to '${expected.primary}'`, + ); return true; } - function checkCache(caption: string, program: Program, fileName: string, expectedContent: ESMap | undefined, getCache: (f: SourceFile) => ModeAwareCache | undefined, entryChecker: (expected: T, original: T) => boolean): void { + function checkCache( + caption: string, + program: Program, + fileName: string, + expectedContent: ESMap | undefined, + getCache: (f: SourceFile) => ModeAwareCache | undefined, + entryChecker: (expected: T, original: T) => boolean, + ): void { const file = program.getSourceFile(fileName); assert.isTrue(file !== undefined, `cannot find file ${fileName}`); const cache = getCache(file!); @@ -179,12 +244,19 @@ namespace ts { } else { assert.isTrue(cache !== undefined, `expected ${caption} to be set`); - assert.isTrue(mapEqualToCache(expectedContent, cache!, entryChecker), `contents of ${caption} did not match the expected contents.`); + assert.isTrue( + mapEqualToCache(expectedContent, cache!, entryChecker), + `contents of ${caption} did not match the expected contents.`, + ); } } /** True if the maps have the same keys and values. */ - function mapEqualToCache(left: ESMap, right: ModeAwareCache, valuesAreEqual?: (left: T, right: T) => boolean): boolean { + function mapEqualToCache( + left: ESMap, + right: ModeAwareCache, + valuesAreEqual?: (left: T, right: T) => boolean, + ): boolean { if (left as any === right) return true; // given the type mismatch (the tests never pass a cache), this'll never be true if (!left || !right) return false; const someInLeftHasNoMatch = forEachEntry(left, (leftValue, leftKey) => { @@ -198,12 +270,27 @@ namespace ts { return !someInRightHasNoMatch; } - function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: ESMap | undefined): void { + function checkResolvedModulesCache( + program: Program, + fileName: string, + expectedContent: ESMap | undefined, + ): void { checkCache("resolved modules", program, fileName, expectedContent, f => f.resolvedModules, checkResolvedModule); } - function checkResolvedTypeDirectivesCache(program: Program, fileName: string, expectedContent: ESMap | undefined): void { - checkCache("resolved type directives", program, fileName, expectedContent, f => f.resolvedTypeReferenceDirectiveNames, checkResolvedTypeDirective); + function checkResolvedTypeDirectivesCache( + program: Program, + fileName: string, + expectedContent: ESMap | undefined, + ): void { + checkCache( + "resolved type directives", + program, + fileName, + expectedContent, + f => f.resolvedTypeReferenceDirectiveNames, + checkResolvedTypeDirective, + ); } describe("unittests:: Reuse program structure:: General", () => { @@ -253,7 +340,10 @@ namespace ts { { name: "/a.ts", text: SourceText.New("", "import {b} from 'b'", "var a = b;") }, { name: "/node_modules/b/index.d.ts", text: SourceText.New("", "export * from './internal';", "") }, { name: "/node_modules/b/internal.d.ts", text: SourceText.New("", "", "export const b = 1;") }, - { name: "/node_modules/b/package.json", text: SourceText.New("", "", JSON.stringify({ name: "b", version: "1.2.3" })) }, + { + name: "/node_modules/b/package.json", + text: SourceText.New("", "", JSON.stringify({ name: "b", version: "1.2.3" })), + }, ]; const options: CompilerOptions = { target, moduleResolution: ModuleResolutionKind.NodeJs }; @@ -318,13 +408,26 @@ namespace ts { it("succeeds if rootdir changes", () => { const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" }); - const program2 = updateProgram(program1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop); + const program2 = updateProgram( + program1, + ["a.ts"], + { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, + noop, + ); assert.equal(program2.structureIsReused, StructureIsReused.Completely); }); it("fails if config path changes", () => { - const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/b/tsconfig.json" }); - const program2 = updateProgram(program1, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/c/tsconfig.json" }, noop); + const program1 = newProgram(files, ["a.ts"], { + target, + module: ModuleKind.CommonJS, + configFilePath: "/a/b/tsconfig.json", + }); + const program2 = updateProgram(program1, ["a.ts"], { + target, + module: ModuleKind.CommonJS, + configFilePath: "/a/c/tsconfig.json", + }, noop); assert.equal(program2.structureIsReused, StructureIsReused.Not); }); @@ -346,7 +449,10 @@ namespace ts { const program1 = newProgram(files, ["a.ts"], options); assert.notDeepEqual(emptyArray, program1.getMissingFilePaths()); - const newTexts: NamedSourceText[] = files.concat([{ name: "non-existing-file.ts", text: SourceText.New("", "", `var x = 1`) }]); + const newTexts: NamedSourceText[] = files.concat([{ + name: "non-existing-file.ts", + text: SourceText.New("", "", `var x = 1`), + }]); const program2 = updateProgram(program1, ["a.ts"], options, noop, newTexts); assert.lengthOf(program2.getMissingFilePaths(), 0); @@ -389,7 +495,11 @@ namespace ts { files[0].text = files[0].text.updateImportsAndExports(newImports); }); assert.equal(program4.structureIsReused, StructureIsReused.SafeModules); - checkResolvedModulesCache(program4, "a.ts", new Map(getEntries({ b: createResolvedModule("b.ts"), c: undefined }))); + checkResolvedModulesCache( + program4, + "a.ts", + new Map(getEntries({ b: createResolvedModule("b.ts"), c: undefined })), + ); }); it("set the resolvedImports after re-using an ambient external module declaration", () => { @@ -402,7 +512,10 @@ namespace ts { const program2 = updateProgram(program1, ["/a.ts"], options, files => { files[0].text = files[0].text.updateProgram('import * as aa from "a";'); }); - assert.isDefined(program2.getSourceFile("/a.ts")!.resolvedModules!.get("a", /*mode*/ undefined), "'a' is not an unresolved module after re-use"); + assert.isDefined( + program2.getSourceFile("/a.ts")!.resolvedModules!.get("a", /*mode*/ undefined), + "'a' is not an unresolved module after re-use", + ); }); it("works with updated SourceFiles", () => { @@ -416,7 +529,10 @@ namespace ts { const program1 = createProgram(["/a.ts"], options, host); let sourceFile = program1.getSourceFile("/a.ts")!; assert.isDefined(sourceFile, "'/a.ts' is included in the program"); - sourceFile = updateSourceFile(sourceFile, "'use strict';" + sourceFile.text, { newLength: "'use strict';".length, span: { start: 0, length: 0 } }); + sourceFile = updateSourceFile(sourceFile, "'use strict';" + sourceFile.text, { + newLength: "'use strict';".length, + span: { start: 0, length: 0 }, + }); assert.strictEqual(sourceFile.statements[2].getSourceFile(), sourceFile, "parent pointers are updated"); const updateHost: TestCompilerHost = { ...host, @@ -425,7 +541,10 @@ namespace ts { }, }; const program2 = createProgram(["/a.ts"], options, updateHost, program1); - assert.isDefined(program2.getSourceFile("/a.ts")!.resolvedModules!.get("a", /*mode*/ undefined), "'a' is not an unresolved module after re-use"); + assert.isDefined( + program2.getSourceFile("/a.ts")!.resolvedModules!.get("a", /*mode*/ undefined), + "'a' is not an unresolved module after re-use", + ); assert.strictEqual(sourceFile.statements[2].getSourceFile(), sourceFile, "parent pointers are not altered"); }); @@ -437,7 +556,11 @@ namespace ts { const options: CompilerOptions = { target, typeRoots: ["/types"] }; const program1 = newProgram(files, ["/a.ts"], options); - checkResolvedTypeDirectivesCache(program1, "/a.ts", new Map(getEntries({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }))); + checkResolvedTypeDirectivesCache( + program1, + "/a.ts", + new Map(getEntries({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })), + ); checkResolvedTypeDirectivesCache(program1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined); const program2 = updateProgram(program1, ["/a.ts"], options, files => { @@ -446,7 +569,11 @@ namespace ts { assert.equal(program2.structureIsReused, StructureIsReused.Completely); // content of resolution cache should not change - checkResolvedTypeDirectivesCache(program1, "/a.ts", new Map(getEntries({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }))); + checkResolvedTypeDirectivesCache( + program1, + "/a.ts", + new Map(getEntries({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })), + ); checkResolvedTypeDirectivesCache(program1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined); // type reference directives has changed - program is not reused @@ -464,14 +591,28 @@ namespace ts { files[0].text = files[0].text.updateReferences(newReferences); }); assert.equal(program4.structureIsReused, StructureIsReused.SafeModules); - checkResolvedTypeDirectivesCache(program1, "/a.ts", new Map(getEntries({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }))); + checkResolvedTypeDirectivesCache( + program1, + "/a.ts", + new Map(getEntries({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })), + ); }); it("fetches imports after npm install", () => { - const file1Ts = { name: "file1.ts", text: SourceText.New("", `import * as a from "a";`, "const myX: number = a.x;") }; + const file1Ts = { + name: "file1.ts", + text: SourceText.New("", `import * as a from "a";`, "const myX: number = a.x;"), + }; const file2Ts = { name: "file2.ts", text: SourceText.New("", "", "") }; - const indexDTS = { name: "node_modules/a/index.d.ts", text: SourceText.New("", "export declare let x: number;", "") }; - const options: CompilerOptions = { target: ScriptTarget.ES2015, traceResolution: true, moduleResolution: ModuleResolutionKind.NodeJs }; + const indexDTS = { + name: "node_modules/a/index.d.ts", + text: SourceText.New("", "export declare let x: number;", ""), + }; + const options: CompilerOptions = { + target: ScriptTarget.ES2015, + traceResolution: true, + moduleResolution: ModuleResolutionKind.NodeJs, + }; const rootFiles = [file1Ts, file2Ts]; const filesAfterNpmInstall = [file1Ts, file2Ts, indexDTS]; @@ -500,7 +641,9 @@ namespace ts { "======== Module name 'a' was not resolved. ========", ], "initialProgram: execute module resolution normally."); - const initialProgramDiagnostics = initialProgram.getSemanticDiagnostics(initialProgram.getSourceFile("file1.ts")); + const initialProgramDiagnostics = initialProgram.getSemanticDiagnostics( + initialProgram.getSourceFile("file1.ts"), + ); assert.lengthOf(initialProgramDiagnostics, 1, `initialProgram: import should fail.`); } @@ -522,8 +665,14 @@ namespace ts { "======== Module name 'a' was successfully resolved to 'node_modules/a/index.d.ts'. ========", ], "afterNpmInstallProgram: execute module resolution normally."); - const afterNpmInstallProgramDiagnostics = afterNpmInstallProgram.getSemanticDiagnostics(afterNpmInstallProgram.getSourceFile("file1.ts")); - assert.lengthOf(afterNpmInstallProgramDiagnostics, 0, `afterNpmInstallProgram: program is well-formed with import.`); + const afterNpmInstallProgramDiagnostics = afterNpmInstallProgram.getSemanticDiagnostics( + afterNpmInstallProgram.getSourceFile("file1.ts"), + ); + assert.lengthOf( + afterNpmInstallProgramDiagnostics, + 0, + `afterNpmInstallProgram: program is well-formed with import.`, + ); } }); @@ -612,8 +761,14 @@ namespace ts { { name: "a2.ts", text: SourceText.New("", "", "let x = 1;") }, { name: "b1.ts", text: SourceText.New("", "export class B { x: number; }", "") }, { name: "b2.ts", text: SourceText.New("", "export class B { x: number; }", "") }, - { name: "node_modules/@types/typerefs1/index.d.ts", text: SourceText.New("", "", "declare let z: string;") }, - { name: "node_modules/@types/typerefs2/index.d.ts", text: SourceText.New("", "", "declare let z: string;") }, + { + name: "node_modules/@types/typerefs1/index.d.ts", + text: SourceText.New("", "", "declare let z: string;"), + }, + { + name: "node_modules/@types/typerefs2/index.d.ts", + text: SourceText.New("", "", "declare let z: string;"), + }, { name: "f1.ts", text: SourceText.New( @@ -632,7 +787,11 @@ namespace ts { }, ]; - const options: CompilerOptions = { target: ScriptTarget.ES2015, traceResolution: true, moduleResolution: ModuleResolutionKind.Classic }; + const options: CompilerOptions = { + target: ScriptTarget.ES2015, + traceResolution: true, + moduleResolution: ModuleResolutionKind.Classic, + }; const program1 = newProgram(files, files.map(f => f.name), options); let expectedErrors = 0; { @@ -666,13 +825,19 @@ namespace ts { } const indexOfF1 = 6; const program2 = updateProgram(program1, program1.getRootFileNames(), options, f => { - const newSourceText = f[indexOfF1].text.updateReferences(`/// ${newLine}/// `); + const newSourceText = f[indexOfF1].text.updateReferences( + `/// ${newLine}/// `, + ); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { const program2Diagnostics = program2.getSemanticDiagnostics(program2.getSourceFile("f2.ts")); - assert.lengthOf(program2Diagnostics, expectedErrors, `removing no-default-lib shouldn't affect any types used.`); + assert.lengthOf( + program2Diagnostics, + expectedErrors, + `removing no-default-lib shouldn't affect any types used.`, + ); assert.deepEqual(program2.host.getTrace(), [ "======== Resolving type reference directive 'typerefs1', containing file 'f1.ts', root directory 'node_modules/@types'. ========", @@ -701,7 +866,11 @@ namespace ts { { const program3Diagnostics = program3.getSemanticDiagnostics(program3.getSourceFile("f2.ts")); - assert.lengthOf(program3Diagnostics, expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`); + assert.lengthOf( + program3Diagnostics, + expectedErrors, + `typerefs2 was unused, so diagnostics should be unaffected.`, + ); assert.deepEqual(program3.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", @@ -725,7 +894,11 @@ namespace ts { { const program4Diagnostics = program4.getSemanticDiagnostics(program4.getSourceFile("f2.ts")); - assert.lengthOf(program4Diagnostics, expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`); + assert.lengthOf( + program4Diagnostics, + expectedErrors, + `a1.ts was unused, so diagnostics should be unaffected.`, + ); assert.deepEqual(program4.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", @@ -749,7 +922,11 @@ namespace ts { { const program5Diagnostics = program5.getSemanticDiagnostics(program5.getSourceFile("f2.ts")); - assert.lengthOf(program5Diagnostics, ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`); + assert.lengthOf( + program5Diagnostics, + ++expectedErrors, + `import of BB in f1 fails. BB is of type any. Add one error`, + ); assert.deepEqual(program5.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", @@ -790,7 +967,11 @@ namespace ts { { const program7Diagnostics = program7.getSemanticDiagnostics(program7.getSourceFile("f2.ts")); - assert.lengthOf(program7Diagnostics, expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`); + assert.lengthOf( + program7Diagnostics, + expectedErrors, + `removing import is noop with respect to program, so no change in diagnostics.`, + ); assert.deepEqual(program7.host.getTrace(), [ "======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========", @@ -812,7 +993,10 @@ namespace ts { const root = "/a.ts"; const compilerOptions = { target, moduleResolution: ModuleResolutionKind.NodeJs }; - function createRedirectProgram(useGetSourceFileByPath: boolean, options?: { bText: string; bVersion: string; }): ProgramWithSourceTexts { + function createRedirectProgram( + useGetSourceFileByPath: boolean, + options?: { bText: string; bVersion: string; }, + ): ProgramWithSourceTexts { const files: NamedSourceText[] = [ { name: "/node_modules/a/index.d.ts", @@ -832,11 +1016,19 @@ namespace ts { }, { name: bxIndex, - text: SourceText.New("", "", options ? options.bText : "export default class X { private x: number; }"), + text: SourceText.New( + "", + "", + options ? options.bText : "export default class X { private x: number; }", + ), }, { name: bxPackage, - text: SourceText.New("", "", JSON.stringify({ name: "x", version: options ? options.bVersion : "1.2.3" })), + text: SourceText.New( + "", + "", + JSON.stringify({ name: "x", version: options ? options.bVersion : "1.2.3" }), + ), }, { name: root, @@ -847,8 +1039,19 @@ namespace ts { return newProgram(files, [root], compilerOptions, useGetSourceFileByPath); } - function updateRedirectProgram(program: ProgramWithSourceTexts, updater: (files: NamedSourceText[]) => void, useGetSourceFileByPath: boolean): ProgramWithSourceTexts { - return updateProgram(program, [root], compilerOptions, updater, /*newTexts*/ undefined, useGetSourceFileByPath); + function updateRedirectProgram( + program: ProgramWithSourceTexts, + updater: (files: NamedSourceText[]) => void, + useGetSourceFileByPath: boolean, + ): ProgramWithSourceTexts { + return updateProgram( + program, + [root], + compilerOptions, + updater, + /*newTexts*/ undefined, + useGetSourceFileByPath, + ); } function verifyRedirects(useGetSourceFileByPath: boolean) { @@ -867,7 +1070,11 @@ namespace ts { assert.lengthOf(program1.getSemanticDiagnostics(), 0); const program2 = updateRedirectProgram(program1, files => { - updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }"); + updateProgramText( + files, + axIndex, + "export default class X { private x: number; private y: number; }", + ); updateProgramText(files, axPackage, JSON.stringify('{ name: "x", version: "1.2.4" }')); }, useGetSourceFileByPath); assert.equal(program2.structureIsReused, StructureIsReused.Not); @@ -878,7 +1085,11 @@ namespace ts { const program1 = createRedirectProgram(useGetSourceFileByPath); const program2 = updateRedirectProgram(program1, files => { - updateProgramText(files, bxIndex, "export default class X { private x: number; private y: number; }"); + updateProgramText( + files, + bxIndex, + "export default class X { private x: number; private y: number; }", + ); updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.4" })); }, useGetSourceFileByPath); assert.equal(program2.structureIsReused, StructureIsReused.Not); @@ -886,7 +1097,10 @@ namespace ts { }); it("Previously duplicate packages -> program structure not reused", () => { - const program1 = createRedirectProgram(useGetSourceFileByPath, { bVersion: "1.2.4", bText: "export = class X { private x: number; }" }); + const program1 = createRedirectProgram(useGetSourceFileByPath, { + bVersion: "1.2.4", + bText: "export = class X { private x: number; }", + }); const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, bxIndex, "export default class X { private x: number; }"); @@ -966,7 +1180,14 @@ namespace ts { configFileName, system, })).getCurrentProgram().getProgram(); - const { fileNames, options } = parseConfigFileWithSystem(configFileName, {}, /*extendedConfigCache*/ undefined, /*watchOptionsToExtend*/ undefined, system, notImplemented)!; // TODO: GH#18217 + const { fileNames, options } = parseConfigFileWithSystem( + configFileName, + {}, + /*extendedConfigCache*/ undefined, + /*watchOptionsToExtend*/ undefined, + system, + notImplemented, + )!; // TODO: GH#18217 verifyProgramIsUptoDate(program, fileNames, options); } @@ -1049,7 +1270,12 @@ namespace ts { content: JSON.stringify({ compilerOptions }), }; - verifyProgram([app, module1, module2, module3, libFile, configFile], [app.path], compilerOptions, configFile.path); + verifyProgram( + [app, module1, module2, module3, libFile, configFile], + [app.path], + compilerOptions, + configFile.path, + ); }); it("has include paths specified in tsconfig file", () => { @@ -1086,7 +1312,10 @@ namespace ts { path: "/src/tsconfig.json", content: JSON.stringify({ compilerOptions, include: ["packages/**/*.ts"] }), }; - verifyProgramWithConfigFile(createTestSystem([app, module1, module2, module3, libFile, configFile]), configFile.path); + verifyProgramWithConfigFile( + createTestSystem([app, module1, module2, module3, libFile, configFile]), + configFile.path, + ); }); it("has the same root file names", () => { const module1: File = { diff --git a/src/testRunner/unittests/semver.ts b/src/testRunner/unittests/semver.ts index 272704c8d0366..867b79c1cd7c9 100644 --- a/src/testRunner/unittests/semver.ts +++ b/src/testRunner/unittests/semver.ts @@ -2,7 +2,10 @@ namespace ts { import theory = Utils.theory; describe("unittests:: semver", () => { describe("Version", () => { - function assertVersion(version: Version, [major, minor, patch, prerelease, build]: [number, number, number, string[]?, string[]?]) { + function assertVersion( + version: Version, + [major, minor, patch, prerelease, build]: [number, number, number, string[]?, string[]?], + ) { assert.strictEqual(version.major, major); assert.strictEqual(version.minor, minor); assert.strictEqual(version.patch, patch); @@ -15,7 +18,10 @@ namespace ts { }); it("parts", () => { assertVersion(new Version(1, 2, 3, "pre.4", "build.5"), [1, 2, 3, ["pre", "4"], ["build", "5"]]); - assertVersion(new Version(1, 2, 3, ["pre", "4"], ["build", "5"]), [1, 2, 3, ["pre", "4"], ["build", "5"]]); + assertVersion(new Version(1, 2, 3, ["pre", "4"], ["build", "5"]), [1, 2, 3, ["pre", "4"], [ + "build", + "5", + ]]); assertVersion(new Version(1, 2, 3), [1, 2, 3]); assertVersion(new Version(1, 2), [1, 2, 0]); assertVersion(new Version(1), [1, 0, 0]); @@ -24,7 +30,10 @@ namespace ts { it("toString", () => { assert.strictEqual(new Version(1, 2, 3, "pre.4", "build.5").toString(), "1.2.3-pre.4+build.5"); assert.strictEqual(new Version(1, 2, 3, "pre.4").toString(), "1.2.3-pre.4"); - assert.strictEqual(new Version(1, 2, 3, /*prerelease*/ undefined, "build.5").toString(), "1.2.3+build.5"); + assert.strictEqual( + new Version(1, 2, 3, /*prerelease*/ undefined, "build.5").toString(), + "1.2.3+build.5", + ); assert.strictEqual(new Version(1, 2, 3).toString(), "1.2.3"); assert.strictEqual(new Version(1, 2).toString(), "1.2.0"); assert.strictEqual(new Version(1).toString(), "1.0.0"); @@ -60,7 +69,10 @@ namespace ts { // https://semver.org/#spec-item-11 // > identifiers with letters or hyphens are compared lexically in ASCII sort order. assert.strictEqual(new Version("1.0.0-a").compareTo(new Version("1.0.0-b")), Comparison.LessThan); - assert.strictEqual(new Version("1.0.0-a-2").compareTo(new Version("1.0.0-a-10")), Comparison.GreaterThan); + assert.strictEqual( + new Version("1.0.0-a-2").compareTo(new Version("1.0.0-a-10")), + Comparison.GreaterThan, + ); assert.strictEqual(new Version("1.0.0-b").compareTo(new Version("1.0.0-a")), Comparison.GreaterThan); assert.strictEqual(new Version("1.0.0-a").compareTo(new Version("1.0.0-a")), Comparison.EqualTo); assert.strictEqual(new Version("1.0.0-A").compareTo(new Version("1.0.0-a")), Comparison.LessThan); @@ -68,24 +80,48 @@ namespace ts { // https://semver.org/#spec-item-11 // > Numeric identifiers always have lower precedence than non-numeric identifiers. assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-alpha")), Comparison.LessThan); - assert.strictEqual(new Version("1.0.0-alpha").compareTo(new Version("1.0.0-0")), Comparison.GreaterThan); + assert.strictEqual( + new Version("1.0.0-alpha").compareTo(new Version("1.0.0-0")), + Comparison.GreaterThan, + ); assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-0")), Comparison.EqualTo); - assert.strictEqual(new Version("1.0.0-alpha").compareTo(new Version("1.0.0-alpha")), Comparison.EqualTo); + assert.strictEqual( + new Version("1.0.0-alpha").compareTo(new Version("1.0.0-alpha")), + Comparison.EqualTo, + ); // https://semver.org/#spec-item-11 // > A larger set of pre-release fields has a higher precedence than a smaller set, if all // > of the preceding identifiers are equal. - assert.strictEqual(new Version("1.0.0-alpha").compareTo(new Version("1.0.0-alpha.0")), Comparison.LessThan); - assert.strictEqual(new Version("1.0.0-alpha.0").compareTo(new Version("1.0.0-alpha")), Comparison.GreaterThan); + assert.strictEqual( + new Version("1.0.0-alpha").compareTo(new Version("1.0.0-alpha.0")), + Comparison.LessThan, + ); + assert.strictEqual( + new Version("1.0.0-alpha.0").compareTo(new Version("1.0.0-alpha")), + Comparison.GreaterThan, + ); // https://semver.org/#spec-item-11 // > Precedence for two pre-release versions with the same major, minor, and patch version // > MUST be determined by comparing each dot separated identifier from left to right until // > a difference is found [...] - assert.strictEqual(new Version("1.0.0-a.0.b.1").compareTo(new Version("1.0.0-a.0.b.2")), Comparison.LessThan); - assert.strictEqual(new Version("1.0.0-a.0.b.1").compareTo(new Version("1.0.0-b.0.a.1")), Comparison.LessThan); - assert.strictEqual(new Version("1.0.0-a.0.b.2").compareTo(new Version("1.0.0-a.0.b.1")), Comparison.GreaterThan); - assert.strictEqual(new Version("1.0.0-b.0.a.1").compareTo(new Version("1.0.0-a.0.b.1")), Comparison.GreaterThan); + assert.strictEqual( + new Version("1.0.0-a.0.b.1").compareTo(new Version("1.0.0-a.0.b.2")), + Comparison.LessThan, + ); + assert.strictEqual( + new Version("1.0.0-a.0.b.1").compareTo(new Version("1.0.0-b.0.a.1")), + Comparison.LessThan, + ); + assert.strictEqual( + new Version("1.0.0-a.0.b.2").compareTo(new Version("1.0.0-a.0.b.1")), + Comparison.GreaterThan, + ); + assert.strictEqual( + new Version("1.0.0-b.0.a.1").compareTo(new Version("1.0.0-a.0.b.1")), + Comparison.GreaterThan, + ); // https://semver.org/#spec-item-11 // > Build metadata does not figure into precedence @@ -179,7 +215,13 @@ namespace ts { function assertRange(rangeText: string, versionText: string, inRange: boolean) { const range = new VersionRange(rangeText); const version = new Version(versionText); - assert.strictEqual(range.test(version), inRange, `Expected version '${version}' ${inRange ? `to be` : `to not be`} in range '${rangeText}' (${range})`); + assert.strictEqual( + range.test(version), + inRange, + `Expected version '${version}' ${ + inRange ? `to be` : `to not be` + } in range '${rangeText}' (${range})`, + ); } theory("comparators", assertRange, [ diff --git a/src/testRunner/unittests/services/cancellableLanguageServiceOperations.ts b/src/testRunner/unittests/services/cancellableLanguageServiceOperations.ts index 706c9d4f92a2e..8e1b01d8012ab 100644 --- a/src/testRunner/unittests/services/cancellableLanguageServiceOperations.ts +++ b/src/testRunner/unittests/services/cancellableLanguageServiceOperations.ts @@ -7,9 +7,14 @@ namespace ts { foo(f); `; it("can cancel signature help mid-request", () => { - verifyOperationCancelledAfter(file, 4, service => - // Two calls are top-level in services, one is the root type, and the second should be for the parameter type - service.getSignatureHelpItems("file.ts", file.lastIndexOf("f"), emptyOptions)!, r => assert.exists(r.items[0])); + verifyOperationCancelledAfter( + file, + 4, + service => + // Two calls are top-level in services, one is the root type, and the second should be for the parameter type + service.getSignatureHelpItems("file.ts", file.lastIndexOf("f"), emptyOptions)!, + r => assert.exists(r.items[0]), + ); }); it("can cancel find all references mid-request", () => { @@ -48,7 +53,15 @@ namespace ts { }; verifyOperationCancelledAfter(file, 1, service => // The LS doesn't do any top-level checks on the token for completion entry details, so the first check is within the checker - service.getCompletionEntryDetails("file.ts", file.lastIndexOf("f"), "foo", options, /*source*/ undefined, {}, /*data*/ undefined)!, r => assert.exists(r.displayParts)); + service.getCompletionEntryDetails( + "file.ts", + file.lastIndexOf("f"), + "foo", + options, + /*source*/ undefined, + {}, + /*data*/ undefined, + )!, r => assert.exists(r.displayParts)); }); it("can cancel suggestion diagnostics mid-request", () => { @@ -66,7 +79,15 @@ namespace ts { }); }); - function verifyOperationCancelledAfter(content: string, cancelAfter: number, operation: (service: LanguageService) => T, validator: (arg: T) => void, fileName?: string, fileContent?: string, options?: CompilerOptions) { + function verifyOperationCancelledAfter( + content: string, + cancelAfter: number, + operation: (service: LanguageService) => T, + validator: (arg: T) => void, + fileName?: string, + fileContent?: string, + options?: CompilerOptions, + ) { let checks = 0; const token: HostCancellationToken = { isCancellationRequested() { diff --git a/src/testRunner/unittests/services/colorization.ts b/src/testRunner/unittests/services/colorization.ts index 4fe4914220e66..f74b4e4900982 100644 --- a/src/testRunner/unittests/services/colorization.ts +++ b/src/testRunner/unittests/services/colorization.ts @@ -9,7 +9,9 @@ interface ClassificationEntry { describe("unittests:: services:: Colorization", () => { // Use the shim adapter to ensure test coverage of the shim layer for the classifier - const languageServiceAdapter = new Harness.LanguageService.ShimLanguageServiceAdapter(/*preprocessToResolve*/ false); + const languageServiceAdapter = new Harness.LanguageService.ShimLanguageServiceAdapter( + /*preprocessToResolve*/ false, + ); const classifier = languageServiceAdapter.getClassifier(); function getEntryAtPosition(result: ts.ClassificationResult, position: number) { @@ -51,105 +53,253 @@ describe("unittests:: services:: Colorization", () => { // TODO: GH#18217 return { value, classification: undefined!, position: 0 }; } - function createClassification(value: string, classification: ts.TokenClass, position?: number): ClassificationEntry { + function createClassification( + value: string, + classification: ts.TokenClass, + position?: number, + ): ClassificationEntry { return { value, classification, position }; } - function testLexicalClassification(text: string, initialEndOfLineState: ts.EndOfLineState, ...expectedEntries: ClassificationEntry[]): void { - const result = classifier.getClassificationsForLine(text, initialEndOfLineState, /*syntacticClassifierAbsent*/ false); + function testLexicalClassification( + text: string, + initialEndOfLineState: ts.EndOfLineState, + ...expectedEntries: ClassificationEntry[] + ): void { + const result = classifier.getClassificationsForLine( + text, + initialEndOfLineState, + /*syntacticClassifierAbsent*/ false, + ); for (const expectedEntry of expectedEntries) { if (expectedEntry.classification === undefined) { - assert.equal(result.finalLexState, expectedEntry.value, "final endOfLineState does not match expected."); + assert.equal( + result.finalLexState, + expectedEntry.value, + "final endOfLineState does not match expected.", + ); } else { - const actualEntryPosition = expectedEntry.position !== undefined ? expectedEntry.position : text.indexOf(expectedEntry.value); - assert(actualEntryPosition >= 0, "token: '" + expectedEntry.value + "' does not exit in text: '" + text + "'."); + const actualEntryPosition = expectedEntry.position !== undefined ? expectedEntry.position + : text.indexOf(expectedEntry.value); + assert( + actualEntryPosition >= 0, + "token: '" + expectedEntry.value + "' does not exit in text: '" + text + "'.", + ); const actualEntry = getEntryAtPosition(result, actualEntryPosition)!; - assert(actualEntry, "Could not find classification entry for '" + expectedEntry.value + "' at position: " + actualEntryPosition); - assert.equal(actualEntry.classification, expectedEntry.classification, "Classification class does not match expected. Expected: " + ts.TokenClass[expectedEntry.classification] + ", Actual: " + ts.TokenClass[actualEntry.classification]); - assert.equal(actualEntry.length, expectedEntry.value.length, "Classification length does not match expected. Expected: " + ts.TokenClass[expectedEntry.value.length] + ", Actual: " + ts.TokenClass[actualEntry.length]); + assert( + actualEntry, + "Could not find classification entry for '" + expectedEntry.value + "' at position: " + + actualEntryPosition, + ); + assert.equal( + actualEntry.classification, + expectedEntry.classification, + "Classification class does not match expected. Expected: " + + ts.TokenClass[expectedEntry.classification] + ", Actual: " + + ts.TokenClass[actualEntry.classification], + ); + assert.equal( + actualEntry.length, + expectedEntry.value.length, + "Classification length does not match expected. Expected: " + + ts.TokenClass[expectedEntry.value.length] + ", Actual: " + ts.TokenClass[actualEntry.length], + ); } } } describe("test getClassifications", () => { it("returns correct token classes", () => { - testLexicalClassification('var x: string = "foo" ?? "bar"; //Hello', ts.EndOfLineState.None, keyword("var"), whitespace(" "), identifier("x"), punctuation(":"), keyword("string"), operator("="), stringLiteral('"foo"'), whitespace(" "), operator("??"), stringLiteral('"foo"'), comment("//Hello"), punctuation(";")); + testLexicalClassification( + 'var x: string = "foo" ?? "bar"; //Hello', + ts.EndOfLineState.None, + keyword("var"), + whitespace(" "), + identifier("x"), + punctuation(":"), + keyword("string"), + operator("="), + stringLiteral('"foo"'), + whitespace(" "), + operator("??"), + stringLiteral('"foo"'), + comment("//Hello"), + punctuation(";"), + ); }); it("correctly classifies a comment after a divide operator", () => { - testLexicalClassification("1 / 2 // comment", ts.EndOfLineState.None, numberLiteral("1"), whitespace(" "), operator("/"), numberLiteral("2"), comment("// comment")); + testLexicalClassification( + "1 / 2 // comment", + ts.EndOfLineState.None, + numberLiteral("1"), + whitespace(" "), + operator("/"), + numberLiteral("2"), + comment("// comment"), + ); }); it("correctly classifies a literal after a divide operator", () => { - testLexicalClassification("1 / 2, 3 / 4", ts.EndOfLineState.None, numberLiteral("1"), whitespace(" "), operator("/"), numberLiteral("2"), numberLiteral("3"), numberLiteral("4"), operator(",")); + testLexicalClassification( + "1 / 2, 3 / 4", + ts.EndOfLineState.None, + numberLiteral("1"), + whitespace(" "), + operator("/"), + numberLiteral("2"), + numberLiteral("3"), + numberLiteral("4"), + operator(","), + ); }); it("correctly classifies a multiline string with one backslash", () => { - testLexicalClassification("'line1\\", ts.EndOfLineState.None, stringLiteral("'line1\\"), finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral)); + testLexicalClassification( + "'line1\\", + ts.EndOfLineState.None, + stringLiteral("'line1\\"), + finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral), + ); }); it("correctly classifies a multiline string with three backslashes", () => { - testLexicalClassification("'line1\\\\\\", ts.EndOfLineState.None, stringLiteral("'line1\\\\\\"), finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral)); + testLexicalClassification( + "'line1\\\\\\", + ts.EndOfLineState.None, + stringLiteral("'line1\\\\\\"), + finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral), + ); }); it("correctly classifies an unterminated single-line string with no backslashes", () => { - testLexicalClassification("'line1", ts.EndOfLineState.None, stringLiteral("'line1"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "'line1", + ts.EndOfLineState.None, + stringLiteral("'line1"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies an unterminated single-line string with two backslashes", () => { - testLexicalClassification("'line1\\\\", ts.EndOfLineState.None, stringLiteral("'line1\\\\"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "'line1\\\\", + ts.EndOfLineState.None, + stringLiteral("'line1\\\\"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies an unterminated single-line string with four backslashes", () => { - testLexicalClassification("'line1\\\\\\\\", ts.EndOfLineState.None, stringLiteral("'line1\\\\\\\\"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "'line1\\\\\\\\", + ts.EndOfLineState.None, + stringLiteral("'line1\\\\\\\\"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the continuing line of a multiline string ending in one backslash", () => { - testLexicalClassification("\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\"), finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral)); + testLexicalClassification( + "\\", + ts.EndOfLineState.InDoubleQuoteStringLiteral, + stringLiteral("\\"), + finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral), + ); }); it("correctly classifies the continuing line of a multiline string ending in three backslashes", () => { - testLexicalClassification("\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\"), finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral)); + testLexicalClassification( + "\\", + ts.EndOfLineState.InDoubleQuoteStringLiteral, + stringLiteral("\\"), + finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral), + ); }); it("correctly classifies the last line of an unterminated multiline string ending in no backslashes", () => { - testLexicalClassification(" ", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral(" "), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + " ", + ts.EndOfLineState.InDoubleQuoteStringLiteral, + stringLiteral(" "), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the last line of an unterminated multiline string ending in two backslashes", () => { - testLexicalClassification("\\\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\\\"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "\\\\", + ts.EndOfLineState.InDoubleQuoteStringLiteral, + stringLiteral("\\\\"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the last line of an unterminated multiline string ending in four backslashes", () => { - testLexicalClassification("\\\\\\\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\\\\\\\"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "\\\\\\\\", + ts.EndOfLineState.InDoubleQuoteStringLiteral, + stringLiteral("\\\\\\\\"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the last line of a multiline string", () => { - testLexicalClassification("'", ts.EndOfLineState.InSingleQuoteStringLiteral, stringLiteral("'"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "'", + ts.EndOfLineState.InSingleQuoteStringLiteral, + stringLiteral("'"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies an unterminated multiline comment", () => { - testLexicalClassification("/*", ts.EndOfLineState.None, comment("/*"), finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + testLexicalClassification( + "/*", + ts.EndOfLineState.None, + comment("/*"), + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia), + ); }); it("correctly classifies the termination of a multiline comment", () => { - testLexicalClassification(" */ ", ts.EndOfLineState.InMultiLineCommentTrivia, comment(" */"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + " */ ", + ts.EndOfLineState.InMultiLineCommentTrivia, + comment(" */"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the continuation of a multiline comment", () => { - testLexicalClassification("LOREM IPSUM DOLOR ", ts.EndOfLineState.InMultiLineCommentTrivia, comment("LOREM IPSUM DOLOR "), finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + testLexicalClassification( + "LOREM IPSUM DOLOR ", + ts.EndOfLineState.InMultiLineCommentTrivia, + comment("LOREM IPSUM DOLOR "), + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia), + ); }); it("correctly classifies an unterminated multiline comment on a line ending in '/*/'", () => { - testLexicalClassification(" /*/", ts.EndOfLineState.None, comment("/*/"), finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + testLexicalClassification( + " /*/", + ts.EndOfLineState.None, + comment("/*/"), + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia), + ); }); it("correctly classifies an unterminated multiline comment with trailing space", () => { - testLexicalClassification("/* ", ts.EndOfLineState.None, comment("/* "), finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + testLexicalClassification( + "/* ", + ts.EndOfLineState.None, + comment("/* "), + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia), + ); }); it("correctly classifies a keyword after a dot", () => { @@ -161,7 +311,14 @@ describe("unittests:: services:: Colorization", () => { }); it("correctly classifies a keyword after a dot separated by comment trivia", () => { - testLexicalClassification("a./*hello world*/ var", ts.EndOfLineState.None, identifier("a"), punctuation("."), comment("/*hello world*/"), identifier("var")); + testLexicalClassification( + "a./*hello world*/ var", + ts.EndOfLineState.None, + identifier("a"), + punctuation("."), + comment("/*hello world*/"), + identifier("var"), + ); }); it("classifies a property access with whitespace around the dot", () => { @@ -169,47 +326,140 @@ describe("unittests:: services:: Colorization", () => { }); it("classifies a keyword after a dot on previous line", () => { - testLexicalClassification("var", ts.EndOfLineState.None, keyword("var"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "var", + ts.EndOfLineState.None, + keyword("var"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies multiple keywords properly", () => { - testLexicalClassification("public static", ts.EndOfLineState.None, keyword("public"), keyword("static"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "public static", + ts.EndOfLineState.None, + keyword("public"), + keyword("static"), + finalEndOfLineState(ts.EndOfLineState.None), + ); - testLexicalClassification("public var", ts.EndOfLineState.None, keyword("public"), identifier("var"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "public var", + ts.EndOfLineState.None, + keyword("public"), + identifier("var"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies a single line no substitution template string correctly", () => { - testLexicalClassification("`number number public string`", ts.EndOfLineState.None, stringLiteral("`number number public string`"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "`number number public string`", + ts.EndOfLineState.None, + stringLiteral("`number number public string`"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies substitution parts of a template string correctly", () => { - testLexicalClassification("`number '${ 1 + 1 }' string '${ 'hello' }'`", ts.EndOfLineState.None, stringLiteral("`number '${"), numberLiteral("1"), operator("+"), numberLiteral("1"), stringLiteral("}' string '${"), stringLiteral("'hello'"), stringLiteral("}'`"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "`number '${ 1 + 1 }' string '${ 'hello' }'`", + ts.EndOfLineState.None, + stringLiteral("`number '${"), + numberLiteral("1"), + operator("+"), + numberLiteral("1"), + stringLiteral("}' string '${"), + stringLiteral("'hello'"), + stringLiteral("}'`"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies an unterminated no substitution template string correctly", () => { - testLexicalClassification("`hello world", ts.EndOfLineState.None, stringLiteral("`hello world"), finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate)); + testLexicalClassification( + "`hello world", + ts.EndOfLineState.None, + stringLiteral("`hello world"), + finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate), + ); }); it("classifies the entire line of an unterminated multiline no-substitution/head template", () => { - testLexicalClassification("...", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("..."), finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate)); + testLexicalClassification( + "...", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("..."), + finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate), + ); }); it("classifies the entire line of an unterminated multiline template middle/end", () => { - testLexicalClassification("...", ts.EndOfLineState.InTemplateMiddleOrTail, stringLiteral("..."), finalEndOfLineState(ts.EndOfLineState.InTemplateMiddleOrTail)); + testLexicalClassification( + "...", + ts.EndOfLineState.InTemplateMiddleOrTail, + stringLiteral("..."), + finalEndOfLineState(ts.EndOfLineState.InTemplateMiddleOrTail), + ); }); it("classifies a termination of a multiline template head", () => { - testLexicalClassification("...${", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("...${"), finalEndOfLineState(ts.EndOfLineState.InTemplateSubstitutionPosition)); + testLexicalClassification( + "...${", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("...${"), + finalEndOfLineState(ts.EndOfLineState.InTemplateSubstitutionPosition), + ); }); it("classifies the termination of a multiline no substitution template", () => { - testLexicalClassification("...`", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("...`"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "...`", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("...`"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies the substitution parts and middle/tail of a multiline template string", () => { - testLexicalClassification("${ 1 + 1 }...`", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("${"), numberLiteral("1"), operator("+"), numberLiteral("1"), stringLiteral("}...`"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "${ 1 + 1 }...`", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("${"), + numberLiteral("1"), + operator("+"), + numberLiteral("1"), + stringLiteral("}...`"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies a template middle and propagates the end of line state", () => { - testLexicalClassification("${ 1 + 1 }...`", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("${"), numberLiteral("1"), operator("+"), numberLiteral("1"), stringLiteral("}...`"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "${ 1 + 1 }...`", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral("${"), + numberLiteral("1"), + operator("+"), + numberLiteral("1"), + stringLiteral("}...`"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies substitution expressions with curly braces appropriately", () => { let pos = 0; let lastLength = 0; - testLexicalClassification("...${ () => { } } ${ { x: `1` } }...`", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral(track("...${"), pos), punctuation(track(" ", "("), pos), punctuation(track(")"), pos), punctuation(track(" ", "=>"), pos), punctuation(track(" ", "{"), pos), punctuation(track(" ", "}"), pos), stringLiteral(track(" ", "} ${"), pos), punctuation(track(" ", "{"), pos), identifier(track(" ", "x"), pos), punctuation(track(":"), pos), stringLiteral(track(" ", "`1`"), pos), punctuation(track(" ", "}"), pos), stringLiteral(track(" ", "}...`"), pos), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "...${ () => { } } ${ { x: `1` } }...`", + ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, + stringLiteral(track("...${"), pos), + punctuation(track(" ", "("), pos), + punctuation(track(")"), pos), + punctuation(track(" ", "=>"), pos), + punctuation(track(" ", "{"), pos), + punctuation(track(" ", "}"), pos), + stringLiteral(track(" ", "} ${"), pos), + punctuation(track(" ", "{"), pos), + identifier(track(" ", "x"), pos), + punctuation(track(":"), pos), + stringLiteral(track(" ", "`1`"), pos), + punctuation(track(" ", "}"), pos), + stringLiteral(track(" ", "}...`"), pos), + finalEndOfLineState(ts.EndOfLineState.None), + ); // Adjusts 'pos' by accounting for the length of each portion of the string, // but only return the last given string @@ -223,13 +473,37 @@ describe("unittests:: services:: Colorization", () => { }); it("classifies partially written generics correctly.", () => { - testLexicalClassification("Foo { @@ -322,7 +596,20 @@ class D { }\r\n\ }); it("'of' keyword", () => { - testLexicalClassification("for (var of of of) { }", ts.EndOfLineState.None, keyword("for"), punctuation("("), keyword("var"), keyword("of"), keyword("of"), keyword("of"), punctuation(")"), punctuation("{"), punctuation("}"), finalEndOfLineState(ts.EndOfLineState.None)); + testLexicalClassification( + "for (var of of of) { }", + ts.EndOfLineState.None, + keyword("for"), + punctuation("("), + keyword("var"), + keyword("of"), + keyword("of"), + keyword("of"), + punctuation(")"), + punctuation("{"), + punctuation("}"), + finalEndOfLineState(ts.EndOfLineState.None), + ); }); }); }); diff --git a/src/testRunner/unittests/services/convertToAsyncFunction.ts b/src/testRunner/unittests/services/convertToAsyncFunction.ts index 6e188a1c492c0..d0c208f930e18 100644 --- a/src/testRunner/unittests/services/convertToAsyncFunction.ts +++ b/src/testRunner/unittests/services/convertToAsyncFunction.ts @@ -274,7 +274,9 @@ interface Array {}`, only: (...args: T) => void; }; - function createTestWrapper(fn: (it: Mocha.PendingTestFunction, ...args: T) => void): WithSkipAndOnly { + function createTestWrapper( + fn: (it: Mocha.PendingTestFunction, ...args: T) => void, + ): WithSkipAndOnly { wrapped.skip = (...args: T) => fn(it.skip, ...args); wrapped.only = (...args: T) => fn(it.only, ...args); return wrapped; @@ -296,7 +298,13 @@ interface Array {}`, ExpectFailed = ExpectNoSuggestionDiagnostic | ExpectNoAction, } - function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: string, text: string, baselineFolder: string, flags: ConvertToAsyncTestFlags) { + function testConvertToAsyncFunction( + it: Mocha.PendingTestFunction, + caption: string, + text: string, + baselineFolder: string, + flags: ConvertToAsyncTestFlags, + ) { const includeLib = !!(flags & ConvertToAsyncTestFlags.IncludeLib); const includeModule = !!(flags & ConvertToAsyncTestFlags.IncludeModule); const expectSuggestionDiagnostic = !!(flags & ConvertToAsyncTestFlags.ExpectSuggestionDiagnostic); @@ -304,7 +312,10 @@ interface Array {}`, const expectAction = !!(flags & ConvertToAsyncTestFlags.ExpectAction); const expectNoAction = !!(flags & ConvertToAsyncTestFlags.ExpectNoAction); const expectFailure = expectNoSuggestionDiagnostic || expectNoAction; - Debug.assert(!(expectSuggestionDiagnostic && expectNoSuggestionDiagnostic), "Cannot combine both 'ExpectSuggestionDiagnostic' and 'ExpectNoSuggestionDiagnostic'"); + Debug.assert( + !(expectSuggestionDiagnostic && expectNoSuggestionDiagnostic), + "Cannot combine both 'ExpectSuggestionDiagnostic' and 'ExpectNoSuggestionDiagnostic'", + ); Debug.assert(!(expectAction && expectNoAction), "Cannot combine both 'ExpectAction' and 'ExpectNoAction'"); const t = extractTest(text); @@ -346,11 +357,17 @@ interface Array {}`, }; const diagnostics = languageService.getSuggestionDiagnostics(f.path); - const diagnostic = find(diagnostics, diagnostic => - diagnostic.messageText === Diagnostics.This_may_be_converted_to_an_async_function.message && - diagnostic.start === context.span.start && diagnostic.length === context.span.length); + const diagnostic = find( + diagnostics, + diagnostic => + diagnostic.messageText === Diagnostics.This_may_be_converted_to_an_async_function.message + && diagnostic.start === context.span.start && diagnostic.length === context.span.length, + ); const actions = codefix.getFixes(context); - const action = find(actions, action => action.description === Diagnostics.Convert_to_async_function.message); + const action = find( + actions, + action => action.description === Diagnostics.Convert_to_async_function.message, + ); let outputText: string | null; if (action?.changes.length) { @@ -364,7 +381,8 @@ interface Array {}`, const newText = textChanges.applyChanges(sourceFile.text, changes[0].textChanges); data.push(newText); - const diagProgram = makeLanguageService({ path, content: newText }, includeLib, includeModule).getProgram()!; + const diagProgram = makeLanguageService({ path, content: newText }, includeLib, includeModule) + .getProgram()!; assert.isFalse(hasSyntacticDiagnostics(diagProgram)); outputText = data.join(newLineCharacter); } @@ -413,23 +431,56 @@ interface Array {}`, } const _testConvertToAsyncFunction = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuccess); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuccess, + ); }); const _testConvertToAsyncFunctionFailed = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectFailed); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectFailed, + ); }); const _testConvertToAsyncFunctionFailedSuggestion = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectNoSuggestionDiagnostic | ConvertToAsyncTestFlags.ExpectAction); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectNoSuggestionDiagnostic + | ConvertToAsyncTestFlags.ExpectAction, + ); }); const _testConvertToAsyncFunctionFailedAction = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuggestionDiagnostic | ConvertToAsyncTestFlags.ExpectNoAction); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuggestionDiagnostic + | ConvertToAsyncTestFlags.ExpectNoAction, + ); }); const _testConvertToAsyncFunctionWithModule = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.IncludeModule | ConvertToAsyncTestFlags.ExpectSuccess); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.IncludeModule + | ConvertToAsyncTestFlags.ExpectSuccess, + ); }); describe("unittests:: services:: convertToAsyncFunction", () => { diff --git a/src/testRunner/unittests/services/documentRegistry.ts b/src/testRunner/unittests/services/documentRegistry.ts index 34ac1d822690d..6d03486bf4a1e 100644 --- a/src/testRunner/unittests/services/documentRegistry.ts +++ b/src/testRunner/unittests/services/documentRegistry.ts @@ -3,8 +3,18 @@ describe("unittests:: services:: DocumentRegistry", () => { const documentRegistry = ts.createDocumentRegistry(); const defaultCompilerOptions = ts.getDefaultCompilerOptions(); - const f1 = documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); - const f2 = documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f1 = documentRegistry.acquireDocument( + "file1.ts", + defaultCompilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); + const f2 = documentRegistry.acquireDocument( + "file1.ts", + defaultCompilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f1 === f2, "DocumentRegistry should return the same document for the same name"); }); @@ -15,25 +25,50 @@ describe("unittests:: services:: DocumentRegistry", () => { // change compilation setting that doesn't affect parsing - should have the same document compilerOptions.declaration = true; - const f1 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f1 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); compilerOptions.declaration = false; - const f2 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f2 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f1 === f2, "Expected to have the same document instance"); // change value of compilation setting that is used during production of AST - new document is required compilerOptions.target = ts.ScriptTarget.ES3; - const f3 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f3 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f1 !== f3, "Changed target: Expected to have different instances of document"); compilerOptions.preserveConstEnums = true; - const f4 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f4 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f3 === f4, "Changed preserveConstEnums: Expected to have the same instance of the document"); compilerOptions.module = ts.ModuleKind.System; - const f5 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f5 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f4 !== f5, "Changed module: Expected to have different instances of the document"); }); @@ -43,10 +78,20 @@ describe("unittests:: services:: DocumentRegistry", () => { const defaultCompilerOptions = ts.getDefaultCompilerOptions(); // Simulate one LS getting the document. - documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + documentRegistry.acquireDocument( + "file1.ts", + defaultCompilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); // Simulate another LS getting the document at another version. - const f2 = documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "2"); + const f2 = documentRegistry.acquireDocument( + "file1.ts", + defaultCompilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "2", + ); assert(f2.version === "2"); }); @@ -59,7 +104,8 @@ describe("unittests:: services:: DocumentRegistry", () => { const snapshot = ts.ScriptSnapshot.fromString(contents); // Always treat any change as a full change. - snapshot.getChangeRange = () => ts.createTextChangeRange(ts.createTextSpan(0, contents.length), contents.length); + snapshot.getChangeRange = () => + ts.createTextChangeRange(ts.createTextSpan(0, contents.length), contents.length); // Simulate one LS getting the document. documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, snapshot, /* version */ "1"); diff --git a/src/testRunner/unittests/services/extract/helpers.ts b/src/testRunner/unittests/services/extract/helpers.ts index 4db9314d84858..c41d4bb039b79 100644 --- a/src/testRunner/unittests/services/extract/helpers.ts +++ b/src/testRunner/unittests/services/extract/helpers.ts @@ -19,8 +19,9 @@ namespace ts { while (pos < source.length) { if ( - source.charCodeAt(pos) === CharacterCodes.openBracket && - (source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$) + source.charCodeAt(pos) === CharacterCodes.openBracket + && (source.charCodeAt(pos + 1) === CharacterCodes.hash + || source.charCodeAt(pos + 1) === CharacterCodes.$) ) { const saved = pos; pos += 2; @@ -41,7 +42,10 @@ namespace ts { pos = saved; } } - else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) { + else if ( + source.charCodeAt(pos) === CharacterCodes.bar + && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket + ) { text += source.substring(lastPos, pos); activeRanges[activeRanges.length - 1].end = text.length; const range = activeRanges.pop()!; @@ -78,14 +82,22 @@ namespace ts { fileExists: notImplemented, }; - export function testExtractSymbol(caption: string, text: string, baselineFolder: string, description: DiagnosticMessage, includeLib?: boolean) { + export function testExtractSymbol( + caption: string, + text: string, + baselineFolder: string, + description: DiagnosticMessage, + includeLib?: boolean, + ) { const t = extractTest(text); const selectionRange = t.ranges.get("selection")!; if (!selectionRange) { throw new Error(`Test ${caption} does not specify selection range`); } - [Extension.Ts, Extension.Js].forEach(extension => it(`${caption} [${extension}]`, () => runBaseline(extension))); + [Extension.Ts, Extension.Js].forEach(extension => + it(`${caption} [${extension}]`, () => runBaseline(extension)) + ); function runBaseline(extension: Extension) { const path = "/a" + extension; @@ -108,8 +120,15 @@ namespace ts { formatContext: formatting.getFormatContext(testFormatSettings, notImplementedHost), preferences: emptyOptions, }; - const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange)); - assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText); + const rangeToExtract = refactor.extractSymbol.getRangeToExtract( + sourceFile, + createTextSpanFromRange(selectionRange), + ); + assert.equal( + rangeToExtract.errors, + undefined, + rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText, + ); const infos = refactor.extractSymbol.getRefactorActionsToExtractSymbol(context); const actions = find(infos, info => info.description === description.message)!.actions; @@ -117,11 +136,15 @@ namespace ts { data.push(`// ==ORIGINAL==`); data.push(text.replace("[#|", "/*[#|*/").replace("|]", "/*|]*/")); for (const action of actions) { - const { renameLocation, edits } = refactor.extractSymbol.getRefactorEditsToExtractSymbol(context, action.name)!; + const { renameLocation, edits } = refactor.extractSymbol.getRefactorEditsToExtractSymbol( + context, + action.name, + )!; assert.lengthOf(edits, 1); data.push(`// ==SCOPE::${action.description}==`); const newText = textChanges.applyChanges(sourceFile.text, edits[0].textChanges); - const newTextWithRename = newText.slice(0, renameLocation) + "/*RENAME*/" + newText.slice(renameLocation); + const newTextWithRename = newText.slice(0, renameLocation) + "/*RENAME*/" + + newText.slice(renameLocation); data.push(newTextWithRename); const { program: diagProgram } = makeProgram({ path, content: newText }, includeLib); @@ -171,8 +194,14 @@ namespace ts { formatContext: formatting.getFormatContext(testFormatSettings, notImplementedHost), preferences: emptyOptions, }; - const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange)); - assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText); + const rangeToExtract = refactor.extractSymbol.getRangeToExtract( + sourceFile, + createTextSpanFromRange(selectionRange), + ); + assert.isUndefined( + rangeToExtract.errors, + rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText, + ); const infos = refactor.extractSymbol.getRefactorActionsToExtractSymbol(context); assert.isUndefined(find(infos, info => info.description === description.message)); }); diff --git a/src/testRunner/unittests/services/extract/ranges.ts b/src/testRunner/unittests/services/extract/ranges.ts index f79fa37d217d0..a3b0a0cb0ecc3 100644 --- a/src/testRunner/unittests/services/extract/ranges.ts +++ b/src/testRunner/unittests/services/extract/ranges.ts @@ -7,7 +7,11 @@ namespace ts { if (!selectionRange) { throw new Error(`Test ${s} does not specify selection range`); } - const result = refactor.extractSymbol.getRangeToExtract(file, createTextSpanFromRange(selectionRange), /*userRequested*/ false); + const result = refactor.extractSymbol.getRangeToExtract( + file, + createTextSpanFromRange(selectionRange), + /*userRequested*/ false, + ); assert(result.targetRange === undefined, "failure expected"); const sortedErrors = result.errors.map(e => e.messageText as string).sort(); assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors"); @@ -329,7 +333,10 @@ function f() { } } `, - [refactor.extractSymbol.Messages.cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message], + [ + refactor.extractSymbol.Messages + .cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message, + ], ); testExtractRangeFailed( @@ -400,7 +407,9 @@ switch (x) { [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message], ); - testExtractRangeFailed("extractRangeFailed9", `var x = ([#||]1 + 2);`, [refactor.extractSymbol.Messages.cannotExtractEmpty.message]); + testExtractRangeFailed("extractRangeFailed9", `var x = ([#||]1 + 2);`, [ + refactor.extractSymbol.Messages.cannotExtractEmpty.message, + ]); testExtractRangeFailed( "extractRangeFailed10", @@ -430,9 +439,13 @@ switch (x) { [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message], ); - testExtractRangeFailed("extractRangeFailed12", `let [#|x|];`, [refactor.extractSymbol.Messages.statementOrExpressionExpected.message]); + testExtractRangeFailed("extractRangeFailed12", `let [#|x|];`, [ + refactor.extractSymbol.Messages.statementOrExpressionExpected.message, + ]); - testExtractRangeFailed("extractRangeFailed13", `[#|return;|]`, [refactor.extractSymbol.Messages.cannotExtractRange.message]); + testExtractRangeFailed("extractRangeFailed13", `[#|return;|]`, [ + refactor.extractSymbol.Messages.cannotExtractRange.message, + ]); testExtractRangeFailed( "extractRangeFailed14", @@ -480,10 +493,16 @@ switch (x) { [refactor.extractSymbol.Messages.cannotExtractRange.message], ); - testExtractRangeFailed("extractRangeFailed18", `[#|{ 1;|] }`, [refactor.extractSymbol.Messages.cannotExtractRange.message]); + testExtractRangeFailed("extractRangeFailed18", `[#|{ 1;|] }`, [ + refactor.extractSymbol.Messages.cannotExtractRange.message, + ]); - testExtractRangeFailed("extractRangeFailed19", `[#|/** @type {number} */|] const foo = 1;`, [refactor.extractSymbol.Messages.cannotExtractJSDoc.message]); + testExtractRangeFailed("extractRangeFailed19", `[#|/** @type {number} */|] const foo = 1;`, [ + refactor.extractSymbol.Messages.cannotExtractJSDoc.message, + ]); - testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, [refactor.extractSymbol.Messages.cannotExtractIdentifier.message]); + testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, [ + refactor.extractSymbol.Messages.cannotExtractIdentifier.message, + ]); }); } diff --git a/src/testRunner/unittests/services/hostNewLineSupport.ts b/src/testRunner/unittests/services/hostNewLineSupport.ts index ce323c41e1d36..12a0a379b1cf5 100644 --- a/src/testRunner/unittests/services/hostNewLineSupport.ts +++ b/src/testRunner/unittests/services/hostNewLineSupport.ts @@ -34,9 +34,22 @@ namespace ts { const result = ls.getEmitOutput("input.ts"); assert(!result.emitSkipped, "emit was skipped"); assert(result.outputFiles.length === 1, "a number of files other than 1 was output"); - assert(result.outputFiles[0].name === "input.js", `Expected output file name input.js, but got ${result.outputFiles[0].name}`); - assert(result.outputFiles[0].text.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/), "expected to find appropriate newlines"); - assert(!result.outputFiles[0].text.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/), "expected not to find inappropriate newlines"); + assert( + result.outputFiles[0].name === "input.js", + `Expected output file name input.js, but got ${result.outputFiles[0].name}`, + ); + assert( + result.outputFiles[0].text.match( + options.newLine === NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/, + ), + "expected to find appropriate newlines", + ); + assert( + !result.outputFiles[0].text.match( + options.newLine === NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/, + ), + "expected not to find inappropriate newlines", + ); } function verifyBothNewLines(content: string) { @@ -52,8 +65,18 @@ namespace ts { }]); const span = ls.getOutliningSpans("input.ts")[0]; const textAfterSpanCollapse = content.substring(span.textSpan.start + span.textSpan.length); - assert(textAfterSpanCollapse.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/), "expected to find appropriate newlines"); - assert(!textAfterSpanCollapse.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/), "expected not to find inappropriate newlines"); + assert( + textAfterSpanCollapse.match( + options.newLine === NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/, + ), + "expected to find appropriate newlines", + ); + assert( + !textAfterSpanCollapse.match( + options.newLine === NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/, + ), + "expected not to find inappropriate newlines", + ); } it("should exist and respect provided compiler options", () => { @@ -65,11 +88,17 @@ namespace ts { }); it("should respect CRLF line endings around outlining spans", () => { - verifyOutliningSpanNewLines('// comment not included\r\n// #region name\r\nlet x: string = "x";\r\n// #endregion name\r\n', { newLine: NewLineKind.CarriageReturnLineFeed }); + verifyOutliningSpanNewLines( + '// comment not included\r\n// #region name\r\nlet x: string = "x";\r\n// #endregion name\r\n', + { newLine: NewLineKind.CarriageReturnLineFeed }, + ); }); it("should respect LF line endings around outlining spans", () => { - verifyOutliningSpanNewLines('// comment not included\n// #region name\nlet x: string = "x";\n// #endregion name\n\n', { newLine: NewLineKind.LineFeed }); + verifyOutliningSpanNewLines( + '// comment not included\n// #region name\nlet x: string = "x";\n// #endregion name\n\n', + { newLine: NewLineKind.LineFeed }, + ); }); }); } diff --git a/src/testRunner/unittests/services/languageService.ts b/src/testRunner/unittests/services/languageService.ts index a3a093cc0650e..dcea7284e9100 100644 --- a/src/testRunner/unittests/services/languageService.ts +++ b/src/testRunner/unittests/services/languageService.ts @@ -113,7 +113,10 @@ export function Component(x: Config): any;`, // Change other projectVersion = "2"; - files.set("/project/other.ts", { version: "2", text: `export function foo() { } export function bar() { }` }); + files.set("/project/other.ts", { + version: "2", + text: `export function foo() { } export function bar() { }`, + }); const program3 = ls.getProgram()!; assert.notStrictEqual(program2, program3); verifyProgramFiles(program3); @@ -176,15 +179,27 @@ export function Component(x: Config): any;`, path: `${tscWatch.projectRoot}/projects/project2/class2.ts`, content: `class class2 {}`, }; - const system = projectSystem.createServerHost([config1, class1, class1Dts, config2, class2, projectSystem.libFile]); - const result = getParsedCommandLineOfConfigFile(`${tscWatch.projectRoot}/projects/project2/tsconfig.json`, /*optionsToExtend*/ undefined, { - useCaseSensitiveFileNames: true, - fileExists: path => system.fileExists(path), - readFile: path => system.readFile(path), - getCurrentDirectory: () => system.getCurrentDirectory(), - readDirectory: (path, extensions, excludes, includes, depth) => system.readDirectory(path, extensions, excludes, includes, depth), - onUnRecoverableConfigFileDiagnostic: noop, - })!; + const system = projectSystem.createServerHost([ + config1, + class1, + class1Dts, + config2, + class2, + projectSystem.libFile, + ]); + const result = getParsedCommandLineOfConfigFile( + `${tscWatch.projectRoot}/projects/project2/tsconfig.json`, + /*optionsToExtend*/ undefined, + { + useCaseSensitiveFileNames: true, + fileExists: path => system.fileExists(path), + readFile: path => system.readFile(path), + getCurrentDirectory: () => system.getCurrentDirectory(), + readDirectory: (path, extensions, excludes, includes, depth) => + system.readDirectory(path, extensions, excludes, includes, depth), + onUnRecoverableConfigFileDiagnostic: noop, + }, + )!; const host: LanguageServiceHost = { useCaseSensitiveFileNames: returnTrue, useSourceOfProjectReferenceRedirect, @@ -200,7 +215,8 @@ export function Component(x: Config): any;`, const text = system.readFile(path); return text ? ScriptSnapshot.fromString(text) : undefined; }, - readDirectory: (path, extensions, excludes, includes, depth) => system.readDirectory(path, extensions, excludes, includes, depth), + readDirectory: (path, extensions, excludes, includes, depth) => + system.readDirectory(path, extensions, excludes, includes, depth), getCurrentDirectory: () => system.getCurrentDirectory(), getDefaultLibFileName: () => projectSystem.libFile.path, getProjectReferences: () => result.projectReferences, @@ -223,7 +239,10 @@ export function Component(x: Config): any;`, [projectSystem.libFile.path, class1.path, class3, class2.path], ); // Add excluded file to referenced project - system.ensureFileOrFolder({ path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + system.ensureFileOrFolder({ + path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); assert.strictEqual(ls.getProgram(), program); // Add output from new class to referenced project system.writeFile(`${tscWatch.projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`); @@ -254,7 +273,10 @@ export function Component(x: Config): any;`, [projectSystem.libFile.path, class1Dts.path, class3Dts, class2.path], ); // Add excluded file to referenced project - system.ensureFileOrFolder({ path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + system.ensureFileOrFolder({ + path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); assert.strictEqual(ls.getProgram(), program2); // Delete output from new class to referenced project system.deleteFile(class3Dts); diff --git a/src/testRunner/unittests/services/organizeImports.ts b/src/testRunner/unittests/services/organizeImports.ts index 37bd76188f91b..a68f6c96ae472 100644 --- a/src/testRunner/unittests/services/organizeImports.ts +++ b/src/testRunner/unittests/services/organizeImports.ts @@ -34,9 +34,18 @@ namespace ts { }); function assertSortsBefore(importString1: string, importString2: string) { - const [{ moduleSpecifier: moduleSpecifier1 }, { moduleSpecifier: moduleSpecifier2 }] = parseImports(importString1, importString2); - assert.equal(OrganizeImports.compareModuleSpecifiers(moduleSpecifier1, moduleSpecifier2), Comparison.LessThan); - assert.equal(OrganizeImports.compareModuleSpecifiers(moduleSpecifier2, moduleSpecifier1), Comparison.GreaterThan); + const [{ moduleSpecifier: moduleSpecifier1 }, { moduleSpecifier: moduleSpecifier2 }] = parseImports( + importString1, + importString2, + ); + assert.equal( + OrganizeImports.compareModuleSpecifiers(moduleSpecifier1, moduleSpecifier2), + Comparison.LessThan, + ); + assert.equal( + OrganizeImports.compareModuleSpecifiers(moduleSpecifier2, moduleSpecifier1), + Comparison.GreaterThan, + ); } }); @@ -48,7 +57,9 @@ namespace ts { it("Sort specifiers - case-insensitive", () => { const sortedImports = parseImports(`import { default as M, a as n, B, y, Z as O } from "lib";`); const actualCoalescedImports = OrganizeImports.coalesceImports(sortedImports); - const expectedCoalescedImports = parseImports(`import { a as n, B, default as M, y, Z as O } from "lib";`); + const expectedCoalescedImports = parseImports( + `import { a as n, B, default as M, y, Z as O } from "lib";`, + ); assertListEqual(actualCoalescedImports, expectedCoalescedImports); }); @@ -225,7 +236,9 @@ namespace ts { it("Sort specifiers - case-insensitive", () => { const sortedExports = parseExports(`export { default as M, a as n, B, y, Z as O } from "lib";`); const actualCoalescedExports = OrganizeImports.coalesceExports(sortedExports); - const expectedCoalescedExports = parseExports(`export { a as n, B, default as M, y, Z as O } from "lib";`); + const expectedCoalescedExports = parseExports( + `export { a as n, B, default as M, y, Z as O } from "lib";`, + ); assertListEqual(actualCoalescedExports, expectedCoalescedExports); }); @@ -353,7 +366,11 @@ export const Other = 1; content: "function F() { }", }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + testFormatSettings, + emptyOptions, + ); assert.isEmpty(changes); }); @@ -363,7 +380,11 @@ export const Other = 1; content: "declare module '*';", }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + testFormatSettings, + emptyOptions, + ); assert.isEmpty(changes); }); @@ -373,7 +394,11 @@ export const Other = 1; content: `import { f } from 'foo';\nf();`, }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + testFormatSettings, + emptyOptions, + ); assert.isEmpty(changes); }); @@ -411,9 +436,12 @@ D(); }, libFile); describe("skipDestructiveCodeActions=true", () => { - testOrganizeImports("Syntax_Error_Body_skipDestructiveCodeActions", /*skipDestructiveCodeActions*/ true, { - path: "/test.ts", - content: ` + testOrganizeImports( + "Syntax_Error_Body_skipDestructiveCodeActions", + /*skipDestructiveCodeActions*/ true, + { + path: "/test.ts", + content: ` import { F1, F2 } from "lib"; import * as NS from "lib"; import D from "lib"; @@ -421,12 +449,17 @@ import D from "lib"; class class class; D; `, - }, libFile); + }, + libFile, + ); }); - testOrganizeImports("Syntax_Error_Imports_skipDestructiveCodeActions", /*skipDestructiveCodeActions*/ true, { - path: "/test.ts", - content: ` + testOrganizeImports( + "Syntax_Error_Imports_skipDestructiveCodeActions", + /*skipDestructiveCodeActions*/ true, + { + path: "/test.ts", + content: ` import { F1, F2 class class class; } from "lib"; import * as NS from "lib"; class class class; @@ -434,7 +467,9 @@ import D from "lib"; D; `, - }, libFile); + }, + libFile, + ); describe("skipDestructiveCodeActions=false", () => { testOrganizeImports("Syntax_Error_Body", /*skipDestructiveCodeActions*/ false, { @@ -468,7 +503,11 @@ D; content: `import { f } from 'foo';\nf();`, }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + testFormatSettings, + emptyOptions, + ); assert.isEmpty(changes); }); @@ -489,7 +528,11 @@ import { } from "lib"; `, }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + testFormatSettings, + emptyOptions, + ); assert.isEmpty(changes); }); @@ -507,9 +550,12 @@ declare module 'caseless' { }`, }); - testOrganizeImports("Unused_preserve_imports_for_module_augmentation_in_non_declaration_file", /*skipDestructiveCodeActions*/ false, { - path: "/test.ts", - content: ` + testOrganizeImports( + "Unused_preserve_imports_for_module_augmentation_in_non_declaration_file", + /*skipDestructiveCodeActions*/ false, + { + path: "/test.ts", + content: ` import foo from 'foo'; import { Caseless } from 'caseless'; @@ -519,7 +565,8 @@ declare module 'caseless' { test(name: KeyType): boolean; } }`, - }); + }, + ); it("Unused_false_positive_shorthand_assignment", () => { const testFile = { @@ -530,7 +577,11 @@ const o = { x }; `, }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + testFormatSettings, + emptyOptions, + ); assert.isEmpty(changes); }); @@ -543,7 +594,11 @@ export { x }; `, }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + testFormatSettings, + emptyOptions, + ); assert.isEmpty(changes); }); @@ -944,18 +999,50 @@ export * from "lib"; }, libFile); }); - function testOrganizeExports(testName: string, testFile: TestFSWithWatch.File, ...otherFiles: TestFSWithWatch.File[]) { - testOrganizeImports(`${testName}.exports`, /*skipDestructiveCodeActions*/ true, testFile, ...otherFiles); + function testOrganizeExports( + testName: string, + testFile: TestFSWithWatch.File, + ...otherFiles: TestFSWithWatch.File[] + ) { + testOrganizeImports( + `${testName}.exports`, + /*skipDestructiveCodeActions*/ true, + testFile, + ...otherFiles, + ); } - function testOrganizeImports(testName: string, skipDestructiveCodeActions: boolean, testFile: TestFSWithWatch.File, ...otherFiles: TestFSWithWatch.File[]) { - it(testName, () => runBaseline(`organizeImports/${testName}.ts`, skipDestructiveCodeActions, testFile, ...otherFiles)); + function testOrganizeImports( + testName: string, + skipDestructiveCodeActions: boolean, + testFile: TestFSWithWatch.File, + ...otherFiles: TestFSWithWatch.File[] + ) { + it( + testName, + () => + runBaseline( + `organizeImports/${testName}.ts`, + skipDestructiveCodeActions, + testFile, + ...otherFiles, + ), + ); } - function runBaseline(baselinePath: string, skipDestructiveCodeActions: boolean, testFile: TestFSWithWatch.File, ...otherFiles: TestFSWithWatch.File[]) { + function runBaseline( + baselinePath: string, + skipDestructiveCodeActions: boolean, + testFile: TestFSWithWatch.File, + ...otherFiles: TestFSWithWatch.File[] + ) { const { path: testPath, content: testContent } = testFile; const languageService = makeLanguageService(testFile, ...otherFiles); - const changes = languageService.organizeImports({ skipDestructiveCodeActions, type: "file", fileName: testPath }, testFormatSettings, emptyOptions); + const changes = languageService.organizeImports( + { skipDestructiveCodeActions, type: "file", fileName: testPath }, + testFormatSettings, + emptyOptions, + ); assert.equal(changes.length, 1); assert.equal(changes[0].fileName, testPath); @@ -974,21 +1061,35 @@ export * from "lib"; function makeLanguageService(...files: TestFSWithWatch.File[]) { const host = projectSystem.createServerHost(files); const projectService = projectSystem.createProjectService(host, { useSingleInferredProject: true }); - projectService.setCompilerOptionsForInferredProjects({ jsx: files.some(f => f.path.endsWith("x")) ? JsxEmit.React : JsxEmit.None }); + projectService.setCompilerOptionsForInferredProjects({ + jsx: files.some(f => f.path.endsWith("x")) ? JsxEmit.React : JsxEmit.None, + }); files.forEach(f => projectService.openClientFile(f.path)); return projectService.inferredProjects[0].getLanguageService(); } }); function parseImports(...importStrings: string[]): readonly ImportDeclaration[] { - const sourceFile = createSourceFile("a.ts", importStrings.join("\n"), ScriptTarget.ES2015, /*setParentNodes*/ true, ScriptKind.TS); + const sourceFile = createSourceFile( + "a.ts", + importStrings.join("\n"), + ScriptTarget.ES2015, + /*setParentNodes*/ true, + ScriptKind.TS, + ); const imports = filter(sourceFile.statements, isImportDeclaration); assert.equal(imports.length, importStrings.length); return imports; } function parseExports(...exportStrings: string[]): readonly ExportDeclaration[] { - const sourceFile = createSourceFile("a.ts", exportStrings.join("\n"), ScriptTarget.ES2015, /*setParentNodes*/ true, ScriptKind.TS); + const sourceFile = createSourceFile( + "a.ts", + exportStrings.join("\n"), + ScriptTarget.ES2015, + /*setParentNodes*/ true, + ScriptKind.TS, + ); const exports = filter(sourceFile.statements, isExportDeclaration); assert.equal(exports.length, exportStrings.length); return exports; diff --git a/src/testRunner/unittests/services/patternMatcher.ts b/src/testRunner/unittests/services/patternMatcher.ts index 9f3cbf4b6d7c6..d6c1ac24241c2 100644 --- a/src/testRunner/unittests/services/patternMatcher.ts +++ b/src/testRunner/unittests/services/patternMatcher.ts @@ -133,7 +133,10 @@ describe("unittests:: services:: PatternMatcher", () => { }); it("TwoUppercaseCharacters", () => { - assertSegmentMatch("SimpleUIElement", "SiUI", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); + assertSegmentMatch("SimpleUIElement", "SiUI", { + kind: ts.PatternMatchKind.camelCase, + isCaseSensitive: true, + }); }); it("PreferCaseSensitiveLowercasePattern", () => { @@ -177,7 +180,10 @@ describe("unittests:: services:: PatternMatcher", () => { }); it("AllLowerPattern1", () => { - assertSegmentMatch("FogBarChangedEventArgs", "changedeventargs", { kind: ts.PatternMatchKind.substring, isCaseSensitive: false }); + assertSegmentMatch("FogBarChangedEventArgs", "changedeventargs", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: false, + }); }); it("AllLowerPattern2", () => { @@ -195,55 +201,94 @@ describe("unittests:: services:: PatternMatcher", () => { describe("MultiWordPattern", () => { it("ExactWithLowercase", () => { - assertSegmentMatch("AddMetadataReference", "addmetadatareference", { kind: ts.PatternMatchKind.exact, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "addmetadatareference", { + kind: ts.PatternMatchKind.exact, + isCaseSensitive: false, + }); }); it("SingleLowercasedSearchWord1", () => { - assertSegmentMatch("AddMetadataReference", "add", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "add", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: false, + }); }); it("SingleLowercasedSearchWord2", () => { - assertSegmentMatch("AddMetadataReference", "metadata", { kind: ts.PatternMatchKind.substring, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "metadata", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: false, + }); }); it("SingleUppercaseSearchWord1", () => { - assertSegmentMatch("AddMetadataReference", "Add", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "Add", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("SingleUppercaseSearchWord2", () => { - assertSegmentMatch("AddMetadataReference", "Metadata", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "Metadata", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: true, + }); }); it("SingleUppercaseSearchLetter1", () => { - assertSegmentMatch("AddMetadataReference", "A", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "A", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("SingleUppercaseSearchLetter2", () => { - assertSegmentMatch("AddMetadataReference", "M", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "M", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: true, + }); }); it("TwoLowercaseWords0", () => { - assertSegmentMatch("AddMetadataReference", "add metadata", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "add metadata", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: false, + }); }); it("TwoLowercaseWords1", () => { - assertSegmentMatch("AddMetadataReference", "A M", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "A M", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("TwoLowercaseWords2", () => { - assertSegmentMatch("AddMetadataReference", "AM", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "AM", { + kind: ts.PatternMatchKind.camelCase, + isCaseSensitive: true, + }); }); it("TwoLowercaseWords3", () => { - assertSegmentMatch("AddMetadataReference", "ref Metadata", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "ref Metadata", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: true, + }); }); it("TwoLowercaseWords4", () => { - assertSegmentMatch("AddMetadataReference", "ref M", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "ref M", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: true, + }); }); it("MixedCamelCase", () => { - assertSegmentMatch("AddMetadataReference", "AMRe", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "AMRe", { + kind: ts.PatternMatchKind.camelCase, + isCaseSensitive: true, + }); }); it("BlankPattern", () => { @@ -255,15 +300,24 @@ describe("unittests:: services:: PatternMatcher", () => { }); it("EachWordSeparately1", () => { - assertSegmentMatch("AddMetadataReference", "add Meta", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "add Meta", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: false, + }); }); it("EachWordSeparately2", () => { - assertSegmentMatch("AddMetadataReference", "Add meta", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "Add meta", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("EachWordSeparately3", () => { - assertSegmentMatch("AddMetadataReference", "Add Meta", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "Add Meta", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("MixedCasing", () => { @@ -297,15 +351,24 @@ describe("unittests:: services:: PatternMatcher", () => { }); it("DottedPattern3", () => { - assertFullMatch("Foo.Bar.Baz", "Quux", "B.B.Q", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertFullMatch("Foo.Bar.Baz", "Quux", "B.B.Q", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("DottedPattern4", () => { - assertFullMatch("Foo.Bar.Baz", "Quux", "Baz.Quux", { kind: ts.PatternMatchKind.exact, isCaseSensitive: true }); + assertFullMatch("Foo.Bar.Baz", "Quux", "Baz.Quux", { + kind: ts.PatternMatchKind.exact, + isCaseSensitive: true, + }); }); it("DottedPattern5", () => { - assertFullMatch("Foo.Bar.Baz", "Quux", "F.B.B.Quux", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertFullMatch("Foo.Bar.Baz", "Quux", "F.B.B.Quux", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("DottedPattern6", () => { @@ -326,8 +389,16 @@ describe("unittests:: services:: PatternMatcher", () => { assert.equal(ts.createPatternMatcher(pattern), undefined); } - function assertFullMatch(dottedContainer: string, candidate: string, pattern: string, expected: ts.PatternMatch | undefined): void { - assert.deepEqual(ts.createPatternMatcher(pattern)!.getFullMatch(dottedContainer.split("."), candidate), expected); + function assertFullMatch( + dottedContainer: string, + candidate: string, + pattern: string, + expected: ts.PatternMatch | undefined, + ): void { + assert.deepEqual( + ts.createPatternMatcher(pattern)!.getFullMatch(dottedContainer.split("."), candidate), + expected, + ); } function spanListToSubstrings(identifier: string, spans: ts.TextSpan[]) { diff --git a/src/testRunner/unittests/services/preProcessFile.ts b/src/testRunner/unittests/services/preProcessFile.ts index bd4618a764dd2..8061398dd3a8a 100644 --- a/src/testRunner/unittests/services/preProcessFile.ts +++ b/src/testRunner/unittests/services/preProcessFile.ts @@ -1,13 +1,35 @@ describe("unittests:: services:: PreProcessFile:", () => { - function test(sourceText: string, readImportFile: boolean, detectJavaScriptImports: boolean, expectedPreProcess: ts.PreProcessedFileInfo): void { + function test( + sourceText: string, + readImportFile: boolean, + detectJavaScriptImports: boolean, + expectedPreProcess: ts.PreProcessedFileInfo, + ): void { const resultPreProcess = ts.preProcessFile(sourceText, readImportFile, detectJavaScriptImports); - assert.equal(resultPreProcess.isLibFile, expectedPreProcess.isLibFile, "Pre-processed file has different value for isLibFile. Expected: " + expectedPreProcess.isLibFile + ". Actual: " + resultPreProcess.isLibFile); + assert.equal( + resultPreProcess.isLibFile, + expectedPreProcess.isLibFile, + "Pre-processed file has different value for isLibFile. Expected: " + expectedPreProcess.isLibFile + + ". Actual: " + resultPreProcess.isLibFile, + ); checkFileReferenceList("Imported files", expectedPreProcess.importedFiles, resultPreProcess.importedFiles); - checkFileReferenceList("Referenced files", expectedPreProcess.referencedFiles, resultPreProcess.referencedFiles); - checkFileReferenceList("Type reference directives", expectedPreProcess.typeReferenceDirectives, resultPreProcess.typeReferenceDirectives); - checkFileReferenceList("Lib reference directives", expectedPreProcess.libReferenceDirectives, resultPreProcess.libReferenceDirectives); + checkFileReferenceList( + "Referenced files", + expectedPreProcess.referencedFiles, + resultPreProcess.referencedFiles, + ); + checkFileReferenceList( + "Type reference directives", + expectedPreProcess.typeReferenceDirectives, + resultPreProcess.typeReferenceDirectives, + ); + checkFileReferenceList( + "Lib reference directives", + expectedPreProcess.libReferenceDirectives, + resultPreProcess.libReferenceDirectives, + ); assert.deepEqual(resultPreProcess.ambientExternalModules, expectedPreProcess.ambientExternalModules); } @@ -16,30 +38,51 @@ describe("unittests:: services:: PreProcessFile:", () => { if (expected === actual) { return; } - assert.deepEqual(actual, expected, `Expected [${kind}] ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`); + assert.deepEqual( + actual, + expected, + `Expected [${kind}] ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`, + ); } describe("Test preProcessFiles,", () => { it("Correctly return referenced files from triple slash", () => { - test('///' + "\n" + '///' + "\n" + '///' + "\n" + '///', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { - referencedFiles: [{ fileName: "refFile1.ts", pos: 22, end: 33 }, { fileName: "refFile2.ts", pos: 59, end: 70 }, { fileName: "refFile3.ts", pos: 94, end: 105 }, { fileName: "..\\refFile4d.ts", pos: 131, end: 146 }], - importedFiles: [] as ts.FileReference[], - typeReferenceDirectives: [], - libReferenceDirectives: [], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + '///' + "\n" + '///' + "\n" + + '///' + "\n" + '///', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [ + { fileName: "refFile1.ts", pos: 22, end: 33 }, + { fileName: "refFile2.ts", pos: 59, end: 70 }, + { fileName: "refFile3.ts", pos: 94, end: 105 }, + { fileName: "..\\refFile4d.ts", pos: 131, end: 146 }, + ], + importedFiles: [] as ts.FileReference[], + typeReferenceDirectives: [], + libReferenceDirectives: [], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Do not return reference path because of invalid triple-slash syntax", () => { - test('///' + "\n" + '///' + "\n" + '///' + "\n" + '///', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { - referencedFiles: [] as ts.FileReference[], - importedFiles: [] as ts.FileReference[], - typeReferenceDirectives: [], - libReferenceDirectives: [], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + '///' + "\n" + '///' + "\n" + + '///' + "\n" + '///', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [] as ts.FileReference[], + importedFiles: [] as ts.FileReference[], + typeReferenceDirectives: [], + libReferenceDirectives: [], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Do not return reference path of non-imports", () => { @@ -65,69 +108,106 @@ describe("unittests:: services:: PreProcessFile:", () => { }); it("Correctly return imported files", () => { - test('import i1 = require("r1.ts"); import i2 =require("r2.ts"); import i3= require("r3.ts"); import i4=require("r4.ts"); import i5 = require ("r5.ts");', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { - referencedFiles: [] as ts.FileReference[], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [{ fileName: "r1.ts", pos: 20, end: 25 }, { fileName: "r2.ts", pos: 49, end: 54 }, { fileName: "r3.ts", pos: 78, end: 83 }, { fileName: "r4.ts", pos: 106, end: 111 }, { fileName: "r5.ts", pos: 138, end: 143 }], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + 'import i1 = require("r1.ts"); import i2 =require("r2.ts"); import i3= require("r3.ts"); import i4=require("r4.ts"); import i5 = require ("r5.ts");', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [] as ts.FileReference[], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "r1.ts", pos: 20, end: 25 }, + { fileName: "r2.ts", pos: 49, end: 54 }, + { fileName: "r3.ts", pos: 78, end: 83 }, + { fileName: "r4.ts", pos: 106, end: 111 }, + { fileName: "r5.ts", pos: 138, end: 143 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Do not return imported files if readImportFiles argument is false", () => { - test('import i1 = require("r1.ts"); import i2 =require("r2.ts"); import i3= require("r3.ts"); import i4=require("r4.ts"); import i5 = require ("r5.ts");', /*readImportFile*/ false, /*detectJavaScriptImports*/ false, { - referencedFiles: [] as ts.FileReference[], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [] as ts.FileReference[], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + 'import i1 = require("r1.ts"); import i2 =require("r2.ts"); import i3= require("r3.ts"); import i4=require("r4.ts"); import i5 = require ("r5.ts");', + /*readImportFile*/ false, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [] as ts.FileReference[], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [] as ts.FileReference[], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Do not return import path because of invalid import syntax", () => { - test('import i1 require("r1.ts"); import = require("r2.ts") import i3= require("r3.ts"); import i5', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { - referencedFiles: [] as ts.FileReference[], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [{ fileName: "r3.ts", pos: 73, end: 78 }], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + 'import i1 require("r1.ts"); import = require("r2.ts") import i3= require("r3.ts"); import i5', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [] as ts.FileReference[], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [{ fileName: "r3.ts", pos: 73, end: 78 }], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly return referenced files and import files", () => { - test('///' + "\n" + '///' + "\n" + 'import i1 = require("r1.ts"); import i2 =require("r2.ts");', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { - referencedFiles: [{ fileName: "refFile1.ts", pos: 20, end: 31 }, { fileName: "refFile2.ts", pos: 57, end: 68 }], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [{ fileName: "r1.ts", pos: 92, end: 97 }, { fileName: "r2.ts", pos: 121, end: 126 }], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + '///' + "\n" + '///' + "\n" + + 'import i1 = require("r1.ts"); import i2 =require("r2.ts");', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [{ fileName: "refFile1.ts", pos: 20, end: 31 }, { + fileName: "refFile2.ts", + pos: 57, + end: 68, + }], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [{ fileName: "r1.ts", pos: 92, end: 97 }, { fileName: "r2.ts", pos: 121, end: 126 }], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly return referenced files and import files even with some invalid syntax", () => { - test('///' + "\n" + '///' + "\n" + 'import i1 = require("r1.ts"); import = require("r2.ts"); import i2 = require("r3.ts");', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { - referencedFiles: [{ fileName: "refFile1.ts", pos: 20, end: 31 }], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [{ fileName: "r1.ts", pos: 91, end: 96 }, { fileName: "r3.ts", pos: 148, end: 153 }], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + '///' + "\n" + '///' + "\n" + + 'import i1 = require("r1.ts"); import = require("r2.ts"); import i2 = require("r3.ts");', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [{ fileName: "refFile1.ts", pos: 20, end: 31 }], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [{ fileName: "r1.ts", pos: 91, end: 96 }, { fileName: "r3.ts", pos: 148, end: 153 }], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly return ES6 imports", () => { test( - 'import * as ns from "m1";' + "\n" + - 'import def, * as ns from "m2";' + "\n" + - 'import def from "m3";' + "\n" + - 'import {a} from "m4";' + "\n" + - 'import {a as A} from "m5";' + "\n" + - 'import {a as A, b, c as C} from "m6";' + "\n" + - 'import def , {a, b, c as C} from "m7";' + "\n", + 'import * as ns from "m1";' + "\n" + + 'import def, * as ns from "m2";' + "\n" + + 'import def from "m3";' + "\n" + + 'import {a} from "m4";' + "\n" + + 'import {a as A} from "m5";' + "\n" + + 'import {a as A, b, c as C} from "m6";' + "\n" + + 'import def , {a, b, c as C} from "m7";' + "\n", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { @@ -152,20 +232,20 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly ignore commented imports following template expression", () => { /* eslint-disable no-template-curly-in-string */ test( - "/**" + "\n" + - " * Before" + "\n" + - " * ```" + "\n" + - ' * import * as a from "a";' + "\n" + - " * ```" + "\n" + - " */" + "\n" + - "type Foo = `${string}`;" + "\n" + - "/**" + "\n" + - " * After" + "\n" + - " * ```" + "\n" + - ' * import { B } from "b";' + "\n" + - ' * import * as c from "c";' + "\n" + - " * ```" + "\n" + - " */", + "/**" + "\n" + + " * Before" + "\n" + + " * ```" + "\n" + + ' * import * as a from "a";' + "\n" + + " * ```" + "\n" + + " */" + "\n" + + "type Foo = `${string}`;" + "\n" + + "/**" + "\n" + + " * After" + "\n" + + " * ```" + "\n" + + ' * import { B } from "b";' + "\n" + + ' * import * as c from "c";' + "\n" + + " * ```" + "\n" + + " */", /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { @@ -182,14 +262,19 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Ignores imports in template strings", () => { /* eslint-disable no-template-curly-in-string */ - test('a ? `&${a}` : `#${b}`;\n\n `import("${moduleSpecifier}").${id}`;', /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + 'a ? `&${a}` : `#${b}`;\n\n `import("${moduleSpecifier}").${id}`;', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); @@ -211,9 +296,9 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly returns dynamic imports from template expression", () => { /* eslint-disable no-template-curly-in-string */ test( - "`${(
Text `` ${} text {} " + "\n" + - '${import("a")} {import("b")} ' + "\n" + - '${/* A comment */} ${/* import("ignored") */}
)}`', + "`${(
Text `` ${} text {} " + "\n" + + '${import("a")} {import("b")} ' + "\n" + + '${/* A comment */} ${/* import("ignored") */}
)}`', /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { @@ -233,46 +318,56 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly returns dynamic imports from nested template expression", () => { /* eslint-disable no-template-curly-in-string */ - test('`${foo(`${bar(`${import("a")} ${import("b")}`, `${baz(`${import("c") ${import("d")}`)}`)}`)}`', /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "a", pos: 24, end: 25 }, - { fileName: "b", pos: 39, end: 40 }, - { fileName: "c", pos: 64, end: 65 }, - { fileName: "d", pos: 78, end: 79 }, - ], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + '`${foo(`${bar(`${import("a")} ${import("b")}`, `${baz(`${import("c") ${import("d")}`)}`)}`)}`', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 24, end: 25 }, + { fileName: "b", pos: 39, end: 40 }, + { fileName: "c", pos: 64, end: 65 }, + { fileName: "d", pos: 78, end: 79 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); it("Correctly returns dynamic imports from tagged template expression", () => { /* eslint-disable no-template-curly-in-string */ - test('foo`${ fn({ a: 100 }, import("a"), `${import("b")}`, import("c"), `${import("d")} foo`, import("e")) }`', /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "a", pos: 29, end: 30 }, - { fileName: "b", pos: 45, end: 46 }, - { fileName: "c", pos: 60, end: 61 }, - { fileName: "d", pos: 76, end: 77 }, - { fileName: "e", pos: 95, end: 96 }, - ], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + 'foo`${ fn({ a: 100 }, import("a"), `${import("b")}`, import("c"), `${import("d")} foo`, import("e")) }`', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 29, end: 30 }, + { fileName: "b", pos: 45, end: 46 }, + { fileName: "c", pos: 60, end: 61 }, + { fileName: "d", pos: 76, end: 77 }, + { fileName: "e", pos: 95, end: 96 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); it("Correctly returns dynamic imports from template expression and imports following it", () => { /* eslint-disable no-template-curly-in-string */ test( - 'const x = `hello ${await import("a").default}`;' + "\n\n" + - 'import { y } from "b";', + 'const x = `hello ${await import("a").default}`;' + "\n\n" + + 'import { y } from "b";', /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { @@ -293,10 +388,10 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly returns dynamic imports from template expressions and other imports", () => { /* eslint-disable no-template-curly-in-string */ test( - 'const x = `x ${await import("a").default}`;' + "\n\n" + - 'import { y } from "b";' + "\n" + - 'const y = `y ${import("c")}`;' + "\n\n" + - 'import { d } from "d";', + 'const x = `x ${await import("a").default}`;' + "\n\n" + + 'import { y } from "b";' + "\n" + + 'const y = `y ${import("c")}`;' + "\n\n" + + 'import { d } from "d";', /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { @@ -331,10 +426,10 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly return ES6 exports", () => { test( - 'export * from "m1";' + "\n" + - 'export {a} from "m2";' + "\n" + - 'export {a as A} from "m3";' + "\n" + - 'export {a as A, b, c as C} from "m4";' + "\n", + 'export * from "m1";' + "\n" + + 'export {a} from "m2";' + "\n" + + 'export {a as A} from "m3";' + "\n" + + 'export {a as A, b, c as C} from "m4";' + "\n", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { @@ -355,18 +450,18 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly handles import types", () => { test( - 'import type * as ns from "m1";' + "\n" + - 'import type def, * as ns from "m2";' + "\n" + - 'import type def from "m3";' + "\n" + - 'import type {a} from "m4";' + "\n" + - 'import type {a as A} from "m5";' + "\n" + - 'import type {a as A, b, c as C} from "m6";' + "\n" + - 'import type def , {a, b, c as C} from "m7";' + "\n" + - 'import type from "m8";' + "\n" + - 'import type T = require("m9");' + "\n" + - 'import type = require("m10");' + "\n" + - 'export import type T = require("m11");' + "\n" + - 'export import type = require("m12");' + "\n", + 'import type * as ns from "m1";' + "\n" + + 'import type def, * as ns from "m2";' + "\n" + + 'import type def from "m3";' + "\n" + + 'import type {a} from "m4";' + "\n" + + 'import type {a as A} from "m5";' + "\n" + + 'import type {a as A, b, c as C} from "m6";' + "\n" + + 'import type def , {a, b, c as C} from "m7";' + "\n" + + 'import type from "m8";' + "\n" + + 'import type T = require("m9");' + "\n" + + 'import type = require("m10");' + "\n" + + 'export import type T = require("m11");' + "\n" + + 'export import type = require("m12");' + "\n", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { @@ -395,10 +490,10 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly handles export types", () => { test( - 'export type * from "m1";' + "\n" + - 'export type {a} from "m2";' + "\n" + - 'export type {a as A} from "m3";' + "\n" + - 'export type {a as A, b, c as C} from "m4";' + "\n", + 'export type * from "m1";' + "\n" + + 'export type {a} from "m2";' + "\n" + + 'export type {a as A} from "m3";' + "\n" + + 'export type {a as A, b, c as C} from "m4";' + "\n", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { @@ -419,9 +514,9 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly handles import type node", () => { test( - 'const x: import("m1") = { x: 0, y: 0 };' + "\n" + - 'let y: import("m2").Bar.I = { a: "", b: 0 };' + "\n" + - 'let shim: typeof import("m3") = { Bar: Bar2 };' + "\n", + 'const x: import("m1") = { x: 0, y: 0 };' + "\n" + + 'let y: import("m2").Bar.I = { a: "", b: 0 };' + "\n" + + 'let shim: typeof import("m3") = { Bar: Bar2 };' + "\n", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { @@ -787,10 +882,10 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly handles dynamic imports with template literals", () => { test( - "const m1 = import('mod1');" + "\n" + - "const m2 = import(`mod2`);" + "\n" + - "Promise.all([import('mod3'), import(`mod4`)]);" + "\n" + - "import(/* webpackChunkName: 'module5' */ `mod5`);" + "\n", + "const m1 = import('mod1');" + "\n" + + "const m2 = import(`mod2`);" + "\n" + + "Promise.all([import('mod3'), import(`mod4`)]);" + "\n" + + "import(/* webpackChunkName: 'module5' */ `mod5`);" + "\n", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { @@ -812,9 +907,9 @@ describe("unittests:: services:: PreProcessFile:", () => { it("Correctly handles require calls with template literals in JS files", () => { test( - "const m1 = require(`mod1`);" + "\n" + - "f(require(`mod2`));" + "\n" + - "const a = { x: require(`mod3`) };" + "\n", + "const m1 = require(`mod1`);" + "\n" + + "f(require(`mod2`));" + "\n" + + "const a = { x: require(`mod3`) };" + "\n", /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { @@ -833,17 +928,22 @@ describe("unittests:: services:: PreProcessFile:", () => { }); it("Correctly handles dependency lists in define(modName, [deplist]) calls with template literals in JS files", () => { - test("define(`mod`, [`mod1`, `mod2`], (m1, m2) => {});", /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "mod1", pos: 15, end: 19 }, - { fileName: "mod2", pos: 23, end: 27 }, - ], - ambientExternalModules: undefined, - isLibFile: false, - }); + test( + "define(`mod`, [`mod1`, `mod2`], (m1, m2) => {});", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "mod1", pos: 15, end: 19 }, + { fileName: "mod2", pos: 23, end: 27 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); }); }); diff --git a/src/testRunner/unittests/services/textChanges.ts b/src/testRunner/unittests/services/textChanges.ts index 2ef3b41b7b74b..6f0badf6a0468 100644 --- a/src/testRunner/unittests/services/textChanges.ts +++ b/src/testRunner/unittests/services/textChanges.ts @@ -19,7 +19,11 @@ namespace ts { const newLineCharacter = getNewLineCharacter(printerOptions); function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean): formatting.FormatContext { - return formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...testFormatSettings, placeOpenBraceOnNewLineForFunctions: true } : testFormatSettings, notImplementedHost); + return formatting.getFormatContext( + placeOpenBraceOnNewLineForFunctions + ? { ...testFormatSettings, placeOpenBraceOnNewLineForFunctions: true } : testFormatSettings, + notImplementedHost, + ); } // validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed. @@ -44,7 +48,13 @@ namespace ts { } } - function runSingleFileTest(caption: string, placeOpenBraceOnNewLineForFunctions: boolean, text: string, validateNodes: boolean, testBlock: (sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker) => void) { + function runSingleFileTest( + caption: string, + placeOpenBraceOnNewLineForFunctions: boolean, + text: string, + validateNodes: boolean, + testBlock: (sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker) => void, + ) { it(caption, () => { const sourceFile = createSourceFile("source.ts", text, ScriptTarget.ES2015, /*setParentNodes*/ true); const rulesProvider = getRuleProvider(placeOpenBraceOnNewLineForFunctions); @@ -54,7 +64,10 @@ namespace ts { assert.equal(changes.length, 1); assert.equal(changes[0].fileName, sourceFile.fileName); const modified = textChanges.applyChanges(sourceFile.text, changes[0].textChanges); - Harness.Baseline.runBaseline(`textChanges/${caption}.js`, `===ORIGINAL===${newLineCharacter}${text}${newLineCharacter}===MODIFIED===${newLineCharacter}${modified}`); + Harness.Baseline.runBaseline( + `textChanges/${caption}.js`, + `===ORIGINAL===${newLineCharacter}${text}${newLineCharacter}===MODIFIED===${newLineCharacter}${modified}`, + ); }); } @@ -80,30 +93,38 @@ namespace M } } }`; - runSingleFileTest("extractMethodLike", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - const statements = (findChild("foo", sourceFile) as FunctionDeclaration).body!.statements.slice(1); - const newFunction = factory.createFunctionDeclaration( - /*modifiers*/ undefined, - /*asteriskToken*/ undefined, - /*name*/ "bar", - /*typeParameters*/ undefined, - /*parameters*/ emptyArray, - /*type*/ factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), - /*body */ factory.createBlock(statements), - ); + runSingleFileTest( + "extractMethodLike", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + const statements = (findChild("foo", sourceFile) as FunctionDeclaration).body!.statements.slice(1); + const newFunction = factory.createFunctionDeclaration( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + /*name*/ "bar", + /*typeParameters*/ undefined, + /*parameters*/ emptyArray, + /*type*/ factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + /*body */ factory.createBlock(statements), + ); - changeTracker.insertNodeBefore(sourceFile, /*before*/ findChild("M2", sourceFile), newFunction); + changeTracker.insertNodeBefore(sourceFile, /*before*/ findChild("M2", sourceFile), newFunction); - // replace statements with return statement - const newStatement = factory.createReturnStatement( - factory.createCallExpression( - /*expression*/ newFunction.name!, - /*typeArguments*/ undefined, - /*argumentsArray*/ emptyArray, - ), - ); - changeTracker.replaceNodeRange(sourceFile, statements[0], last(statements), newStatement, { suffix: newLineCharacter }); - }); + // replace statements with return statement + const newStatement = factory.createReturnStatement( + factory.createCallExpression( + /*expression*/ newFunction.name!, + /*typeArguments*/ undefined, + /*argumentsArray*/ emptyArray, + ), + ); + changeTracker.replaceNodeRange(sourceFile, statements[0], last(statements), newStatement, { + suffix: newLineCharacter, + }); + }, + ); } { const text = ` @@ -115,9 +136,18 @@ function bar() { return 2; } `; - runSingleFileTest("deleteRange1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteRange(sourceFile, { pos: text.indexOf("function foo"), end: text.indexOf("function bar") }); - }); + runSingleFileTest( + "deleteRange1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteRange(sourceFile, { + pos: text.indexOf("function foo"), + end: text.indexOf("function bar"), + }); + }, + ); } function findVariableStatementContaining(name: string, sourceFile: SourceFile): VariableStatement { return cast(findVariableDeclarationContaining(name, sourceFile).parent.parent, isVariableStatement); @@ -135,21 +165,58 @@ var x = 1; // some comment - 1 var y = 2; // comment 3 var z = 3; // comment 4 `; - runSingleFileTest("deleteNode1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile)); - }); - runSingleFileTest("deleteNode2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNode3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNode4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNode5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("x", sourceFile)); - }); + runSingleFileTest( + "deleteNode1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNode2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + }); + }, + ); + runSingleFileTest( + "deleteNode3", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { + trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, + }); + }, + ); + runSingleFileTest( + "deleteNode4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, + }); + }, + ); + runSingleFileTest( + "deleteNode5", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("x", sourceFile)); + }, + ); } { const text = ` @@ -161,21 +228,74 @@ var z = 3; // comment 5 // comment 6 var a = 4; // comment 7 `; - runSingleFileTest("deleteNodeRange1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile)); - }); - runSingleFileTest("deleteNodeRange2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNodeRange3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNodeRange4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); - }); + runSingleFileTest( + "deleteNodeRange1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + ); + }, + ); + runSingleFileTest( + "deleteNodeRange2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude }, + ); + }, + ); + runSingleFileTest( + "deleteNodeRange3", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }, + ); + }, + ); + runSingleFileTest( + "deleteNodeRange4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, + }, + ); + }, + ); } function createTestVariableDeclaration(name: string) { - return factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createObjectLiteralExpression([factory.createPropertyAssignment("p1", factory.createNumericLiteral(1))], /*multiline*/ true)); + return factory.createVariableDeclaration( + name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createObjectLiteralExpression([ + factory.createPropertyAssignment("p1", factory.createNumericLiteral(1)), + ], /*multiline*/ true), + ); } function createTestClass() { return factory.createClassDeclaration( @@ -188,7 +308,10 @@ var a = 4; // comment 7 factory.createHeritageClause( SyntaxKind.ImplementsKeyword, [ - factory.createExpressionWithTypeArguments(factory.createIdentifier("interface1"), /*typeArguments*/ undefined), + factory.createExpressionWithTypeArguments( + factory.createIdentifier("interface1"), + /*typeArguments*/ undefined, + ), ], ), ], @@ -212,17 +335,48 @@ var y = 2; // comment 4 var z = 3; // comment 5 // comment 6 var a = 4; // comment 7`; - runSingleFileTest("replaceRange", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceRange(sourceFile, { pos: text.indexOf("var y"), end: text.indexOf("var a") }, createTestClass(), { suffix: newLineCharacter }); - }); - runSingleFileTest("replaceRangeWithForcedIndentation", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceRange(sourceFile, { pos: text.indexOf("var y"), end: text.indexOf("var a") }, createTestClass(), { suffix: newLineCharacter, indentation: 8, delta: 0 }); - }); + runSingleFileTest( + "replaceRange", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceRange( + sourceFile, + { pos: text.indexOf("var y"), end: text.indexOf("var a") }, + createTestClass(), + { suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceRangeWithForcedIndentation", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceRange( + sourceFile, + { pos: text.indexOf("var y"), end: text.indexOf("var a") }, + createTestClass(), + { suffix: newLineCharacter, indentation: 8, delta: 0 }, + ); + }, + ); - runSingleFileTest("replaceRangeNoLineBreakBefore", /*placeOpenBraceOnNewLineForFunctions*/ true, `const x = 1, y = "2";`, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = createTestVariableDeclaration("z1"); - changeTracker.replaceRange(sourceFile, { pos: sourceFile.text.indexOf("y"), end: sourceFile.text.indexOf(";") }, newNode); - }); + runSingleFileTest( + "replaceRangeNoLineBreakBefore", + /*placeOpenBraceOnNewLineForFunctions*/ true, + `const x = 1, y = "2";`, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = createTestVariableDeclaration("z1"); + changeTracker.replaceRange(sourceFile, { + pos: sourceFile.text.indexOf("y"), + end: sourceFile.text.indexOf(";"), + }, newNode); + }, + ); } { const text = ` @@ -230,10 +384,16 @@ namespace A { const x = 1, y = "2"; } `; - runSingleFileTest("replaceNode1NoLineBreakBefore", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = createTestVariableDeclaration("z1"); - changeTracker.replaceNode(sourceFile, findChild("y", sourceFile), newNode); - }); + runSingleFileTest( + "replaceNode1NoLineBreakBefore", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = createTestVariableDeclaration("z1"); + changeTracker.replaceNode(sourceFile, findChild("y", sourceFile), newNode); + }, + ); } { const text = ` @@ -244,21 +404,86 @@ var y = 2; // comment 4 var z = 3; // comment 5 // comment 6 var a = 4; // comment 7`; - runSingleFileTest("replaceNode1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { suffix: newLineCharacter }); - }); - runSingleFileTest("replaceNode2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, suffix: newLineCharacter, prefix: newLineCharacter }); - }); - runSingleFileTest("replaceNode3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }); - }); - runSingleFileTest("replaceNode4", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); - }); - runSingleFileTest("replaceNode5", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("x", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); - }); + runSingleFileTest( + "replaceNode1", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + { suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceNode2", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + suffix: newLineCharacter, + prefix: newLineCharacter, + }, + ); + }, + ); + runSingleFileTest( + "replaceNode3", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceNode4", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, + }, + ); + }, + ); + runSingleFileTest( + "replaceNode5", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("x", sourceFile), + createTestClass(), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, + }, + ); + }, + ); } { const text = ` @@ -269,18 +494,73 @@ var y = 2; // comment 4 var z = 3; // comment 5 // comment 6 var a = 4; // comment 7`; - runSingleFileTest("replaceNodeRange1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { suffix: newLineCharacter }); - }); - runSingleFileTest("replaceNodeRange2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, suffix: newLineCharacter, prefix: newLineCharacter }); - }); - runSingleFileTest("replaceNodeRange3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }); - }); - runSingleFileTest("replaceNodeRange4", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); - }); + runSingleFileTest( + "replaceNodeRange1", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + createTestClass(), + { suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceNodeRange2", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + createTestClass(), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + suffix: newLineCharacter, + prefix: newLineCharacter, + }, + ); + }, + ); + runSingleFileTest( + "replaceNodeRange3", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + createTestClass(), + { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceNodeRange4", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + createTestClass(), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, + }, + ); + }, + ); } { const text = ` @@ -291,12 +571,32 @@ var y; // comment 4 var z = 3; // comment 5 // comment 6 var a = 4; // comment 7`; - runSingleFileTest("insertNodeBefore3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeBefore(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass()); - }); - runSingleFileTest("insertNodeAfterVariableDeclaration", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findVariableDeclarationContaining("y", sourceFile), createTestVariableDeclaration("z1")); - }); + runSingleFileTest( + "insertNodeBefore3", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeBefore( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + ); + }, + ); + runSingleFileTest( + "insertNodeAfterVariableDeclaration", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter( + sourceFile, + findVariableDeclarationContaining("y", sourceFile), + createTestVariableDeclaration("z1"), + ); + }, + ); } { const text = ` @@ -309,23 +609,58 @@ namespace M { // comment 6 var a = 4; // comment 7 }`; - runSingleFileTest("insertNodeBefore1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeBefore(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass()); - }); - runSingleFileTest("insertNodeBefore2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeBefore(sourceFile, findChild("M", sourceFile), createTestClass()); - }); - runSingleFileTest("insertNodeAfter1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass()); - }); - runSingleFileTest("insertNodeAfter2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findChild("M", sourceFile), createTestClass()); - }); + runSingleFileTest( + "insertNodeBefore1", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeBefore( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + ); + }, + ); + runSingleFileTest( + "insertNodeBefore2", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeBefore(sourceFile, findChild("M", sourceFile), createTestClass()); + }, + ); + runSingleFileTest( + "insertNodeAfter1", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + ); + }, + ); + runSingleFileTest( + "insertNodeAfter2", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter(sourceFile, findChild("M", sourceFile), createTestClass()); + }, + ); } function findConstructor(sourceFile: SourceFile): ConstructorDeclaration { const classDecl = sourceFile.statements[0] as ClassDeclaration; - return find(classDecl.members, (m): m is ConstructorDeclaration => isConstructorDeclaration(m) && !!m.body)!; + return find( + classDecl.members, + (m): m is ConstructorDeclaration => isConstructorDeclaration(m) && !!m.body, + )!; } function createTestSuperCall() { const superCall = factory.createCallExpression( @@ -343,9 +678,19 @@ class A { } } `; - runSingleFileTest("insertNodeAtConstructorStart", /*placeOpenBraceOnNewLineForFunctions*/ false, text1, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAtConstructorStart(sourceFile, findConstructor(sourceFile), createTestSuperCall()); - }); + runSingleFileTest( + "insertNodeAtConstructorStart", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text1, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAtConstructorStart( + sourceFile, + findConstructor(sourceFile), + createTestSuperCall(), + ); + }, + ); const text2 = ` class A { constructor() { @@ -353,9 +698,19 @@ class A { } } `; - runSingleFileTest("insertNodeAfter4", /*placeOpenBraceOnNewLineForFunctions*/ false, text2, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), createTestSuperCall()); - }); + runSingleFileTest( + "insertNodeAfter4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text2, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter( + sourceFile, + findVariableStatementContaining("x", sourceFile), + createTestSuperCall(), + ); + }, + ); const text3 = ` class A { constructor() { @@ -363,33 +718,79 @@ class A { } } `; - runSingleFileTest("insertNodeAtConstructorStart-block with newline", /*placeOpenBraceOnNewLineForFunctions*/ false, text3, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAtConstructorStart(sourceFile, findConstructor(sourceFile), createTestSuperCall()); - }); + runSingleFileTest( + "insertNodeAtConstructorStart-block with newline", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text3, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAtConstructorStart( + sourceFile, + findConstructor(sourceFile), + createTestSuperCall(), + ); + }, + ); } { const text = `var a = 1, b = 2, c = 3;`; - runSingleFileTest("deleteNodeInList1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList3", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = `var a = 1,b = 2,c = 3;`; - runSingleFileTest("deleteNodeInList1_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList2_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList3_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList1_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList2_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList3_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` @@ -398,15 +799,33 @@ namespace M { b = 2, c = 3; }`; - runSingleFileTest("deleteNodeInList4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList6", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList5", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList6", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` @@ -417,45 +836,99 @@ namespace M { // comment 4 c = 3; // comment 5 }`; - runSingleFileTest("deleteNodeInList4_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList5_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList6_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList4_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList5_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList6_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` function foo(a: number, b: string, c = true) { return 1; }`; - runSingleFileTest("deleteNodeInList7", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList8", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList9", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList7", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList8", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList9", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` function foo(a: number,b: string,c = true) { return 1; }`; - runSingleFileTest("deleteNodeInList10", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList11", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList12", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList10", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList11", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList12", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` @@ -465,102 +938,303 @@ function foo( c = true) { return 1; }`; - runSingleFileTest("deleteNodeInList13", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList14", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList15", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList13", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList14", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList15", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` const x = 1, y = 2;`; - runSingleFileTest("insertNodeInListAfter1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1))); - }); - runSingleFileTest("insertNodeInListAfter2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(1), + ), + ); + }, + ); + runSingleFileTest( + "insertNodeInListAfter2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("y", sourceFile), + factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` const /*x*/ x = 1, /*y*/ y = 2;`; - runSingleFileTest("insertNodeInListAfter3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1))); - }); - runSingleFileTest("insertNodeInListAfter4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter3", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(1), + ), + ); + }, + ); + runSingleFileTest( + "insertNodeInListAfter4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("y", sourceFile), + factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` const x = 1;`; - runSingleFileTest("insertNodeInListAfter5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter5", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` const x = 1, y = 2;`; - runSingleFileTest("insertNodeInListAfter6", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1))); - }); - runSingleFileTest("insertNodeInListAfter7", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter6", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(1), + ), + ); + }, + ); + runSingleFileTest( + "insertNodeInListAfter7", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("y", sourceFile), + factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` const /*x*/ x = 1, /*y*/ y = 2;`; - runSingleFileTest("insertNodeInListAfter8", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1))); - }); - runSingleFileTest("insertNodeInListAfter9", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter8", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(1), + ), + ); + }, + ); + runSingleFileTest( + "insertNodeInListAfter9", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("y", sourceFile), + factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` import { x } from "bar"`; - runSingleFileTest("insertNodeInListAfter10", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier("b"), factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter10", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier("b"), + factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` import { x // this is x } from "bar"`; - runSingleFileTest("insertNodeInListAfter11", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier("b"), factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter11", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier("b"), + factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` import { x } from "bar"`; - runSingleFileTest("insertNodeInListAfter12", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - // eslint-disable-next-line local/boolean-trivia - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter12", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + // eslint-disable-next-line local/boolean-trivia + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a")), + ); + }, + ); } { const text = ` import { x // this is x } from "bar"`; - runSingleFileTest("insertNodeInListAfter13", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - // eslint-disable-next-line local/boolean-trivia - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter13", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + // eslint-disable-next-line local/boolean-trivia + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a")), + ); + }, + ); } { const text = ` @@ -568,9 +1242,23 @@ import { x0, x } from "bar"`; - runSingleFileTest("insertNodeInListAfter14", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier("b"), factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter14", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier("b"), + factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` @@ -578,9 +1266,23 @@ import { x0, x // this is x } from "bar"`; - runSingleFileTest("insertNodeInListAfter15", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier("b"), factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter15", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier("b"), + factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` @@ -588,10 +1290,20 @@ import { x0, x } from "bar"`; - runSingleFileTest("insertNodeInListAfter16", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - // eslint-disable-next-line local/boolean-trivia - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter16", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + // eslint-disable-next-line local/boolean-trivia + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a")), + ); + }, + ); } { const text = ` @@ -599,29 +1311,63 @@ import { x0, x // this is x } from "bar"`; - runSingleFileTest("insertNodeInListAfter17", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - // eslint-disable-next-line local/boolean-trivia - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter17", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + // eslint-disable-next-line local/boolean-trivia + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a")), + ); + }, + ); } { const text = ` import { x0, x } from "bar"`; - runSingleFileTest("insertNodeInListAfter18", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - // eslint-disable-next-line local/boolean-trivia - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter18", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + // eslint-disable-next-line local/boolean-trivia + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier("a")), + ); + }, + ); } { const runTest = (name: string, text: string) => - runSingleFileTest(name, /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - for (const specifier of ["x3", "x4", "x5"]) { - // eslint-disable-next-line local/boolean-trivia - changeTracker.insertNodeInListAfter(sourceFile, findChild("x2", sourceFile), factory.createImportSpecifier(/*isTypeOnly*/ false, undefined, factory.createIdentifier(specifier))); - } - }); + runSingleFileTest( + name, + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + for (const specifier of ["x3", "x4", "x5"]) { + // eslint-disable-next-line local/boolean-trivia + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x2", sourceFile), + factory.createImportSpecifier( + /*isTypeOnly*/ false, + undefined, + factory.createIdentifier(specifier), + ), + ); + } + }, + ); const crlfText = 'import {\r\nx1,\r\nx2\r\n} from "bar";'; runTest("insertNodeInListAfter19", crlfText); @@ -634,19 +1380,25 @@ import { class A { x; }`; - runSingleFileTest("insertNodeAfterMultipleNodes", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNodes = []; - for (let i = 0; i < 11 /*error doesn't occur with fewer nodes*/; ++i) { - newNodes.push( - // eslint-disable-next-line local/boolean-trivia - factory.createPropertyDeclaration(undefined, i + "", undefined, undefined, undefined), - ); - } - const insertAfter = findChild("x", sourceFile); - for (const newNode of newNodes) { - changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode); - } - }); + runSingleFileTest( + "insertNodeAfterMultipleNodes", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNodes = []; + for (let i = 0; i < 11 /*error doesn't occur with fewer nodes*/; ++i) { + newNodes.push( + // eslint-disable-next-line local/boolean-trivia + factory.createPropertyDeclaration(undefined, i + "", undefined, undefined, undefined), + ); + } + const insertAfter = findChild("x", sourceFile); + for (const newNode of newNodes) { + changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode); + } + }, + ); } { const text = ` @@ -654,10 +1406,26 @@ class A { x } `; - runSingleFileTest("insertNodeAfterInClass1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - // eslint-disable-next-line local/boolean-trivia - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), factory.createPropertyDeclaration(undefined, "a", undefined, factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword), undefined)); - }); + runSingleFileTest( + "insertNodeAfterInClass1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + // eslint-disable-next-line local/boolean-trivia + changeTracker.insertNodeAfter( + sourceFile, + findChild("x", sourceFile), + factory.createPropertyDeclaration( + undefined, + "a", + undefined, + factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword), + undefined, + ), + ); + }, + ); } { const text = ` @@ -665,10 +1433,26 @@ class A { x; } `; - runSingleFileTest("insertNodeAfterInClass2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - // eslint-disable-next-line local/boolean-trivia - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), factory.createPropertyDeclaration(undefined, "a", undefined, factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword), undefined)); - }); + runSingleFileTest( + "insertNodeAfterInClass2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + // eslint-disable-next-line local/boolean-trivia + changeTracker.insertNodeAfter( + sourceFile, + findChild("x", sourceFile), + factory.createPropertyDeclaration( + undefined, + "a", + undefined, + factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword), + undefined, + ), + ); + }, + ); } { const text = ` @@ -677,9 +1461,15 @@ class A { y = 1; } `; - runSingleFileTest("deleteNodeAfterInClass1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findChild("x", sourceFile)); - }); + runSingleFileTest( + "deleteNodeAfterInClass1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findChild("x", sourceFile)); + }, + ); } { const text = ` @@ -688,9 +1478,15 @@ class A { y = 1; } `; - runSingleFileTest("deleteNodeAfterInClass2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findChild("x", sourceFile)); - }); + runSingleFileTest( + "deleteNodeAfterInClass2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findChild("x", sourceFile)); + }, + ); } { const text = ` @@ -698,16 +1494,22 @@ class A { x = foo } `; - runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = factory.createPropertyDeclaration( - /*modifiers*/ undefined, - factory.createComputedPropertyName(factory.createNumericLiteral(1)), - /*questionToken*/ undefined, - factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), - /*initializer*/ undefined, - ); - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInClassAfterNodeWithoutSeparator1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = factory.createPropertyDeclaration( + /*modifiers*/ undefined, + factory.createComputedPropertyName(factory.createNumericLiteral(1)), + /*questionToken*/ undefined, + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + /*initializer*/ undefined, + ); + changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); + }, + ); } { const text = ` @@ -716,16 +1518,22 @@ class A { } } `; - runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = factory.createPropertyDeclaration( - /*modifiers*/ undefined, - factory.createComputedPropertyName(factory.createNumericLiteral(1)), - /*questionToken*/ undefined, - factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), - /*initializer*/ undefined, - ); - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInClassAfterNodeWithoutSeparator2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = factory.createPropertyDeclaration( + /*modifiers*/ undefined, + factory.createComputedPropertyName(factory.createNumericLiteral(1)), + /*questionToken*/ undefined, + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + /*initializer*/ undefined, + ); + changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); + }, + ); } { const text = ` @@ -733,16 +1541,22 @@ interface A { x } `; - runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = factory.createPropertyDeclaration( - /*modifiers*/ undefined, - factory.createComputedPropertyName(factory.createNumericLiteral(1)), - /*questionToken*/ undefined, - factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), - /*initializer*/ undefined, - ); - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInInterfaceAfterNodeWithoutSeparator1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = factory.createPropertyDeclaration( + /*modifiers*/ undefined, + factory.createComputedPropertyName(factory.createNumericLiteral(1)), + /*questionToken*/ undefined, + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + /*initializer*/ undefined, + ); + changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); + }, + ); } { const text = ` @@ -750,25 +1564,43 @@ interface A { x() } `; - runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = factory.createPropertyDeclaration( - /*modifiers*/ undefined, - factory.createComputedPropertyName(factory.createNumericLiteral(1)), - /*questionToken*/ undefined, - factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), - /*initializer*/ undefined, - ); - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInInterfaceAfterNodeWithoutSeparator2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = factory.createPropertyDeclaration( + /*modifiers*/ undefined, + factory.createComputedPropertyName(factory.createNumericLiteral(1)), + /*questionToken*/ undefined, + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + /*initializer*/ undefined, + ); + changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); + }, + ); } { const text = ` let x = foo `; - runSingleFileTest("insertNodeInStatementListAfterNodeWithoutSeparator1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = factory.createExpressionStatement(factory.createParenthesizedExpression(factory.createNumericLiteral(1))); - changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInStatementListAfterNodeWithoutSeparator1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = factory.createExpressionStatement( + factory.createParenthesizedExpression(factory.createNumericLiteral(1)), + ); + changeTracker.insertNodeAfter( + sourceFile, + findVariableStatementContaining("x", sourceFile), + newNode, + ); + }, + ); } }); } diff --git a/src/testRunner/unittests/services/transpile.ts b/src/testRunner/unittests/services/transpile.ts index c4518544060c2..d5247483fb056 100644 --- a/src/testRunner/unittests/services/transpile.ts +++ b/src/testRunner/unittests/services/transpile.ts @@ -36,7 +36,8 @@ namespace ts { transpileOptions.reportDiagnostics = true; - const justName = "transpile/" + name.replace(/[^a-z0-9\-. ]/ig, "") + (transpileOptions.compilerOptions.jsx ? Extension.Tsx : Extension.Ts); + const justName = "transpile/" + name.replace(/[^a-z0-9\-. ]/ig, "") + + (transpileOptions.compilerOptions.jsx ? Extension.Tsx : Extension.Ts); const toBeCompiled = [{ unitName, content: input, @@ -48,7 +49,13 @@ namespace ts { if (canUseOldTranspile) { oldTranspileDiagnostics = []; - oldTranspileResult = transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, oldTranspileDiagnostics, transpileOptions.moduleName); + oldTranspileResult = transpile( + input, + transpileOptions.compilerOptions, + transpileOptions.fileName, + oldTranspileDiagnostics, + transpileOptions.moduleName, + ); } }); @@ -60,12 +67,20 @@ namespace ts { /* eslint-disable no-null/no-null */ it("Correct errors for " + justName, () => { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".errors.txt"), transpileResult.diagnostics!.length === 0 ? null : Harness.Compiler.getErrorBaseline(toBeCompiled, transpileResult.diagnostics!)); + Harness.Baseline.runBaseline( + justName.replace(/\.tsx?$/, ".errors.txt"), + transpileResult.diagnostics!.length === 0 ? null + : Harness.Compiler.getErrorBaseline(toBeCompiled, transpileResult.diagnostics!), + ); }); if (canUseOldTranspile) { it("Correct errors (old transpile) for " + justName, () => { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.errors.txt"), oldTranspileDiagnostics.length === 0 ? null : Harness.Compiler.getErrorBaseline(toBeCompiled, oldTranspileDiagnostics)); + Harness.Baseline.runBaseline( + justName.replace(/\.tsx?$/, ".oldTranspile.errors.txt"), + oldTranspileDiagnostics.length === 0 ? null + : Harness.Compiler.getErrorBaseline(toBeCompiled, oldTranspileDiagnostics), + ); }); } /* eslint-enable no-null/no-null */ @@ -76,7 +91,10 @@ namespace ts { if (canUseOldTranspile) { it("Correct output (old transpile) for " + justName, () => { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.js"), oldTranspileResult); + Harness.Baseline.runBaseline( + justName.replace(/\.tsx?$/, ".oldTranspile.js"), + oldTranspileResult, + ); }); } }); @@ -116,7 +134,10 @@ var x = 0;`, }); transpilesCorrectly("Sets module name", "var x = 1;", { - options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, moduleName: "NamedModule" }, + options: { + compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, + moduleName: "NamedModule", + }, }); transpilesCorrectly("No extra errors for file without extension", `"use strict";\r\nvar x = 0;`, { @@ -125,49 +146,58 @@ var x = 0;`, transpilesCorrectly( "Rename dependencies - System", - `import {foo} from "SomeName";\n` + - `declare function use(a: any);\n` + - `use(foo);`, + `import {foo} from "SomeName";\n` + + `declare function use(a: any);\n` + + `use(foo);`, { - options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } }, + options: { + compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, + renamedDependencies: { SomeName: "SomeOtherName" }, + }, }, ); transpilesCorrectly( "Rename dependencies - AMD", - `import {foo} from "SomeName";\n` + - `declare function use(a: any);\n` + - `use(foo);`, + `import {foo} from "SomeName";\n` + + `declare function use(a: any);\n` + + `use(foo);`, { - options: { compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } }, + options: { + compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, + renamedDependencies: { SomeName: "SomeOtherName" }, + }, }, ); transpilesCorrectly( "Rename dependencies - UMD", - `import {foo} from "SomeName";\n` + - `declare function use(a: any);\n` + - `use(foo);`, + `import {foo} from "SomeName";\n` + + `declare function use(a: any);\n` + + `use(foo);`, { - options: { compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } }, + options: { + compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, + renamedDependencies: { SomeName: "SomeOtherName" }, + }, }, ); transpilesCorrectly( "Transpile with emit decorators and emit metadata", - `import {db} from './db';\n` + - `function someDecorator(target) {\n` + - ` return target;\n` + - `} \n` + - `@someDecorator\n` + - `class MyClass {\n` + - ` db: db;\n` + - ` constructor(db: db) {\n` + - ` this.db = db;\n` + - ` this.db.doSomething(); \n` + - ` }\n` + - `}\n` + - `export {MyClass}; \n`, + `import {db} from './db';\n` + + `function someDecorator(target) {\n` + + ` return target;\n` + + `} \n` + + `@someDecorator\n` + + `class MyClass {\n` + + ` db: db;\n` + + ` constructor(db: db) {\n` + + ` this.db = db;\n` + + ` this.db.doSomething(); \n` + + ` }\n` + + `}\n` + + `export {MyClass}; \n`, { options: { compilerOptions: { @@ -191,7 +221,11 @@ var x = 0;`, }); transpilesCorrectly("transpile .js files", "const a = 10;", { - options: { compilerOptions: { newLine: NewLineKind.LineFeed, module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { newLine: NewLineKind.LineFeed, module: ModuleKind.CommonJS }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports urls in file name", "var x", { @@ -217,11 +251,19 @@ var x = 0;`, }); transpilesCorrectly("Support options with lib values", "const a = 10;", { - options: { compilerOptions: { lib: ["es6", "dom"], module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { lib: ["es6", "dom"], module: ModuleKind.CommonJS }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Support options with types values", "const a = 10;", { - options: { compilerOptions: { types: ["jquery", "typescript"], module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { types: ["jquery", "typescript"], module: ModuleKind.CommonJS }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'allowJs'", "x;", { @@ -229,7 +271,11 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'allowSyntheticDefaultImports'", "x;", { - options: { compilerOptions: { allowSyntheticDefaultImports: true }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { allowSyntheticDefaultImports: true }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'allowUnreachableCode'", "x;", { @@ -245,7 +291,11 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'baseUrl'", "x;", { - options: { compilerOptions: { baseUrl: "./folder/baseUrl" }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { baseUrl: "./folder/baseUrl" }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'charset'", "x;", { @@ -257,7 +307,11 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'declarationDir'", "x;", { - options: { compilerOptions: { declarationDir: "out/declarations" }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { declarationDir: "out/declarations" }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'emitBOM'", "x;", { @@ -265,15 +319,27 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'emitDecoratorMetadata'", "x;", { - options: { compilerOptions: { emitDecoratorMetadata: true, experimentalDecorators: true }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { emitDecoratorMetadata: true, experimentalDecorators: true }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'experimentalDecorators'", "x;", { - options: { compilerOptions: { experimentalDecorators: true }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { experimentalDecorators: true }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'forceConsistentCasingInFileNames'", "x;", { - options: { compilerOptions: { forceConsistentCasingInFileNames: true }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { forceConsistentCasingInFileNames: true }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'isolatedModules'", "x;", { @@ -293,15 +359,27 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'module'", "x;", { - options: { compilerOptions: { module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { module: ModuleKind.CommonJS }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'moduleResolution'", "x;", { - options: { compilerOptions: { moduleResolution: ModuleResolutionKind.NodeJs }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { moduleResolution: ModuleResolutionKind.NodeJs }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'newLine'", "x;", { - options: { compilerOptions: { newLine: NewLineKind.CarriageReturnLineFeed }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { newLine: NewLineKind.CarriageReturnLineFeed }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'noEmit'", "x;", { @@ -321,7 +399,11 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'noFallthroughCasesInSwitch'", "x;", { - options: { compilerOptions: { noFallthroughCasesInSwitch: true }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { noFallthroughCasesInSwitch: true }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'noImplicitAny'", "x;", { @@ -361,7 +443,11 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'paths'", "x;", { - options: { compilerOptions: { paths: { "*": ["./generated*"] } }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { paths: { "*": ["./generated*"] } }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'preserveConstEnums'", "x;", { @@ -373,11 +459,19 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'jsxFactory'", "x;", { - options: { compilerOptions: { jsxFactory: "createElement" }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { jsxFactory: "createElement" }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'jsxFragmentFactory'", "x;", { - options: { compilerOptions: { jsxFactory: "x", jsxFragmentFactory: "frag" }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { jsxFactory: "x", jsxFragmentFactory: "frag" }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'removeComments'", "x;", { @@ -385,7 +479,11 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'rootDir'", "x;", { - options: { compilerOptions: { rootDir: "./rootDir" }, fileName: "./rootDir/input.js", reportDiagnostics: true }, + options: { + compilerOptions: { rootDir: "./rootDir" }, + fileName: "./rootDir/input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'rootDirs'", "x;", { @@ -409,11 +507,19 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'suppressExcessPropertyErrors'", "x;", { - options: { compilerOptions: { suppressExcessPropertyErrors: true }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { suppressExcessPropertyErrors: true }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'suppressImplicitAnyIndexErrors'", "x;", { - options: { compilerOptions: { suppressImplicitAnyIndexErrors: true }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { suppressImplicitAnyIndexErrors: true }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'target'", "x;", { @@ -421,7 +527,11 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'types'", "x;", { - options: { compilerOptions: { types: ["jquery", "jasmine"] }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { types: ["jquery", "jasmine"] }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports setting 'typeRoots'", "x;", { @@ -437,17 +547,21 @@ var x = 0;`, }); transpilesCorrectly("Supports setting 'tsbuildinfo'", "x;", { - options: { compilerOptions: { incremental: true, tsBuildInfoFile: "./folder/config.tsbuildinfo" }, fileName: "input.js", reportDiagnostics: true }, + options: { + compilerOptions: { incremental: true, tsBuildInfoFile: "./folder/config.tsbuildinfo" }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly( "Correctly serialize metadata when transpile with CommonJS option", - `import * as ng from "angular2/core";` + - `declare function foo(...args: any[]);` + - `@foo` + - `export class MyClass1 {` + - ` constructor(private _elementRef: ng.ElementRef){}` + - `}`, + `import * as ng from "angular2/core";` + + `declare function foo(...args: any[]);` + + `@foo` + + `export class MyClass1 {` + + ` constructor(private _elementRef: ng.ElementRef){}` + + `}`, { options: { compilerOptions: { @@ -464,12 +578,12 @@ var x = 0;`, transpilesCorrectly( "Correctly serialize metadata when transpile with System option", - `import * as ng from "angular2/core";` + - `declare function foo(...args: any[]);` + - `@foo` + - `export class MyClass1 {` + - ` constructor(private _elementRef: ng.ElementRef){}` + - `}`, + `import * as ng from "angular2/core";` + + `declare function foo(...args: any[]);` + + `@foo` + + `export class MyClass1 {` + + ` constructor(private _elementRef: ng.ElementRef){}` + + `}`, { options: { compilerOptions: { @@ -509,8 +623,8 @@ export * as alias from './file';`, transpilesCorrectly( "Elides import equals referenced only by export type", - `import IFoo = Namespace.IFoo;` + - `export type { IFoo };`, + `import IFoo = Namespace.IFoo;` + + `export type { IFoo };`, { options: { compilerOptions: { module: ModuleKind.CommonJS } }, }, @@ -518,8 +632,8 @@ export * as alias from './file';`, transpilesCorrectly( "Elides import equals referenced only by type only export specifier", - `import IFoo = Namespace.IFoo;` + - `export { type IFoo };`, + `import IFoo = Namespace.IFoo;` + + `export { type IFoo };`, { options: { compilerOptions: { module: ModuleKind.CommonJS } }, }, diff --git a/src/testRunner/unittests/transform.ts b/src/testRunner/unittests/transform.ts index 4cba3107a6c82..fe537cda909bb 100644 --- a/src/testRunner/unittests/transform.ts +++ b/src/testRunner/unittests/transform.ts @@ -253,8 +253,18 @@ namespace ts { const result = factory.updateSourceFile( sourceFile, factory.createNodeArray([ - factory.createClassDeclaration(/*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, /*members*/ undefined!), // TODO: GH#18217 - factory.createModuleDeclaration(/*modifiers*/ undefined, factory.createIdentifier("Foo"), factory.createModuleBlock([factory.createEmptyStatement()])), + factory.createClassDeclaration( + /*modifiers*/ undefined, + "Foo", + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + /*members*/ undefined!, + ), // TODO: GH#18217 + factory.createModuleDeclaration( + /*modifiers*/ undefined, + factory.createIdentifier("Foo"), + factory.createModuleBlock([factory.createEmptyStatement()]), + ), ]), ); return result; @@ -296,9 +306,18 @@ namespace ts { if (node.kind === SyntaxKind.ExportDeclaration) { const ed = node as Node as ExportDeclaration; const exports = [{ name: "x" }]; - const exportSpecifiers = exports.map(e => factory.createExportSpecifier(/*isTypeOnly*/ false, e.name, e.name)); + const exportSpecifiers = exports.map(e => + factory.createExportSpecifier(/*isTypeOnly*/ false, e.name, e.name) + ); const exportClause = factory.createNamedExports(exportSpecifiers); - const newEd = factory.updateExportDeclaration(ed, ed.modifiers, ed.isTypeOnly, exportClause, ed.moduleSpecifier, ed.assertClause); + const newEd = factory.updateExportDeclaration( + ed, + ed.modifiers, + ed.isTypeOnly, + exportClause, + ed.moduleSpecifier, + ed.assertClause, + ); return newEd as Node as T; } @@ -360,9 +379,24 @@ namespace ts { }; function visitNode(sf: SourceFile) { // produce `class Foo { @Bar baz() {} }`; - const classDecl = factory.createClassDeclaration(/*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [ - factory.createMethodDeclaration([factory.createDecorator(factory.createIdentifier("Bar"))], /**/ undefined, "baz", /**/ undefined, /**/ undefined, [], /**/ undefined, factory.createBlock([])), - ]); + const classDecl = factory.createClassDeclaration( + /*modifiers*/ undefined, + "Foo", + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [ + factory.createMethodDeclaration( + [factory.createDecorator(factory.createIdentifier("Bar"))], + /**/ undefined, + "baz", + /**/ undefined, + /**/ undefined, + [], + /**/ undefined, + factory.createBlock([]), + ), + ], + ); return factory.updateSourceFile(sf, [classDecl]); } } @@ -399,21 +433,42 @@ namespace ts { function visitNode(sf: SourceFile) { // produce `class Foo { constructor(@Dec private x) {} }`; // The decorator is required to trigger ts.ts transformations. - const classDecl = factory.createClassDeclaration([], "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [ - factory.createConstructorDeclaration(/*modifiers*/ undefined, [ - factory.createParameterDeclaration([factory.createDecorator(factory.createIdentifier("Dec")), factory.createModifier(SyntaxKind.PrivateKeyword)], /*dotDotDotToken*/ undefined, "x"), - ], factory.createBlock([])), - ]); + const classDecl = factory.createClassDeclaration( + [], + "Foo", + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [ + factory.createConstructorDeclaration(/*modifiers*/ undefined, [ + factory.createParameterDeclaration( + [ + factory.createDecorator(factory.createIdentifier("Dec")), + factory.createModifier(SyntaxKind.PrivateKeyword), + ], + /*dotDotDotToken*/ undefined, + "x", + ), + ], factory.createBlock([])), + ], + ); return factory.updateSourceFile(sf, [classDecl]); } } }); function baselineDeclarationTransform(text: string, opts: TranspileOptions) { - const fs = vfs.createFromFileSystem(Harness.IO, /*caseSensitive*/ true, { documents: [new documents.TextDocument("/.src/index.ts", text)] }); + const fs = vfs.createFromFileSystem(Harness.IO, /*caseSensitive*/ true, { + documents: [new documents.TextDocument("/.src/index.ts", text)], + }); const host = new fakes.CompilerHost(fs, opts.compilerOptions); const program = createProgram(["/.src/index.ts"], opts.compilerOptions!, host); - program.emit(program.getSourceFile("/.src/index.ts"), (p, s, bom) => host.writeFile(p, s, bom), /*cancellationToken*/ undefined, /*onlyDts*/ true, opts.transformers); + program.emit( + program.getSourceFile("/.src/index.ts"), + (p, s, bom) => host.writeFile(p, s, bom), + /*cancellationToken*/ undefined, + /*onlyDts*/ true, + opts.transformers, + ); return fs.readFileSync("/.src/index.d.ts").toString(); } @@ -425,7 +480,13 @@ namespace ts { function rootTransform(node: T): VisitResult { if (nodeFilter(node)) { setEmitFlags(node, EmitFlags.NoLeadingComments); - setSyntheticLeadingComments(node, [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "comment", pos: -1, end: -1, hasTrailingNewLine: true }]); + setSyntheticLeadingComments(node, [{ + kind: SyntaxKind.MultiLineCommentTrivia, + text: "comment", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }]); } return visitEachChild(node, rootTransform, context); } @@ -483,7 +544,12 @@ export {Value}; `, { transformers: { - before: [addSyntheticComment(n => isImportDeclaration(n) || isExportDeclaration(n) || isImportSpecifier(n) || isExportSpecifier(n))], + before: [ + addSyntheticComment(n => + isImportDeclaration(n) || isExportDeclaration(n) || isImportSpecifier(n) + || isExportSpecifier(n) + ), + ], }, compilerOptions: { target: ScriptTarget.ES5, @@ -509,7 +575,12 @@ class Clazz { `, { transformers: { - before: [addSyntheticComment(n => isPropertyDeclaration(n) || isParameterPropertyDeclaration(n, n.parent) || isClassDeclaration(n) || isConstructorDeclaration(n))], + before: [ + addSyntheticComment(n => + isPropertyDeclaration(n) || isParameterPropertyDeclaration(n, n.parent) + || isClassDeclaration(n) || isConstructorDeclaration(n) + ), + ], }, compilerOptions: { target: ScriptTarget.ES2015, @@ -568,7 +639,13 @@ module MyModule { }; function rootTransform(node: T): Node { if (isVariableDeclaration(node)) { - return factory.updateVariableDeclaration(node, factory.createIdentifier("newName"), /*exclamationToken*/ undefined, /*type*/ undefined, node.initializer); + return factory.updateVariableDeclaration( + node, + factory.createIdentifier("newName"), + /*exclamationToken*/ undefined, + /*type*/ undefined, + node.initializer, + ); } return visitEachChild(node, rootTransform, context); } @@ -578,7 +655,10 @@ module MyModule { // https://github.com/Microsoft/TypeScript/issues/24709 testBaseline("issue24709", () => { const fs = vfs.createFromFileSystem(Harness.IO, /*caseSensitive*/ true); - const transformed = transform(createSourceFile("source.ts", "class X { echo(x: string) { return x; } }", ScriptTarget.ES3), [transformSourceFile]); + const transformed = transform( + createSourceFile("source.ts", "class X { echo(x: string) { return x; } }", ScriptTarget.ES3), + [transformSourceFile], + ); const transformedSourceFile = transformed.transformed[0]; transformed.dispose(); const host = new fakes.CompilerHost(fs); @@ -644,18 +724,32 @@ module MyModule { }; function rootTransform(node: T): Node { if (isClassLike(node)) { - const newMembers = [factory.createPropertyDeclaration([factory.createModifier(SyntaxKind.StaticKeyword)], "newField", /* questionOrExclamationToken */ undefined, /* type */ undefined, factory.createStringLiteral("x"))]; - setSyntheticLeadingComments(newMembers[0], [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "comment", pos: -1, end: -1, hasTrailingNewLine: true }]); - return isClassDeclaration(node) ? - factory.updateClassDeclaration( + const newMembers = [ + factory.createPropertyDeclaration( + [factory.createModifier(SyntaxKind.StaticKeyword)], + "newField", + /* questionOrExclamationToken */ undefined, + /* type */ undefined, + factory.createStringLiteral("x"), + ), + ]; + setSyntheticLeadingComments(newMembers[0], [{ + kind: SyntaxKind.MultiLineCommentTrivia, + text: "comment", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }]); + return isClassDeclaration(node) + ? factory.updateClassDeclaration( node, node.modifiers, node.name, node.typeParameters, node.heritageClauses, newMembers, - ) : - factory.updateClassExpression( + ) + : factory.updateClassExpression( node, node.modifiers, node.name, diff --git a/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts b/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts index a02880b6cc791..aa7b158ae0075 100644 --- a/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts +++ b/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts @@ -147,14 +147,20 @@ ${internal} export enum internalEnum { a, b, c }`, verifyOutFileScenario({ subScenario: "stripInternal", modifyFs: stripInternalScenario, - modifyAgainFs: fs => replaceText(fs, "/src/lib/file1.ts", `export const`, `/*@internal*/ export const`), + modifyAgainFs: fs => + replaceText(fs, "/src/lib/file1.ts", `export const`, `/*@internal*/ export const`), }); }); describe("when the module resolution finds original source file", () => { function modifyFs(fs: vfs.FileSystem) { // Make lib to output to parent dir - replaceText(fs, "/src/lib/tsconfig.json", `"outFile": "module.js"`, `"outFile": "../module.js", "rootDir": "../"`); + replaceText( + fs, + "/src/lib/tsconfig.json", + `"outFile": "module.js"`, + `"outFile": "../module.js", "rootDir": "../"`, + ); // Change reference to file1 module to resolve to lib/file1 replaceText(fs, "/src/app/file3.ts", "file1", "lib/file1"); } diff --git a/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts b/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts index 0adc6567d2cb0..c7f638905e231 100644 --- a/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts +++ b/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts @@ -10,13 +10,15 @@ namespace ts { function verifyEmitDeclarationOnly(disableMap?: true) { verifyTscWithEdits({ - subScenario: `only dts output in circular import project with emitDeclarationOnly${disableMap ? "" : " and declarationMap"}`, + subScenario: `only dts output in circular import project with emitDeclarationOnly${ + disableMap ? "" : " and declarationMap" + }`, fs: () => projFs, scenario: "emitDeclarationOnly", commandLineArgs: ["--b", "/src", "--verbose"], - modifyFs: disableMap ? - (fs => replaceText(fs, "/src/tsconfig.json", `"declarationMap": true,`, "")) : - undefined, + modifyFs: disableMap + ? (fs => replaceText(fs, "/src/tsconfig.json", `"declarationMap": true,`, "")) + : undefined, edits: [{ subScenario: "incremental-declaration-changes", modifyFs: fs => replaceText(fs, "/src/src/a.ts", "b: B;", "b: B; foo: any;"), diff --git a/src/testRunner/unittests/tsbuild/graphOrdering.ts b/src/testRunner/unittests/tsbuild/graphOrdering.ts index 0f98fa01c1f52..a8ef62bc6a4f5 100644 --- a/src/testRunner/unittests/tsbuild/graphOrdering.ts +++ b/src/testRunner/unittests/tsbuild/graphOrdering.ts @@ -47,7 +47,11 @@ namespace ts { }); function checkGraphOrdering(rootNames: string[], expectedBuildSet: string[], circular?: true) { - const builder = createSolutionBuilder(host!, rootNames.map(getProjectFileName), { dry: true, force: false, verbose: false }); + const builder = createSolutionBuilder(host!, rootNames.map(getProjectFileName), { + dry: true, + force: false, + verbose: false, + }); const buildOrder = builder.getBuildOrder(); assert.equal(isCircularBuildOrder(buildOrder), !!circular); const buildQueue = getBuildOrderFromAnyBuildOrder(buildOrder); @@ -58,7 +62,11 @@ namespace ts { const child = getProjectFileName(dep[0]); if (buildQueue.indexOf(child) < 0) continue; const parent = getProjectFileName(dep[1]); - assert.isAbove(buildQueue.indexOf(child), buildQueue.indexOf(parent), `Expecting child ${child} to be built after parent ${parent}`); + assert.isAbove( + buildQueue.indexOf(child), + buildQueue.indexOf(parent), + `Expecting child ${child} to be built after parent ${parent}`, + ); } } } @@ -70,8 +78,12 @@ namespace ts { function writeProjects(fileSystem: vfs.FileSystem, projectNames: string[], deps: [string, string][]): string[] { const projFileNames: string[] = []; for (const dep of deps) { - if (projectNames.indexOf(dep[0]) < 0) throw new Error(`Invalid dependency - project ${dep[0]} does not exist`); - if (projectNames.indexOf(dep[1]) < 0) throw new Error(`Invalid dependency - project ${dep[1]} does not exist`); + if (projectNames.indexOf(dep[0]) < 0) { + throw new Error(`Invalid dependency - project ${dep[0]} does not exist`); + } + if (projectNames.indexOf(dep[1]) < 0) { + throw new Error(`Invalid dependency - project ${dep[1]} does not exist`); + } } for (const proj of projectNames) { fileSystem.mkdirpSync(`/project/${proj}`); diff --git a/src/testRunner/unittests/tsbuild/helpers.ts b/src/testRunner/unittests/tsbuild/helpers.ts index e2f6ae65eccb7..757c11058fdd3 100644 --- a/src/testRunner/unittests/tsbuild/helpers.ts +++ b/src/testRunner/unittests/tsbuild/helpers.ts @@ -63,7 +63,11 @@ namespace ts { return content.lastIndexOf(searchStr); } - export function expectedLocationIndexOf(fs: vfs.FileSystem, file: string, searchStr: string): fakes.ExpectedDiagnosticLocation { + export function expectedLocationIndexOf( + fs: vfs.FileSystem, + file: string, + searchStr: string, + ): fakes.ExpectedDiagnosticLocation { return { file, start: indexOf(fs, file, searchStr), @@ -71,7 +75,11 @@ namespace ts { }; } - export function expectedLocationLastIndexOf(fs: vfs.FileSystem, file: string, searchStr: string): fakes.ExpectedDiagnosticLocation { + export function expectedLocationLastIndexOf( + fs: vfs.FileSystem, + file: string, + searchStr: string, + ): fakes.ExpectedDiagnosticLocation { return { file, start: lastIndexOf(fs, file, searchStr), @@ -158,7 +166,13 @@ interface Symbol { } } - function generateBundleFileSectionInfo(sys: System, originalReadCall: System["readFile"], baselineRecorder: Harness.Compiler.WriterAggregator, bundleFileInfo: BundleFileInfo | undefined, outFile: string | undefined) { + function generateBundleFileSectionInfo( + sys: System, + originalReadCall: System["readFile"], + baselineRecorder: Harness.Compiler.WriterAggregator, + bundleFileInfo: BundleFileInfo | undefined, + outFile: string | undefined, + ) { if (!length(bundleFileInfo && bundleFileInfo.sections) && !outFile) return; // Nothing to baseline const content = outFile && sys.fileExists(outFile) ? originalReadCall.call(sys, outFile, "utf8")! : ""; @@ -174,7 +188,9 @@ interface Symbol { Debug.assert(section.pos === first(section.texts).pos); Debug.assert(section.end === last(section.texts).end); for (const text of section.texts) { - baselineRecorder.WriteLine(">>--------------------------------------------------------------------"); + baselineRecorder.WriteLine( + ">>--------------------------------------------------------------------", + ); writeSectionHeader(text); writeTextOfSection(text.pos, text.end); } @@ -193,40 +209,65 @@ interface Symbol { } function writeSectionHeader(section: BundleFileSection) { - baselineRecorder.WriteLine(`${section.kind}: (${section.pos}-${section.end})${section.data ? ":: " + section.data : ""}${section.kind === BundleFileSectionKind.Prepend ? " texts:: " + section.texts.length : ""}`); + baselineRecorder.WriteLine( + `${section.kind}: (${section.pos}-${section.end})${section.data ? ":: " + section.data : ""}${ + section.kind === BundleFileSectionKind.Prepend ? " texts:: " + section.texts.length : "" + }`, + ); } } type ReadableProgramBuildInfoDiagnostic = string | [string, readonly ReusableDiagnostic[]]; type ReadableProgramBuilderInfoFilePendingEmit = [string, "DtsOnly" | "Full"]; type ReadableProgramBuildInfoEmitSignature = string | [string, string]; - type ReadableProgramBuildInfoFileInfo = Omit & { impliedFormat: string | undefined; }; - type ReadableProgramMultiFileEmitBuildInfo = Omit & { - fileNamesList: readonly (readonly string[])[] | undefined; - fileInfos: MapLike; - referencedMap?: MapLike; - exportedModulesMap?: MapLike; - semanticDiagnosticsPerFile?: readonly ReadableProgramBuildInfoDiagnostic[]; - affectedFilesPendingEmit?: readonly ReadableProgramBuilderInfoFilePendingEmit[]; - changeFileSet?: readonly string[]; - emitSignatures?: readonly ReadableProgramBuildInfoEmitSignature[]; + type ReadableProgramBuildInfoFileInfo = Omit & { + impliedFormat: string | undefined; }; + type ReadableProgramMultiFileEmitBuildInfo = + & Omit< + ProgramMultiFileEmitBuildInfo, + | "fileIdsList" + | "fileInfos" + | "referencedMap" + | "exportedModulesMap" + | "semanticDiagnosticsPerFile" + | "affectedFilesPendingEmit" + | "changeFileSet" + | "emitSignatures" + > + & { + fileNamesList: readonly (readonly string[])[] | undefined; + fileInfos: MapLike; + referencedMap?: MapLike; + exportedModulesMap?: MapLike; + semanticDiagnosticsPerFile?: readonly ReadableProgramBuildInfoDiagnostic[]; + affectedFilesPendingEmit?: readonly ReadableProgramBuilderInfoFilePendingEmit[]; + changeFileSet?: readonly string[]; + emitSignatures?: readonly ReadableProgramBuildInfoEmitSignature[]; + }; type ReadableProgramBundleEmitBuildInfo = Omit & { fileInfos: MapLike; }; type ReadableProgramBuildInfo = ReadableProgramMultiFileEmitBuildInfo | ReadableProgramBundleEmitBuildInfo; - function isReadableProgramBundleEmitBuildInfo(info: ReadableProgramBuildInfo | undefined): info is ReadableProgramBundleEmitBuildInfo { + function isReadableProgramBundleEmitBuildInfo( + info: ReadableProgramBuildInfo | undefined, + ): info is ReadableProgramBundleEmitBuildInfo { return !!info && !!outFile(info.options || {}); } - type ReadableBuildInfo = Omit & { program: ReadableProgramBuildInfo | undefined; size: number; }; + type ReadableBuildInfo = Omit & { + program: ReadableProgramBuildInfo | undefined; + size: number; + }; function generateBuildInfoProgramBaseline(sys: System, buildInfoPath: string, buildInfo: BuildInfo) { let program: ReadableProgramBuildInfo | undefined; let fileNamesList: string[][] | undefined; if (buildInfo.program && isProgramBundleEmitBuildInfo(buildInfo.program)) { const fileInfos: ReadableProgramBundleEmitBuildInfo["fileInfos"] = {}; - buildInfo.program?.fileInfos?.forEach((fileInfo, index) => fileInfos[toFileName(index + 1 as ProgramBuildInfoFileId)] = fileInfo); + buildInfo.program?.fileInfos?.forEach((fileInfo, index) => + fileInfos[toFileName(index + 1 as ProgramBuildInfoFileId)] = fileInfo + ); program = { ...buildInfo.program, fileInfos, @@ -234,7 +275,9 @@ interface Symbol { } else if (buildInfo.program) { const fileInfos: ReadableProgramMultiFileEmitBuildInfo["fileInfos"] = {}; - buildInfo.program?.fileInfos?.forEach((fileInfo, index) => fileInfos[toFileName(index + 1 as ProgramBuildInfoFileId)] = toReadableFileInfo(fileInfo)); + buildInfo.program?.fileInfos?.forEach((fileInfo, index) => + fileInfos[toFileName(index + 1 as ProgramBuildInfoFileId)] = toReadableFileInfo(fileInfo) + ); fileNamesList = buildInfo.program.fileIdsList?.map(fileIdsListId => fileIdsListId.map(toFileName)); program = buildInfo.program && { fileNames: buildInfo.program.fileNames, @@ -244,21 +287,21 @@ interface Symbol { referencedMap: toMapOfReferencedSet(buildInfo.program.referencedMap), exportedModulesMap: toMapOfReferencedSet(buildInfo.program.exportedModulesMap), semanticDiagnosticsPerFile: buildInfo.program.semanticDiagnosticsPerFile?.map(d => - isNumber(d) ? - toFileName(d) : - [toFileName(d[0]), d[1]] + isNumber(d) + ? toFileName(d) + : [toFileName(d[0]), d[1]] ), affectedFilesPendingEmit: buildInfo.program.affectedFilesPendingEmit?.map(([fileId, emitKind]) => [ toFileName(fileId), - emitKind === BuilderFileEmit.DtsOnly ? "DtsOnly" : - emitKind === BuilderFileEmit.Full ? "Full" : - Debug.assertNever(emitKind), + emitKind === BuilderFileEmit.DtsOnly ? "DtsOnly" + : emitKind === BuilderFileEmit.Full ? "Full" + : Debug.assertNever(emitKind), ]), changeFileSet: buildInfo.program.changeFileSet?.map(toFileName), emitSignatures: buildInfo.program.emitSignatures?.map(s => - isNumber(s) ? - toFileName(s) : - [toFileName(s[0]), s[1]] + isNumber(s) + ? toFileName(s) + : [toFileName(s[0]), s[1]] ), latestChangedDtsFile: buildInfo.program.latestChangedDtsFile, }; @@ -300,11 +343,14 @@ interface Symbol { const info = toBuilderStateFileInfo(fileInfo); return { ...info, - impliedFormat: info.impliedFormat && getNameOfCompilerOptionValue(info.impliedFormat, moduleOptionDeclaration.type), + impliedFormat: info.impliedFormat + && getNameOfCompilerOptionValue(info.impliedFormat, moduleOptionDeclaration.type), }; } - function toMapOfReferencedSet(referenceMap: ProgramBuildInfoReferencedMap | undefined): MapLike | undefined { + function toMapOfReferencedSet( + referenceMap: ProgramBuildInfoReferencedMap | undefined, + ): MapLike | undefined { if (!referenceMap) return undefined; const result: MapLike = {}; for (const [fileNamesKey, fileNamesListKey] of referenceMap) { @@ -327,7 +373,10 @@ interface Symbol { if (!buildInfoPath || !sys.writtenFiles!.has(toPathWithSystem(sys, buildInfoPath))) return; if (!sys.fileExists(buildInfoPath)) return; - const buildInfo = getBuildInfo(buildInfoPath, (originalReadCall || sys.readFile).call(sys, buildInfoPath, "utf8")!); + const buildInfo = getBuildInfo( + buildInfoPath, + (originalReadCall || sys.readFile).call(sys, buildInfoPath, "utf8")!, + ); if (!buildInfo) return sys.writeFile(`${buildInfoPath}.baseline.txt`, "Error reading valid buildinfo file"); generateBuildInfoProgramBaseline(sys, buildInfoPath, buildInfo); @@ -339,7 +388,13 @@ interface Symbol { // Write the baselines: const baselineRecorder = new Harness.Compiler.WriterAggregator(); generateBundleFileSectionInfo(sys, originalReadCall || sys.readFile, baselineRecorder, bundle.js, jsFilePath); - generateBundleFileSectionInfo(sys, originalReadCall || sys.readFile, baselineRecorder, bundle.dts, declarationFilePath); + generateBundleFileSectionInfo( + sys, + originalReadCall || sys.readFile, + baselineRecorder, + bundle.dts, + declarationFilePath, + ); baselineRecorder.Close(); const text = baselineRecorder.lines.join("\r\n"); sys.writeFile(`${buildInfoPath}.baseline.txt`, text); @@ -385,24 +440,42 @@ interface Symbol { const incrementalBuildText = newSys.readFile(outputFile); if (isBuildInfoFile(outputFile)) { // Check only presence and absence and not text as we will do that for readable baseline - if (!sys.fileExists(`${outputFile}.readable.baseline.txt`)) addBaseline(`Readable baseline not present in clean build:: File:: ${outputFile}`); - if (!newSys.fileExists(`${outputFile}.readable.baseline.txt`)) addBaseline(`Readable baseline not present in incremental build:: File:: ${outputFile}`); - verifyPresenceAbsence(incrementalBuildText, cleanBuildText, `Incremental and clean tsbuildinfo file presence differs:: File:: ${outputFile}`); + if (!sys.fileExists(`${outputFile}.readable.baseline.txt`)) { + addBaseline(`Readable baseline not present in clean build:: File:: ${outputFile}`); + } + if (!newSys.fileExists(`${outputFile}.readable.baseline.txt`)) { + addBaseline(`Readable baseline not present in incremental build:: File:: ${outputFile}`); + } + verifyPresenceAbsence( + incrementalBuildText, + cleanBuildText, + `Incremental and clean tsbuildinfo file presence differs:: File:: ${outputFile}`, + ); } else if (!fileExtensionIs(outputFile, ".tsbuildinfo.readable.baseline.txt")) { verifyTextEqual(incrementalBuildText, cleanBuildText, `File: ${outputFile}`); } else if (incrementalBuildText !== cleanBuildText) { // Verify build info without affectedFilesPendingEmit - const { buildInfo: incrementalBuildInfo, readableBuildInfo: incrementalReadableBuildInfo } = getBuildInfoForIncrementalCorrectnessCheck(incrementalBuildText); - const { buildInfo: cleanBuildInfo, readableBuildInfo: cleanReadableBuildInfo } = getBuildInfoForIncrementalCorrectnessCheck(cleanBuildText); - verifyTextEqual(incrementalBuildInfo, cleanBuildInfo, `TsBuild info text without affectedFilesPendingEmit:: ${outputFile}::`); + const { buildInfo: incrementalBuildInfo, readableBuildInfo: incrementalReadableBuildInfo } = + getBuildInfoForIncrementalCorrectnessCheck(incrementalBuildText); + const { buildInfo: cleanBuildInfo, readableBuildInfo: cleanReadableBuildInfo } = + getBuildInfoForIncrementalCorrectnessCheck(cleanBuildText); + verifyTextEqual( + incrementalBuildInfo, + cleanBuildInfo, + `TsBuild info text without affectedFilesPendingEmit:: ${outputFile}::`, + ); // Verify file info sigantures verifyMapLike( - incrementalReadableBuildInfo?.program?.fileInfos as ReadableProgramMultiFileEmitBuildInfo["fileInfos"], + incrementalReadableBuildInfo?.program + ?.fileInfos as ReadableProgramMultiFileEmitBuildInfo["fileInfos"], cleanReadableBuildInfo?.program?.fileInfos as ReadableProgramMultiFileEmitBuildInfo["fileInfos"], (key, incrementalFileInfo, cleanFileInfo) => { - if (incrementalFileInfo.signature !== cleanFileInfo.signature && incrementalFileInfo.signature !== incrementalFileInfo.version) { + if ( + incrementalFileInfo.signature !== cleanFileInfo.signature + && incrementalFileInfo.signature !== incrementalFileInfo.version + ) { return [ `Incremental signature is neither dts signature nor file version for File:: ${key}`, `Incremental:: ${JSON.stringify(incrementalFileInfo, /*replacer*/ undefined, 2)}`, @@ -419,13 +492,36 @@ interface Symbol { incrementalReadableBuildInfo?.program?.exportedModulesMap, cleanReadableBuildInfo?.program?.exportedModulesMap, (key, incrementalReferenceSet, cleanReferenceSet) => { - if (!arrayIsEqualTo(incrementalReferenceSet, cleanReferenceSet) && !arrayIsEqualTo(incrementalReferenceSet, (incrementalReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key])) { + if ( + !arrayIsEqualTo(incrementalReferenceSet, cleanReferenceSet) + && !arrayIsEqualTo( + incrementalReferenceSet, + (incrementalReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo) + .referencedMap![key], + ) + ) { return [ `Incremental Reference set is neither from dts nor files reference map for File:: ${key}::`, - `Incremental:: ${JSON.stringify(incrementalReferenceSet, /*replacer*/ undefined, 2)}`, + `Incremental:: ${ + JSON.stringify(incrementalReferenceSet, /*replacer*/ undefined, 2) + }`, `Clean:: ${JSON.stringify(cleanReferenceSet, /*replacer*/ undefined, 2)}`, - `IncrementalReferenceMap:: ${JSON.stringify((incrementalReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key], /*replacer*/ undefined, 2)}`, - `CleanReferenceMap:: ${JSON.stringify((cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key], /*replacer*/ undefined, 2)}`, + `IncrementalReferenceMap:: ${ + JSON.stringify( + (incrementalReadableBuildInfo! + .program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key], + /*replacer*/ undefined, + 2, + ) + }`, + `CleanReferenceMap:: ${ + JSON.stringify( + (cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo) + .referencedMap![key], + /*replacer*/ undefined, + 2, + ) + }`, ]; } }, @@ -442,7 +538,12 @@ interface Symbol { } let expectedIndex = 0; incrementalReadableBuildInfo.program.affectedFilesPendingEmit.forEach(([actualFile]) => { - expectedIndex = findIndex((cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit, ([expectedFile]) => actualFile === expectedFile, expectedIndex); + expectedIndex = findIndex( + (cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo) + .affectedFilesPendingEmit, + ([expectedFile]) => actualFile === expectedFile, + expectedIndex, + ); if (expectedIndex === -1) { addBaseline( `Incremental build contains ${actualFile} file as pending emit, clean build does not have it: ${outputFile}::`, @@ -456,14 +557,21 @@ interface Symbol { } } } - if (!headerAdded && discrepancyExplanation) addBaseline("*** Supplied discrepancy explanation but didnt file any difference"); + if (!headerAdded && discrepancyExplanation) { + addBaseline("*** Supplied discrepancy explanation but didnt file any difference"); + } return baselines; function verifyTextEqual(incrementalText: string | undefined, cleanText: string | undefined, message: string) { if (incrementalText !== cleanText) writeNotEqual(incrementalText, cleanText, message); } - function verifyMapLike(incremental: MapLike | undefined, clean: MapLike | undefined, verifyValue: (key: string, incrementalValue: T, cleanValue: T) => string[] | undefined, message: string) { + function verifyMapLike( + incremental: MapLike | undefined, + clean: MapLike | undefined, + verifyValue: (key: string, incrementalValue: T, cleanValue: T) => string[] | undefined, + message: string, + ) { verifyPresenceAbsence(incremental, clean, `Incremental and clean do not match:: ${message}`); if (!incremental || !clean) return; const incrementalMap = new Map(getEntries(incremental)); @@ -514,7 +622,10 @@ interface Symbol { function addBaseline(...text: string[]) { if (!baselines || !headerAdded) { - (baselines ||= []).push(`${index}:: ${subScenario}`, ...(discrepancyExplanation?.() || ["*** Needs explanation"])); + (baselines ||= []).push( + `${index}:: ${subScenario}`, + ...(discrepancyExplanation?.() || ["*** Needs explanation"]), + ); headerAdded = true; } baselines.push(...text); @@ -550,7 +661,8 @@ interface Symbol { options: { ...readableBuildInfo.program.options, noEmit: undefined }, exportedModulesMap: undefined, affectedFilesPendingEmit: undefined, - latestChangedDtsFile: readableBuildInfo.program.latestChangedDtsFile ? "FakeFileName" : undefined, + latestChangedDtsFile: readableBuildInfo.program.latestChangedDtsFile ? "FakeFileName" + : undefined, }, size: undefined, // Size doesnt need to be equal }, @@ -597,7 +709,10 @@ interface Symbol { let baseFs: vfs.FileSystem; let editsSys: TscCompileSystem[]; before(() => { - Debug.assert(!!edits.length, `${scenario}/${subScenario}:: No incremental scenarios, you probably want to use verifyTsc instead.`); + Debug.assert( + !!edits.length, + `${scenario}/${subScenario}:: No incremental scenarios, you probably want to use verifyTsc instead.`, + ); baseFs = fs().makeReadonly(); sys = testTscCompile({ scenario, @@ -665,7 +780,9 @@ interface Symbol { }); } Harness.Baseline.runBaseline( - `${isBuild(commandLineArgs) ? "tsbuild" : "tsc"}/${scenario}/${subScenario.split(" ").join("-")}-discrepancies.js`, + `${isBuild(commandLineArgs) ? "tsbuild" : "tsc"}/${scenario}/${ + subScenario.split(" ").join("-") + }-discrepancies.js`, baselines ? baselines.join("\r\n") : null, // eslint-disable-line no-null/no-null ); }); diff --git a/src/testRunner/unittests/tsbuild/moduleResolution.ts b/src/testRunner/unittests/tsbuild/moduleResolution.ts index 4d37eeda2c127..d55f47ec9af97 100644 --- a/src/testRunner/unittests/tsbuild/moduleResolution.ts +++ b/src/testRunner/unittests/tsbuild/moduleResolution.ts @@ -60,7 +60,8 @@ namespace ts.tscWatch { verifyTscWatch({ scenario: "moduleResolution", - subScenario: `resolves specifier in output declaration file from referenced project correctly with preserveSymlinks`, + subScenario: + `resolves specifier in output declaration file from referenced project correctly with preserveSymlinks`, sys: () => sys({ preserveSymlinks: true }), commandLineArgs: ["-b", "packages/pkg1", "--verbose", "--traceResolution"], changes: emptyArray, @@ -68,7 +69,8 @@ namespace ts.tscWatch { verifyTsc({ scenario: "moduleResolution", - subScenario: `type reference resolution uses correct options for different resolution options referenced project`, + subScenario: + `type reference resolution uses correct options for different resolution options referenced project`, fs: () => loadProjectFromFiles({ "/src/packages/pkg1_index.ts": `export const theNum: TheNum = "type1";`, @@ -84,7 +86,13 @@ namespace ts.tscWatch { }), "/src/packages/typeroot2/sometype/index.d.ts": Utils.dedent`declare type TheNum2 = "type2";`, }), - commandLineArgs: ["-b", "/src/packages/pkg1.tsconfig.json", "/src/packages/pkg2.tsconfig.json", "--verbose", "--traceResolution"], + commandLineArgs: [ + "-b", + "/src/packages/pkg1.tsconfig.json", + "/src/packages/pkg2.tsconfig.json", + "--verbose", + "--traceResolution", + ], }); }); } diff --git a/src/testRunner/unittests/tsbuild/noEmit.ts b/src/testRunner/unittests/tsbuild/noEmit.ts index 89a4ebae2ac02..2f955cdf6803f 100644 --- a/src/testRunner/unittests/tsbuild/noEmit.ts +++ b/src/testRunner/unittests/tsbuild/noEmit.ts @@ -26,7 +26,12 @@ namespace ts { function verifyNoEmit(subScenario: string, aTsContent: string) { verifyNoEmitWorker(subScenario, aTsContent, ["--b", "/src/tsconfig.json", "-v"]); - verifyNoEmitWorker(`${subScenario} with incremental`, aTsContent, ["--b", "/src/tsconfig.json", "-v", "--incremental"]); + verifyNoEmitWorker(`${subScenario} with incremental`, aTsContent, [ + "--b", + "/src/tsconfig.json", + "-v", + "--incremental", + ]); } verifyNoEmit("syntax errors", `const a = "hello`); diff --git a/src/testRunner/unittests/tsbuild/outFile.ts b/src/testRunner/unittests/tsbuild/outFile.ts index d3ef9bd4c6dfb..3a4456a7c76eb 100644 --- a/src/testRunner/unittests/tsbuild/outFile.ts +++ b/src/testRunner/unittests/tsbuild/outFile.ts @@ -58,9 +58,9 @@ namespace ts { baselineReadFileCalls: !baselineOnly, edits, }; - return edits.length ? - verifyTscWithEdits(input) : - verifyTsc(input); + return edits.length + ? verifyTscWithEdits(input) + : verifyTsc(input); } // Verify initial + incremental edits @@ -392,7 +392,11 @@ namespace ts { ); } - function stripInternalScenario(fs: vfs.FileSystem, removeCommentsDisabled?: boolean, jsDocStyle?: boolean) { + function stripInternalScenario( + fs: vfs.FileSystem, + removeCommentsDisabled?: boolean, + jsDocStyle?: boolean, + ) { const internal: string = jsDocStyle ? `/**@internal*/` : `/*@internal*/`; if (removeCommentsDisabled) { diableRemoveCommentsInAll(fs); @@ -435,14 +439,16 @@ ${internal} enum internalEnum { a, b, c }`, verifyOutFileScenario({ subScenario: "stripInternal", modifyFs: stripInternalScenario, - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), }); // Verify ignore dtsChanged verifyOutFileScenario({ subScenario: "stripInternal with comments emit enabled", modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ true), - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), ignoreDtsChanged: true, baselineOnly: true, }); @@ -451,7 +457,8 @@ ${internal} enum internalEnum { a, b, c }`, verifyOutFileScenario({ subScenario: "stripInternal jsdoc style comment", modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true), - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"), ignoreDtsChanged: true, baselineOnly: true, }); @@ -476,7 +483,11 @@ ${internal} enum internalEnum { a, b, c }`, replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../first", "prepend": true },`, ""); } - function stripInternalWithDependentOrder(fs: vfs.FileSystem, removeCommentsDisabled?: boolean, jsDocStyle?: boolean) { + function stripInternalWithDependentOrder( + fs: vfs.FileSystem, + removeCommentsDisabled?: boolean, + jsDocStyle?: boolean, + ) { stripInternalScenario(fs, removeCommentsDisabled, jsDocStyle); makeOneTwoThreeDependOrder(fs); } @@ -485,14 +496,17 @@ ${internal} enum internalEnum { a, b, c }`, verifyOutFileScenario({ subScenario: "stripInternal when one-two-three are prepended in order", modifyFs: stripInternalWithDependentOrder, - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), }); // Verify ignore dtsChanged verifyOutFileScenario({ - subScenario: "stripInternal with comments emit enabled when one-two-three are prepended in order", + subScenario: + "stripInternal with comments emit enabled when one-two-three are prepended in order", modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ true), - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), ignoreDtsChanged: true, baselineOnly: true, }); @@ -500,16 +514,20 @@ ${internal} enum internalEnum { a, b, c }`, // Verify ignore dtsChanged verifyOutFileScenario({ subScenario: "stripInternal jsdoc style comment when one-two-three are prepended in order", - modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true), - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"), + modifyFs: fs => + stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"), ignoreDtsChanged: true, baselineOnly: true, }); // Verify ignore dtsChanged verifyOutFileScenario({ - subScenario: "stripInternal jsdoc style with comments emit enabled when one-two-three are prepended in order", - modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ true, /*jsDocStyle*/ true), + subScenario: + "stripInternal jsdoc style with comments emit enabled when one-two-three are prepended in order", + modifyFs: fs => + stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ true, /*jsDocStyle*/ true), ignoreDtsChanged: true, baselineOnly: true, }); @@ -673,13 +691,38 @@ ${internal} enum internalEnum { a, b, c }`, commandLineArgs: ["--b", "/src/third", "--verbose"], modifyFs: fs => { // No prepend - replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../first", "prepend": true }`, `{ "path": "../first" }`); - replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../second", "prepend": true }`, `{ "path": "../second" }`); + replaceText( + fs, + "/src/third/tsconfig.json", + `{ "path": "../first", "prepend": true }`, + `{ "path": "../first" }`, + ); + replaceText( + fs, + "/src/third/tsconfig.json", + `{ "path": "../second", "prepend": true }`, + `{ "path": "../second" }`, + ); // Non Modules - replaceText(fs, "/src/first/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`); - replaceText(fs, "/src/second/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`); - replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`); + replaceText( + fs, + "/src/first/tsconfig.json", + `"composite": true,`, + `"composite": true, "module": "none",`, + ); + replaceText( + fs, + "/src/second/tsconfig.json", + `"composite": true,`, + `"composite": true, "module": "none",`, + ); + replaceText( + fs, + "/src/third/tsconfig.json", + `"composite": true,`, + `"composite": true, "module": "none",`, + ); // Own file emit replaceText(fs, "/src/first/tsconfig.json", `"outFile": "./bin/first-output.js",`, ""); diff --git a/src/testRunner/unittests/tsbuild/outputPaths.ts b/src/testRunner/unittests/tsbuild/outputPaths.ts index f0afa5de0da38..6003b00dc2efd 100644 --- a/src/testRunner/unittests/tsbuild/outputPaths.ts +++ b/src/testRunner/unittests/tsbuild/outputPaths.ts @@ -2,7 +2,8 @@ namespace ts { describe("unittests:: tsbuild - output file paths", () => { const noChangeProject: TestTscEdit = { modifyFs: noop, - subScenario: "Normal build without change, that does not block emit on error to show files that get emitted", + subScenario: + "Normal build without change, that does not block emit on error to show files that get emitted", commandLineArgs: ["-p", "/src/tsconfig.json"], }; const edits: TestTscEdit[] = [ @@ -10,7 +11,10 @@ namespace ts { noChangeProject, ]; - function verify(input: Pick, expectedOuptutNames: readonly string[]) { + function verify( + input: Pick, + expectedOuptutNames: readonly string[], + ) { verifyTscWithEdits({ scenario: "outputPaths", commandLineArgs: ["--b", "/src/tsconfig.json", "-v"], @@ -18,11 +22,20 @@ namespace ts { }); it("verify getOutputFileNames", () => { - const sys = new fakes.System(input.fs().makeReadonly(), { executingFilePath: "/lib/tsc" }) as TscCompileSystem; + const sys = new fakes.System(input.fs().makeReadonly(), { + executingFilePath: "/lib/tsc", + }) as TscCompileSystem; assert.deepEqual( getOutputFileNames( - parseConfigFileWithSystem("/src/tsconfig.json", {}, /*extendedConfigCache*/ undefined, {}, sys, noop)!, + parseConfigFileWithSystem( + "/src/tsconfig.json", + {}, + /*extendedConfigCache*/ undefined, + {}, + sys, + noop, + )!, "/src/src/index.ts", /*ignoreCase*/ false, ), diff --git a/src/testRunner/unittests/tsbuild/publicApi.ts b/src/testRunner/unittests/tsbuild/publicApi.ts index 0f2fcc4c41611..f2eddf35b20c4 100644 --- a/src/testRunner/unittests/tsbuild/publicApi.ts +++ b/src/testRunner/unittests/tsbuild/publicApi.ts @@ -52,12 +52,18 @@ export function f22() { } // trailing`, /*createProgram*/ undefined, createDiagnosticReporter(sys, /*pretty*/ true), createBuilderStatusReporter(sys, /*pretty*/ true), - (errorCount, filesInError) => sys.write(getErrorSummaryText(errorCount, filesInError, sys.newLine, sys)), + (errorCount, filesInError) => + sys.write(getErrorSummaryText(errorCount, filesInError, sys.newLine, sys)), ); buildHost.afterProgramEmitAndDiagnostics = cb; buildHost.afterEmitBundle = cb; const builder = createSolutionBuilder(buildHost, [commandLineArgs[1]], { verbose: true }); - const exitStatus = builder.build(/*project*/ undefined, /*cancellationToken*/ undefined, /*writeFile*/ undefined, getCustomTransformers); + const exitStatus = builder.build( + /*project*/ undefined, + /*cancellationToken*/ undefined, + /*writeFile*/ undefined, + getCustomTransformers, + ); sys.exit(exitStatus); sys.write(`exitCode:: ExitStatus.${ExitStatus[sys.exitCode as ExitStatus]}\n`); const baseline: string[] = []; @@ -91,7 +97,12 @@ ${patch ? vfs.formatPatch(patch) : ""}`, } } function visitFunction(node: FunctionDeclaration) { - addSyntheticLeadingComment(node, SyntaxKind.MultiLineCommentTrivia, `@before${project}`, /*hasTrailingNewLine*/ true); + addSyntheticLeadingComment( + node, + SyntaxKind.MultiLineCommentTrivia, + `@before${project}`, + /*hasTrailingNewLine*/ true, + ); return node; } }; diff --git a/src/testRunner/unittests/tsbuild/resolveJsonModule.ts b/src/testRunner/unittests/tsbuild/resolveJsonModule.ts index cb239320dca67..99d91d22fb5ec 100644 --- a/src/testRunner/unittests/tsbuild/resolveJsonModule.ts +++ b/src/testRunner/unittests/tsbuild/resolveJsonModule.ts @@ -59,7 +59,13 @@ export default hello.hello`, subScenario: "sourcemap", fs: () => projFs, commandLineArgs: ["--b", "src/tsconfig_withFiles.json", "--verbose", "--explainFiles"], - modifyFs: fs => replaceText(fs, "src/tsconfig_withFiles.json", `"composite": true,`, `"composite": true, "sourceMap": true,`), + modifyFs: fs => + replaceText( + fs, + "src/tsconfig_withFiles.json", + `"composite": true,`, + `"composite": true, "sourceMap": true,`, + ), edits: noChangeOnlyRuns, }); diff --git a/src/testRunner/unittests/tsbuild/sample.ts b/src/testRunner/unittests/tsbuild/sample.ts index 68d9f4e99e52a..e312a7242c7ad 100644 --- a/src/testRunner/unittests/tsbuild/sample.ts +++ b/src/testRunner/unittests/tsbuild/sample.ts @@ -54,7 +54,12 @@ namespace ts { fs.writeFileSync( "/src/logic/tsconfig.json", JSON.stringify({ - compilerOptions: { composite: true, declaration: true, sourceMap: true, declarationDir: "out/decls" }, + compilerOptions: { + composite: true, + declaration: true, + sourceMap: true, + declarationDir: "out/decls", + }, references: [{ path: "../core" }], }), ), @@ -141,7 +146,13 @@ namespace ts { }, { subScenario: "rebuilds when tsconfig changes", - modifyFs: fs => replaceText(fs, "/src/tests/tsconfig.json", `"composite": true`, `"composite": true, "target": "es3"`), + modifyFs: fs => + replaceText( + fs, + "/src/tests/tsconfig.json", + `"composite": true`, + `"composite": true, "target": "es3"`, + ), }, ], }); @@ -207,10 +218,16 @@ namespace ts { verifyTscCompileLike(testTscCompileLike, { scenario: "sample1", - subScenario: "does not rebuild if there is no program and bundle in the ts build info event if version doesnt match ts version", + subScenario: + "does not rebuild if there is no program and bundle in the ts build info event if version doesnt match ts version", fs: () => { const fs = projFs.shadow(); - const host = fakes.SolutionBuilderHost.create(fs, /*options*/ undefined, /*setParentNodes*/ undefined, createAbstractBuilder); + const host = fakes.SolutionBuilderHost.create( + fs, + /*options*/ undefined, + /*setParentNodes*/ undefined, + createAbstractBuilder, + ); const builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); builder.build(); fs.makeReadonly(); @@ -231,12 +248,21 @@ namespace ts { fs: () => projFs, commandLineArgs: ["--b", "/src/tests", "--verbose"], modifyFs: fs => { - fs.writeFileSync("/src/tests/tsconfig.base.json", JSON.stringify({ compilerOptions: { target: "es3" } })); - replaceText(fs, "/src/tests/tsconfig.json", `"references": [`, `"extends": "./tsconfig.base.json", "references": [`); + fs.writeFileSync( + "/src/tests/tsconfig.base.json", + JSON.stringify({ compilerOptions: { target: "es3" } }), + ); + replaceText( + fs, + "/src/tests/tsconfig.json", + `"references": [`, + `"extends": "./tsconfig.base.json", "references": [`, + ); }, edits: [{ subScenario: "incremental-declaration-changes", - modifyFs: fs => fs.writeFileSync("/src/tests/tsconfig.base.json", JSON.stringify({ compilerOptions: {} })), + modifyFs: fs => + fs.writeFileSync("/src/tests/tsconfig.base.json", JSON.stringify({ compilerOptions: {} })), }], }); @@ -299,7 +325,10 @@ namespace ts { verifyBuildNextResult(); // logic verifyBuildNextResult(); // tests verifyBuildNextResult(); // All Done - Harness.Baseline.runBaseline(`tsbuild/sample1/building-using-getNextInvalidatedProject.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tsbuild/sample1/building-using-getNextInvalidatedProject.js`, + baseline.join("\r\n"), + ); function verifyBuildNextResult() { const project = builder.getNextInvalidatedProject(); @@ -369,7 +398,11 @@ namespace ts { ); const host = createSolutionBuilderHostForBaseline(system); - const builder = createSolutionBuilder(host, [testsConfig.path], { dry: false, force: false, verbose: false }); + const builder = createSolutionBuilder(host, [testsConfig.path], { + dry: false, + force: false, + verbose: false, + }); builder.build(); baselineState("Build of project"); @@ -384,7 +417,10 @@ namespace ts { // Rebuild this project system.appendFile(logicIndex.path, `export class cNew {}`); verifyInvalidation("Dts change to Logic"); - Harness.Baseline.runBaseline(`tsbuild/sample1/invalidates-projects-correctly.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tsbuild/sample1/invalidates-projects-correctly.js`, + baseline.join("\r\n"), + ); function verifyInvalidation(heading: string) { // Rebuild this project @@ -514,7 +550,13 @@ class someClass2 { }`, ), edits: [{ subScenario: "incremental-declaration-changes", - modifyFs: fs => replaceText(fs, "/src/core/tsconfig.json", `"incremental": true,`, `"incremental": true, "declaration": true,`), + modifyFs: fs => + replaceText( + fs, + "/src/core/tsconfig.json", + `"incremental": true,`, + `"incremental": true, "declaration": true,`, + ), }], }); @@ -570,7 +612,8 @@ class someClass2 { }`, ), edits: [{ subScenario: "incremental-declaration-changes", - modifyFs: fs => replaceText(fs, "/src/core/tsconfig.json", `"module": "commonjs"`, `"module": "amd"`), + modifyFs: fs => + replaceText(fs, "/src/core/tsconfig.json", `"module": "commonjs"`, `"module": "amd"`), }], }); @@ -599,7 +642,13 @@ class someClass2 { }`, ), edits: [{ subScenario: "incremental-declaration-changes", - modifyFs: fs => replaceText(fs, "/src/tests/tsconfig.json", `"esModuleInterop": false`, `"esModuleInterop": true`), + modifyFs: fs => + replaceText( + fs, + "/src/tests/tsconfig.json", + `"esModuleInterop": false`, + `"esModuleInterop": true`, + ), }], }); diff --git a/src/testRunner/unittests/tsbuildWatch/demo.ts b/src/testRunner/unittests/tsbuildWatch/demo.ts index 30a55d653d702..26e1f47c981f3 100644 --- a/src/testRunner/unittests/tsbuildWatch/demo.ts +++ b/src/testRunner/unittests/tsbuildWatch/demo.ts @@ -13,7 +13,10 @@ namespace ts.tscWatch { zooFiles = subProjectFiles("zoo", ["tsconfig.json", "zoo.ts"]); solutionFile = projectFile("tsconfig.json"); baseConfig = projectFile("tsconfig-base.json"); - allFiles = [...coreFiles, ...animalFiles, ...zooFiles, solutionFile, baseConfig, { path: libFile.path, content: libContent }]; + allFiles = [...coreFiles, ...animalFiles, ...zooFiles, solutionFile, baseConfig, { + path: libFile.path, + content: libContent, + }]; }); after(() => { diff --git a/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts b/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts index 0c486826b8200..7c20dafb6dcce 100644 --- a/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts +++ b/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts @@ -7,7 +7,10 @@ namespace ts.tscWatch { createWatchedSystem( [ { path: `${projectRoot}/project1/index.ts`, content: `import { foo } from "file";` }, - { path: `${projectRoot}/project1/node_modules/file/index.d.ts`, content: "export const foo = 10;" }, + { + path: `${projectRoot}/project1/node_modules/file/index.d.ts`, + content: "export const foo = 10;", + }, { path: `${projectRoot}/project1/tsconfig.json`, content: JSON.stringify({ @@ -24,8 +27,14 @@ namespace ts.tscWatch { files: ["index.ts"], }), }, - { path: `${projectRoot}/node_modules/@types/foo/index.d.ts`, content: "export const foo = 10;" }, - { path: `${projectRoot}/node_modules/@types/bar/index.d.ts`, content: "export const bar = 10;" }, + { + path: `${projectRoot}/node_modules/@types/foo/index.d.ts`, + content: "export const foo = 10;", + }, + { + path: `${projectRoot}/node_modules/@types/bar/index.d.ts`, + content: "export const bar = 10;", + }, { path: `${projectRoot}/tsconfig.json`, content: JSON.stringify({ @@ -55,7 +64,8 @@ namespace ts.tscWatch { verifyTscWatch({ scenario: "moduleResolution", - subScenario: `resolves specifier in output declaration file from referenced project correctly with cts and mts extensions`, + subScenario: + `resolves specifier in output declaration file from referenced project correctly with cts and mts extensions`, sys: () => createWatchedSystem([ { @@ -120,24 +130,35 @@ namespace ts.tscWatch { changes: [ { caption: "reports import errors after change to package file", - change: sys => replaceFileText(sys, `${projectRoot}/packages/pkg1/package.json`, `"module"`, `"commonjs"`), + change: sys => + replaceFileText(sys, `${projectRoot}/packages/pkg1/package.json`, `"module"`, `"commonjs"`), timeouts: runQueuedTimeoutCallbacks, }, { caption: "removes those errors when a package file is changed back", - change: sys => replaceFileText(sys, `${projectRoot}/packages/pkg1/package.json`, `"commonjs"`, `"module"`), + change: sys => + replaceFileText(sys, `${projectRoot}/packages/pkg1/package.json`, `"commonjs"`, `"module"`), timeouts: runQueuedTimeoutCallbacks, }, { caption: "reports import errors after change to package file", - change: sys => replaceFileText(sys, `${projectRoot}/packages/pkg1/package.json`, `"module"`, `"commonjs"`), + change: sys => + replaceFileText(sys, `${projectRoot}/packages/pkg1/package.json`, `"module"`, `"commonjs"`), timeouts: runQueuedTimeoutCallbacks, }, { caption: "removes those errors when a package file is changed to cjs extensions", change: sys => { - replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `"build/index.js"`, `"build/index.cjs"`); - sys.renameFile(`${projectRoot}/packages/pkg2/index.ts`, `${projectRoot}/packages/pkg2/index.cts`); + replaceFileText( + sys, + `${projectRoot}/packages/pkg2/package.json`, + `"build/index.js"`, + `"build/index.cjs"`, + ); + sys.renameFile( + `${projectRoot}/packages/pkg2/index.ts`, + `${projectRoot}/packages/pkg2/index.cts`, + ); }, timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // building pkg2 @@ -215,12 +236,14 @@ namespace ts.tscWatch { changes: [ { caption: "reports import errors after change to package file", - change: sys => replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `index.js`, `other.js`), + change: sys => + replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `index.js`, `other.js`), timeouts: runQueuedTimeoutCallbacks, }, { caption: "removes those errors when a package file is changed back", - change: sys => replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `other.js`, `index.js`), + change: sys => + replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `other.js`, `index.js`), timeouts: runQueuedTimeoutCallbacks, }, ], diff --git a/src/testRunner/unittests/tsbuildWatch/noEmit.ts b/src/testRunner/unittests/tsbuildWatch/noEmit.ts index 4f442e013383b..39c4756c72a4f 100644 --- a/src/testRunner/unittests/tsbuildWatch/noEmit.ts +++ b/src/testRunner/unittests/tsbuildWatch/noEmit.ts @@ -10,7 +10,10 @@ namespace ts.tscWatch { { path: libFile.path, content: libContent }, { path: `${projectRoot}/a.js`, content: "" }, { path: `${projectRoot}/b.ts`, content: "" }, - { path: `${projectRoot}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { allowJs: true, noEmit: true } }) }, + { + path: `${projectRoot}/tsconfig.json`, + content: JSON.stringify({ compilerOptions: { allowJs: true, noEmit: true } }), + }, ], { currentDirectory: projectRoot }, ), diff --git a/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts b/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts index 91b76c4e6bf17..f5238586e26a4 100644 --- a/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts +++ b/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts @@ -3,7 +3,8 @@ namespace ts.tscWatch { function change(caption: string, content: string): TscWatchCompileChange { return { caption, - change: sys => sys.writeFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, content), + change: sys => + sys.writeFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, content), // build project timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout, }; @@ -11,7 +12,11 @@ namespace ts.tscWatch { const noChange: TscWatchCompileChange = { caption: "No change", - change: sys => sys.writeFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, sys.readFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`)!), + change: sys => + sys.writeFile( + `${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, + sys.readFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`)!, + ), // build project timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout, }; diff --git a/src/testRunner/unittests/tsbuildWatch/programUpdates.ts b/src/testRunner/unittests/tsbuildWatch/programUpdates.ts index 35f7a1d70ffae..e3abdedc63689 100644 --- a/src/testRunner/unittests/tsbuildWatch/programUpdates.ts +++ b/src/testRunner/unittests/tsbuildWatch/programUpdates.ts @@ -9,7 +9,12 @@ namespace ts.tscWatch { } type ReadonlyFile = Readonly; /** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */ - type SubProjectFiles = [tsconfig: ReadonlyFile, index: ReadonlyFile] | [tsconfig: ReadonlyFile, index: ReadonlyFile, anotherModule: ReadonlyFile, someDecl: ReadonlyFile]; + type SubProjectFiles = [tsconfig: ReadonlyFile, index: ReadonlyFile] | [ + tsconfig: ReadonlyFile, + index: ReadonlyFile, + anotherModule: ReadonlyFile, + someDecl: ReadonlyFile, + ]; function projectFilePath(subProject: SubProject, baseFileName: string) { return `${TestFSWithWatch.getTsBuildProjectFilePath("sample1", subProject)}/${baseFileName.toLowerCase()}`; } @@ -29,10 +34,15 @@ namespace ts.tscWatch { return [tsconfig, index, anotherModule, someDecl]; } - function changeFile(fileName: string | (() => string), content: string | (() => string), caption: string): TscWatchCompileChange { + function changeFile( + fileName: string | (() => string), + content: string | (() => string), + caption: string, + ): TscWatchCompileChange { return { caption, - change: sys => sys.writeFile(isString(fileName) ? fileName : fileName(), isString(content) ? content : content()), + change: sys => + sys.writeFile(isString(fileName) ? fileName : fileName(), isString(content) ? content : content()), timeouts: checkSingleTimeoutQueueLengthAndRun, // Builds core }; } @@ -72,9 +82,13 @@ namespace ts.tscWatch { }); it("verify building references watches only those projects", () => { - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(allFiles, { currentDirectory: projectsLocation })); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem(allFiles, { currentDirectory: projectsLocation }), + ); const host = createSolutionBuilderWithWatchHostForBaseline(sys, cb); - const solutionBuilder = createSolutionBuilderWithWatch(host, [`sample1/${SubProject.tests}`], { watch: true }); + const solutionBuilder = createSolutionBuilderWithWatch(host, [`sample1/${SubProject.tests}`], { + watch: true, + }); solutionBuilder.buildReferences(`sample1/${SubProject.tests}`); runWatchBaseline({ scenario: "programUpdates", @@ -266,7 +280,9 @@ export class someClass2 { }`), path: logic[1].path, content: `function bar() { return foo() + 1 };`, }; - return createWatchedSystem([libFile, coreTsConfig, coreIndex, logicTsConfig, logicIndex], { currentDirectory: projectsLocation }); + return createWatchedSystem([libFile, coreTsConfig, coreIndex, logicTsConfig, logicIndex], { + currentDirectory: projectsLocation, + }); }, changes: [ changeCore(() => @@ -300,7 +316,8 @@ export function createSomeObject(): SomeObject }; verifyTscWatch({ scenario: "programUpdates", - subScenario: "when referenced project change introduces error in the down stream project and then fixes it", + subScenario: + "when referenced project change introduces error in the down stream project and then fixes it", commandLineArgs: ["-b", "-w", "App"], sys: () => { const libraryTsconfig: File = { @@ -418,7 +435,8 @@ let x: string = 10;`, const changeFileWithoutError: TscWatchCompileChange = { caption: "Change fileWithoutError", - change: sys => sys.writeFile(fileWithoutError.path, fileWithoutError.content.replace(/myClass/g, "myClass2")), + change: sys => + sys.writeFile(fileWithoutError.path, fileWithoutError.content.replace(/myClass/g, "myClass2")), timeouts: incrementalBuild, }; @@ -459,7 +477,8 @@ let x: string = 10;`, verifyTscWatch({ scenario: "programUpdates", - subScenario: "reportErrors/declarationEmitErrors/introduceError/when fixing errors only changed file is emitted", + subScenario: + "reportErrors/declarationEmitErrors/introduceError/when fixing errors only changed file is emitted", commandLineArgs: ["-b", "-w", subProject], sys: () => createWatchedSystem( @@ -474,7 +493,8 @@ let x: string = 10;`, verifyTscWatch({ scenario: "programUpdates", - subScenario: "reportErrors/declarationEmitErrors/introduceError/when file with no error changes", + subScenario: + "reportErrors/declarationEmitErrors/introduceError/when file with no error changes", commandLineArgs: ["-b", "-w", subProject], sys: () => createWatchedSystem( @@ -583,7 +603,10 @@ export function someFn() { }`, commandLineArgs: ["-b", "-w", `sample1/${SubProject.core}`, "-verbose"], sys: () => { const [coreConfig, ...rest] = core; - const newCoreConfig: File = { path: coreConfig.path, content: JSON.stringify({ compilerOptions: { composite: true, outDir: "outDir" } }) }; + const newCoreConfig: File = { + path: coreConfig.path, + content: JSON.stringify({ compilerOptions: { composite: true, outDir: "outDir" } }), + }; return createWatchedSystem([libFile, newCoreConfig, ...rest], { currentDirectory: projectsLocation }); }, changes: [ diff --git a/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts b/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts index e469bc7c3fe3c..b0a1f08d5c6f8 100644 --- a/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts +++ b/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts @@ -20,9 +20,9 @@ namespace ts.tscWatch { path: `${projectRoot}/pkg${index}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true }, - references: index === 0 ? - undefined : - [{ path: `../pkg0` }], + references: index === 0 + ? undefined + : [{ path: `../pkg0` }], }), }, ]; diff --git a/src/testRunner/unittests/tsbuildWatch/publicApi.ts b/src/testRunner/unittests/tsbuildWatch/publicApi.ts index 6077ddb5e04b4..bfde5d53ac992 100644 --- a/src/testRunner/unittests/tsbuildWatch/publicApi.ts +++ b/src/testRunner/unittests/tsbuildWatch/publicApi.ts @@ -40,7 +40,11 @@ export enum e2 { } export function f22() { } // trailing`, }; const commandLineArgs = ["--b", "--w"]; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([libFile, solution, sharedConfig, sharedIndex, webpackConfig, webpackIndex], { currentDirectory: projectRoot })); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([libFile, solution, sharedConfig, sharedIndex, webpackConfig, webpackIndex], { + currentDirectory: projectRoot, + }), + ); const buildHost = createSolutionBuilderWithWatchHostForBaseline(sys, cb); buildHost.getCustomTransformers = getCustomTransformers; const builder = createSolutionBuilderWithWatch(buildHost, [solution.path], { verbose: true }); @@ -79,7 +83,12 @@ export function f22() { } // trailing`, } } function visitFunction(node: FunctionDeclaration) { - addSyntheticLeadingComment(node, SyntaxKind.MultiLineCommentTrivia, `@before${project}`, /*hasTrailingNewLine*/ true); + addSyntheticLeadingComment( + node, + SyntaxKind.MultiLineCommentTrivia, + `@before${project}`, + /*hasTrailingNewLine*/ true, + ); return node; } }; diff --git a/src/testRunner/unittests/tsbuildWatch/reexport.ts b/src/testRunner/unittests/tsbuildWatch/reexport.ts index f104121ca9953..f330829463c1d 100644 --- a/src/testRunner/unittests/tsbuildWatch/reexport.ts +++ b/src/testRunner/unittests/tsbuildWatch/reexport.ts @@ -23,7 +23,13 @@ namespace ts.tscWatch { changes: [ { caption: "Introduce error", - change: sys => replaceFileText(sys, `${TestFSWithWatch.tsbuildProjectsLocation}/reexport/src/pure/session.ts`, "// ", ""), + change: sys => + replaceFileText( + sys, + `${TestFSWithWatch.tsbuildProjectsLocation}/reexport/src/pure/session.ts`, + "// ", + "", + ), timeouts: sys => { sys.checkTimeoutQueueLengthAndRun(1); // build src/pure sys.checkTimeoutQueueLengthAndRun(1); // build src/main and src @@ -32,7 +38,13 @@ namespace ts.tscWatch { }, { caption: "Fix error", - change: sys => replaceFileText(sys, `${TestFSWithWatch.tsbuildProjectsLocation}/reexport/src/pure/session.ts`, "bar: ", "// bar: "), + change: sys => + replaceFileText( + sys, + `${TestFSWithWatch.tsbuildProjectsLocation}/reexport/src/pure/session.ts`, + "bar: ", + "// bar: ", + ), timeouts: sys => { sys.checkTimeoutQueueLengthAndRun(1); // build src/pure sys.checkTimeoutQueueLengthAndRun(1); // build src/main and src diff --git a/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts b/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts index 68e30d9f2b549..bfd0bf0dc3f96 100644 --- a/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts +++ b/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts @@ -10,11 +10,16 @@ namespace ts.tscWatch { }; const allPkgFiles = pkgs(pkgFiles); - const system = createWatchedSystem([libFile, typing, ...flatArray(allPkgFiles)], { currentDirectory: project }); + const system = createWatchedSystem([libFile, typing, ...flatArray(allPkgFiles)], { + currentDirectory: project, + }); writePkgReferences(system); const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(system); const host = createSolutionBuilderWithWatchHostForBaseline(sys, cb); - const solutionBuilder = createSolutionBuilderWithWatch(host, ["tsconfig.json"], { watch: true, verbose: true }); + const solutionBuilder = createSolutionBuilderWithWatch(host, ["tsconfig.json"], { + watch: true, + verbose: true, + }); solutionBuilder.build(); runWatchBaseline({ scenario: "watchEnvironment", diff --git a/src/testRunner/unittests/tsc/cancellationToken.ts b/src/testRunner/unittests/tsc/cancellationToken.ts index ead140e0360c2..7be72eab19ad4 100644 --- a/src/testRunner/unittests/tsc/cancellationToken.ts +++ b/src/testRunner/unittests/tsc/cancellationToken.ts @@ -105,7 +105,10 @@ namespace ts.tscWatch { noChange("Clean build"); baselineCleanBuild(); - Harness.Baseline.runBaseline(`tsc/cancellationToken/${scenario.split(" ").join("-")}.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tsc/cancellationToken/${scenario.split(" ").join("-")}.js`, + baseline.join("\r\n"), + ); function noChange(caption: string) { oldSnap = applyChange(sys, baseline, noop, caption); @@ -117,13 +120,13 @@ namespace ts.tscWatch { } function createIncrementalProgram() { - builderProgram = useBuildInfo ? - ts.createIncrementalProgram({ + builderProgram = useBuildInfo + ? ts.createIncrementalProgram({ rootNames: parsedConfig.fileNames, options: parsedConfig.options, host, - }) : - builderProgram = builderProgram = createEmitAndSemanticDiagnosticsBuilderProgram( + }) + : builderProgram = builderProgram = createEmitAndSemanticDiagnosticsBuilderProgram( parsedConfig.fileNames, parsedConfig.options, host, diff --git a/src/testRunner/unittests/tsc/composite.ts b/src/testRunner/unittests/tsc/composite.ts index cc9570e85bf86..27d5c272b363a 100644 --- a/src/testRunner/unittests/tsc/composite.ts +++ b/src/testRunner/unittests/tsc/composite.ts @@ -66,7 +66,8 @@ namespace ts { verifyTsc({ scenario: "composite", - subScenario: "when setting composite false and tsbuildinfo as null on command line but has tsbuild info in config", + subScenario: + "when setting composite false and tsbuildinfo as null on command line but has tsbuild info in config", fs: () => loadProjectFromFiles({ "/src/project/src/main.ts": "export const x = 10;", diff --git a/src/testRunner/unittests/tsc/declarationEmit.ts b/src/testRunner/unittests/tsc/declarationEmit.ts index cb12eed00ec8f..1bce75d406811 100644 --- a/src/testRunner/unittests/tsc/declarationEmit.ts +++ b/src/testRunner/unittests/tsc/declarationEmit.ts @@ -7,13 +7,22 @@ namespace ts { changeCaseFileTestPath: (path: string) => boolean; } - function changeCaseFile(file: TestFSWithWatch.FileOrFolderOrSymLink, testPath: (path: string) => boolean, replacePath: (path: string) => string): TestFSWithWatch.FileOrFolderOrSymLink { - return !TestFSWithWatch.isSymLink(file) || !testPath(file.symLink) ? - testPath(file.path) ? { ...file, path: replacePath(file.path) } : file : - { path: testPath(file.path) ? replacePath(file.path) : file.path, symLink: replacePath(file.symLink) }; + function changeCaseFile( + file: TestFSWithWatch.FileOrFolderOrSymLink, + testPath: (path: string) => boolean, + replacePath: (path: string) => string, + ): TestFSWithWatch.FileOrFolderOrSymLink { + return !TestFSWithWatch.isSymLink(file) || !testPath(file.symLink) + ? testPath(file.path) ? { ...file, path: replacePath(file.path) } : file + : { + path: testPath(file.path) ? replacePath(file.path) : file.path, + symLink: replacePath(file.symLink), + }; } - function verifyDeclarationEmit({ subScenario, files, rootProject, changeCaseFileTestPath }: VerifyDeclarationEmitInput) { + function verifyDeclarationEmit( + { subScenario, files, rootProject, changeCaseFileTestPath }: VerifyDeclarationEmitInput, + ) { describe(subScenario, () => { tscWatch.verifyTscWatch({ scenario: "declarationEmit", @@ -31,7 +40,9 @@ namespace ts { subScenario: caseChangeScenario, sys: () => tscWatch.createWatchedSystem( - files.map(f => changeCaseFile(f, changeCaseFileTestPath, str => str.replace("myproject", "myProject"))), + files.map(f => + changeCaseFile(f, changeCaseFileTestPath, str => str.replace("myproject", "myProject")) + ), { currentDirectory: tscWatch.projectRoot }, ), commandLineArgs: ["-p", rootProject, "--explainFiles"], @@ -112,21 +123,37 @@ namespace ts { rootProject: "plugin-one", files: [ { path: `${tscWatch.projectRoot}/plugin-two/index.d.ts`, content: pluginTwoDts() }, - { path: `${tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() }, - { path: `${tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() }, + { + path: `${tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/package.json`, + content: fsaPackageJson(), + }, + { + path: `${tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/index.d.ts`, + content: fsaIndex(), + }, { path: `${tscWatch.projectRoot}/plugin-one/tsconfig.json`, content: pluginOneConfig() }, { path: `${tscWatch.projectRoot}/plugin-one/index.ts`, content: pluginOneIndex() }, { path: `${tscWatch.projectRoot}/plugin-one/action.ts`, content: pluginOneAction() }, - { path: `${tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() }, - { path: `${tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() }, - { path: `${tscWatch.projectRoot}/plugin-one/node_modules/plugin-two`, symLink: `${tscWatch.projectRoot}/plugin-two` }, + { + path: `${tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/package.json`, + content: fsaPackageJson(), + }, + { + path: `${tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/index.d.ts`, + content: fsaIndex(), + }, + { + path: `${tscWatch.projectRoot}/plugin-one/node_modules/plugin-two`, + symLink: `${tscWatch.projectRoot}/plugin-two`, + }, tscWatch.libFile, ], changeCaseFileTestPath: str => stringContains(str, "/plugin-two"), }); verifyDeclarationEmit({ - subScenario: "when same version is referenced through source and another symlinked package with indirect link", + subScenario: + "when same version is referenced through source and another symlinked package with indirect link", rootProject: "plugin-one", files: [ { @@ -138,18 +165,33 @@ namespace ts { }), }, { path: `${tscWatch.projectRoot}/plugin-two/dist/commonjs/index.d.ts`, content: pluginTwoDts() }, - { path: `${tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() }, - { path: `${tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() }, + { + path: `${tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/package.json`, + content: fsaPackageJson(), + }, + { + path: `${tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/index.d.ts`, + content: fsaIndex(), + }, { path: `${tscWatch.projectRoot}/plugin-one/tsconfig.json`, content: pluginOneConfig() }, { path: `${tscWatch.projectRoot}/plugin-one/index.ts`, content: `${pluginOneIndex()} ${pluginOneAction()}`, }, - { path: `${tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() }, - { path: `${tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() }, + { + path: `${tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/package.json`, + content: fsaPackageJson(), + }, + { + path: `${tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/index.d.ts`, + content: fsaIndex(), + }, { path: `/temp/yarn/data/link/plugin-two`, symLink: `${tscWatch.projectRoot}/plugin-two` }, - { path: `${tscWatch.projectRoot}/plugin-one/node_modules/plugin-two`, symLink: `/temp/yarn/data/link/plugin-two` }, + { + path: `${tscWatch.projectRoot}/plugin-one/node_modules/plugin-two`, + symLink: `/temp/yarn/data/link/plugin-two`, + }, tscWatch.libFile, ], changeCaseFileTestPath: str => stringContains(str, "/plugin-two"), diff --git a/src/testRunner/unittests/tsc/helpers.ts b/src/testRunner/unittests/tsc/helpers.ts index a6579000719f2..50834e762bbef 100644 --- a/src/testRunner/unittests/tsc/helpers.ts +++ b/src/testRunner/unittests/tsc/helpers.ts @@ -47,9 +47,9 @@ namespace ts { if (isAnyProgram(program)) { baselineBuildInfo(program.getCompilerOptions(), sys, originalReadCall); (programs || (programs = [])).push( - isBuilderProgram(program) ? - [program.getProgram(), program] : - [program], + isBuilderProgram(program) + ? [program.getProgram(), program] + : [program], ); } else { @@ -95,7 +95,10 @@ namespace ts { const fs = inputFs.shadow(); // Create system - const sys = new fakes.System(fs, { executingFilePath: "/lib/tsc", env: environmentVariables }) as TscCompileSystem; + const sys = new fakes.System(fs, { + executingFilePath: "/lib/tsc", + env: environmentVariables, + }) as TscCompileSystem; if (input.disableUseFileVersionAsSignature) sys.disableUseFileVersionAsSignature = true; sys.storeFilesChangingSignatureDuringEmit = true; sys.write(`${sys.getExecutingFilePath()} ${commandLineArgs.join(" ")}\n`); @@ -105,12 +108,14 @@ namespace ts { additionalBaseline?.(sys); fs.makeReadonly(); sys.baseLine = () => { - const baseFsPatch = diffWithInitial ? - inputFs.diff(initialFs, { includeChangedFileWithSameContent: true }) : - inputFs.diff(/*base*/ undefined, { baseIsNotShadowRoot: true }); + const baseFsPatch = diffWithInitial + ? inputFs.diff(initialFs, { includeChangedFileWithSameContent: true }) + : inputFs.diff(/*base*/ undefined, { baseIsNotShadowRoot: true }); const patch = fs.diff(inputFs, { includeChangedFileWithSameContent: true }); return { - file: `${isBuild(commandLineArgs) ? "tsbuild" : "tsc"}/${scenario}/${subScenario.split(" ").join("-")}.js`, + file: `${isBuild(commandLineArgs) ? "tsbuild" : "tsc"}/${scenario}/${ + subScenario.split(" ").join("-") + }.js`, text: `Input:: ${baseFsPatch ? vfs.formatPatch(baseFsPatch) : ""} @@ -150,7 +155,12 @@ ${patch ? vfs.formatPatch(patch) : ""}`, ) { if (sys instanceof fakes.System) makeSystemReadyForBaseline(sys, versionToWrite); const { cb } = commandLineCallbacks(sys, originalRead); - const host = createSolutionBuilderHost(sys, /*createProgram*/ undefined, createDiagnosticReporter(sys, /*pretty*/ true), createBuilderStatusReporter(sys, /*pretty*/ true)); + const host = createSolutionBuilderHost( + sys, + /*createProgram*/ undefined, + createDiagnosticReporter(sys, /*pretty*/ true), + createBuilderStatusReporter(sys, /*pretty*/ true), + ); host.afterProgramEmitAndDiagnostics = cb; host.afterEmitBundle = cb; return host; @@ -222,7 +232,10 @@ ${patch ? vfs.formatPatch(patch) : ""}`, /** * Verify by baselining after initializing FS and custom compile */ - export function verifyTscCompileLike(verifier: (input: T) => { baseLine: TscCompileSystem["baseLine"]; }, input: T) { + export function verifyTscCompileLike( + verifier: (input: T) => { baseLine: TscCompileSystem["baseLine"]; }, + input: T, + ) { describe(`tsc ${input.commandLineArgs.join(" ")} ${input.scenario}:: ${input.subScenario}`, () => { describe(input.scenario, () => { describe(input.subScenario, () => { diff --git a/src/testRunner/unittests/tsc/incremental.ts b/src/testRunner/unittests/tsc/incremental.ts index 3da8ad6eca15b..7959eeb6cb29f 100644 --- a/src/testRunner/unittests/tsc/incremental.ts +++ b/src/testRunner/unittests/tsc/incremental.ts @@ -17,7 +17,14 @@ namespace ts { ] }`, }), - commandLineArgs: ["--incremental", "--p", "src/project", "--tsBuildInfoFile", "src/project/.tsbuildinfo", "--explainFiles"], + commandLineArgs: [ + "--incremental", + "--p", + "src/project", + "--tsBuildInfoFile", + "src/project/.tsbuildinfo", + "--explainFiles", + ], edits: noChangeOnlyRuns, }); @@ -102,7 +109,11 @@ namespace ts { projFs = undefined!; }); - function verifyNoEmitOnError(subScenario: string, fixModifyFs: TestTscEdit["modifyFs"], modifyFs?: TestTscEdit["modifyFs"]) { + function verifyNoEmitOnError( + subScenario: string, + fixModifyFs: TestTscEdit["modifyFs"], + modifyFs?: TestTscEdit["modifyFs"], + ) { verifyTscWithEdits({ scenario: "incremental", subScenario, @@ -163,18 +174,18 @@ const a: string = 10;`, "Clean build will not have latestChangedDtsFile as there was no emit and emitSignatures as undefined for files", "Incremental will store the past latestChangedDtsFile and emitSignatures", ]; - const discrepancyIfNoDtsEmit = getEmitDeclarations(compilerOptions) ? - undefined : - noChangeWithExportsDiscrepancyRun.discrepancyExplanation; + const discrepancyIfNoDtsEmit = getEmitDeclarations(compilerOptions) + ? undefined + : noChangeWithExportsDiscrepancyRun.discrepancyExplanation; const noChangeRunWithNoEmit: TestTscEdit = { ...noChangeRun, subScenario: "No Change run with noEmit", commandLineArgs: ["--p", "src/project", "--noEmit"], - discrepancyExplanation: compilerOptions.composite ? - discrepancyExplanation : - !compilerOptions.declaration ? - noChangeWithExportsDiscrepancyRun.discrepancyExplanation : - undefined, + discrepancyExplanation: compilerOptions.composite + ? discrepancyExplanation + : !compilerOptions.declaration + ? noChangeWithExportsDiscrepancyRun.discrepancyExplanation + : undefined, }; const noChangeRunWithEmit: TestTscEdit = { ...noChangeRun, @@ -201,11 +212,11 @@ const a: string = 10;`, subScenario: "Introduce error but still noEmit", commandLineArgs: ["--p", "src/project", "--noEmit"], modifyFs: fs => replaceText(fs, "/src/project/src/class.ts", "prop", "prop1"), - discrepancyExplanation: compilerOptions.composite ? - discrepancyExplanation : - compilerOptions.declaration ? - noChangeWithExportsDiscrepancyRun.discrepancyExplanation : - undefined, + discrepancyExplanation: compilerOptions.composite + ? discrepancyExplanation + : compilerOptions.declaration + ? noChangeWithExportsDiscrepancyRun.discrepancyExplanation + : undefined, }, { subScenario: "Fix error and emit", @@ -229,9 +240,9 @@ const a: string = 10;`, subScenario: "Fix error and no emit", commandLineArgs: ["--p", "src/project", "--noEmit"], modifyFs: fs => replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"), - discrepancyExplanation: compilerOptions.composite ? - discrepancyExplanation : - noChangeWithExportsDiscrepancyRun.discrepancyExplanation, + discrepancyExplanation: compilerOptions.composite + ? discrepancyExplanation + : noChangeWithExportsDiscrepancyRun.discrepancyExplanation, }, noChangeRunWithEmit, noChangeRunWithNoEmit, @@ -255,9 +266,9 @@ const a: string = 10;`, { subScenario: "Fix error and no emit", modifyFs: fs => replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"), - discrepancyExplanation: compilerOptions.composite ? - discrepancyExplanation : - noChangeWithExportsDiscrepancyRun.discrepancyExplanation, + discrepancyExplanation: compilerOptions.composite + ? discrepancyExplanation + : noChangeWithExportsDiscrepancyRun.discrepancyExplanation, }, noChangeRunWithEmit, ], @@ -339,7 +350,8 @@ const a: string = 10;`, }, { subScenario: "Write file that could not be resolved", - modifyFs: fs => fs.writeFileSync(`/src/project/src/fileNotFound.ts`, "function something2() { return 20; }"), + modifyFs: fs => + fs.writeFileSync(`/src/project/src/fileNotFound.ts`, "function something2() { return 20; }"), }, { subScenario: "Modify main file", @@ -373,7 +385,14 @@ declare global { "/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result "/src/project/node_modules/@types/react/index.d.ts": getJsxLibraryContent(), // doesn't contain a jsx-runtime definition "/src/project/src/index.tsx": `export const App = () =>
;`, - "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" } }), + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "commonjs", + jsx: "react-jsx", + incremental: true, + jsxImportSource: "react", + }, + }), }), commandLineArgs: ["--p", "src/project"], }); @@ -386,7 +405,14 @@ declare global { "/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result "/src/project/node_modules/@types/react/index.d.ts": getJsxLibraryContent(), // doesn't contain a jsx-runtime definition "/src/project/src/index.tsx": `export const App = () =>
;`, - "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" } }), + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "commonjs", + jsx: "react-jsx", + incremental: true, + jsxImportSource: "react", + }, + }), }), commandLineArgs: ["--p", "src/project", "--strict"], }); @@ -429,7 +455,8 @@ declare global { }, { subScenario: "Add output of class3", - modifyFs: fs => fs.writeFileSync("/src/projects/project1/class3.d.ts", `declare class class3 {}`, "utf-8"), + modifyFs: fs => + fs.writeFileSync("/src/projects/project1/class3.d.ts", `declare class class3 {}`, "utf-8"), }, { subScenario: "Add excluded file to project1", @@ -448,7 +475,8 @@ declare global { }, { subScenario: "Create output for class3", - modifyFs: fs => fs.writeFileSync("/src/projects/project1/class3.d.ts", `declare class class3 {}`, "utf-8"), + modifyFs: fs => + fs.writeFileSync("/src/projects/project1/class3.d.ts", `declare class class3 {}`, "utf-8"), }, ], }); @@ -555,7 +583,8 @@ console.log(a);`, verifyTscWithEdits({ scenario: "incremental", - subScenario: "change to type that gets used as global through export in another file through indirect import", + subScenario: + "change to type that gets used as global through export in another file through indirect import", commandLineArgs: ["-p", `src/project`], fs: () => loadProjectFromFiles({ @@ -575,7 +604,9 @@ console.log(a);`, function verifyModifierChange(declaration: boolean) { verifyTscWithEdits({ scenario: "incremental", - subScenario: `change to modifier of class expression field${declaration ? " with declaration emit enabled" : ""}`, + subScenario: `change to modifier of class expression field${ + declaration ? " with declaration emit enabled" : "" + }`, commandLineArgs: ["-p", "src/project", "--incremental"], fs: () => loadProjectFromFiles({ diff --git a/src/testRunner/unittests/tsc/runWithoutArgs.ts b/src/testRunner/unittests/tsc/runWithoutArgs.ts index c4f3ea628b141..e17db76256087 100644 --- a/src/testRunner/unittests/tsc/runWithoutArgs.ts +++ b/src/testRunner/unittests/tsc/runWithoutArgs.ts @@ -10,7 +10,8 @@ namespace ts { verifyTsc({ scenario: "runWithoutArgs", - subScenario: "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped when host can't provide terminal width", + subScenario: + "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped when host can't provide terminal width", fs: () => loadProjectFromFiles({}), commandLineArgs: [], }); diff --git a/src/testRunner/unittests/tscWatch/consoleClearing.ts b/src/testRunner/unittests/tscWatch/consoleClearing.ts index 9315bd2993ae8..5fd4f2afaddd1 100644 --- a/src/testRunner/unittests/tscWatch/consoleClearing.ts +++ b/src/testRunner/unittests/tscWatch/consoleClearing.ts @@ -56,7 +56,8 @@ namespace ts.tscWatch { }); verifyTscWatch({ scenario, - subScenario: "when preserveWatchOutput is true in config file/when createWatchProgram is invoked with configFileParseResult on WatchCompilerHostOfConfigFile", + subScenario: + "when preserveWatchOutput is true in config file/when createWatchProgram is invoked with configFileParseResult on WatchCompilerHostOfConfigFile", commandLineArgs: ["--w", "-p", configFile.path], sys: () => createWatchedSystem(files), changes: makeChangeToFile, diff --git a/src/testRunner/unittests/tscWatch/emit.ts b/src/testRunner/unittests/tscWatch/emit.ts index b3d6291de367d..3e07413cf344e 100644 --- a/src/testRunner/unittests/tscWatch/emit.ts +++ b/src/testRunner/unittests/tscWatch/emit.ts @@ -39,11 +39,13 @@ namespace ts.tscWatch { sys: () => { const file1: File = { path: "/a/b/output/AnotherDependency/file1.d.ts", - content: "declare namespace Common.SomeComponent.DynamicMenu { enum Z { Full = 0, Min = 1, Average = 2, } }", + content: + "declare namespace Common.SomeComponent.DynamicMenu { enum Z { Full = 0, Min = 1, Average = 2, } }", }; const file2: File = { path: "/a/b/dependencies/file2.d.ts", - content: "declare namespace Dependencies.SomeComponent { export class SomeClass { version: string; } }", + content: + "declare namespace Dependencies.SomeComponent { export class SomeClass { version: string; } }", }; const file3: File = { path: "/a/b/project/src/main.ts", @@ -51,14 +53,15 @@ namespace ts.tscWatch { }; const file4: File = { path: "/a/b/project/src/main2.ts", - content: "namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }", + content: + "namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }", }; const configFile: File = { path: "/a/b/project/tsconfig.json", content: JSON.stringify({ - compilerOptions: useOutFile ? - { outFile: "../output/common.js", target: "es5" } : - { outDir: "../output", target: "es5" }, + compilerOptions: useOutFile + ? { outFile: "../output/common.js", target: "es5" } + : { outDir: "../output", target: "es5" }, files: [file1.path, file2.path, file3.path, file4.path], }), }; @@ -129,11 +132,20 @@ namespace ts.tscWatch { content: JSON.stringify(configObj || {}), }; const additionalFiles = getAdditionalFileOrFolder?.() || emptyArray; - const files = [moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile, ...additionalFiles]; + const files = [ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ...additionalFiles, + ]; return createWatchedSystem( - firstReloadFileList ? - map(firstReloadFileList, fileName => find(files, file => file.path === fileName)!) : - files, + firstReloadFileList + ? map(firstReloadFileList, fileName => find(files, file => file.path === fileName)!) + : files, ); }, changes, @@ -150,12 +162,18 @@ namespace ts.tscWatch { }; verifyTscWatchEmit({ - subScenario: "should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", + subScenario: + "should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", changes: [ changeModuleFile1Shape, { - caption: "Change the content of moduleFile1 to `export var T: number;export function Foo() { console.log('hi'); };`", - change: sys => sys.writeFile(moduleFile1Path, `export var T: number;export function Foo() { console.log('hi'); };`), + caption: + "Change the content of moduleFile1 to `export var T: number;export function Foo() { console.log('hi'); };`", + change: sys => + sys.writeFile( + moduleFile1Path, + `export var T: number;export function Foo() { console.log('hi'); };`, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, ], @@ -172,11 +190,13 @@ namespace ts.tscWatch { changeModuleFile1Shape, { caption: "Add the import statements back to file1Consumer1", - change: sys => sys.writeFile(file1Consumer1Path, `import {Foo} from "./moduleFile1";let y = Foo();`), + change: sys => + sys.writeFile(file1Consumer1Path, `import {Foo} from "./moduleFile1";let y = Foo();`), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { - caption: "Change the content of moduleFile1 to `export var T: number;export var T2: string;export function Foo() { };`", + caption: + "Change the content of moduleFile1 to `export var T: number;export var T2: string;export function Foo() { };`", change: sys => sys.writeFile(moduleFile1Path, `export let y = Foo();`), timeouts: checkSingleTimeoutQueueLengthAndRun, }, @@ -441,7 +461,8 @@ export var x = Foo();`, changes: [ { caption: "Append content to file3", - change: sys => sys.appendFile("/user/someone/projects/myproject/file3.ts", "function foo2() { return 2; }"), + change: sys => + sys.appendFile("/user/someone/projects/myproject/file3.ts", "function foo2() { return 2; }"), timeouts: checkSingleTimeoutQueueLengthAndRun, }, ], @@ -466,12 +487,18 @@ export var x = Foo();`, }), }; const files = [file, configFile, libFile]; - return createWatchedSystem(files, { currentDirectory: projectLocation, useCaseSensitiveFileNames: true }); + return createWatchedSystem(files, { + currentDirectory: projectLocation, + useCaseSensitiveFileNames: true, + }); }, changes: [ { caption: "file is deleted and then created to modify content", - change: sys => sys.appendFile("/home/username/project/app/file.ts", "\nvar b = 10;", { invokeFileDeleteCreateAsPartInsteadOfChange: true }), + change: sys => + sys.appendFile("/home/username/project/app/file.ts", "\nvar b = 10;", { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + }), timeouts: checkSingleTimeoutQueueLengthAndRun, }, ], @@ -481,7 +508,8 @@ export var x = Foo();`, describe("unittests:: tsc-watch:: emit with when module emit is specified as node", () => { verifyTscWatch({ scenario, - subScenario: "when module emit is specified as node/when instead of filechanged recursive directory watcher is invoked", + subScenario: + "when module emit is specified as node/when instead of filechanged recursive directory watcher is invoked", commandLineArgs: ["--w", "--p", "/a/rootFolder/project/tsconfig.json"], sys: () => { const configFile: File = { diff --git a/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts b/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts index 3fbb93dd5a60c..6cf62ef38e63a 100644 --- a/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts +++ b/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts @@ -286,21 +286,43 @@ export class Data { function verifyTransitiveExports(subScenario: string, files: readonly File[]) { verifyEmitAndErrorUpdates({ subScenario: `transitive exports/${subScenario}`, - files: () => [lib1ToolsInterface, lib1ToolsPublic, app, lib2Public, lib1Public, ...files, config, libFile], + files: () => [ + lib1ToolsInterface, + lib1ToolsPublic, + app, + lib2Public, + lib1Public, + ...files, + config, + libFile, + ], changes: [ { caption: "Rename property title to title2 of interface ITest to initialize signatures", - change: sys => sys.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title", "title2")), + change: sys => + sys.writeFile( + lib1ToolsInterface.path, + lib1ToolsInterface.content.replace("title", "title2"), + ), timeouts: runQueuedTimeoutCallbacks, }, { - caption: "Rename property title2 to title of interface ITest to revert back to original text", - change: sys => sys.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title2", "title")), + caption: + "Rename property title2 to title of interface ITest to revert back to original text", + change: sys => + sys.writeFile( + lib1ToolsInterface.path, + lib1ToolsInterface.content.replace("title2", "title"), + ), timeouts: runQueuedTimeoutCallbacks, }, { caption: "Rename property title to title2 of interface ITest", - change: sys => sys.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title", "title2")), + change: sys => + sys.writeFile( + lib1ToolsInterface.path, + lib1ToolsInterface.content.replace("title", "title2"), + ), timeouts: runQueuedTimeoutCallbacks, }, ], @@ -343,14 +365,19 @@ export class Data2 { function change(caption: string, content: string): TscWatchCompileChange { return { caption, - change: sys => sys.writeFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, content), + change: sys => + sys.writeFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, content), // build project timeouts: checkSingleTimeoutQueueLengthAndRun, }; } const noChange: TscWatchCompileChange = { caption: "No change", - change: sys => sys.writeFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, sys.readFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`)!), + change: sys => + sys.writeFile( + `${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, + sys.readFile(`${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`)!, + ), // build project timeouts: checkSingleTimeoutQueueLengthAndRun, }; @@ -359,7 +386,10 @@ export class Data2 { currentDirectory: `${TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError`, files: () => ["shared/types/db.ts", "src/main.ts", "src/other.ts", "tsconfig.json"] - .map(f => TestFSWithWatch.getTsBuildProjectFile("noEmitOnError", f)).concat({ path: libFile.path, content: libContent }), + .map(f => TestFSWithWatch.getTsBuildProjectFile("noEmitOnError", f)).concat({ + path: libFile.path, + content: libContent, + }), changes: [ noChange, change( diff --git a/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts b/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts index 828bfcff7e50f..8e2a42014f223 100644 --- a/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts +++ b/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts @@ -15,7 +15,9 @@ namespace ts.tscWatch { }), }; - function verifyConsistentFileNames({ subScenario, changes }: { subScenario: string; changes: TscWatchCompileChange[]; }) { + function verifyConsistentFileNames( + { subScenario, changes }: { subScenario: string; changes: TscWatchCompileChange[]; }, + ) { verifyTscWatch({ scenario: "forceConsistentCasingInFileNames", subScenario, @@ -68,7 +70,9 @@ namespace ts.tscWatch { path: `${projectRoot}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }), }; - return createWatchedSystem([moduleA, moduleB, moduleC, libFile, tsconfig], { currentDirectory: projectRoot }); + return createWatchedSystem([moduleA, moduleB, moduleC, libFile, tsconfig], { + currentDirectory: projectRoot, + }); }, changes: [ { @@ -117,7 +121,11 @@ export const Fragment: unique symbol; { path: `${projectRoot}/tsconfig.json`, content: JSON.stringify({ - compilerOptions: { jsx: "react-jsx", jsxImportSource: "react", forceConsistentCasingInFileNames: true }, + compilerOptions: { + jsx: "react-jsx", + jsxImportSource: "react", + forceConsistentCasingInFileNames: true, + }, files: ["node_modules/react/Jsx-Runtime/index.d.ts", "index.tsx"], }), }, @@ -151,7 +159,10 @@ a;b; path: `${windowsStyleRoot}/${projectRootRelative}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }), }; - return createWatchedSystem([moduleA, moduleB, libFile, tsconfig], { windowsStyleRoot, useCaseSensitiveFileNames: false }); + return createWatchedSystem([moduleA, moduleB, libFile, tsconfig], { + windowsStyleRoot, + useCaseSensitiveFileNames: false, + }); }, changes: [ { @@ -201,7 +212,9 @@ a;b; path: `${projectRoot}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }), }; - return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { currentDirectory: projectRoot }); + return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { + currentDirectory: projectRoot, + }); }, changes: [ { @@ -218,11 +231,36 @@ a;b; }); } - verifyFileSymlink("when both file symlink target and import match disk", `${projectRoot}/XY.ts`, `${projectRoot}/XY.ts`, `./XY`); - verifyFileSymlink("when file symlink target matches disk but import does not", `${projectRoot}/XY.ts`, `${projectRoot}/Xy.ts`, `./XY`); - verifyFileSymlink("when import matches disk but file symlink target does not", `${projectRoot}/XY.ts`, `${projectRoot}/XY.ts`, `./Xy`); - verifyFileSymlink("when import and file symlink target agree but do not match disk", `${projectRoot}/XY.ts`, `${projectRoot}/Xy.ts`, `./Xy`); - verifyFileSymlink("when import, file symlink target, and disk are all different", `${projectRoot}/XY.ts`, `${projectRoot}/Xy.ts`, `./yX`); + verifyFileSymlink( + "when both file symlink target and import match disk", + `${projectRoot}/XY.ts`, + `${projectRoot}/XY.ts`, + `./XY`, + ); + verifyFileSymlink( + "when file symlink target matches disk but import does not", + `${projectRoot}/XY.ts`, + `${projectRoot}/Xy.ts`, + `./XY`, + ); + verifyFileSymlink( + "when import matches disk but file symlink target does not", + `${projectRoot}/XY.ts`, + `${projectRoot}/XY.ts`, + `./Xy`, + ); + verifyFileSymlink( + "when import and file symlink target agree but do not match disk", + `${projectRoot}/XY.ts`, + `${projectRoot}/Xy.ts`, + `./Xy`, + ); + verifyFileSymlink( + "when import, file symlink target, and disk are all different", + `${projectRoot}/XY.ts`, + `${projectRoot}/Xy.ts`, + `./yX`, + ); function verifyDirSymlink(subScenario: string, diskPath: string, targetPath: string, importedPath: string) { verifyTscWatch({ @@ -253,9 +291,17 @@ a;b; const tsconfig: File = { path: `${projectRoot}/tsconfig.json`, // Use outFile because otherwise the real and linked files will have the same output path - content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true, outFile: "out.js", module: "system" } }), + content: JSON.stringify({ + compilerOptions: { + forceConsistentCasingInFileNames: true, + outFile: "out.js", + module: "system", + }, + }), }; - return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { currentDirectory: projectRoot }); + return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { + currentDirectory: projectRoot, + }); }, changes: [ { @@ -272,11 +318,36 @@ a;b; }); } - verifyDirSymlink("when both directory symlink target and import match disk", `${projectRoot}/XY`, `${projectRoot}/XY`, `./XY`); - verifyDirSymlink("when directory symlink target matches disk but import does not", `${projectRoot}/XY`, `${projectRoot}/Xy`, `./XY`); - verifyDirSymlink("when import matches disk but directory symlink target does not", `${projectRoot}/XY`, `${projectRoot}/XY`, `./Xy`); - verifyDirSymlink("when import and directory symlink target agree but do not match disk", `${projectRoot}/XY`, `${projectRoot}/Xy`, `./Xy`); - verifyDirSymlink("when import, directory symlink target, and disk are all different", `${projectRoot}/XY`, `${projectRoot}/Xy`, `./yX`); + verifyDirSymlink( + "when both directory symlink target and import match disk", + `${projectRoot}/XY`, + `${projectRoot}/XY`, + `./XY`, + ); + verifyDirSymlink( + "when directory symlink target matches disk but import does not", + `${projectRoot}/XY`, + `${projectRoot}/Xy`, + `./XY`, + ); + verifyDirSymlink( + "when import matches disk but directory symlink target does not", + `${projectRoot}/XY`, + `${projectRoot}/XY`, + `./Xy`, + ); + verifyDirSymlink( + "when import and directory symlink target agree but do not match disk", + `${projectRoot}/XY`, + `${projectRoot}/Xy`, + `./Xy`, + ); + verifyDirSymlink( + "when import, directory symlink target, and disk are all different", + `${projectRoot}/XY`, + `${projectRoot}/Xy`, + `./yX`, + ); verifyTscWatch({ scenario: "forceConsistentCasingInFileNames", diff --git a/src/testRunner/unittests/tscWatch/helpers.ts b/src/testRunner/unittests/tscWatch/helpers.ts index 72f4bca13028c..295986f489acb 100644 --- a/src/testRunner/unittests/tscWatch/helpers.ts +++ b/src/testRunner/unittests/tscWatch/helpers.ts @@ -23,7 +23,11 @@ namespace ts.tscWatch { checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles); } - export function getDiagnosticMessageChain(message: DiagnosticMessage, args?: (string | number)[], next?: DiagnosticMessageChain[]): DiagnosticMessageChain { + export function getDiagnosticMessageChain( + message: DiagnosticMessage, + args?: (string | number)[], + next?: DiagnosticMessageChain[], + ): DiagnosticMessageChain { let text = getLocaleSpecificMessage(message); if (args?.length) { text = formatStringFromArgs(text, args); @@ -36,49 +40,105 @@ namespace ts.tscWatch { }; } - function isDiagnosticMessageChain(message: DiagnosticMessage | DiagnosticMessageChain): message is DiagnosticMessageChain { + function isDiagnosticMessageChain( + message: DiagnosticMessage | DiagnosticMessageChain, + ): message is DiagnosticMessageChain { return !!(message as DiagnosticMessageChain).messageText; } - export function getDiagnosticOfFileFrom(file: SourceFile | undefined, start: number | undefined, length: number | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: (string | number)[]): Diagnostic { + export function getDiagnosticOfFileFrom( + file: SourceFile | undefined, + start: number | undefined, + length: number | undefined, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: (string | number)[] + ): Diagnostic { return { file, start, length, - messageText: isDiagnosticMessageChain(message) ? - message : - getDiagnosticMessageChain(message, args).messageText, + messageText: isDiagnosticMessageChain(message) + ? message + : getDiagnosticMessageChain(message, args).messageText, category: message.category, code: message.code, }; } - export function getDiagnosticWithoutFile(message: DiagnosticMessage | DiagnosticMessageChain, ...args: (string | number)[]): Diagnostic { + export function getDiagnosticWithoutFile( + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: (string | number)[] + ): Diagnostic { return getDiagnosticOfFileFrom(/*file*/ undefined, /*start*/ undefined, /*length*/ undefined, message, ...args); } - export function getDiagnosticOfFile(file: SourceFile, start: number, length: number, message: DiagnosticMessage | DiagnosticMessageChain, ...args: (string | number)[]): Diagnostic { + export function getDiagnosticOfFile( + file: SourceFile, + start: number, + length: number, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: (string | number)[] + ): Diagnostic { return getDiagnosticOfFileFrom(file, start, length, message, ...args); } - export function getDiagnosticOfFileFromProgram(program: Program, filePath: string, start: number, length: number, message: DiagnosticMessage | DiagnosticMessageChain, ...args: (string | number)[]): Diagnostic { - return getDiagnosticOfFileFrom(program.getSourceFileByPath(toPath(filePath, program.getCurrentDirectory(), s => s.toLowerCase())), start, length, message, ...args); + export function getDiagnosticOfFileFromProgram( + program: Program, + filePath: string, + start: number, + length: number, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: (string | number)[] + ): Diagnostic { + return getDiagnosticOfFileFrom( + program.getSourceFileByPath(toPath(filePath, program.getCurrentDirectory(), s => s.toLowerCase())), + start, + length, + message, + ...args, + ); } export function getUnknownCompilerOption(program: Program, configFile: File, option: string) { const quotedOption = `"${option}"`; - return getDiagnosticOfFile(program.getCompilerOptions().configFile!, configFile.content.indexOf(quotedOption), quotedOption.length, Diagnostics.Unknown_compiler_option_0, option); + return getDiagnosticOfFile( + program.getCompilerOptions().configFile!, + configFile.content.indexOf(quotedOption), + quotedOption.length, + Diagnostics.Unknown_compiler_option_0, + option, + ); } - export function getUnknownDidYouMeanCompilerOption(program: Program, configFile: File, option: string, didYouMean: string) { + export function getUnknownDidYouMeanCompilerOption( + program: Program, + configFile: File, + option: string, + didYouMean: string, + ) { const quotedOption = `"${option}"`; - return getDiagnosticOfFile(program.getCompilerOptions().configFile!, configFile.content.indexOf(quotedOption), quotedOption.length, Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, option, didYouMean); + return getDiagnosticOfFile( + program.getCompilerOptions().configFile!, + configFile.content.indexOf(quotedOption), + quotedOption.length, + Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, + option, + didYouMean, + ); } export function getDiagnosticModuleNotFoundOfFile(program: Program, file: File, moduleName: string) { const quotedModuleName = `"${moduleName}"`; - return getDiagnosticOfFileFromProgram(program, file.path, file.content.indexOf(quotedModuleName), quotedModuleName.length, Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option, moduleName); + return getDiagnosticOfFileFromProgram( + program, + file.path, + file.content.indexOf(quotedModuleName), + quotedModuleName.length, + Diagnostics + .Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option, + moduleName, + ); } export function runQueuedTimeoutCallbacks(sys: WatchedSystem) { @@ -94,7 +154,11 @@ namespace ts.tscWatch { sys.checkTimeoutQueueLength(0); } - export type WatchOrSolution = void | SolutionBuilder | WatchOfConfigFile | WatchOfFilesAndCompilerOptions; + export type WatchOrSolution = + | void + | SolutionBuilder + | WatchOfConfigFile + | WatchOfFilesAndCompilerOptions; export interface TscWatchCompileChange { caption: string; change: (sys: TestFSWithWatch.TestServerHostTrackingWrittenFiles) => void; @@ -108,7 +172,9 @@ namespace ts.tscWatch { baselineSourceMap?: boolean; baselineDependencies?: boolean; } - export interface TscWatchCompileBase extends TscWatchCheckOptions { + export interface TscWatchCompileBase + extends TscWatchCheckOptions + { scenario: string; subScenario: string; commandLineArgs: readonly string[]; @@ -169,7 +235,10 @@ namespace ts.tscWatch { export interface Baseline extends BaselineBase, CommandLineCallbacks { } - export function createBaseline(system: WatchedSystem, modifySystem?: (sys: WatchedSystem, originalRead: WatchedSystem["readFile"]) => void): Baseline { + export function createBaseline( + system: WatchedSystem, + modifySystem?: (sys: WatchedSystem, originalRead: WatchedSystem["readFile"]) => void, + ): Baseline { const originalRead = system.readFile; const initialSys = fakes.patchHostForBuildInfoReadWrite(system); modifySystem?.(initialSys, originalRead); @@ -182,18 +251,28 @@ namespace ts.tscWatch { } export function createSolutionBuilderWithWatchHostForBaseline(sys: WatchedSystem, cb: ExecuteCommandLineCallbacks) { - const host = createSolutionBuilderWithWatchHost(sys, /*createProgram*/ undefined, createDiagnosticReporter(sys, /*pretty*/ true), createBuilderStatusReporter(sys, /*pretty*/ true), createWatchStatusReporter(sys, /*pretty*/ true)); + const host = createSolutionBuilderWithWatchHost( + sys, + /*createProgram*/ undefined, + createDiagnosticReporter(sys, /*pretty*/ true), + createBuilderStatusReporter(sys, /*pretty*/ true), + createWatchStatusReporter(sys, /*pretty*/ true), + ); host.afterProgramEmitAndDiagnostics = cb; host.afterEmitBundle = cb; return host; } - interface CreateWatchCompilerHostOfConfigFileForBaseline extends CreateWatchCompilerHostOfConfigFileInput { + interface CreateWatchCompilerHostOfConfigFileForBaseline + extends CreateWatchCompilerHostOfConfigFileInput + { system: WatchedSystem; cb: ExecuteCommandLineCallbacks; } - export function createWatchCompilerHostOfConfigFileForBaseline( + export function createWatchCompilerHostOfConfigFileForBaseline< + T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram, + >( input: CreateWatchCompilerHostOfConfigFileForBaseline, ) { const host = createWatchCompilerHostOfConfigFile({ @@ -205,11 +284,15 @@ namespace ts.tscWatch { return host; } - interface CreateWatchCompilerHostOfFilesAndCompilerOptionsForBaseline extends CreateWatchCompilerHostOfFilesAndCompilerOptionsInput { + interface CreateWatchCompilerHostOfFilesAndCompilerOptionsForBaseline + extends CreateWatchCompilerHostOfFilesAndCompilerOptionsInput + { system: WatchedSystem; cb: ExecuteCommandLineCallbacks; } - export function createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline( + export function createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline< + T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram, + >( input: CreateWatchCompilerHostOfFilesAndCompilerOptionsForBaseline, ) { const host = createWatchCompilerHostOfFilesAndCompilerOptions({ @@ -221,7 +304,10 @@ namespace ts.tscWatch { return host; } - function updateWatchHostForBaseline(host: WatchCompilerHost, cb: ExecuteCommandLineCallbacks) { + function updateWatchHostForBaseline( + host: WatchCompilerHost, + cb: ExecuteCommandLineCallbacks, + ) { const emitFilesAndReportErrors = host.afterProgramCreate!; host.afterProgramCreate = builderProgram => { emitFilesAndReportErrors.call(host, builderProgram); @@ -230,7 +316,12 @@ namespace ts.tscWatch { return host; } - export function applyChange(sys: BaselineBase["sys"], baseline: BaselineBase["baseline"], change: TscWatchCompileChange["change"], caption?: TscWatchCompileChange["caption"]) { + export function applyChange( + sys: BaselineBase["sys"], + baseline: BaselineBase["baseline"], + change: TscWatchCompileChange["change"], + caption?: TscWatchCompileChange["caption"], + ) { const oldSnap = sys.snap(); baseline.push(`Change::${caption ? " " + caption : ""}`, ""); change(sys); @@ -281,7 +372,12 @@ namespace ts.tscWatch { baselineDependencies, }); } - Harness.Baseline.runBaseline(`${isBuild(commandLineArgs) ? "tsbuild" : "tsc"}${isWatch(commandLineArgs) ? "Watch" : ""}/${scenario}/${subScenario.split(" ").join("-")}.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `${isBuild(commandLineArgs) ? "tsbuild" : "tsc"}${isWatch(commandLineArgs) ? "Watch" : ""}/${scenario}/${ + subScenario.split(" ").join("-") + }.js`, + baseline.join("\r\n"), + ); } function isWatch(commandLineArgs: readonly string[]) { @@ -296,7 +392,9 @@ namespace ts.tscWatch { oldPrograms: readonly (CommandLineProgram | undefined)[]; getPrograms: () => readonly CommandLineProgram[]; } - export function watchBaseline({ baseline, getPrograms, oldPrograms, sys, oldSnap, baselineSourceMap, baselineDependencies }: WatchBaseline) { + export function watchBaseline( + { baseline, getPrograms, oldPrograms, sys, oldSnap, baselineSourceMap, baselineDependencies }: WatchBaseline, + ) { if (baselineSourceMap) generateSourceMapBaselineFiles(sys); sys.serializeOutput(baseline); const programs = baselinePrograms(baseline, getPrograms, oldPrograms, baselineDependencies); @@ -310,7 +408,12 @@ namespace ts.tscWatch { return programs; } - export function baselinePrograms(baseline: string[], getPrograms: () => readonly CommandLineProgram[], oldPrograms: readonly (CommandLineProgram | undefined)[], baselineDependencies: boolean | undefined) { + export function baselinePrograms( + baseline: string[], + getPrograms: () => readonly CommandLineProgram[], + oldPrograms: readonly (CommandLineProgram | undefined)[], + baselineDependencies: boolean | undefined, + ) { const programs = getPrograms(); for (let i = 0; i < programs.length; i++) { baselineProgram(baseline, programs[i], oldPrograms[i], baselineDependencies); @@ -318,7 +421,12 @@ namespace ts.tscWatch { return programs; } - function baselineProgram(baseline: string[], [program, builderProgram]: CommandLineProgram, oldProgram: CommandLineProgram | undefined, baselineDependencies: boolean | undefined) { + function baselineProgram( + baseline: string[], + [program, builderProgram]: CommandLineProgram, + oldProgram: CommandLineProgram | undefined, + baselineDependencies: boolean | undefined, + ) { if (program !== oldProgram?.[0]) { const options = program.getCompilerOptions(); baseline.push(`Program root files: ${JSON.stringify(program.getRootFileNames())}`); @@ -341,7 +449,10 @@ namespace ts.tscWatch { if (state.semanticDiagnosticsPerFile?.size) { baseline.push("Semantic diagnostics in builder refreshed for::"); for (const file of program.getSourceFiles()) { - if (!internalState.semanticDiagnosticsFromOldState || !internalState.semanticDiagnosticsFromOldState.has(file.resolvedPath)) { + if ( + !internalState.semanticDiagnosticsFromOldState + || !internalState.semanticDiagnosticsFromOldState.has(file.resolvedPath) + ) { baseline.push(file.fileName); } } @@ -406,12 +517,21 @@ namespace ts.tscWatch { }); } - export function replaceFileText(sys: WatchedSystem, file: string, searchValue: string | RegExp, replaceValue: string) { + export function replaceFileText( + sys: WatchedSystem, + file: string, + searchValue: string | RegExp, + replaceValue: string, + ) { const content = Debug.checkDefined(sys.readFile(file)); sys.writeFile(file, content.replace(searchValue, replaceValue)); } - export function createSolutionBuilder(system: WatchedSystem, rootNames: readonly string[], originalRead?: WatchedSystem["readFile"]) { + export function createSolutionBuilder( + system: WatchedSystem, + rootNames: readonly string[], + originalRead?: WatchedSystem["readFile"], + ) { const host = createSolutionBuilderHostForBaseline(system, /*versionToWrite*/ undefined, originalRead); return ts.createSolutionBuilder(host, rootNames, {}); } @@ -422,7 +542,11 @@ namespace ts.tscWatch { assert.equal(host.getOutput().length, 0, JSON.stringify(host.getOutput(), /*replacer*/ undefined, " ")); } - export function solutionBuildWithBaseline(sys: WatchedSystem, solutionRoots: readonly string[], originalRead?: WatchedSystem["readFile"]) { + export function solutionBuildWithBaseline( + sys: WatchedSystem, + solutionRoots: readonly string[], + originalRead?: WatchedSystem["readFile"], + ) { const originalReadFile = sys.readFile; const originalWrite = sys.write; const originalWriteFile = sys.writeFile; @@ -440,7 +564,11 @@ namespace ts.tscWatch { return sys; } - export function createSystemWithSolutionBuild(solutionRoots: readonly string[], files: TestFSWithWatch.FileOrFolderOrSymLinkMap | readonly TestFSWithWatch.FileOrFolderOrSymLink[], params?: TestFSWithWatch.TestServerHostCreationParameters) { + export function createSystemWithSolutionBuild( + solutionRoots: readonly string[], + files: TestFSWithWatch.FileOrFolderOrSymLinkMap | readonly TestFSWithWatch.FileOrFolderOrSymLink[], + params?: TestFSWithWatch.TestServerHostCreationParameters, + ) { return solutionBuildWithBaseline(createWatchedSystem(files, params), solutionRoots); } } diff --git a/src/testRunner/unittests/tscWatch/incremental.ts b/src/testRunner/unittests/tscWatch/incremental.ts index 02b3f3ae8a44a..05d51bb143f4a 100644 --- a/src/testRunner/unittests/tscWatch/incremental.ts +++ b/src/testRunner/unittests/tscWatch/incremental.ts @@ -28,7 +28,9 @@ namespace ts.tscWatch { { subScenario, files, optionsToExtend, modifyFs }: VerifyIncrementalWatchEmitInput, incremental: boolean, ) { - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(files(), { currentDirectory: project })); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem(files(), { currentDirectory: project }), + ); if (incremental) sys.exit = exitCode => sys.exitCode = exitCode; const argsToPass = [incremental ? "-i" : "-w", ...(optionsToExtend || emptyArray)]; baseline.push(`${sys.getExecutingFilePath()} ${argsToPass.join(" ")}`); @@ -40,7 +42,12 @@ namespace ts.tscWatch { build(oldSnap); } - Harness.Baseline.runBaseline(`${isBuild(argsToPass) ? "tsbuild/watchMode" : "tscWatch"}/incremental/${subScenario.split(" ").join("-")}-${incremental ? "incremental" : "watch"}.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `${isBuild(argsToPass) ? "tsbuild/watchMode" : "tscWatch"}/incremental/${ + subScenario.split(" ").join("-") + }-${incremental ? "incremental" : "watch"}.js`, + baseline.join("\r\n"), + ); function build(oldSnap: SystemSnap) { const closer = executeCommandLine( @@ -133,9 +140,18 @@ namespace ts.tscWatch { }); it("verify that state is read correctly", () => { - const system = createWatchedSystem([libFile, file1, fileModified, config], { currentDirectory: project }); + const system = createWatchedSystem([libFile, file1, fileModified, config], { + currentDirectory: project, + }); const reportDiagnostic = createDiagnosticReporter(system); - const parsedConfig = parseConfigFileWithSystem("tsconfig.json", {}, /*extendedConfigCache*/ undefined, /*watchOptionsToExtend*/ undefined, system, reportDiagnostic)!; + const parsedConfig = parseConfigFileWithSystem( + "tsconfig.json", + {}, + /*extendedConfigCache*/ undefined, + /*watchOptionsToExtend*/ undefined, + system, + reportDiagnostic, + )!; performIncrementalCompilation({ rootNames: parsedConfig.fileNames, options: parsedConfig.options, @@ -145,7 +161,14 @@ namespace ts.tscWatch { system, }); - const command = parseConfigFileWithSystem("tsconfig.json", {}, /*extendedConfigCache*/ undefined, /*watchOptionsToExtend*/ undefined, system, noop)!; + const command = parseConfigFileWithSystem( + "tsconfig.json", + {}, + /*extendedConfigCache*/ undefined, + /*watchOptionsToExtend*/ undefined, + system, + noop, + )!; const builderProgram = createIncrementalProgram({ rootNames: command.fileNames, options: command.options, @@ -208,7 +231,9 @@ namespace ts.tscWatch { verifyIncrementalWatchEmit({ files: () => [libFile, file1, file2, { path: configFile.path, - content: JSON.stringify({ compilerOptions: { incremental: true, module: "amd", outFile: "out.js" } }), + content: JSON.stringify({ + compilerOptions: { incremental: true, module: "amd", outFile: "out.js" }, + }), }], subScenario: "module compilation/with --out", }); @@ -286,7 +311,12 @@ export interface A { }); describe("with option jsxImportSource", () => { - const jsxImportSourceOptions = { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" }; + const jsxImportSourceOptions = { + module: "commonjs", + jsx: "react-jsx", + incremental: true, + jsxImportSource: "react", + }; const jsxLibraryContent = `export namespace JSX { interface Element {} interface IntrinsicElements { @@ -305,13 +335,26 @@ export const Fragment: unique symbol; files: () => [ { path: libFile.path, content: libContent }, { path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent }, - { path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) }, - { path: `${project}/node_modules/preact/jsx-runtime/index.d.ts`, content: jsxLibraryContent.replace("propA", "propB") }, - { path: `${project}/node_modules/preact/package.json`, content: JSON.stringify({ name: "preact", version: "0.0.1" }) }, + { + path: `${project}/node_modules/react/package.json`, + content: JSON.stringify({ name: "react", version: "0.0.1" }), + }, + { + path: `${project}/node_modules/preact/jsx-runtime/index.d.ts`, + content: jsxLibraryContent.replace("propA", "propB"), + }, + { + path: `${project}/node_modules/preact/package.json`, + content: JSON.stringify({ name: "preact", version: "0.0.1" }), + }, { path: `${project}/index.tsx`, content: `export const App = () =>
;` }, { path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }, ], - modifyFs: host => host.writeFile(configFile.path, JSON.stringify({ compilerOptions: { ...jsxImportSourceOptions, jsxImportSource: "preact" } })), + modifyFs: host => + host.writeFile( + configFile.path, + JSON.stringify({ compilerOptions: { ...jsxImportSourceOptions, jsxImportSource: "preact" } }), + ), optionsToExtend: ["--explainFiles"], }); @@ -327,7 +370,10 @@ export const Fragment: unique symbol; host.createDirectory(`${project}/node_modules/react`); host.createDirectory(`${project}/node_modules/react/jsx-runtime`); host.writeFile(`${project}/node_modules/react/jsx-runtime/index.d.ts`, jsxLibraryContent); - host.writeFile(`${project}/node_modules/react/package.json`, JSON.stringify({ name: "react", version: "0.0.1" })); + host.writeFile( + `${project}/node_modules/react/package.json`, + JSON.stringify({ name: "react", version: "0.0.1" }), + ); }, }); @@ -336,7 +382,10 @@ export const Fragment: unique symbol; files: () => [ { path: libFile.path, content: libContent }, { path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent }, - { path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) }, + { + path: `${project}/node_modules/react/package.json`, + content: JSON.stringify({ name: "react", version: "0.0.1" }), + }, { path: `${project}/index.tsx`, content: `export const App = () =>
;` }, { path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }, ], @@ -350,8 +399,14 @@ export const Fragment: unique symbol; subScenario: "importHelpers backing types removed", files: () => [ { path: libFile.path, content: libContent }, - { path: `${project}/node_modules/tslib/index.d.ts`, content: "export function __assign(...args: any[]): any;" }, - { path: `${project}/node_modules/tslib/package.json`, content: JSON.stringify({ name: "tslib", version: "0.0.1" }) }, + { + path: `${project}/node_modules/tslib/index.d.ts`, + content: "export function __assign(...args: any[]): any;", + }, + { + path: `${project}/node_modules/tslib/package.json`, + content: JSON.stringify({ name: "tslib", version: "0.0.1" }), + }, { path: `${project}/index.tsx`, content: `export const x = {...{}};` }, { path: configFile.path, content: JSON.stringify({ compilerOptions: { importHelpers: true } }) }, ], @@ -367,14 +422,29 @@ export const Fragment: unique symbol; subScenario: "editing module augmentation", files: () => [ { path: libFile.path, content: libContent }, - { path: `${project}/node_modules/classnames/index.d.ts`, content: `export interface Result {} export default function classNames(): Result;` }, - { path: `${project}/src/types/classnames.d.ts`, content: `export {}; declare module "classnames" { interface Result { foo } }` }, - { path: `${project}/src/index.ts`, content: `import classNames from "classnames"; classNames().foo;` }, - { path: configFile.path, content: JSON.stringify({ compilerOptions: { module: "commonjs", incremental: true } }) }, + { + path: `${project}/node_modules/classnames/index.d.ts`, + content: `export interface Result {} export default function classNames(): Result;`, + }, + { + path: `${project}/src/types/classnames.d.ts`, + content: `export {}; declare module "classnames" { interface Result { foo } }`, + }, + { + path: `${project}/src/index.ts`, + content: `import classNames from "classnames"; classNames().foo;`, + }, + { + path: configFile.path, + content: JSON.stringify({ compilerOptions: { module: "commonjs", incremental: true } }), + }, ], modifyFs: host => { // delete 'foo' - host.writeFile(`${project}/src/types/classnames.d.ts`, `export {}; declare module "classnames" { interface Result {} }`); + host.writeFile( + `${project}/src/types/classnames.d.ts`, + `export {}; declare module "classnames" { interface Result {} }`, + ); }, }); }); diff --git a/src/testRunner/unittests/tscWatch/moduleResolution.ts b/src/testRunner/unittests/tscWatch/moduleResolution.ts index 28d8de1c42579..389f02fff8e82 100644 --- a/src/testRunner/unittests/tscWatch/moduleResolution.ts +++ b/src/testRunner/unittests/tscWatch/moduleResolution.ts @@ -57,7 +57,8 @@ namespace ts.tscWatch { changes: [ { caption: "reports import errors after change to package file", - change: sys => replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `index.js`, `other.js`), + change: sys => + replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `index.js`, `other.js`), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // invalidates failed lookups sys.runQueuedTimeoutCallbacks(); // actual update @@ -65,7 +66,8 @@ namespace ts.tscWatch { }, { caption: "removes those errors when a package file is changed back", - change: sys => replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `other.js`, `index.js`), + change: sys => + replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `other.js`, `index.js`), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // invalidates failed lookups sys.runQueuedTimeoutCallbacks(); // actual update @@ -176,7 +178,11 @@ namespace ts.tscWatch { }, { caption: "Modify package.json file to remove type module", - change: sys => sys.writeFile(`${projectRoot}/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })), + change: sys => + sys.writeFile( + `${projectRoot}/package.json`, + JSON.stringify({ name: "app", version: "1.0.0" }), + ), timeouts: host => { host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update @@ -230,7 +236,11 @@ namespace ts.tscWatch { changes: [ { caption: "Modify package.json file to remove type module", - change: sys => sys.writeFile(`${projectRoot}/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })), + change: sys => + sys.writeFile( + `${projectRoot}/package.json`, + JSON.stringify({ name: "app", version: "1.0.0" }), + ), timeouts: host => { host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update @@ -262,7 +272,11 @@ namespace ts.tscWatch { }, { caption: "Modify package json file to without type module", - change: sys => sys.writeFile(`${projectRoot}/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })), + change: sys => + sys.writeFile( + `${projectRoot}/package.json`, + JSON.stringify({ name: "app", version: "1.0.0" }), + ), timeouts: host => { host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update diff --git a/src/testRunner/unittests/tscWatch/nodeNextWatch.ts b/src/testRunner/unittests/tscWatch/nodeNextWatch.ts index 181feeb115603..29dbf4487f52b 100644 --- a/src/testRunner/unittests/tscWatch/nodeNextWatch.ts +++ b/src/testRunner/unittests/tscWatch/nodeNextWatch.ts @@ -38,7 +38,10 @@ namespace ts.tscWatch { path: "/project/src/deps.d.ts", content: `declare module "thing";`, }; - return createWatchedSystem([configFile, file1, declFile, packageFile, { ...libFile, path: "/a/lib/lib.es2020.full.d.ts" }]); + return createWatchedSystem([configFile, file1, declFile, packageFile, { + ...libFile, + path: "/a/lib/lib.es2020.full.d.ts", + }]); }, changes: [ { diff --git a/src/testRunner/unittests/tscWatch/programUpdates.ts b/src/testRunner/unittests/tscWatch/programUpdates.ts index 80d2d250f0757..0acc65ccd68e2 100644 --- a/src/testRunner/unittests/tscWatch/programUpdates.ts +++ b/src/testRunner/unittests/tscWatch/programUpdates.ts @@ -142,7 +142,8 @@ namespace ts.tscWatch { verifyTscWatch({ scenario, - subScenario: "handles the missing files - that were added to program because they were added with tripleSlashRefs", + subScenario: + "handles the missing files - that were added to program because they were added with tripleSlashRefs", commandLineArgs: ["-w", "/a/b/commonFile1.ts"], sys: () => { const file1: File = { @@ -301,7 +302,11 @@ export class A { sys.modifyFile( "/tsconfig.json", JSON.stringify({ - compilerOptions: { target: "es6", importsNotUsedAsValues: "error", experimentalDecorators: true }, + compilerOptions: { + target: "es6", + importsNotUsedAsValues: "error", + experimentalDecorators: true, + }, }), ), timeouts: checkSingleTimeoutQueueLengthAndRun, @@ -312,7 +317,12 @@ export class A { sys.modifyFile( "/tsconfig.json", JSON.stringify({ - compilerOptions: { target: "es6", importsNotUsedAsValues: "error", experimentalDecorators: true, emitDecoratorMetadata: true }, + compilerOptions: { + target: "es6", + importsNotUsedAsValues: "error", + experimentalDecorators: true, + emitDecoratorMetadata: true, + }, }), ), timeouts: checkSingleTimeoutQueueLengthAndRun, @@ -553,7 +563,9 @@ export class A { path: "/a/d/f3.ts", content: "export let y = 1;", }; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([libFile, file1, file2, file3])); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([libFile, file1, file2, file3]), + ); const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ rootFiles: [file2.path, file3.path], system: sys, @@ -592,12 +604,16 @@ export class A { sys.checkTimeoutQueueLength(0); baseline.push(`First program is not updated:: ${getPrograms() === emptyArray}`); baseline.push(`Second program is not updated:: ${getPrograms2() === emptyArray}`); - Harness.Baseline.runBaseline(`tscWatch/${scenario}/two-watch-programs-are-not-affected-by-each-other.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/${scenario}/two-watch-programs-are-not-affected-by-each-other.js`, + baseline.join("\r\n"), + ); }); verifyTscWatch({ scenario, - subScenario: "can correctly update configured project when set of root files has changed (new file on disk)", + subScenario: + "can correctly update configured project when set of root files has changed (new file on disk)", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { const file1 = { @@ -617,7 +633,8 @@ export class A { verifyTscWatch({ scenario, - subScenario: "can correctly update configured project when set of root files has changed (new file in list of files)", + subScenario: + "can correctly update configured project when set of root files has changed (new file in list of files)", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { const file1 = { @@ -637,7 +654,11 @@ export class A { changes: [ { caption: "Modify config to make f2 as root too", - change: sys => sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })), + change: sys => + sys.writeFile( + configFilePath, + JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }), + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, ], @@ -645,7 +666,8 @@ export class A { verifyTscWatch({ scenario, - subScenario: "correctly parses wild card directories from implicit glob when two keys differ only in directory seperator", + subScenario: + "correctly parses wild card directories from implicit glob when two keys differ only in directory seperator", commandLineArgs: ["-w", "--extendedDiagnostics"], sys: () => { const file1 = { @@ -689,7 +711,9 @@ export class A { path: `${projectRoot}/Project/tsconfig.json`, content: JSON.stringify({ include: [".", "./**/*.json"] }), }; - return createWatchedSystem([file1, libFile, configFile], { currentDirectory: `${projectRoot}/Project` }); + return createWatchedSystem([file1, libFile, configFile], { + currentDirectory: `${projectRoot}/Project`, + }); }, changes: [ { @@ -722,7 +746,11 @@ export class A { changes: [ { caption: "Modify config to set outFile option", - change: sys => sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] })), + change: sys => + sys.writeFile( + configFilePath, + JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] }), + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, ], @@ -832,7 +860,9 @@ declare const eval: any`, }, ), }; - return createWatchedSystem([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" }); + return createWatchedSystem([libES5, libES2015Promise, app, config1], { + executingFilePath: "/compiler/tsc.js", + }); }, changes: [ { @@ -1075,7 +1105,8 @@ declare const eval: any`, verifyTscWatch({ scenario, - subScenario: "non-existing directories listed in config file input array should be tolerated without crashing the server", + subScenario: + "non-existing directories listed in config file input array should be tolerated without crashing the server", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { const configFile = { @@ -1096,7 +1127,8 @@ declare const eval: any`, verifyTscWatch({ scenario, - subScenario: "non-existing directories listed in config file input array should be able to handle @types if input file list is empty", + subScenario: + "non-existing directories listed in config file input array should be able to handle @types if input file list is empty", commandLineArgs: ["-w", "-p", "/a/tsconfig.json"], sys: () => { const f = { @@ -1118,7 +1150,9 @@ declare const eval: any`, path: "/a/node_modules/@types/typings/lib.d.ts", content: `export const x: number`, }; - return createWatchedSystem([f, config, t1, t2, libFile], { currentDirectory: getDirectoryPath(f.path) }); + return createWatchedSystem([f, config, t1, t2, libFile], { + currentDirectory: getDirectoryPath(f.path), + }); }, changes: emptyArray, }); @@ -1151,7 +1185,8 @@ declare const eval: any`, verifyTscWatch({ scenario, - subScenario: "Options Diagnostic locations reported correctly with changes in configFile contents when options change", + subScenario: + "Options Diagnostic locations reported correctly with changes in configFile contents when options change", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { const file = { @@ -1210,7 +1245,9 @@ declare const eval: any`, path: `${projectRoot}/tsconfig.json`, content: generateTSConfig(options, emptyArray, "\n"), }; - return createWatchedSystem([file1, file2, libFile, tsconfig], { currentDirectory: projectRoot }); + return createWatchedSystem([file1, file2, libFile, tsconfig], { + currentDirectory: projectRoot, + }); }, changes: [ noopChange, @@ -1257,7 +1294,8 @@ declare const eval: any`, verifyTscWatch({ scenario, - subScenario: "shouldnt report error about unused function incorrectly when file changes from global to module", + subScenario: + "shouldnt report error about unused function incorrectly when file changes from global to module", commandLineArgs: ["-w", "/a/b/file.ts", "--noUnusedLocals"], sys: () => { const file: File = { @@ -1308,7 +1346,8 @@ export function two() { changes: [ { caption: "Rename file1 to file2", - change: sys => sys.renameFile("/home/username/project/src/file1.ts", "/home/username/project/src/file2.ts"), + change: sys => + sys.renameFile("/home/username/project/src/file1.ts", "/home/username/project/src/file2.ts"), timeouts: runQueuedTimeoutCallbacks, }, ], @@ -1317,7 +1356,13 @@ export function two() { function changeParameterTypeOfBFile(parameterName: string, toType: string): TscWatchCompileChange { return { caption: `Changed ${parameterName} type to ${toType}`, - change: sys => replaceFileText(sys, `${projectRoot}/b.ts`, new RegExp(`${parameterName}\: [a-z]*`), `${parameterName}: ${toType}`), + change: sys => + replaceFileText( + sys, + `${projectRoot}/b.ts`, + new RegExp(`${parameterName}\: [a-z]*`), + `${parameterName}: ${toType}`, + ), timeouts: runQueuedTimeoutCallbacks, }; } @@ -1378,17 +1423,26 @@ foo().hello`, changes: [ { caption: "Enable strict null checks", - change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { strictNullChecks: true } })), + change: sys => + sys.writeFile( + `${projectRoot}/tsconfig.json`, + JSON.stringify({ compilerOptions: { strictNullChecks: true } }), + ), timeouts: runQueuedTimeoutCallbacks, }, { caption: "Set always strict false", - change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { strict: true, alwaysStrict: false } })), // Avoid changing 'alwaysStrict' or must re-bind + change: sys => + sys.writeFile( + `${projectRoot}/tsconfig.json`, + JSON.stringify({ compilerOptions: { strict: true, alwaysStrict: false } }), + ), // Avoid changing 'alwaysStrict' or must re-bind timeouts: runQueuedTimeoutCallbacks, }, { caption: "Disable strict", - change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: {} })), + change: sys => + sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: {} })), timeouts: runQueuedTimeoutCallbacks, }, ], @@ -1421,7 +1475,11 @@ v === 'foo';`, changes: [ { caption: "Enable noErrorTruncation", - change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { noErrorTruncation: true } })), + change: sys => + sys.writeFile( + `${projectRoot}/tsconfig.json`, + JSON.stringify({ compilerOptions: { noErrorTruncation: true } }), + ), timeouts: runQueuedTimeoutCallbacks, }, ], @@ -1446,7 +1504,11 @@ class D extends C { prop = 1; }`, changes: [ { caption: "Enable useDefineForClassFields", - change: sys => sys.writeFile(`/tsconfig.json`, JSON.stringify({ compilerOptions: { target: "es6", useDefineForClassFields: true } })), + change: sys => + sys.writeFile( + `/tsconfig.json`, + JSON.stringify({ compilerOptions: { target: "es6", useDefineForClassFields: true } }), + ), timeouts: runQueuedTimeoutCallbacks, }, ], @@ -1475,17 +1537,29 @@ export function f(p: C) { return p; }`, changes: [ { caption: 'Set to "remove"', - change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "remove" } })), + change: sys => + sys.writeFile( + `${projectRoot}/tsconfig.json`, + JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "remove" } }), + ), timeouts: runQueuedTimeoutCallbacks, }, { caption: 'Set to "error"', - change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "error" } })), + change: sys => + sys.writeFile( + `${projectRoot}/tsconfig.json`, + JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "error" } }), + ), timeouts: runQueuedTimeoutCallbacks, }, { caption: 'Set to "preserve"', - change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "preserve" } })), + change: sys => + sys.writeFile( + `${projectRoot}/tsconfig.json`, + JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "preserve" } }), + ), timeouts: runQueuedTimeoutCallbacks, }, ], @@ -1513,7 +1587,11 @@ export function f(p: C) { return p; }`, changes: [ { caption: "Enable forceConsistentCasingInFileNames", - change: sys => sys.writeFile(`/tsconfig.json`, JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } })), + change: sys => + sys.writeFile( + `/tsconfig.json`, + JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }), + ), timeouts: runQueuedTimeoutCallbacks, }, ], @@ -1541,7 +1619,11 @@ export function f(p: C) { return p; }`, changes: [ { caption: "Enable resolveJsonModule", - change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { moduleResolution: "node", resolveJsonModule: true } })), + change: sys => + sys.writeFile( + `${projectRoot}/tsconfig.json`, + JSON.stringify({ compilerOptions: { moduleResolution: "node", resolveJsonModule: true } }), + ), timeouts: runQueuedTimeoutCallbacks, }, ], @@ -1609,7 +1691,11 @@ interface Document { changes: [ { caption: "Remove document declaration from file", - change: sys => sys.writeFile(aFile.path, aFile.content.replace(fieldWithoutReadonly, "var x: string;")), + change: sys => + sys.writeFile( + aFile.path, + aFile.content.replace(fieldWithoutReadonly, "var x: string;"), + ), timeouts: runQueuedTimeoutCallbacks, }, { @@ -1686,7 +1772,9 @@ interface Document { path: `${projectRoot}/tsconfig.json`, content: "{}", }; - return createWatchedSystem([aFile, bFile, configFile, libFileWithDocument], { currentDirectory: projectRoot }); + return createWatchedSystem([aFile, bFile, configFile, libFileWithDocument], { + currentDirectory: projectRoot, + }); }, changes: [ changeWhenLibCheckChanges({ skipLibCheck: true }), @@ -1792,7 +1880,8 @@ import { x } from "../b";`, changes: [ { caption: "Update 'jsx' to 'react'", - change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, '{ "compilerOptions": { "jsx": "react" } }'), + change: sys => + sys.writeFile(`${projectRoot}/tsconfig.json`, '{ "compilerOptions": { "jsx": "react" } }'), timeouts: runQueuedTimeoutCallbacks, }, ], @@ -1916,12 +2005,18 @@ import { x } from "../b";`, include: ["client/**/*", "folder2"], }), }; - return createWatchedSystem([module1, module2, symlink, config, libFile], { currentDirectory: projectRoot }); + return createWatchedSystem([module1, module2, symlink, config, libFile], { + currentDirectory: projectRoot, + }); }, changes: [ { caption: "Add module3 to folder2", - change: sys => sys.writeFile(`${projectRoot}/client/linktofolder2/module3.ts`, `import * as M from "folder1/module1";`), + change: sys => + sys.writeFile( + `${projectRoot}/client/linktofolder2/module3.ts`, + `import * as M from "folder1/module1";`, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, ], @@ -1977,12 +2072,17 @@ import { x } from "../b";`, }, { caption: "Add output of class3", - change: sys => sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), + change: sys => + sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Add excluded file to project1", - change: sys => sys.ensureFileOrFolder({ path: `${projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }), + change: sys => + sys.ensureFileOrFolder({ + path: `${projectRoot}/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }), timeouts: sys => sys.checkTimeoutQueueLength(0), }, { @@ -1992,7 +2092,8 @@ import { x } from "../b";`, }, { caption: "Add output of class3", - change: sys => sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), + change: sys => + sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), timeouts: checkSingleTimeoutQueueLengthAndRun, }, ], diff --git a/src/testRunner/unittests/tscWatch/projectsWithReferences.ts b/src/testRunner/unittests/tscWatch/projectsWithReferences.ts index 45c7a0d0542d7..1e984afd08fb1 100644 --- a/src/testRunner/unittests/tscWatch/projectsWithReferences.ts +++ b/src/testRunner/unittests/tscWatch/projectsWithReferences.ts @@ -24,7 +24,10 @@ namespace ts.tscWatch { { caption: "local edit in logic ts, and build logic", change: sys => { - sys.appendFile(TestFSWithWatch.getTsBuildProjectFilePath("sample1", "logic/index.ts"), `function foo() { }`); + sys.appendFile( + TestFSWithWatch.getTsBuildProjectFilePath("sample1", "logic/index.ts"), + `function foo() { }`, + ); const solutionBuilder = createSolutionBuilder(sys, ["logic"]); solutionBuilder.build(); }, @@ -35,7 +38,10 @@ namespace ts.tscWatch { { caption: "non local edit in logic ts, and build logic", change: sys => { - sys.appendFile(TestFSWithWatch.getTsBuildProjectFilePath("sample1", "logic/index.ts"), `export function gfoo() { }`); + sys.appendFile( + TestFSWithWatch.getTsBuildProjectFilePath("sample1", "logic/index.ts"), + `export function gfoo() { }`, + ); const solutionBuilder = createSolutionBuilder(sys, ["logic"]); solutionBuilder.build(); }, @@ -89,7 +95,10 @@ namespace ts.tscWatch { { caption: "non local edit b ts, and build b", change: sys => { - sys.appendFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b.ts"), `export function gfoo() { }`); + sys.appendFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b.ts"), + `export function gfoo() { }`, + ); const solutionBuilder = createSolutionBuilder(sys, ["tsconfig.b.json"]); solutionBuilder.build(); }, @@ -100,45 +109,78 @@ namespace ts.tscWatch { change: sys => { sys.ensureFileOrFolder({ path: TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"), - content: sys.readFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!, + content: sys.readFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"), + )!, }); - changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), { "@ref/*": ["./nrefs/*"] }); + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), + { "@ref/*": ["./nrefs/*"] }, + ); }, timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Revert config file edit", - change: sys => changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), { "@ref/*": ["./refs/*"] }), + change: sys => + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), + { "@ref/*": ["./refs/*"] }, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "edit in referenced config file", - change: sys => changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), { "@ref/*": ["./nrefs/*"] }), + change: sys => + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), + { "@ref/*": ["./nrefs/*"] }, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Revert referenced config file edit", - change: sys => changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), { "@ref/*": ["./refs/*"] }), + change: sys => + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), + { "@ref/*": ["./refs/*"] }, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "deleting referenced config file", - change: sys => sys.deleteFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json")), + change: sys => + sys.deleteFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Revert deleting referenced config file", - change: sys => sys.ensureFileOrFolder(TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.b.json")), + change: sys => + sys.ensureFileOrFolder( + TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.b.json"), + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "deleting transitively referenced config file", - change: sys => sys.deleteFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.a.json")), + change: sys => + sys.deleteFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.a.json"), + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Revert deleting transitively referenced config file", - change: sys => sys.ensureFileOrFolder(TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json")), + change: sys => + sys.ensureFileOrFolder( + TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json"), + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, ], @@ -234,7 +276,10 @@ X;`, { caption: "non local edit b ts, and build b", change: sys => { - sys.appendFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), `export function gfoo() { }`); + sys.appendFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), + `export function gfoo() { }`, + ); const solutionBuilder = createSolutionBuilder(sys, ["b"]); solutionBuilder.build(); }, @@ -245,30 +290,54 @@ X;`, change: sys => { sys.ensureFileOrFolder({ path: TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"), - content: sys.readFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!, + content: sys.readFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"), + )!, }); - changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }); + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + { "@ref/*": ["../nrefs/*"] }, + ); }, timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Revert config file edit", - change: sys => changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../refs/*"] }), + change: sys => + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + { "@ref/*": ["../refs/*"] }, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "edit in referenced config file", - change: sys => changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }), + change: sys => + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + { "@ref/*": ["../nrefs/*"] }, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Revert referenced config file edit", - change: sys => changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../refs/*"] }), + change: sys => + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + { "@ref/*": ["../refs/*"] }, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "deleting referenced config file", - change: sys => sys.deleteFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json")), + change: sys => + sys.deleteFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + ), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), }, { @@ -286,7 +355,10 @@ X;`, }, { caption: "deleting transitively referenced config file", - change: sys => sys.deleteFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json")), + change: sys => + sys.deleteFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), + ), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), }, { @@ -356,7 +428,10 @@ X;`, { caption: "non local edit b ts, and build b", change: sys => { - sys.appendFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), `export function gfoo() { }`); + sys.appendFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), + `export function gfoo() { }`, + ); const solutionBuilder = createSolutionBuilder(sys, ["b"]); solutionBuilder.build(); }, @@ -367,30 +442,54 @@ X;`, change: sys => { sys.ensureFileOrFolder({ path: TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"), - content: sys.readFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!, + content: sys.readFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"), + )!, }); - changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }); + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + { "@ref/*": ["../nrefs/*"] }, + ); }, timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Revert config file edit", - change: sys => changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../refs/*"] }), + change: sys => + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + { "@ref/*": ["../refs/*"] }, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "edit in referenced config file", - change: sys => changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }), + change: sys => + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + { "@ref/*": ["../nrefs/*"] }, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Revert referenced config file edit", - change: sys => changeCompilerOpitonsPaths(sys, TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../refs/*"] }), + change: sys => + changeCompilerOpitonsPaths( + sys, + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + { "@ref/*": ["../refs/*"] }, + ), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "deleting referenced config file", - change: sys => sys.deleteFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json")), + change: sys => + sys.deleteFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + ), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), }, { @@ -407,7 +506,10 @@ X;`, }, { caption: "deleting transitively referenced config file", - change: sys => sys.deleteFile(TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json")), + change: sys => + sys.deleteFile( + TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), + ), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), }, { diff --git a/src/testRunner/unittests/tscWatch/resolutionCache.ts b/src/testRunner/unittests/tscWatch/resolutionCache.ts index d958cbaca7e2c..6ee8e1424ef1b 100644 --- a/src/testRunner/unittests/tscWatch/resolutionCache.ts +++ b/src/testRunner/unittests/tscWatch/resolutionCache.ts @@ -11,7 +11,9 @@ namespace ts.tscWatch { content: `foo()`, }; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([root, imported, libFile])); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([root, imported, libFile]), + ); const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ rootFiles: [root.path], system: sys, @@ -155,7 +157,9 @@ namespace ts.tscWatch { content: `export const y = 1;export const x = 10;`, }; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([root, imported, libFile])); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([root, imported, libFile]), + ); const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ rootFiles: [root.path], system: sys, @@ -323,7 +327,9 @@ declare module "fs" { }, }), }; - return createWatchedSystem([file1, file2, module1, libFile, configFile], { currentDirectory: "/a/b/projects/myProject/" }); + return createWatchedSystem([file1, file2, module1, libFile, configFile], { + currentDirectory: "/a/b/projects/myProject/", + }); }, changes: [ { @@ -384,7 +390,8 @@ declare module "fs" { caption: "npm install file and folder that start with '.'", change: sys => sys.ensureFileOrFolder({ - path: `${projectRoot}/node_modules/.cache/babel-loader/89c02171edab901b9926470ba6d5677e.ts`, + path: + `${projectRoot}/node_modules/.cache/babel-loader/89c02171edab901b9926470ba6d5677e.ts`, content: JSON.stringify({ something: 10 }), }), timeouts: sys => sys.checkTimeoutQueueLength(0), @@ -445,8 +452,14 @@ declare namespace myapp { change: noop, timeouts: (sys, [[oldProgram, oldBuilderProgram]], watchorSolution) => { sys.checkTimeoutQueueLength(0); - const newProgram = (watchorSolution as WatchOfConfigFile).getProgram(); - assert.strictEqual(newProgram, oldBuilderProgram, "No change so builder program should be same"); + const newProgram = + (watchorSolution as WatchOfConfigFile) + .getProgram(); + assert.strictEqual( + newProgram, + oldBuilderProgram, + "No change so builder program should be same", + ); assert.strictEqual(newProgram.getProgram(), oldProgram, "No change so program should be same"); }, }, @@ -477,7 +490,12 @@ declare namespace myapp { }; const linkedPackageJson: File = { path: `${linkedPackageRoot}/package.json`, - content: JSON.stringify({ name: "@scoped/linked-package", version: "0.0.1", types: "dist/index.d.ts", main: "dist/index.js" }), + content: JSON.stringify({ + name: "@scoped/linked-package", + version: "0.0.1", + types: "dist/index.d.ts", + main: "dist/index.js", + }), }; const linkedPackageIndex: File = { path: `${linkedPackageRoot}/dist/index.d.ts`, @@ -487,7 +505,15 @@ declare namespace myapp { path: `${linkedPackageRoot}/dist/other.d.ts`, content: 'export declare const Foo = "BAR";', }; - const files = [libFile, mainFile, config, linkedPackageInMain, linkedPackageJson, linkedPackageIndex, linkedPackageOther]; + const files = [ + libFile, + mainFile, + config, + linkedPackageInMain, + linkedPackageJson, + linkedPackageIndex, + linkedPackageOther, + ]; return createWatchedSystem(files, { currentDirectory: mainPackageRoot }); }, changes: emptyArray, @@ -501,7 +527,8 @@ declare namespace myapp { }; const nodeAtTypesBase: File = { path: `${projectRoot}/node_modules/@types/node/base.d.ts`, - content: `// Base definitions for all NodeJS modules that are not specific to any version of TypeScript: + content: + `// Base definitions for all NodeJS modules that are not specific to any version of TypeScript: /// `, }; const nodeAtTypes36Base: File = { @@ -521,7 +548,8 @@ declare namespace NodeJS { } verifyTscWatch({ scenario, - subScenario: "works when installing something in node_modules or @types when there is no notification from fs for index file", + subScenario: + "works when installing something in node_modules or @types when there is no notification from fs for index file", commandLineArgs: ["--w", `--extendedDiagnostics`], sys: () => { const file: File = { @@ -532,8 +560,17 @@ declare namespace NodeJS { path: `${projectRoot}/tsconfig.json`, content: "{}", }; - const { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals } = getNodeAtTypes(); - return createWatchedSystem([file, libFile, tsconfig, nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals], { currentDirectory: projectRoot }); + const { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals } = + getNodeAtTypes(); + return createWatchedSystem([ + file, + libFile, + tsconfig, + nodeAtTypesIndex, + nodeAtTypesBase, + nodeAtTypes36Base, + nodeAtTypesGlobals, + ], { currentDirectory: projectRoot }); }, changes: [ { @@ -556,13 +593,24 @@ declare namespace NodeJS { timeouts: runQueuedTimeoutCallbacks, }, { - caption: `npm ci step four: create atTypes write all the files but dont invoke watcher for index.d.ts`, + caption: + `npm ci step four: create atTypes write all the files but dont invoke watcher for index.d.ts`, change: sys => { - const { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals } = getNodeAtTypes(); + const { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals } = + getNodeAtTypes(); sys.ensureFileOrFolder(nodeAtTypesBase); - sys.ensureFileOrFolder(nodeAtTypesIndex, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true); - sys.ensureFileOrFolder(nodeAtTypes36Base, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true); - sys.ensureFileOrFolder(nodeAtTypesGlobals, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true); + sys.ensureFileOrFolder( + nodeAtTypesIndex, + /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true, + ); + sys.ensureFileOrFolder( + nodeAtTypes36Base, + /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true, + ); + sys.ensureFileOrFolder( + nodeAtTypesGlobals, + /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true, + ); }, timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // update failed lookups diff --git a/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts b/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts index fc157aa299a79..c4089fdce9556 100644 --- a/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts +++ b/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts @@ -55,7 +55,16 @@ namespace ts.tscWatch { const indexTs = getFileFromProject("demo", "animals/index.ts"); const animalsConfig = getFileFromProject("demo", "animals/tsconfig.json"); return { - files: [{ path: libFile.path, content: libContent }, baseConfig, coreTs, coreConfig, animalTs, dogTs, indexTs, animalsConfig], + files: [ + { path: libFile.path, content: libContent }, + baseConfig, + coreTs, + coreConfig, + animalTs, + dogTs, + indexTs, + animalsConfig, + ], config: animalsConfig.path, subScenario: "with simple project", }; diff --git a/src/testRunner/unittests/tscWatch/watchApi.ts b/src/testRunner/unittests/tscWatch/watchApi.ts index e47960819dfc9..31efc7a963c91 100644 --- a/src/testRunner/unittests/tscWatch/watchApi.ts +++ b/src/testRunner/unittests/tscWatch/watchApi.ts @@ -68,9 +68,17 @@ namespace ts.tscWatch { system: sys, cb, }); - host.resolveModuleNames = (moduleNames, containingFile, _reusedNames, _redirectedReference, options) => moduleNames.map(m => resolveModuleName(m, containingFile, options, host).resolvedModule); + host.resolveModuleNames = ( + moduleNames, + containingFile, + _reusedNames, + _redirectedReference, + options, + ) => moduleNames.map(m => resolveModuleName(m, containingFile, options, host).resolvedModule); // Invalidate resolutions only when ts file is created - if (implementHasInvalidatedResolution) host.hasInvalidatedResolutions = () => sys.fileExists(`${projectRoot}/other.ts`); + if (implementHasInvalidatedResolution) { + host.hasInvalidatedResolutions = () => sys.fileExists(`${projectRoot}/other.ts`); + } const watch = createWatchProgram(host); runWatchBaseline({ scenario: "watchApi", @@ -88,7 +96,8 @@ namespace ts.tscWatch { }, { caption: "change other file", - change: sys => sys.appendFile(`${projectRoot}/other.d.ts`, "export function bar(): void;"), + change: sys => + sys.appendFile(`${projectRoot}/other.d.ts`, "export function bar(): void;"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { @@ -104,7 +113,10 @@ namespace ts.tscWatch { }); }); } - verifyWatch("host implements does not implement hasInvalidatedResolutions", /*implementHasInvalidatedResolution*/ false); + verifyWatch( + "host implements does not implement hasInvalidatedResolutions", + /*implementHasInvalidatedResolution*/ false, + ); verifyWatch("host implements hasInvalidatedResolutions", /*implementHasInvalidatedResolution*/ true); }); }); @@ -163,7 +175,9 @@ namespace ts.tscWatch { path: `${projectRoot}/main.ts`, content: "const x = 10;", }; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([config, mainFile, libFile])); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([config, mainFile, libFile]), + ); const host = createWatchCompilerHostOfConfigFileForBaseline({ configFileName: config.path, system: sys, @@ -288,8 +302,18 @@ namespace ts.tscWatch { function verifyOutputs(baseline: string[], sys: System, emitSys: System) { baseline.push("Checking if output is same as EmitAndSemanticDiagnosticsBuilderProgram::"); - for (const output of [`${projectRoot}/main.js`, `${projectRoot}/main.d.ts`, `${projectRoot}/other.js`, `${projectRoot}/other.d.ts`, `${projectRoot}/tsconfig.tsbuildinfo`]) { - baseline.push(`Output file text for ${output} is same:: ${sys.readFile(output) === emitSys.readFile(output)}`); + for ( + const output of [ + `${projectRoot}/main.js`, + `${projectRoot}/main.d.ts`, + `${projectRoot}/other.js`, + `${projectRoot}/other.d.ts`, + `${projectRoot}/tsconfig.tsbuildinfo`, + ] + ) { + baseline.push( + `Output file text for ${output} is same:: ${sys.readFile(output) === emitSys.readFile(output)}`, + ); } baseline.push(""); } @@ -328,7 +352,10 @@ namespace ts.tscWatch { } it("verifies that noEmit is handled on createSemanticDiagnosticsBuilderProgram and typechecking happens only on affected files", () => { - const { sys, baseline, oldSnap, cb, getPrograms, config, mainFile } = createSystem("{}", "export const x = 10;"); + const { sys, baseline, oldSnap, cb, getPrograms, config, mainFile } = createSystem( + "{}", + "export const x = 10;", + ); const host = createWatchCompilerHostOfConfigFileForBaseline({ configFileName: config.path, optionsToExtend: { noEmit: true }, @@ -366,22 +393,60 @@ namespace ts.tscWatch { const { sys, config, mainFile, emitSys } = result; // No Emit - verifyBuilder(baseline, emitBaseline, config, sys, emitSys, createEmitAndSemanticDiagnosticsBuilderProgram, { noEmit: true }); + verifyBuilder( + baseline, + emitBaseline, + config, + sys, + emitSys, + createEmitAndSemanticDiagnosticsBuilderProgram, + { noEmit: true }, + ); // Emit on both sys should result in same output - verifyBuilder(baseline, emitBaseline, config, sys, emitSys, createEmitAndSemanticDiagnosticsBuilderProgram); + verifyBuilder( + baseline, + emitBaseline, + config, + sys, + emitSys, + createEmitAndSemanticDiagnosticsBuilderProgram, + ); // Change file - applyChangeForBuilderTest(baseline, emitBaseline, sys, emitSys, sys => sys.appendFile(mainFile.path, "\n// SomeComment"), "Add comment"); + applyChangeForBuilderTest( + baseline, + emitBaseline, + sys, + emitSys, + sys => sys.appendFile(mainFile.path, "\n// SomeComment"), + "Add comment", + ); // Verify noEmit results in same output - verifyBuilder(baseline, emitBaseline, config, sys, emitSys, createSemanticDiagnosticsBuilderProgram, { noEmit: true }); + verifyBuilder(baseline, emitBaseline, config, sys, emitSys, createSemanticDiagnosticsBuilderProgram, { + noEmit: true, + }); // Emit on both sys should result in same output - verifyBuilder(baseline, emitBaseline, config, sys, emitSys, createEmitAndSemanticDiagnosticsBuilderProgram); + verifyBuilder( + baseline, + emitBaseline, + config, + sys, + emitSys, + createEmitAndSemanticDiagnosticsBuilderProgram, + ); // Change file - applyChangeForBuilderTest(baseline, emitBaseline, sys, emitSys, sys => sys.appendFile(mainFile.path, "\n// SomeComment"), "Add comment"); + applyChangeForBuilderTest( + baseline, + emitBaseline, + sys, + emitSys, + sys => sys.appendFile(mainFile.path, "\n// SomeComment"), + "Add comment", + ); // Emit on both the builders should result in same files verifyBuilder(baseline, emitBaseline, config, sys, emitSys, createSemanticDiagnosticsBuilderProgram); @@ -391,10 +456,16 @@ namespace ts.tscWatch { emitBaseline = undefined!; }); it("noEmit with composite writes the tsbuildinfo with pending affected files correctly", () => { - Harness.Baseline.runBaseline(`tscWatch/watchApi/noEmit-with-composite-with-semantic-builder.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/watchApi/noEmit-with-composite-with-semantic-builder.js`, + baseline.join("\r\n"), + ); }); it("baseline in createEmitAndSemanticDiagnosticsBuilderProgram:: noEmit with composite writes the tsbuildinfo with pending affected files correctly", () => { - Harness.Baseline.runBaseline(`tscWatch/watchApi/noEmit-with-composite-with-emit-builder.js`, emitBaseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/watchApi/noEmit-with-composite-with-emit-builder.js`, + emitBaseline.join("\r\n"), + ); }); }); @@ -413,30 +484,53 @@ namespace ts.tscWatch { verifyBuilder(baseline, emitBaseline, config, sys, emitSys, createSemanticDiagnosticsBuilderProgram); // Change file - applyChangeForBuilderTest(baseline, emitBaseline, sys, emitSys, sys => sys.appendFile(mainFile.path, "\n// SomeComment"), "Add comment"); + applyChangeForBuilderTest( + baseline, + emitBaseline, + sys, + emitSys, + sys => sys.appendFile(mainFile.path, "\n// SomeComment"), + "Add comment", + ); // Verify noEmit results in same output verifyBuilder(baseline, emitBaseline, config, sys, emitSys, createSemanticDiagnosticsBuilderProgram); // Fix error const fixed = "export const x = 10;"; - applyChangeForBuilderTest(baseline, emitBaseline, sys, emitSys, sys => sys.writeFile(mainFile.path, fixed), "Fix error"); + applyChangeForBuilderTest( + baseline, + emitBaseline, + sys, + emitSys, + sys => sys.writeFile(mainFile.path, fixed), + "Fix error", + ); // Emit on both the builders should result in same files verifyBuilder(baseline, emitBaseline, config, sys, emitSys, createSemanticDiagnosticsBuilderProgram); }); it("noEmitOnError with composite writes the tsbuildinfo with pending affected files correctly", () => { - Harness.Baseline.runBaseline(`tscWatch/watchApi/noEmitOnError-with-composite-with-semantic-builder.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/watchApi/noEmitOnError-with-composite-with-semantic-builder.js`, + baseline.join("\r\n"), + ); }); it("baseline in createEmitAndSemanticDiagnosticsBuilderProgram:: noEmitOnError with composite writes the tsbuildinfo with pending affected files correctly", () => { - Harness.Baseline.runBaseline(`tscWatch/watchApi/noEmitOnError-with-composite-with-emit-builder.js`, emitBaseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/watchApi/noEmitOnError-with-composite-with-emit-builder.js`, + emitBaseline.join("\r\n"), + ); }); }); it("SemanticDiagnosticsBuilderProgram emitDtsOnly does not update affected files pending emit", () => { // Initial - const { sys, baseline, config, mainFile } = createSystem(JSON.stringify({ compilerOptions: { composite: true, noEmitOnError: true } }), "export const x: string = 10;"); + const { sys, baseline, config, mainFile } = createSystem( + JSON.stringify({ compilerOptions: { composite: true, noEmitOnError: true } }), + "export const x: string = 10;", + ); createWatch(baseline, config, sys, createSemanticDiagnosticsBuilderProgram); // Fix error and emit @@ -457,9 +551,17 @@ namespace ts.tscWatch { const diagnostics = sortAndDeduplicateDiagnostics(program.getSemanticDiagnostics()); diagnostics.forEach(reportDiagnostic); // Buildinfo should still have affectedFilesPendingEmit since we are only emitting dts files - program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDts*/ true); + program.emit( + /*targetSourceFile*/ undefined, + /*writeFile*/ undefined, + /*cancellationToken*/ undefined, + /*emitOnlyDts*/ true, + ); reportWatchStatus( - createCompilerDiagnostic(getWatchErrorSummaryDiagnosticMessage(diagnostics.length), diagnostics.length), + createCompilerDiagnostic( + getWatchErrorSummaryDiagnosticMessage(diagnostics.length), + diagnostics.length, + ), sys.newLine, program.getCompilerOptions(), diagnostics.length, @@ -532,7 +634,8 @@ namespace ts.tscWatch { fileExists: path => system.fileExists(path), readFile: path => system.readFile(path), getCurrentDirectory: () => system.getCurrentDirectory(), - readDirectory: (path, extensions, excludes, includes, depth) => system.readDirectory(path, extensions, excludes, includes, depth), + readDirectory: (path, extensions, excludes, includes, depth) => + system.readDirectory(path, extensions, excludes, includes, depth), onUnRecoverableConfigFileDiagnostic: noop, }); }; @@ -544,7 +647,8 @@ namespace ts.tscWatch { const { watch, baseline, config2, calledGetParsedCommandLine } = setup(returnTrue); runWatchBaseline({ scenario: "watchApi", - subScenario: "when new file is added to the referenced project with host implementing getParsedCommandLine", + subScenario: + "when new file is added to the referenced project with host implementing getParsedCommandLine", commandLineArgs: ["--w", "-p", config2.path, "--extendedDiagnostics"], ...baseline, changes: [ @@ -558,12 +662,17 @@ namespace ts.tscWatch { }, { caption: "Add excluded file to project1", - change: sys => sys.ensureFileOrFolder({ path: `${projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }), + change: sys => + sys.ensureFileOrFolder({ + path: `${projectRoot}/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }), timeouts: sys => sys.checkTimeoutQueueLength(0), }, { caption: "Add output of class3", - change: sys => sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), + change: sys => + sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), timeouts: sys => sys.checkTimeoutQueueLength(0), }, ], @@ -575,7 +684,8 @@ namespace ts.tscWatch { const { watch, baseline, config2, calledGetParsedCommandLine } = setup(); runWatchBaseline({ scenario: "watchApi", - subScenario: "when new file is added to the referenced project with host implementing getParsedCommandLine without implementing useSourceOfProjectReferenceRedirect", + subScenario: + "when new file is added to the referenced project with host implementing getParsedCommandLine without implementing useSourceOfProjectReferenceRedirect", commandLineArgs: ["--w", "-p", config2.path, "--extendedDiagnostics"], ...baseline, changes: [ @@ -589,12 +699,17 @@ namespace ts.tscWatch { }, { caption: "Add class3 output to project1", - change: sys => sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), + change: sys => + sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), timeouts: checkSingleTimeoutQueueLengthAndRun, }, { caption: "Add excluded file to project1", - change: sys => sys.ensureFileOrFolder({ path: `${projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }), + change: sys => + sys.ensureFileOrFolder({ + path: `${projectRoot}/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }), timeouts: sys => sys.checkTimeoutQueueLength(0), }, { @@ -604,7 +719,8 @@ namespace ts.tscWatch { }, { caption: "Add output of class3", - change: sys => sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), + change: sys => + sys.writeFile(`${projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`), timeouts: checkSingleTimeoutQueueLengthAndRun, }, ], diff --git a/src/testRunner/unittests/tscWatch/watchEnvironment.ts b/src/testRunner/unittests/tscWatch/watchEnvironment.ts index 50340d3e2c7ca..4e29bb06fc1b8 100644 --- a/src/testRunner/unittests/tscWatch/watchEnvironment.ts +++ b/src/testRunner/unittests/tscWatch/watchEnvironment.ts @@ -51,8 +51,13 @@ namespace ts.tscWatch { timeouts: (sys, programs) => { const initialProgram = programs[0][0]; const mediumPollingIntervalThreshold = unchangedPollThresholds[PollingInterval.Medium]; - const newThreshold = unchangedPollThresholds[PollingInterval.Low] + mediumPollingIntervalThreshold; - for (let fileUnchangeDetected = 1; fileUnchangeDetected < newThreshold; fileUnchangeDetected++) { + const newThreshold = unchangedPollThresholds[PollingInterval.Low] + + mediumPollingIntervalThreshold; + for ( + let fileUnchangeDetected = 1; + fileUnchangeDetected < newThreshold; + fileUnchangeDetected++ + ) { // For high + Medium/low polling interval sys.checkTimeoutQueueLengthAndRun(2); assert.deepEqual(programs[0][0], initialProgram); @@ -165,11 +170,20 @@ namespace ts.tscWatch { }); } - verifyRenamingFileInSubFolder("uses watchFile when renaming file in subfolder", Tsc_WatchDirectory.WatchFile); + verifyRenamingFileInSubFolder( + "uses watchFile when renaming file in subfolder", + Tsc_WatchDirectory.WatchFile, + ); - verifyRenamingFileInSubFolder("uses non recursive watchDirectory when renaming file in subfolder", Tsc_WatchDirectory.NonRecursiveWatchDirectory); + verifyRenamingFileInSubFolder( + "uses non recursive watchDirectory when renaming file in subfolder", + Tsc_WatchDirectory.NonRecursiveWatchDirectory, + ); - verifyRenamingFileInSubFolder("uses non recursive dynamic polling when renaming file in subfolder", Tsc_WatchDirectory.DynamicPolling); + verifyRenamingFileInSubFolder( + "uses non recursive dynamic polling when renaming file in subfolder", + Tsc_WatchDirectory.DynamicPolling, + ); verifyTscWatch({ scenario, @@ -209,7 +223,17 @@ namespace ts.tscWatch { path: `${cwd}/node_modules/realb/node_modules/a`, symLink: `${cwd}/node_modules/a`, }; - const files = [libFile, file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB]; + const files = [ + libFile, + file1, + tsconfig, + realA, + realB, + symLinkA, + symLinkB, + symLinkBInA, + symLinkAInB, + ]; const environmentVariables = new Map(); environmentVariables.set("TSC_WATCHDIRECTORY", Tsc_WatchDirectory.NonRecursiveWatchDirectory); return createWatchedSystem(files, { environmentVariables, currentDirectory: cwd }); @@ -278,7 +302,8 @@ namespace ts.tscWatch { }, { caption: "npm install index file in file2", - change: sys => sys.writeFile(`${projectRoot}/node_modules/file2/index.d.ts`, `export const x = 10;`), + change: sys => + sys.writeFile(`${projectRoot}/node_modules/file2/index.d.ts`, `export const x = 10;`), timeouts: sys => sys.checkTimeoutQueueLength(1), // To update folder structure }, { @@ -310,7 +335,8 @@ namespace ts.tscWatch { verifyTscWatch({ scenario, - subScenario: "watchDirectories/with non synchronous watch directory with outDir and declaration enabled", + subScenario: + "watchDirectories/with non synchronous watch directory with outDir and declaration enabled", commandLineArgs: ["--w", "-p", `${projectRoot}/tsconfig.json`], sys: () => { const configFile: File = { @@ -341,7 +367,8 @@ namespace ts.tscWatch { timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), // Scheduling failed lookup update and program update }, { - caption: "After program emit with new file, should schedule and run timeout to update directory watcher", + caption: + "After program emit with new file, should schedule and run timeout to update directory watcher", change: noop, timeouts: checkSingleTimeoutQueueLengthAndRun, // Update the child watch }, @@ -446,7 +473,10 @@ namespace ts.tscWatch { }), }; const files = [libFile, commonFile1, commonFile2, configFile]; - return createWatchedSystem(files, { runWithoutRecursiveWatches: true, runWithFallbackPolling: true }); + return createWatchedSystem(files, { + runWithoutRecursiveWatches: true, + runWithFallbackPolling: true, + }); }, changes: emptyArray, }); @@ -505,7 +535,8 @@ namespace ts.tscWatch { changes: [ { caption: "Change foo", - change: sys => replaceFileText(sys, `${projectRoot}/node_modules/bar/foo.d.ts`, "foo", "fooBar"), + change: sys => + replaceFileText(sys, `${projectRoot}/node_modules/bar/foo.d.ts`, "foo", "fooBar"), timeouts: sys => sys.checkTimeoutQueueLength(0), }, ], @@ -527,7 +558,9 @@ namespace ts.tscWatch { verifyTscWatch({ scenario, - subScenario: `watchOptions/with excludeDirectories option with recursive directory watching${additionalFlags.join("")}`, + subScenario: `watchOptions/with excludeDirectories option with recursive directory watching${ + additionalFlags.join("") + }`, commandLineArgs: ["-w", ...additionalFlags], sys: () => sys({ excludeDirectories: ["**/temp"] }, /*runWithoutRecursiveWatches*/ true), changes: [ @@ -541,7 +574,11 @@ namespace ts.tscWatch { }, { caption: "add new folder to temp", - change: sys => sys.ensureFileOrFolder({ path: `${projectRoot}/node_modules/bar/temp/fooBar/index.d.ts`, content: "export function temp(): string;" }), + change: sys => + sys.ensureFileOrFolder({ + path: `${projectRoot}/node_modules/bar/temp/fooBar/index.d.ts`, + content: "export function temp(): string;", + }), timeouts: sys => sys.checkTimeoutQueueLength(0), }, ], @@ -584,7 +621,10 @@ namespace ts.tscWatch { }, { caption: "Replace file with rename event that fixes error", - change: sys => sys.modifyFile(`${projectRoot}/foo.ts`, `export declare function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }), + change: sys => + sys.modifyFile(`${projectRoot}/foo.ts`, `export declare function foo(): string;`, { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + }), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, ], @@ -601,7 +641,10 @@ namespace ts.tscWatch { [libFile.path]: libFile.content, [`${projectRoot}/main.ts`]: `import { foo } from "./foo"; foo();`, [`${projectRoot}/foo.d.ts`]: `export function foo(): string;`, - [`${projectRoot}/tsconfig.json`]: JSON.stringify({ watchOptions: { watchFile: "useFsEvents" }, files: ["foo.d.ts", "main.ts"] }), + [`${projectRoot}/tsconfig.json`]: JSON.stringify({ + watchOptions: { watchFile: "useFsEvents" }, + files: ["foo.d.ts", "main.ts"], + }), }, { currentDirectory: projectRoot, @@ -611,12 +654,18 @@ namespace ts.tscWatch { changes: [ { caption: "Replace file with rename event that introduces error", - change: sys => sys.modifyFile(`${projectRoot}/foo.d.ts`, `export function foo2(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }), + change: sys => + sys.modifyFile(`${projectRoot}/foo.d.ts`, `export function foo2(): string;`, { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + }), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), }, { caption: "Replace file with rename event that fixes error", - change: sys => sys.modifyFile(`${projectRoot}/foo.d.ts`, `export function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }), + change: sys => + sys.modifyFile(`${projectRoot}/foo.d.ts`, `export function foo(): string;`, { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + }), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), }, ], @@ -632,7 +681,10 @@ namespace ts.tscWatch { [libFile.path]: libFile.content, [`${projectRoot}/main.ts`]: `import { foo } from "./foo"; foo();`, [`${projectRoot}/foo.d.ts`]: `export function foo(): string;`, - [`${projectRoot}/tsconfig.json`]: JSON.stringify({ watchOptions: { watchFile: "useFsEvents" }, files: ["foo.d.ts", "main.ts"] }), + [`${projectRoot}/tsconfig.json`]: JSON.stringify({ + watchOptions: { watchFile: "useFsEvents" }, + files: ["foo.d.ts", "main.ts"], + }), }, { currentDirectory: projectRoot, @@ -642,12 +694,20 @@ namespace ts.tscWatch { changes: [ { caption: "Replace file with rename event that introduces error", - change: sys => sys.modifyFile(`${projectRoot}/foo.d.ts`, `export function foo2(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, useTildeAsSuffixInRenameEventFileName: true }), + change: sys => + sys.modifyFile(`${projectRoot}/foo.d.ts`, `export function foo2(): string;`, { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + useTildeAsSuffixInRenameEventFileName: true, + }), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), }, { caption: "Replace file with rename event that fixes error", - change: sys => sys.modifyFile(`${projectRoot}/foo.d.ts`, `export function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, useTildeAsSuffixInRenameEventFileName: true }), + change: sys => + sys.modifyFile(`${projectRoot}/foo.d.ts`, `export function foo(): string;`, { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + useTildeAsSuffixInRenameEventFileName: true, + }), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), }, ], @@ -655,7 +715,8 @@ namespace ts.tscWatch { verifyTscWatch({ scenario, - subScenario: `fsWatch/when using file watching thats on inode when rename occurs when file is still on the disk`, + subScenario: + `fsWatch/when using file watching thats on inode when rename occurs when file is still on the disk`, commandLineArgs: ["-w", "--extendedDiagnostics"], sys: () => createWatchedSystem( @@ -688,7 +749,10 @@ namespace ts.tscWatch { }, { caption: "Replace file with rename event that fixes error", - change: sys => sys.modifyFile(`${projectRoot}/foo.ts`, `export declare function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }), + change: sys => + sys.modifyFile(`${projectRoot}/foo.ts`, `export declare function foo(): string;`, { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + }), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, ], diff --git a/src/testRunner/unittests/tsserver/autoImportProvider.ts b/src/testRunner/unittests/tsserver/autoImportProvider.ts index dd4f68772e110..22523025a9f36 100644 --- a/src/testRunner/unittests/tsserver/autoImportProvider.ts +++ b/src/testRunner/unittests/tsserver/autoImportProvider.ts @@ -38,7 +38,9 @@ namespace ts.projectSystem { indexTs, ]); openFilesForSession([indexTs], session); - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); }); it("Auto import provider program is not created if dependencies are already in main program", () => { @@ -50,7 +52,9 @@ namespace ts.projectSystem { { path: indexTs.path, content: "import '@angular/forms';" }, ]); openFilesForSession([indexTs], session); - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); }); it("Auto-import program is not created for projects already inside node_modules", () => { @@ -75,22 +79,36 @@ namespace ts.projectSystem { }); it("Auto-importable file is in inferred project until imported", () => { - const { projectService, session, updateFile } = setup([angularFormsDts, angularFormsPackageJson, tsconfig, packageJson, indexTs]); + const { projectService, session, updateFile } = setup([ + angularFormsDts, + angularFormsPackageJson, + tsconfig, + packageJson, + indexTs, + ]); checkNumberOfInferredProjects(projectService, 0); openFilesForSession([angularFormsDts], session); checkNumberOfInferredProjects(projectService, 1); assert.equal( - projectService.getDefaultProjectForFile(angularFormsDts.path as server.NormalizedPath, /*ensureProject*/ true)?.projectKind, + projectService.getDefaultProjectForFile( + angularFormsDts.path as server.NormalizedPath, + /*ensureProject*/ true, + )?.projectKind, server.ProjectKind.Inferred, ); updateFile(indexTs.path, "import '@angular/forms'"); assert.equal( - projectService.getDefaultProjectForFile(angularFormsDts.path as server.NormalizedPath, /*ensureProject*/ true)?.projectKind, + projectService.getDefaultProjectForFile( + angularFormsDts.path as server.NormalizedPath, + /*ensureProject*/ true, + )?.projectKind, server.ProjectKind.Configured, ); - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); }); it("Responds to package.json changes", () => { @@ -103,10 +121,14 @@ namespace ts.projectSystem { ]); openFilesForSession([indexTs], session); - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); host.writeFile(packageJson.path, packageJson.content); - assert.ok(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.ok( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); }); it("Reuses autoImportProvider when program structure is unchanged", () => { @@ -119,7 +141,8 @@ namespace ts.projectSystem { ]); openFilesForSession([indexTs], session); - const autoImportProvider = projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(); + const autoImportProvider = projectService.configuredProjects.get(tsconfig.path)!.getLanguageService() + .getAutoImportProvider(); assert.ok(autoImportProvider); updateFile(indexTs.path, "console.log(0)"); @@ -183,7 +206,9 @@ namespace ts.projectSystem { openFilesForSession([indexTs], session); const project = projectService.configuredProjects.get(tsconfig.path)!; - const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true }); + const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { + includeCompletionsForModuleExports: true, + }); assert.isTrue(completionsBefore?.entries.some(c => c.name === "PatternValidator")); // Directory watchers only fire for add/remove, not change. @@ -192,7 +217,9 @@ namespace ts.projectSystem { host.writeFile(angularFormsDts.path, ""); const autoImportProvider = project.getLanguageService().getAutoImportProvider(); - const completionsAfter = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true }); + const completionsAfter = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { + includeCompletionsForModuleExports: true, + }); assert.equal(autoImportProvider!.getSourceFile(angularFormsDts.path)!.getText(), ""); assert.isFalse(completionsAfter?.entries.some(c => c.name === "PatternValidator")); }); @@ -210,11 +237,15 @@ namespace ts.projectSystem { openFilesForSession([indexTs, angularFormsDts], session); const project = projectService.configuredProjects.get(tsconfig.path)!; - const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true }); + const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { + includeCompletionsForModuleExports: true, + }); assert.isTrue(completionsBefore?.entries.some(c => c.name === "PatternValidator")); updateFile(angularFormsDts.path, "export class ValidatorPattern {}"); - const completionsAfter = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true }); + const completionsAfter = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { + includeCompletionsForModuleExports: true, + }); assert.isFalse(completionsAfter?.entries.some(c => c.name === "PatternValidator")); assert.isTrue(completionsAfter?.entries.some(c => c.name === "ValidatorPattern")); }); @@ -229,10 +260,14 @@ namespace ts.projectSystem { ]); openFilesForSession([indexTs], session); - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); host.writeFile(packageJson.path, packageJson.content); - assert.ok(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.ok( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); }); it("Does not create an auto import provider if there are too many dependencies", () => { @@ -264,12 +299,18 @@ namespace ts.projectSystem { angularFormsPackageJson, // root - { path: tsconfig.path, content: `{ "references": [{ "path": "packages/a" }, { "path": "packages/b" }] }` }, + { + path: tsconfig.path, + content: `{ "references": [{ "path": "packages/a" }, { "path": "packages/b" }] }`, + }, { path: packageJson.path, content: `{ "private": true }` }, // packages/a { path: "/packages/a/package.json", content: packageJson.content }, - { path: "/packages/a/tsconfig.json", content: `{ "compilerOptions": { "composite": true }, "references": [{ "path": "../b" }] }` }, + { + path: "/packages/a/tsconfig.json", + content: `{ "compilerOptions": { "composite": true }, "references": [{ "path": "../b" }] }`, + }, { path: "/packages/a/index.ts", content: "import { B } from '../b';" }, // packages/b @@ -286,26 +327,40 @@ namespace ts.projectSystem { checkNumberOfConfiguredProjects(projectService, 3); // Solution (no files), A, B // Project for A is created - ensure it doesn't have an autoImportProvider - assert.isUndefined(projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getLanguageService() + .getAutoImportProvider(), + ); }); it("Does not close when root files are redirects that don't actually exist", () => { const files = [ // packages/a { path: "/packages/a/package.json", content: `{ "dependencies": { "b": "*" } }` }, - { path: "/packages/a/tsconfig.json", content: `{ "compilerOptions": { "composite": true }, "references": [{ "path": "./node_modules/b" }] }` }, + { + path: "/packages/a/tsconfig.json", + content: + `{ "compilerOptions": { "composite": true }, "references": [{ "path": "./node_modules/b" }] }`, + }, { path: "/packages/a/index.ts", content: "" }, // packages/b { path: "/packages/a/node_modules/b/package.json", content: `{ "types": "dist/index.d.ts" }` }, - { path: "/packages/a/node_modules/b/tsconfig.json", content: `{ "compilerOptions": { "composite": true, "outDir": "dist" } }` }, + { + path: "/packages/a/node_modules/b/tsconfig.json", + content: `{ "compilerOptions": { "composite": true, "outDir": "dist" } }`, + }, { path: "/packages/a/node_modules/b/index.ts", content: `export class B {}` }, ]; const { projectService, session } = setup(files); openFilesForSession([files[2]], session); - assert.isDefined(projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider()); - assert.isDefined(projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider()); + assert.isDefined( + projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider(), + ); + assert.isDefined( + projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider(), + ); }); it("Can use the same document registry bucket key as main program", () => { diff --git a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts index 96dba1f36f513..28a0697d48756 100644 --- a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts +++ b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts @@ -12,13 +12,15 @@ namespace ts.projectSystem { type CalledMaps = CalledMapsWithSingleArg | CalledMapsWithFiveArgs; type CalledWithFiveArgs = [readonly string[], readonly string[], readonly string[], number]; function createLoggerTrackingHostCalls(host: TestServerHost) { - const calledMaps: Record> & Record> = { - fileExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.fileExists), - directoryExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.directoryExists), - getDirectories: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.getDirectories), - readFile: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.readFile), - readDirectory: setCallsTrackingWithFiveArgFn(CalledMapsWithFiveArgs.readDirectory), - }; + const calledMaps: + & Record> + & Record> = { + fileExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.fileExists), + directoryExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.directoryExists), + getDirectories: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.getDirectories), + readFile: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.readFile), + readDirectory: setCallsTrackingWithFiveArgFn(CalledMapsWithFiveArgs.readDirectory), + }; return logCacheAndClear; @@ -43,7 +45,10 @@ namespace ts.projectSystem { } function logCacheEntry(logger: Logger, callback: CalledMaps) { - const result = arrayFrom<[string, (true | CalledWithFiveArgs)[]], { key: string; count: number; }>(calledMaps[callback].entries(), ([key, arr]) => ({ key, count: arr.length })); + const result = arrayFrom<[string, (true | CalledWithFiveArgs)[]], { key: string; count: number; }>( + calledMaps[callback].entries(), + ([key, arr]) => ({ key, count: arr.length }), + ); logger.info(`${callback}:: ${JSON.stringify(result)}`); calledMaps[callback].clear(); } @@ -111,7 +116,11 @@ namespace ts.projectSystem { logCacheAndClear(projectService.logger); // setting compiler options discards module resolution cache - projectService.setCompilerOptionsForInferredProjects({ module: ModuleKind.AMD, noLib: true, target: ScriptTarget.ES5 }); + projectService.setCompilerOptionsForInferredProjects({ + module: ModuleKind.AMD, + noLib: true, + target: ScriptTarget.ES5, + }); logSemanticDiagnostics(projectService, project, imported); logCacheAndClear(projectService.logger); baselineTsserverLogs("cachingFileSystemInformation", "works using legacy resolution logic", projectService); @@ -200,12 +209,15 @@ namespace ts.projectSystem { const logCacheAndClear = createLoggerTrackingHostCalls(host); // Get definitions shouldnt make host requests - const getDefinitionRequest = makeSessionRequest(protocol.CommandTypes.Definition, { - file: clientFile.path, - position: clientFile.content.indexOf("/vessel") + 1, - line: undefined!, // TODO: GH#18217 - offset: undefined!, // TODO: GH#18217 - }); + const getDefinitionRequest = makeSessionRequest( + protocol.CommandTypes.Definition, + { + file: clientFile.path, + position: clientFile.content.indexOf("/vessel") + 1, + line: undefined!, // TODO: GH#18217 + offset: undefined!, // TODO: GH#18217 + }, + ); session.executeCommand(getDefinitionRequest); logCacheAndClear(session.logger); @@ -285,7 +297,13 @@ namespace ts.projectSystem { projectService.openClientFile(file3.path); logCacheAndClear(projectService.logger); - baselineTsserverLogs("cachingFileSystemInformation", `watchDirectories for config file with case ${useCaseSensitiveFileNames ? "" : "in"}sensitive file system`, projectService); + baselineTsserverLogs( + "cachingFileSystemInformation", + `watchDirectories for config file with case ${ + useCaseSensitiveFileNames ? "" : "in" + }sensitive file system`, + projectService, + ); }); } verifyWatchDirectoriesCaseSensitivity(/*useCaseSensitiveFileNames*/ false); @@ -318,8 +336,14 @@ namespace ts.projectSystem { const project = service.configuredProjects.get(tsconfig.path)!; checkProjectActualFiles(project, files.map(f => f.path)); - assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), ["Cannot find module 'debug' or its corresponding type declarations."]); - assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), ["Cannot find module 'debug' or its corresponding type declarations."]); + assert.deepEqual( + project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), + ["Cannot find module 'debug' or its corresponding type declarations."], + ); + assert.deepEqual( + project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), + ["Cannot find module 'debug' or its corresponding type declarations."], + ); const debugTypesFile: File = { path: `${projectLocation}/node_modules/debug/index.d.ts`, @@ -330,8 +354,14 @@ namespace ts.projectSystem { host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions host.runQueuedTimeoutCallbacks(); // Actual update checkProjectActualFiles(project, files.map(f => f.path)); - assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), []); - assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), []); + assert.deepEqual( + project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), + [], + ); + assert.deepEqual( + project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), + [], + ); } it("Includes the parent folder FLLs in node module resolution mode", () => { @@ -398,8 +428,16 @@ namespace ts.projectSystem { { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff" }, { path: "/a/b/node_modules/.staging/rxjs-22375c61" }, { path: "/a/b/node_modules/.staging/typescript-8493ea5d" }, - { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/package.json", content: '{\n "name": "symbol-observable",\n "version": "1.0.4",\n "description": "Symbol.observable ponyfill",\n "license": "MIT",\n "repository": "blesh/symbol-observable",\n "author": {\n "name": "Ben Lesh",\n "email": "ben@benlesh.com"\n },\n "engines": {\n "node": ">=0.10.0"\n },\n "scripts": {\n "test": "npm run build && mocha && tsc ./ts-test/test.ts && node ./ts-test/test.js && check-es3-syntax -p lib/ --kill",\n "build": "babel es --out-dir lib",\n "prepublish": "npm test"\n },\n "files": [\n "' }, - { path: "/a/b/node_modules/.staging/lodash-b0733faa/package.json", content: '{\n "name": "lodash",\n "version": "4.17.4",\n "description": "Lodash modular utilities.",\n "keywords": "modules, stdlib, util",\n "homepage": "https://lodash.com/",\n "repository": "lodash/lodash",\n "icon": "https://lodash.com/icon.svg",\n "license": "MIT",\n "main": "lodash.js",\n "author": "John-David Dalton (http://allyoucanleet.com/)",\n "contributors": [\n "John-David Dalton (http://allyoucanleet.com/)",\n "Mathias Bynens =0.10.0"\n },\n "scripts": {\n "test": "npm run build && mocha && tsc ./ts-test/test.ts && node ./ts-test/test.js && check-es3-syntax -p lib/ --kill",\n "build": "babel es --out-dir lib",\n "prepublish": "npm test"\n },\n "files": [\n "', + }, + { + path: "/a/b/node_modules/.staging/lodash-b0733faa/package.json", + content: + '{\n "name": "lodash",\n "version": "4.17.4",\n "description": "Lodash modular utilities.",\n "keywords": "modules, stdlib, util",\n "homepage": "https://lodash.com/",\n "repository": "lodash/lodash",\n "icon": "https://lodash.com/icon.svg",\n "license": "MIT",\n "main": "lodash.js",\n "author": "John-David Dalton (http://allyoucanleet.com/)",\n "contributors": [\n "John-David Dalton (http://allyoucanleet.com/)",\n "Mathias Bynens =4.2.0"\n },\n "devDependencies": {\n "@types/browserify": "latest",\n "@types/chai": "latest",\n "@types/convert-source-map": "latest",\n "@types/del": "latest",\n "@types/glob": "latest",\n "@types/gulp": "latest",\n "@types/gulp-concat": "latest",\n "@types/gulp-help": "latest",\n "@types/gulp-newer": "latest",\n "@types/gulp-sourcemaps": "latest",\n "@types/merge2": "latest",\n "@types/minimatch": "latest",\n "@types/minimist": "latest",\n "@types/mkdirp": "latest",\n "@types/mocha": "latest",\n "@types/node": "latest",\n "@types/q": "latest",\n "@types/run-sequence": "latest",\n "@types/through2": "latest",\n "browserify": "latest",\n "chai": "latest",\n "convert-source-map": "latest",\n "del": "latest",\n "gulp": "latest",\n "gulp-clone": "latest",\n "gulp-concat": "latest",\n "gulp-help": "latest",\n "gulp-insert": "latest",\n "gulp-newer": "latest",\n "gulp-sourcemaps": "latest",\n "gulp-typescript": "latest",\n "into-stream": "latest",\n "istanbul": "latest",\n "jake": "latest",\n "merge2": "latest",\n "minimist": "latest",\n "mkdirp": "latest",\n "mocha": "latest",\n "mocha-fivemat-progress-reporter": "latest",\n "q": "latest",\n "run-sequence": "latest",\n "sorcery": "latest",\n "through2": "latest",\n "travis-fold": "latest",\n "ts-node": "latest",\n "eslint": "5.16.0",\n "typescript": "^2.4"\n },\n "scripts": {\n "pretest": "jake tests",\n "test": "jake runtests-parallel",\n "build": "npm run build:compiler && npm run build:tests",\n "build:compiler": "jake local",\n "build:tests": "jake tests",\n "start": "node lib/tsc",\n "clean": "jake clean",\n "gulp": "gulp",\n "jake": "jake",\n "lint": "jake lint",\n "setup-hooks": "node scripts/link-hooks.js"\n },\n "browser": {\n "buffer": false,\n "fs": false,\n "os": false,\n "path": false\n }\n}', }, - { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.js", content: "module.exports = require('./lib/index');\n" }, - { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.d.ts", content: "declare const observableSymbol: symbol;\nexport default observableSymbol;\n" }, + { + path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.js", + content: "module.exports = require('./lib/index');\n", + }, + { + path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.d.ts", + content: "declare const observableSymbol: symbol;\nexport default observableSymbol;\n", + }, { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib" }, - { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib/index.js", content: "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _ponyfill = require('./ponyfill');\n\nvar _ponyfill2 = _interopRequireDefault(_ponyfill);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar root; /* global window */\n\n\nif (typeof self !== 'undefined') {\n root = self;\n} else if (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = global;\n} else if (typeof module !== 'undefined') {\n root = module;\n} else {\n root = Function('return this')();\n}\n\nvar result = (0, _ponyfill2['default'])(root);\nexports['default'] = result;" }, + { + path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib/index.js", + content: + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _ponyfill = require('./ponyfill');\n\nvar _ponyfill2 = _interopRequireDefault(_ponyfill);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar root; /* global window */\n\n\nif (typeof self !== 'undefined') {\n root = self;\n} else if (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = global;\n} else if (typeof module !== 'undefined') {\n root = module;\n} else {\n root = Function('return this')();\n}\n\nvar result = (0, _ponyfill2['default'])(root);\nexports['default'] = result;", + }, ].map(getRootedFileOrFolder); verifyAfterPartialOrCompleteNpmInstall(2); @@ -425,7 +473,10 @@ namespace ts.projectSystem { content: '{\n "name": "@types/lodash",\n "version": "4.14.74",\n "description": "TypeScript definitions for Lo-Dash",\n "license": "MIT",\n "contributors": [\n {\n "name": "Brian Zengel",\n "url": "https://github.com/bczengel"\n },\n {\n "name": "Ilya Mochalov",\n "url": "https://github.com/chrootsu"\n },\n {\n "name": "Stepan Mikhaylyuk",\n "url": "https://github.com/stepancar"\n },\n {\n "name": "Eric L Anderson",\n "url": "https://github.com/ericanderson"\n },\n {\n "name": "AJ Richardson",\n "url": "https://github.com/aj-r"\n },\n {\n "name": "Junyoung Clare Jang",\n "url": "https://github.com/ailrun"\n }\n ],\n "main": "",\n "repository": {\n "type": "git",\n "url": "https://www.github.com/DefinitelyTyped/DefinitelyTyped.git"\n },\n "scripts": {},\n "dependencies": {},\n "typesPublisherContentHash": "12af578ffaf8d86d2df37e591857906a86b983fa9258414326544a0fe6af0de8",\n "typeScriptVersion": "2.2"\n}', }, - { path: "/a/b/node_modules/.staging/lodash-b0733faa/index.js", content: "module.exports = require('./lodash');" }, + { + path: "/a/b/node_modules/.staging/lodash-b0733faa/index.js", + content: "module.exports = require('./lodash');", + }, { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594", content: "" }, ].map(getRootedFileOrFolder)); // Since we added/removed in .staging no timeout @@ -440,7 +491,11 @@ namespace ts.projectSystem { { path: "/a/b/node_modules/.staging/rxjs-22375c61/bundles" }, { path: "/a/b/node_modules/.staging/rxjs-22375c61/operator" }, { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/add/observable/dom" }, - { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/index.d.ts", content: "\n// Stub for lodash\nexport = _;\nexport as namespace _;\ndeclare var _: _.LoDashStatic;\ndeclare namespace _ {\n interface LoDashStatic {\n someProp: string;\n }\n class SomeClass {\n someMethod(): void;\n }\n}" }, + { + path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/index.d.ts", + content: + "\n// Stub for lodash\nexport = _;\nexport as namespace _;\ndeclare var _: _.LoDashStatic;\ndeclare namespace _ {\n interface LoDashStatic {\n someProp: string;\n }\n class SomeClass {\n someMethod(): void;\n }\n}", + }, ].map(getRootedFileOrFolder)); verifyAfterPartialOrCompleteNpmInstall(0); @@ -486,7 +541,10 @@ namespace ts.projectSystem { baselineTsserverLogs( "cachingFileSystemInformation", - `npm install works when ${timeoutDuringPartialInstallation ? "timeout occurs inbetween installation" : "timeout occurs after installation"}`, + `npm install works when ${ + timeoutDuringPartialInstallation ? "timeout occurs inbetween installation" + : "timeout occurs after installation" + }`, projectService, ); @@ -534,7 +592,10 @@ namespace ts.projectSystem { const project = service.configuredProjects.get(tsconfig.path)!; checkProjectActualFiles(project, files.map(f => f.path)); - assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), ["Cannot find module 'debug' or its corresponding type declarations."]); + assert.deepEqual( + project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), + ["Cannot find module 'debug' or its corresponding type declarations."], + ); const debugTypesFile: File = { path: `${projectLocation}/node_modules/@types/debug/index.d.ts`, @@ -551,7 +612,10 @@ namespace ts.projectSystem { host.writeFile(debugTypesFile.path, debugTypesFile.content); host.runQueuedTimeoutCallbacks(); checkProjectActualFiles(project, files.map(f => f.path)); - assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), []); + assert.deepEqual( + project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), + [], + ); }); it("when creating new file in symlinked folder", () => { @@ -586,7 +650,13 @@ namespace ts.projectSystem { host.writeFile(`${symlink.path}/module3.ts`, `import * as M from "folder1/module1";`); host.runQueuedTimeoutCallbacks(); checkNumberOfProjects(service, { configuredProjects: 1 }); - checkProjectActualFiles(project, [module1.path, `${symlink.path}/module2.ts`, config.path, libFile.path, `${symlink.path}/module3.ts`]); + checkProjectActualFiles(project, [ + module1.path, + `${symlink.path}/module2.ts`, + config.path, + libFile.path, + `${symlink.path}/module3.ts`, + ]); }); }); } diff --git a/src/testRunner/unittests/tsserver/cancellationToken.ts b/src/testRunner/unittests/tsserver/cancellationToken.ts index 9dd07d1d00d69..25c0e7b8cabf4 100644 --- a/src/testRunner/unittests/tsserver/cancellationToken.ts +++ b/src/testRunner/unittests/tsserver/cancellationToken.ts @@ -267,7 +267,10 @@ namespace ts.projectSystem { assert(e instanceof OperationCanceledException); operationCanceledExceptionThrown = true; } - assert(operationCanceledExceptionThrown, "Operation Canceled Exception not thrown for request: " + JSON.stringify(request)); + assert( + operationCanceledExceptionThrown, + "Operation Canceled Exception not thrown for request: " + JSON.stringify(request), + ); } }); }); diff --git a/src/testRunner/unittests/tsserver/compileOnSave.ts b/src/testRunner/unittests/tsserver/compileOnSave.ts index 64eb89c9e3ef1..a2ea76192040e 100644 --- a/src/testRunner/unittests/tsserver/compileOnSave.ts +++ b/src/testRunner/unittests/tsserver/compileOnSave.ts @@ -5,20 +5,38 @@ namespace ts.projectSystem { } describe("unittests:: tsserver:: compileOnSave:: affected list", () => { - function sendAffectedFileRequestAndCheckResult(session: server.Session, request: server.protocol.Request, expectedFileList: { projectFileName: string; files: File[]; }[]) { - const response = session.executeCommand(request).response as server.protocol.CompileOnSaveAffectedFileListSingleProject[]; - const actualResult = response.sort((list1, list2) => compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName)); - expectedFileList = expectedFileList.sort((list1, list2) => compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName)); - - assert.equal(actualResult.length, expectedFileList.length, `Actual result project number is different from the expected project number`); + function sendAffectedFileRequestAndCheckResult( + session: server.Session, + request: server.protocol.Request, + expectedFileList: { projectFileName: string; files: File[]; }[], + ) { + const response = session.executeCommand(request) + .response as server.protocol.CompileOnSaveAffectedFileListSingleProject[]; + const actualResult = response.sort((list1, list2) => + compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName) + ); + expectedFileList = expectedFileList.sort((list1, list2) => + compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName) + ); + + assert.equal( + actualResult.length, + expectedFileList.length, + `Actual result project number is different from the expected project number`, + ); for (let i = 0; i < actualResult.length; i++) { const actualResultSingleProject = actualResult[i]; const expectedResultSingleProject = expectedFileList[i]; - assert.equal(actualResultSingleProject.projectFileName, expectedResultSingleProject.projectFileName, `Actual result contains different projects than the expected result`); + assert.equal( + actualResultSingleProject.projectFileName, + expectedResultSingleProject.projectFileName, + `Actual result contains different projects than the expected result`, + ); const actualResultSingleProjectFileNameList = actualResultSingleProject.fileNames.sort(); - const expectedResultSingleProjectFileNameList = map(expectedResultSingleProject.files, f => f.path).sort(); + const expectedResultSingleProjectFileNameList = map(expectedResultSingleProject.files, f => f.path) + .sort(); assert.isTrue( arrayIsEqualTo(actualResultSingleProjectFileNameList, expectedResultSingleProjectFileNameList), `For project ${actualResultSingleProject.projectFileName}, the actual result is ${actualResultSingleProjectFileNameList}, while expected ${expectedResultSingleProjectFileNameList}`, @@ -72,137 +90,231 @@ namespace ts.projectSystem { }; // Change the content of file1 to `export var T: number;export function Foo() { };` - changeModuleFile1ShapeRequest1 = makeSessionRequest(CommandNames.Change, { - file: moduleFile1.path, - line: 1, - offset: 1, - endLine: 1, - endOffset: 1, - insertString: `export var T: number;`, - }); + changeModuleFile1ShapeRequest1 = makeSessionRequest( + CommandNames.Change, + { + file: moduleFile1.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 1, + insertString: `export var T: number;`, + }, + ); // Change the content of file1 to `export var T: number;export function Foo() { };` - changeModuleFile1InternalRequest1 = makeSessionRequest(CommandNames.Change, { - file: moduleFile1.path, - line: 1, - offset: 1, - endLine: 1, - endOffset: 1, - insertString: `var T1: number;`, - }); + changeModuleFile1InternalRequest1 = makeSessionRequest( + CommandNames.Change, + { + file: moduleFile1.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 1, + insertString: `var T1: number;`, + }, + ); - moduleFile1FileListRequest = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path, projectFileName: configFile.path }); + moduleFile1FileListRequest = makeSessionRequest( + CommandNames.CompileOnSaveAffectedFileList, + { file: moduleFile1.path, projectFileName: configFile.path }, + ); }); it("should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", () => { - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const typingsInstaller = createTestTypingsInstaller(host); const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1, file1Consumer1], session); // Send an initial compileOnSave request - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2], + }]); session.executeCommand(changeModuleFile1ShapeRequest1); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2], + }]); // Change the content of file1 to `export var T: number;export function Foo() { console.log('hi'); };` - const changeFile1InternalRequest = makeSessionRequest(CommandNames.Change, { - file: moduleFile1.path, - line: 1, - offset: 46, - endLine: 1, - endOffset: 46, - insertString: `console.log('hi');`, - }); + const changeFile1InternalRequest = makeSessionRequest( + CommandNames.Change, + { + file: moduleFile1.path, + line: 1, + offset: 46, + endLine: 1, + endOffset: 46, + insertString: `console.log('hi');`, + }, + ); session.executeCommand(changeFile1InternalRequest); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1], + }]); }); it("should be up-to-date with the reference map changes", () => { - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const typingsInstaller = createTestTypingsInstaller(host); const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1, file1Consumer1], session); // Send an initial compileOnSave request - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2], + }]); // Change file2 content to `let y = Foo();` - const removeFile1Consumer1ImportRequest = makeSessionRequest(CommandNames.Change, { - file: file1Consumer1.path, - line: 1, - offset: 1, - endLine: 1, - endOffset: 28, - insertString: "", - }); + const removeFile1Consumer1ImportRequest = makeSessionRequest( + CommandNames.Change, + { + file: file1Consumer1.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 28, + insertString: "", + }, + ); session.executeCommand(removeFile1Consumer1ImportRequest); session.executeCommand(changeModuleFile1ShapeRequest1); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer2], + }]); // Add the import statements back to file2 - const addFile2ImportRequest = makeSessionRequest(CommandNames.Change, { - file: file1Consumer1.path, - line: 1, - offset: 1, - endLine: 1, - endOffset: 1, - insertString: `import {Foo} from "./moduleFile1";`, - }); + const addFile2ImportRequest = makeSessionRequest( + CommandNames.Change, + { + file: file1Consumer1.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 1, + insertString: `import {Foo} from "./moduleFile1";`, + }, + ); session.executeCommand(addFile2ImportRequest); // Change the content of file1 to `export var T2: string;export var T: number;export function Foo() { };` - const changeModuleFile1ShapeRequest2 = makeSessionRequest(CommandNames.Change, { - file: moduleFile1.path, - line: 1, - offset: 1, - endLine: 1, - endOffset: 1, - insertString: `export var T2: string;`, - }); + const changeModuleFile1ShapeRequest2 = makeSessionRequest( + CommandNames.Change, + { + file: moduleFile1.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 1, + insertString: `export var T2: string;`, + }, + ); session.executeCommand(changeModuleFile1ShapeRequest2); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2], + }]); }); it("should be up-to-date with changes made in non-open files", () => { - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const typingsInstaller = createTestTypingsInstaller(host); const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1], session); // Send an initial compileOnSave request - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2], + }]); host.writeFile(file1Consumer1.path, `let y = 10;`); session.executeCommand(changeModuleFile1ShapeRequest1); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer2], + }]); }); it("should be up-to-date with deleted files", () => { - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const typingsInstaller = createTestTypingsInstaller(host); const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1], session); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2], + }]); session.executeCommand(changeModuleFile1ShapeRequest1); // Delete file1Consumer2 host.deleteFile(file1Consumer2.path); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1], + }]); }); it("should be up-to-date with newly created files", () => { - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const typingsInstaller = createTestTypingsInstaller(host); const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1], session); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2], + }]); const file1Consumer3: File = { path: "/a/b/file1Consumer3.ts", @@ -211,7 +323,10 @@ namespace ts.projectSystem { host.writeFile(file1Consumer3.path, file1Consumer3.content); host.runQueuedTimeoutCallbacks(); session.executeCommand(changeModuleFile1ShapeRequest1); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2, file1Consumer3] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2, file1Consumer3], + }]); }); it("should detect changes in non-root files", () => { @@ -238,36 +353,62 @@ namespace ts.projectSystem { const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1, file1Consumer1], session); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1], + }]); // change file1 shape now, and verify both files are affected session.executeCommand(changeModuleFile1ShapeRequest1); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1], + }]); // change file1 internal, and verify only file1 is affected session.executeCommand(changeModuleFile1InternalRequest1); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1], + }]); }); it("should return all files if a global file changed shape", () => { - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const typingsInstaller = createTestTypingsInstaller(host); const session = createSession(host, { typingsInstaller }); openFilesForSession([globalFile3], session); - const changeGlobalFile3ShapeRequest = makeSessionRequest(CommandNames.Change, { - file: globalFile3.path, - line: 1, - offset: 1, - endLine: 1, - endOffset: 1, - insertString: `var T2: string;`, - }); + const changeGlobalFile3ShapeRequest = makeSessionRequest( + CommandNames.Change, + { + file: globalFile3.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 1, + insertString: `var T2: string;`, + }, + ); // check after file1 shape changes session.executeCommand(changeGlobalFile3ShapeRequest); - const globalFile3FileListRequest = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: globalFile3.path }); - sendAffectedFileRequestAndCheckResult(session, globalFile3FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2] }]); + const globalFile3FileListRequest = makeSessionRequest( + CommandNames.CompileOnSaveAffectedFileList, + { file: globalFile3.path }, + ); + sendAffectedFileRequestAndCheckResult(session, globalFile3FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2], + }]); }); it("should return empty array if CompileOnSave is not enabled", () => { @@ -316,12 +457,22 @@ namespace ts.projectSystem { }`, }; - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + configFile2, + configFile, + libFile, + ]); const typingsInstaller = createTestTypingsInstaller(host); const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1, file1Consumer1], session); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer2], + }]); }); it("should always return the file itself if '--isolatedModules' is specified", () => { @@ -340,16 +491,22 @@ namespace ts.projectSystem { const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1], session); - const file1ChangeShapeRequest = makeSessionRequest(CommandNames.Change, { - file: moduleFile1.path, - line: 1, - offset: 27, - endLine: 1, - endOffset: 27, - insertString: `Point,`, - }); + const file1ChangeShapeRequest = makeSessionRequest( + CommandNames.Change, + { + file: moduleFile1.path, + line: 1, + offset: 27, + endLine: 1, + endOffset: 27, + insertString: `Point,`, + }, + ); session.executeCommand(file1ChangeShapeRequest); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1], + }]); }); it("should always return the file itself if '--out' or '--outFile' is specified", () => { @@ -369,16 +526,22 @@ namespace ts.projectSystem { const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1], session); - const file1ChangeShapeRequest = makeSessionRequest(CommandNames.Change, { - file: moduleFile1.path, - line: 1, - offset: 27, - endLine: 1, - endOffset: 27, - insertString: `Point,`, - }); + const file1ChangeShapeRequest = makeSessionRequest( + CommandNames.Change, + { + file: moduleFile1.path, + line: 1, + offset: 27, + endLine: 1, + endOffset: 27, + insertString: `Point,`, + }, + ); session.executeCommand(file1ChangeShapeRequest); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1], + }]); }); it("should return cascaded affected file list", () => { @@ -386,24 +549,40 @@ namespace ts.projectSystem { path: "/a/b/file1Consumer1Consumer1.ts", content: `import {y} from "./file1Consumer1";`, }; - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer1Consumer1, globalFile3, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer1Consumer1, + globalFile3, + configFile, + libFile, + ]); const typingsInstaller = createTestTypingsInstaller(host); const session = createSession(host, { typingsInstaller }); openFilesForSession([moduleFile1, file1Consumer1], session); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer1Consumer1] }]); - - const changeFile1Consumer1ShapeRequest = makeSessionRequest(CommandNames.Change, { - file: file1Consumer1.path, - line: 2, - offset: 1, - endLine: 2, - endOffset: 1, - insertString: `export var T: number;`, - }); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer1Consumer1], + }]); + + const changeFile1Consumer1ShapeRequest = makeSessionRequest( + CommandNames.Change, + { + file: file1Consumer1.path, + line: 2, + offset: 1, + endLine: 2, + endOffset: 1, + insertString: `export var T: number;`, + }, + ); session.executeCommand(changeModuleFile1ShapeRequest1); session.executeCommand(changeFile1Consumer1ShapeRequest); - sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer1Consumer1] }]); + sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ + projectFileName: configFile.path, + files: [moduleFile1, file1Consumer1, file1Consumer1Consumer1], + }]); }); it("should work fine for files with circular references", () => { @@ -424,8 +603,14 @@ namespace ts.projectSystem { const session = createSession(host, { typingsInstaller }); openFilesForSession([file1, file2], session); - const file1AffectedListRequest = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: file1.path }); - sendAffectedFileRequestAndCheckResult(session, file1AffectedListRequest, [{ projectFileName: configFile.path, files: [file1, file2] }]); + const file1AffectedListRequest = makeSessionRequest( + CommandNames.CompileOnSaveAffectedFileList, + { file: file1.path }, + ); + sendAffectedFileRequestAndCheckResult(session, file1AffectedListRequest, [{ + projectFileName: configFile.path, + files: [file1, file2], + }]); }); it("should return results for all projects if not specifying projectFileName", () => { @@ -439,7 +624,10 @@ namespace ts.projectSystem { const session = createSession(host); openFilesForSession([file1, file2, file3], session); - const file1AffectedListRequest = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: file1.path }); + const file1AffectedListRequest = makeSessionRequest( + CommandNames.CompileOnSaveAffectedFileList, + { file: file1.path }, + ); sendAffectedFileRequestAndCheckResult(session, file1AffectedListRequest, [ { projectFileName: configFile1.path, files: [file1, file2] }, @@ -460,11 +648,17 @@ namespace ts.projectSystem { openFilesForSession([referenceFile1], session); host.deleteFile(moduleFile1.path); - const request = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); + const request = makeSessionRequest( + CommandNames.CompileOnSaveAffectedFileList, + { file: referenceFile1.path }, + ); sendAffectedFileRequestAndCheckResult(session, request, [ { projectFileName: configFile.path, files: [referenceFile1] }, ]); - const requestForMissingFile = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path }); + const requestForMissingFile = makeSessionRequest( + CommandNames.CompileOnSaveAffectedFileList, + { file: moduleFile1.path }, + ); sendAffectedFileRequestAndCheckResult(session, requestForMissingFile, []); }); @@ -479,7 +673,10 @@ namespace ts.projectSystem { const session = createSession(host); openFilesForSession([referenceFile1], session); - const request = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); + const request = makeSessionRequest( + CommandNames.CompileOnSaveAffectedFileList, + { file: referenceFile1.path }, + ); sendAffectedFileRequestAndCheckResult(session, request, [ { projectFileName: configFile.path, files: [referenceFile1] }, ]); @@ -487,7 +684,12 @@ namespace ts.projectSystem { }); describe("for changes in declaration files", () => { - function testDTS(dtsFileContents: string, tsFileContents: string, opts: CompilerOptions, expectDTSEmit: boolean) { + function testDTS( + dtsFileContents: string, + tsFileContents: string, + opts: CompilerOptions, + expectDTSEmit: boolean, + ) { const dtsFile = { path: "/a/runtime/a.d.ts", content: dtsFileContents, @@ -529,11 +731,23 @@ namespace ts.projectSystem { arguments: { file: dtsFile.path }, } as protocol.CompileOnSaveAffectedFileListRequest); if (expectDTSEmit) { - assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project"); - assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[])[0].fileNames.length, 2, "expected to affect 2 files"); + assert.equal( + (response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, + 1, + "expected output from 1 project", + ); + assert.equal( + (response as protocol.CompileOnSaveAffectedFileListSingleProject[])[0].fileNames.length, + 2, + "expected to affect 2 files", + ); } else { - assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 0, "expected no output"); + assert.equal( + (response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, + 0, + "expected no output", + ); } const { response: response2 } = session.executeCommand({ @@ -542,7 +756,11 @@ namespace ts.projectSystem { command: "compileOnSaveAffectedFileList", arguments: { file: f2.path }, } as protocol.CompileOnSaveAffectedFileListRequest); - assert.equal((response2 as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project"); + assert.equal( + (response2 as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, + 1, + "expected output from 1 project", + ); } it("should return empty array if change is made in a global declaration file", () => { @@ -623,9 +841,21 @@ namespace ts.projectSystem { command: "compileOnSaveAffectedFileList", arguments: { file: f1.path }, } as protocol.CompileOnSaveAffectedFileListRequest); - assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output for 1 project"); - assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[])[0].fileNames.length, 2, "expected output for 1 project"); - assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[])[0].projectUsesOutFile, expectedUsesOutFile, "usesOutFile"); + assert.equal( + (response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, + 1, + "expected output for 1 project", + ); + assert.equal( + (response as protocol.CompileOnSaveAffectedFileListSingleProject[])[0].fileNames.length, + 2, + "expected output for 1 project", + ); + assert.equal( + (response as protocol.CompileOnSaveAffectedFileListSingleProject[])[0].projectUsesOutFile, + expectedUsesOutFile, + "usesOutFile", + ); } it("projectUsesOutFile should not be returned if not set", () => { @@ -669,7 +899,11 @@ namespace ts.projectSystem { }; session.executeCommand(emitFileRequest); const emitOutput = host.readFile(path + Extension.Js); - assert.equal(emitOutput, f.content + newLine, "content of emit output should be identical with the input + newline"); + assert.equal( + emitOutput, + f.content + newLine, + "content of emit output should be identical with the input + newline", + ); } }); @@ -691,12 +925,18 @@ namespace ts.projectSystem { const session = createSession(host, { typingsInstaller }); openFilesForSession([file1, file2], session); - const compileFileRequest = makeSessionRequest(CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: configFile.path }); + const compileFileRequest = makeSessionRequest( + CommandNames.CompileOnSaveEmitFile, + { file: file1.path, projectFileName: configFile.path }, + ); session.executeCommand(compileFileRequest); const expectedEmittedFileName = "/a/b/f1.js"; assert.isTrue(host.fileExists(expectedEmittedFileName)); - assert.equal(host.readFile(expectedEmittedFileName), `"use strict";\r\nexports.__esModule = true;\r\nexports.Foo = void 0;\r\nfunction Foo() { return 10; }\r\nexports.Foo = Foo;\r\n`); + assert.equal( + host.readFile(expectedEmittedFileName), + `"use strict";\r\nexports.__esModule = true;\r\nexports.Foo = void 0;\r\nfunction Foo() { return 10; }\r\nexports.Foo = Foo;\r\n`, + ); }); it("shoud not emit js files in external projects", () => { @@ -728,7 +968,10 @@ namespace ts.projectSystem { projectFileName: externalProjectName, }); - const emitRequest = makeSessionRequest(CommandNames.CompileOnSaveEmitFile, { file: file1.path }); + const emitRequest = makeSessionRequest( + CommandNames.CompileOnSaveEmitFile, + { file: file1.path }, + ); session.executeCommand(emitRequest); const expectedOutFileName = "/a/b/dist.js"; @@ -761,7 +1004,10 @@ namespace ts.projectSystem { projectFileName: externalProjectName, }); - const emitRequest = makeSessionRequest(CommandNames.CompileOnSaveEmitFile, { file: file1.path }); + const emitRequest = makeSessionRequest( + CommandNames.CompileOnSaveEmitFile, + { file: file1.path }, + ); session.executeCommand(emitRequest); // Verify js file @@ -847,9 +1093,14 @@ namespace ts.projectSystem { start: undefined, end: undefined, fileName: undefined, - text: formatStringFromArgs(Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file.message, [`${tscWatch.projectRoot}/test/file1.d.ts`]), + text: formatStringFromArgs( + Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file.message, + [`${tscWatch.projectRoot}/test/file1.d.ts`], + ), code: Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file.code, - category: diagnosticCategoryName(Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file), + category: diagnosticCategoryName( + Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file, + ), reportsUnnecessary: undefined, reportsDeprecated: undefined, relatedInformation: undefined, @@ -947,14 +1198,17 @@ function bar() { assert.isTrue(response); assert.strictEqual( host.readFile(changeExtension(file.path, ".js")), - file === module ? - `"use strict";\nexports.__esModule = true;\nexports.xyz = void 0;\nexports.xyz = 4;\n` : - `${file.content.replace("const", "var")}\n`, + file === module + ? `"use strict";\nexports.__esModule = true;\nexports.xyz = void 0;\nexports.xyz = 4;\n` + : `${file.content.replace("const", "var")}\n`, ); if (declaration) { assert.strictEqual( host.readFile(changeExtension(file.path, ".d.ts")), - (file.content.substr(0, file.content.indexOf(" {") === -1 ? file.content.length : file.content.indexOf(" {")) + (file.content.substr( + 0, + file.content.indexOf(" {") === -1 ? file.content.length : file.content.indexOf(" {"), + ) .replace("const ", "declare const ") .replace("function ", "declare function ") .replace(")", "): string;")) + "\n", @@ -962,7 +1216,12 @@ function bar() { } } - function verifyLocalEdit(file: File, oldText: string, newText: string, returnsAllFilesAsAffected?: boolean) { + function verifyLocalEdit( + file: File, + oldText: string, + newText: string, + returnsAllFilesAsAffected?: boolean, + ) { // Change file1 get affected file list session.executeCommandSeq({ command: protocol.CommandTypes.UpdateOpen, @@ -976,12 +1235,22 @@ function bar() { }], }, }); - const affectedFileResponse = session.executeCommandSeq({ + const affectedFileResponse = session.executeCommandSeq< + protocol.CompileOnSaveAffectedFileListRequest + >({ command: protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: file.path }, }).response as protocol.CompileOnSaveAffectedFileListSingleProject[]; assert.deepEqual(affectedFileResponse, [ - { fileNames: [file.path, ...(returnsAllFilesAsAffected ? files.filter(f => f !== file).map(f => f.path) : emptyArray)], projectFileName: config.path, projectUsesOutFile: false }, + { + fileNames: [ + file.path, + ...(returnsAllFilesAsAffected ? files.filter(f => f !== file).map(f => f.path) + : emptyArray), + ], + projectFileName: config.path, + projectUsesOutFile: false, + }, ]); file.content = file.content.replace(oldText, newText); verifyFileSave(file); diff --git a/src/testRunner/unittests/tsserver/completions.ts b/src/testRunner/unittests/tsserver/completions.ts index 0d6ba2b655b9d..81f893c80dfde 100644 --- a/src/testRunner/unittests/tsserver/completions.ts +++ b/src/testRunner/unittests/tsserver/completions.ts @@ -23,11 +23,15 @@ namespace ts.projectSystem { offset: 3, }; - const response = executeSessionRequest(session, protocol.CommandTypes.CompletionInfo, { - ...requestLocation, - includeExternalModuleExports: true, - prefix: "foo", - }); + const response = executeSessionRequest( + session, + protocol.CommandTypes.CompletionInfo, + { + ...requestLocation, + includeExternalModuleExports: true, + prefix: "foo", + }, + ); const entry: protocol.CompletionEntry = { hasAction: true, insertText: undefined, @@ -42,7 +46,12 @@ namespace ts.projectSystem { source: "/a", sourceDisplay: undefined, isSnippet: undefined, - data: { exportName: "foo", fileName: "/a.ts", ambientModuleName: undefined, isPackageJsonImport: undefined }, + data: { + exportName: "foo", + fileName: "/a.ts", + ambientModuleName: undefined, + isPackageJsonImport: undefined, + }, labelDetails: undefined, }; @@ -63,10 +72,17 @@ namespace ts.projectSystem { const detailsRequestArgs: protocol.CompletionDetailsRequestArgs = { ...requestLocation, - entryNames: [{ name: "foo", source: "/a", data: { exportName: "foo", fileName: "/a.ts", exportMapKey } }], + entryNames: [{ + name: "foo", + source: "/a", + data: { exportName: "foo", fileName: "/a.ts", exportMapKey }, + }], }; - const detailsResponse = executeSessionRequest(session, protocol.CommandTypes.CompletionDetails, detailsRequestArgs); + const detailsResponse = executeSessionRequest< + protocol.CompletionDetailsRequest, + protocol.CompletionDetailsResponse + >(session, protocol.CommandTypes.CompletionDetails, detailsRequestArgs); const detailsCommon: protocol.CompletionEntryDetails & CompletionEntryDetails = { displayParts: [ keywordPart(SyntaxKind.ConstKeyword), @@ -115,7 +131,10 @@ namespace ts.projectSystem { interface CompletionDetailsFullResponse extends protocol.Response { readonly body?: readonly CompletionEntryDetails[]; } - const detailsFullResponse = executeSessionRequest(session, protocol.CommandTypes.CompletionDetailsFull, detailsRequestArgs); + const detailsFullResponse = executeSessionRequest< + CompletionDetailsFullRequest, + CompletionDetailsFullResponse + >(session, protocol.CommandTypes.CompletionDetailsFull, detailsRequestArgs); assert.deepEqual(detailsFullResponse, [ { codeActions: [ @@ -124,7 +143,9 @@ namespace ts.projectSystem { changes: [ { fileName: "/b.ts", - textChanges: [createTextChange(createTextSpan(0, 0), 'import { foo } from "./a";\n\n')], + textChanges: [ + createTextChange(createTextSpan(0, 0), 'import { foo } from "./a";\n\n'), + ], }, ], commands: undefined, @@ -253,7 +274,10 @@ export interface BrowserRouterProps { openFilesForSession([appFile], session); checkNumberOfProjects(service, { inferredProjects: 1 }); const windowsStyleLibFilePath = "c:/" + libFile.path.substring(1); - checkProjectActualFiles(service.inferredProjects[0], filesInProject.map(f => f.path).concat(windowsStyleLibFilePath)); + checkProjectActualFiles( + service.inferredProjects[0], + filesInProject.map(f => f.path).concat(windowsStyleLibFilePath), + ); session.executeCommandSeq({ command: protocol.CommandTypes.CompletionInfo, arguments: { diff --git a/src/testRunner/unittests/tsserver/completionsIncomplete.ts b/src/testRunner/unittests/tsserver/completionsIncomplete.ts index 16705c45caff4..035251f59adf0 100644 --- a/src/testRunner/unittests/tsserver/completionsIncomplete.ts +++ b/src/testRunner/unittests/tsserver/completionsIncomplete.ts @@ -6,7 +6,12 @@ namespace ts.projectSystem { }; } - function createExportingModuleFiles(pathPrefix: string, fileCount: number, exportCount: number, getExportPrefix: (fileIndex: number) => string): File[] { + function createExportingModuleFiles( + pathPrefix: string, + fileCount: number, + exportCount: number, + getExportPrefix: (fileIndex: number) => string, + ): File[] { return fill(fileCount, fileIndex => createExportingModuleFile( `${pathPrefix}_${fileIndex}.ts`, @@ -15,8 +20,18 @@ namespace ts.projectSystem { )); } - function createNodeModulesPackage(packageName: string, fileCount: number, exportCount: number, getExportPrefix: (fileIndex: number) => string): File[] { - const exportingFiles = createExportingModuleFiles(`/node_modules/${packageName}/file`, fileCount, exportCount, getExportPrefix); + function createNodeModulesPackage( + packageName: string, + fileCount: number, + exportCount: number, + getExportPrefix: (fileIndex: number) => string, + ): File[] { + const exportingFiles = createExportingModuleFiles( + `/node_modules/${packageName}/file`, + fileCount, + exportCount, + getExportPrefix, + ); return [ { path: `/node_modules/${packageName}/package.json`, @@ -25,7 +40,13 @@ namespace ts.projectSystem { { path: `/node_modules/${packageName}/index.d.ts`, content: exportingFiles - .map(f => `export * from "./${removeFileExtension(convertToRelativePath(f.path, `/node_modules/${packageName}/`, identity))}";`) + .map(f => + `export * from "./${ + removeFileExtension( + convertToRelativePath(f.path, `/node_modules/${packageName}/`, identity), + ) + }";` + ) .join("\n") + `\nexport default function main(): void;`, }, ...exportingFiles, @@ -50,22 +71,39 @@ namespace ts.projectSystem { describe("unittests:: tsserver:: completionsIncomplete", () => { it("works", () => { const excessFileCount = Completions.moduleSpecifierResolutionLimit + 50; - const exportingFiles = createExportingModuleFiles(`/lib/a`, Completions.moduleSpecifierResolutionLimit + excessFileCount, 1, i => `aa_${i}_`); + const exportingFiles = createExportingModuleFiles( + `/lib/a`, + Completions.moduleSpecifierResolutionLimit + excessFileCount, + 1, + i => `aa_${i}_`, + ); const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles]); openFilesForSession([indexFile], session); typeToTriggerCompletions(indexFile.path, "a", completions => { assert(completions.isIncomplete); - assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), Completions.moduleSpecifierResolutionLimit); - assert.lengthOf(completions.entries.filter(entry => entry.source && !(entry.data as any)?.moduleSpecifier), excessFileCount); + assert.lengthOf( + completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), + Completions.moduleSpecifierResolutionLimit, + ); + assert.lengthOf( + completions.entries.filter(entry => entry.source && !(entry.data as any)?.moduleSpecifier), + excessFileCount, + ); }) .continueTyping("a", completions => { assert(completions.isIncomplete); - assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), Completions.moduleSpecifierResolutionLimit * 2); + assert.lengthOf( + completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), + Completions.moduleSpecifierResolutionLimit * 2, + ); }) .continueTyping("_", completions => { assert(!completions.isIncomplete); - assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), exportingFiles.length); + assert.lengthOf( + completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), + exportingFiles.length, + ); }); }); @@ -81,7 +119,12 @@ namespace ts.projectSystem { it("resolves more when available from module specifier cache (2)", () => { const excessFileCount = 50; - const exportingFiles = createExportingModuleFiles(`/lib/a`, Completions.moduleSpecifierResolutionLimit + excessFileCount, 1, i => `aa_${i}_`); + const exportingFiles = createExportingModuleFiles( + `/lib/a`, + Completions.moduleSpecifierResolutionLimit + excessFileCount, + 1, + i => `aa_${i}_`, + ); const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles]); openFilesForSession([indexFile], session); @@ -96,26 +139,53 @@ namespace ts.projectSystem { content: `declare module "ambient_${i}" { export const aa_${i} = ${i}; }`, })); - const exportingFiles = createExportingModuleFiles(`/lib/a`, Completions.moduleSpecifierResolutionLimit, 5, i => `aa_${i}_`); - const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...ambientFiles, ...exportingFiles]); + const exportingFiles = createExportingModuleFiles( + `/lib/a`, + Completions.moduleSpecifierResolutionLimit, + 5, + i => `aa_${i}_`, + ); + const { typeToTriggerCompletions, session } = setup([ + tsconfigFile, + indexFile, + ...ambientFiles, + ...exportingFiles, + ]); openFilesForSession([indexFile], session); typeToTriggerCompletions(indexFile.path, "a", completions => { assert(!completions.isIncomplete); - assert.lengthOf(completions.entries.filter(e => (e.data as any)?.moduleSpecifier), ambientFiles.length * 5 + exportingFiles.length); + assert.lengthOf( + completions.entries.filter(e => (e.data as any)?.moduleSpecifier), + ambientFiles.length * 5 + exportingFiles.length, + ); }); }); it("works with PackageJsonAutoImportProvider", () => { - const exportingFiles = createExportingModuleFiles(`/lib/a`, Completions.moduleSpecifierResolutionLimit, 1, i => `aa_${i}_`); + const exportingFiles = createExportingModuleFiles( + `/lib/a`, + Completions.moduleSpecifierResolutionLimit, + 1, + i => `aa_${i}_`, + ); const nodeModulesPackage = createNodeModulesPackage("dep-a", 50, 1, i => `depA_${i}_`); - const { typeToTriggerCompletions, assertCompletionDetailsOk, session } = setup([tsconfigFile, packageJsonFile, indexFile, ...exportingFiles, ...nodeModulesPackage]); + const { typeToTriggerCompletions, assertCompletionDetailsOk, session } = setup([ + tsconfigFile, + packageJsonFile, + indexFile, + ...exportingFiles, + ...nodeModulesPackage, + ]); openFilesForSession([indexFile], session); typeToTriggerCompletions(indexFile.path, "a", completions => assert(completions.isIncomplete)) .continueTyping("_", completions => { assert(!completions.isIncomplete); - assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier?.startsWith("dep-a")), 50); + assert.lengthOf( + completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier?.startsWith("dep-a")), + 50, + ); assertCompletionDetailsOk( indexFile.path, completions.entries.find(entry => (entry.data as any)?.moduleSpecifier?.startsWith("dep-a"))!, @@ -131,8 +201,18 @@ namespace ts.projectSystem { declare const exp: {} & { [K in Signals]: K }; export = exp;`, }; - const exportingFiles = createExportingModuleFiles("/lib/a", Completions.moduleSpecifierResolutionLimit, 1, i => `S${i}`); - const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles, constantsDts]); + const exportingFiles = createExportingModuleFiles( + "/lib/a", + Completions.moduleSpecifierResolutionLimit, + 1, + i => `S${i}`, + ); + const { typeToTriggerCompletions, session } = setup([ + tsconfigFile, + indexFile, + ...exportingFiles, + constantsDts, + ]); openFilesForSession([indexFile], session); typeToTriggerCompletions(indexFile.path, "s", completions => { @@ -166,12 +246,25 @@ namespace ts.projectSystem { return { host, session, projectService, typeToTriggerCompletions, assertCompletionDetailsOk }; - function typeToTriggerCompletions(fileName: string, typedCharacters: string, cb?: (completions: protocol.CompletionInfo) => void) { - const project = projectService.getDefaultProjectForFile(server.toNormalizedPath(fileName), /*ensureProject*/ true)!; + function typeToTriggerCompletions( + fileName: string, + typedCharacters: string, + cb?: (completions: protocol.CompletionInfo) => void, + ) { + const project = projectService.getDefaultProjectForFile( + server.toNormalizedPath(fileName), + /*ensureProject*/ true, + )!; return type(typedCharacters, cb, /*isIncompleteContinuation*/ false); - function type(typedCharacters: string, cb: ((completions: protocol.CompletionInfo) => void) | undefined, isIncompleteContinuation: boolean) { - const file = Debug.checkDefined(project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName)); + function type( + typedCharacters: string, + cb: ((completions: protocol.CompletionInfo) => void) | undefined, + isIncompleteContinuation: boolean, + ) { + const file = Debug.checkDefined( + project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName), + ); const { line, character } = getLineAndCharacterOfPosition(file, file.text.length); const oneBasedEditPosition = { line: line + 1, offset: character + 1 }; session.executeCommandSeq({ @@ -210,10 +303,15 @@ namespace ts.projectSystem { } function backspace(n = 1) { - const file = Debug.checkDefined(project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName)); + const file = Debug.checkDefined( + project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName), + ); const startLineCharacter = getLineAndCharacterOfPosition(file, file.text.length - n); const endLineCharacter = getLineAndCharacterOfPosition(file, file.text.length); - const oneBasedStartPosition = { line: startLineCharacter.line + 1, offset: startLineCharacter.character + 1 }; + const oneBasedStartPosition = { + line: startLineCharacter.line + 1, + offset: startLineCharacter.character + 1, + }; const oneBasedEndPosition = { line: endLineCharacter.line + 1, offset: endLineCharacter.character + 1 }; session.executeCommandSeq({ command: protocol.CommandTypes.UpdateOpen, @@ -239,8 +337,13 @@ namespace ts.projectSystem { } function assertCompletionDetailsOk(fileName: string, entry: protocol.CompletionEntry) { - const project = projectService.getDefaultProjectForFile(server.toNormalizedPath(fileName), /*ensureProject*/ true)!; - const file = Debug.checkDefined(project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName)); + const project = projectService.getDefaultProjectForFile( + server.toNormalizedPath(fileName), + /*ensureProject*/ true, + )!; + const file = Debug.checkDefined( + project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName), + ); const { line, character } = getLineAndCharacterOfPosition(file, file.text.length - 1); const details = session.executeCommandSeq({ command: protocol.CommandTypes.CompletionDetails, @@ -258,7 +361,11 @@ namespace ts.projectSystem { assert(details[0]); assert(details[0].codeActions); - assert(details[0].codeActions[0].changes[0].textChanges[0].newText.includes(`"${(entry.data as any).moduleSpecifier}"`)); + assert( + details[0].codeActions[0].changes[0].textChanges[0].newText.includes( + `"${(entry.data as any).moduleSpecifier}"`, + ), + ); return details; } } diff --git a/src/testRunner/unittests/tsserver/configFileSearch.ts b/src/testRunner/unittests/tsserver/configFileSearch.ts index 7005b0035bca5..7506128ce8a23 100644 --- a/src/testRunner/unittests/tsserver/configFileSearch.ts +++ b/src/testRunner/unittests/tsserver/configFileSearch.ts @@ -45,7 +45,11 @@ namespace ts.projectSystem { host.deleteFile(configFile.path); host.runQueuedTimeoutCallbacks(); checkNumberOfProjects(service, { inferredProjects: 1 }); - baselineTsserverLogs("configFileSearch", "should use projectRootPath when searching for inferred project again", service); + baselineTsserverLogs( + "configFileSearch", + "should use projectRootPath when searching for inferred project again", + service, + ); }); it("should use projectRootPath when searching for inferred project again 2", () => { @@ -74,7 +78,11 @@ namespace ts.projectSystem { // Delete config file - should create inferred project with project root path set host.deleteFile(configFile.path); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("configFileSearch", "should use projectRootPath when searching for inferred project again 2", service); + baselineTsserverLogs( + "configFileSearch", + "should use projectRootPath when searching for inferred project again 2", + service, + ); }); describe("when the opened file is not from project root", () => { @@ -90,7 +98,12 @@ namespace ts.projectSystem { function openClientFile(files: File[]) { const host = createServerHost(files); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); - projectService.openClientFile(file.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a/b/projects/proj"); + projectService.openClientFile( + file.path, + /*fileContent*/ undefined, + /*scriptKind*/ undefined, + "/a/b/projects/proj", + ); return { host, projectService }; } @@ -123,7 +136,9 @@ namespace ts.projectSystem { function verifyConfigFileWatch(scenario: string, projectRootPath: string | undefined) { it(scenario, () => { const path = `/root/teams/VSCode68/Shared Documents/General/jt-ts-test-workspace/x.js`; - const host = createServerHost([libFile, { path, content: "const x = 10" }], { useCaseSensitiveFileNames: true }); + const host = createServerHost([libFile, { path, content: "const x = 10" }], { + useCaseSensitiveFileNames: true, + }); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); service.openClientFile(path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectRootPath); baselineTsserverLogs("configFileSearch", scenario, service); diff --git a/src/testRunner/unittests/tsserver/configuredProjects.ts b/src/testRunner/unittests/tsserver/configuredProjects.ts index 5146f2b886f59..e09bc76e24e78 100644 --- a/src/testRunner/unittests/tsserver/configuredProjects.ts +++ b/src/testRunner/unittests/tsserver/configuredProjects.ts @@ -29,7 +29,10 @@ namespace ts.projectSystem { const { configFileName, configFileErrors } = projectService.openClientFile(file1.path); assert(configFileName, "should find config file"); - assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); + assert.isTrue( + !configFileErrors || configFileErrors.length === 0, + `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`, + ); baselineTsserverLogs("configuredProjects", "create configured project without file list", projectService); }); @@ -61,7 +64,10 @@ namespace ts.projectSystem { const { configFileName, configFileErrors } = projectService.openClientFile(file1.path); assert(configFileName, "should find config file"); - assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); + assert.isTrue( + !configFileErrors || configFileErrors.length === 0, + `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`, + ); baselineTsserverLogs("configuredProjects", "create configured project with the file list", projectService); }); @@ -96,7 +102,11 @@ namespace ts.projectSystem { host.deleteFile(configFile.path); host.checkTimeoutQueueLengthAndRun(1); // Refresh inferred projects - baselineTsserverLogs("configuredProjects", "add and then remove a config file in a folder with loose files", projectService); + baselineTsserverLogs( + "configuredProjects", + "add and then remove a config file in a folder with loose files", + projectService, + ); }); it("add new files to a configured project without file list", () => { @@ -111,7 +121,11 @@ namespace ts.projectSystem { // add a new ts file host.writeFile(commonFile2.path, commonFile2.content); host.checkTimeoutQueueLengthAndRun(2); - baselineTsserverLogs("configuredProjects", "add new files to a configured project without file list", projectService); + baselineTsserverLogs( + "configuredProjects", + "add new files to a configured project without file list", + projectService, + ); }); it("should ignore non-existing files specified in the config file", () => { @@ -427,7 +441,12 @@ namespace ts.projectSystem { host.writeFile(configFile.path, configFile.content); host.checkTimeoutQueueLengthAndRun(2); // load configured project from disk + ensureProjectsForOpenFiles checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); - checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, file3.path, configFile.path]); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [ + file1.path, + file2.path, + file3.path, + configFile.path, + ]); assert.isTrue(projectService.inferredProjects[0].isOrphan()); assert.isTrue(projectService.inferredProjects[1].isOrphan()); }); @@ -510,7 +529,10 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, configFile.path]); - host.writeFile(configFile.path, JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] })); + host.writeFile( + configFile.path, + JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] }), + ); checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectRootFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path]); @@ -583,7 +605,11 @@ namespace ts.projectSystem { projectService.testhost.baselineHost("File5 written"); projectService.openClientFile(file5.path); - baselineTsserverLogs("configuredProjects", "Open ref of configured project when open file gets added to the project as part of configured file update", projectService); + baselineTsserverLogs( + "configuredProjects", + "Open ref of configured project when open file gets added to the project as part of configured file update", + projectService, + ); }); it("Open ref of configured project when open file gets added to the project as part of configured file update buts its open file references are all closed when the update happens", () => { @@ -671,7 +697,9 @@ namespace ts.projectSystem { }; const host = createServerHost([f1, f2, f3, config]); const originalGetFileSize = host.getFileSize; - host.getFileSize = (filePath: string) => filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath); + host.getFileSize = (filePath: string) => + filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 + : originalGetFileSize.call(host, filePath); const projectService = createProjectService(host); projectService.openClientFile(f1.path); @@ -690,7 +718,11 @@ namespace ts.projectSystem { // All the script infos should be present and contain the project since it is still alive. const scriptInfo = projectService.getScriptInfoForNormalizedPath(server.toNormalizedPath(f.path))!; assert.equal(scriptInfo.containingProjects.length, 1, `expect 1 containing projects for '${f.path}'`); - assert.equal(scriptInfo.containingProjects[0], project, `expect configured project to be the only containing project for '${f.path}'`); + assert.equal( + scriptInfo.containingProjects[0], + project, + `expect configured project to be the only containing project for '${f.path}'`, + ); } const f4 = { @@ -724,8 +756,13 @@ namespace ts.projectSystem { }; const host = createServerHost([f1, f2, config]); const originalGetFileSize = host.getFileSize; - host.getFileSize = (filePath: string) => filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath); - const { session, events } = createSessionWithEventTracking(host, server.ProjectLanguageServiceStateEvent); + host.getFileSize = (filePath: string) => + filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 + : originalGetFileSize.call(host, filePath); + const { session, events } = createSessionWithEventTracking( + host, + server.ProjectLanguageServiceStateEvent, + ); session.executeCommand({ seq: 0, type: "request", @@ -798,7 +835,11 @@ declare var console: { const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([fooIndex, barIndex], session); verifyGetErrRequest({ session, host, files: [barIndex, fooIndex] }); - baselineTsserverLogs("configuredProjects", "when multiple projects are open detects correct default project", session); + baselineTsserverLogs( + "configuredProjects", + "when multiple projects are open detects correct default project", + session, + ); }); it("when file name starts with ^", () => { @@ -838,21 +879,24 @@ declare var console: { path: `${tscWatch.projectRoot}/src/sub/fooBar.ts`, content: "export function fooBar() { }", }; - function verifySessionWorker({ withExclude, openFileBeforeCreating }: VerifySession, errorOnNewFileBeforeOldFile: boolean) { + function verifySessionWorker( + { withExclude, openFileBeforeCreating }: VerifySession, + errorOnNewFileBeforeOldFile: boolean, + ) { const host = createServerHost([ foo, bar, libFile, { path: `${tscWatch.projectRoot}/src/sub` }, - withExclude ? - { + withExclude + ? { path: config.path, content: JSON.stringify({ include: ["./src"], exclude: ["./src/sub"], }), - } : - config, + } + : config, ]); const session = createSession(host, { canUseEvents: true, @@ -883,12 +927,20 @@ declare var console: { verifyGetErrRequest({ session, host, - files: errorOnNewFileBeforeOldFile ? - [fooBar, foo] : - [foo, fooBar], + files: errorOnNewFileBeforeOldFile + ? [fooBar, foo] + : [foo, fooBar], existingTimeouts: withExclude ? 0 : 2, }); - baselineTsserverLogs("configuredProjects", `creating new file and then open it ${openFileBeforeCreating ? "before" : "after"} watcher is invoked, ask errors on it ${errorOnNewFileBeforeOldFile ? "before" : "after"} old one${withExclude ? " without file being in config" : ""}`, session); + baselineTsserverLogs( + "configuredProjects", + `creating new file and then open it ${ + openFileBeforeCreating ? "before" : "after" + } watcher is invoked, ask errors on it ${errorOnNewFileBeforeOldFile ? "before" : "after"} old one${ + withExclude ? " without file being in config" : "" + }`, + session, + ); } interface VerifySession { withExclude?: boolean; @@ -960,18 +1012,40 @@ foo();`, path: `${tscWatch.projectRoot}/foo/index.ts`, content: `export function foo() {}`, }; - const host = createServerHost([barConfig, barIndex, fooBarConfig, fooBarIndex, fooConfig, fooIndex, libFile]); + const host = createServerHost([ + barConfig, + barIndex, + fooBarConfig, + fooBarIndex, + fooConfig, + fooIndex, + libFile, + ]); tscWatch.ensureErrorFreeBuild(host, [fooConfig.path]); const fooDts = `${tscWatch.projectRoot}/foo/lib/index.d.ts`; assert.isTrue(host.fileExists(fooDts)); const session = createSession(host); const service = session.getProjectService(); service.openClientFile(barIndex.path); - checkProjectActualFiles(service.configuredProjects.get(barConfig.path)!, [barIndex.path, fooDts, libFile.path, barConfig.path]); + checkProjectActualFiles(service.configuredProjects.get(barConfig.path)!, [ + barIndex.path, + fooDts, + libFile.path, + barConfig.path, + ]); service.openClientFile(fooBarIndex.path); - checkProjectActualFiles(service.configuredProjects.get(fooBarConfig.path)!, [fooBarIndex.path, fooDts, libFile.path, fooBarConfig.path]); + checkProjectActualFiles(service.configuredProjects.get(fooBarConfig.path)!, [ + fooBarIndex.path, + fooDts, + libFile.path, + fooBarConfig.path, + ]); service.openClientFile(fooIndex.path); - checkProjectActualFiles(service.configuredProjects.get(fooConfig.path)!, [fooIndex.path, libFile.path, fooConfig.path]); + checkProjectActualFiles(service.configuredProjects.get(fooConfig.path)!, [ + fooIndex.path, + libFile.path, + fooConfig.path, + ]); service.openClientFile(fooDts); session.executeCommandSeq({ command: protocol.CommandTypes.GetApplicableRefactors, @@ -983,7 +1057,10 @@ foo();`, endOffset: 1, }, }); - assert.equal(service.tryGetDefaultProjectForFile(server.toNormalizedPath(fooDts)), service.configuredProjects.get(barConfig.path)); + assert.equal( + service.tryGetDefaultProjectForFile(server.toNormalizedPath(fooDts)), + service.configuredProjects.get(barConfig.path), + ); }); describe("watches extended config files", () => { @@ -1021,13 +1098,31 @@ foo();`, content: `let b = 1;`, }; - const host = createServerHost([alphaExtendedConfig, aConfig, aFile, bravoExtendedConfig, bConfig, bFile, ...(additionalFiles || emptyArray)]); + const host = createServerHost([ + alphaExtendedConfig, + aConfig, + aFile, + bravoExtendedConfig, + bConfig, + bFile, + ...(additionalFiles || emptyArray), + ]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); - return { host, projectService, aFile, bFile, aConfig, bConfig, alphaExtendedConfig, bravoExtendedConfig }; + return { + host, + projectService, + aFile, + bFile, + aConfig, + bConfig, + alphaExtendedConfig, + bravoExtendedConfig, + }; } it("should watch the extended configs of multiple projects", () => { - const { host, projectService, aFile, bFile, bConfig, alphaExtendedConfig, bravoExtendedConfig } = getService(); + const { host, projectService, aFile, bFile, bConfig, alphaExtendedConfig, bravoExtendedConfig } = + getService(); projectService.openClientFile(aFile.path); projectService.openClientFile(bFile.path); @@ -1063,7 +1158,11 @@ foo();`, host.writeFile(alphaExtendedConfig.path, "{}"); host.checkTimeoutQueueLengthAndRun(3); - baselineTsserverLogs("configuredProjects", "should watch the extended configs of multiple projects", projectService); + baselineTsserverLogs( + "configuredProjects", + "should watch the extended configs of multiple projects", + projectService, + ); }); it("should stop watching the extended configs of closed projects", () => { @@ -1088,7 +1187,11 @@ foo();`, projectService.closeClientFile(aFile.path); projectService.closeClientFile(dummy.path); projectService.openClientFile(dummy.path); - baselineTsserverLogs("configuredProjects", "should stop watching the extended configs of closed projects", projectService); + baselineTsserverLogs( + "configuredProjects", + "should stop watching the extended configs of closed projects", + projectService, + ); }); }); }); @@ -1116,7 +1219,11 @@ foo();`, checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); const inferredProject = projectService.inferredProjects[0]; assert.isTrue(inferredProject.containsFile(file1.path as server.NormalizedPath)); - assert.isFalse(projectService.configuredProjects.get(configFile.path)!.containsFile(file1.path as server.NormalizedPath)); + assert.isFalse( + projectService.configuredProjects.get(configFile.path)!.containsFile( + file1.path as server.NormalizedPath, + ), + ); }); it("should be able to handle @types if input file list is empty", () => { @@ -1200,7 +1307,11 @@ foo();`, // On next file open the files file2a should be closed and not watched any more projectService.openClientFile(file2.path); - baselineTsserverLogs("configuredProjects", "changed module resolution reflected when specifying files list", projectService); + baselineTsserverLogs( + "configuredProjects", + "changed module resolution reflected when specifying files list", + projectService, + ); }); it("Failed lookup locations uses parent most node_modules directory", () => { @@ -1232,7 +1343,11 @@ foo();`, const host = createServerHost(files); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(file1.path); - baselineTsserverLogs("configuredProjects", "failed lookup locations uses parent most node_modules directory", projectService); + baselineTsserverLogs( + "configuredProjects", + "failed lookup locations uses parent most node_modules directory", + projectService, + ); }); }); @@ -1248,12 +1363,15 @@ foo();`, }; const host = createServerHost([file1, libFile, configFile]); - const { session, events } = createSessionWithEventTracking(host, server.ConfigFileDiagEvent); + const { session, events } = createSessionWithEventTracking( + host, + server.ConfigFileDiagEvent, + ); const originalReadFile = host.readFile; host.readFile = f => { - return f === configFile.path ? - undefined : - originalReadFile.call(host, f); + return f === configFile.path + ? undefined + : originalReadFile.call(host, f); }; openFilesForSession([file1], session); diff --git a/src/testRunner/unittests/tsserver/declarationFileMaps.ts b/src/testRunner/unittests/tsserver/declarationFileMaps.ts index 8725f8152d32f..09a623714e1e0 100644 --- a/src/testRunner/unittests/tsserver/declarationFileMaps.ts +++ b/src/testRunner/unittests/tsserver/declarationFileMaps.ts @@ -1,6 +1,9 @@ namespace ts.projectSystem { - function documentSpanFromSubstring({ file, text, contextText, options, contextOptions }: DocumentSpanFromSubstring): DocumentSpan { - const contextSpan = contextText !== undefined ? documentSpanFromSubstring({ file, text: contextText, options: contextOptions }) : undefined; + function documentSpanFromSubstring( + { file, text, contextText, options, contextOptions }: DocumentSpanFromSubstring, + ): DocumentSpan { + const contextSpan = contextText !== undefined + ? documentSpanFromSubstring({ file, text: contextText, options: contextOptions }) : undefined; return { fileName: file.path, textSpan: textSpanFromSubstring(file.content, text, options), @@ -16,7 +19,9 @@ namespace ts.projectSystem { isDefinition?: boolean; isWriteAccess?: boolean; } - function makeReferencedSymbolEntry({ isDefinition, isWriteAccess, ...rest }: MakeReferenceEntry): ReferencedSymbolEntry { + function makeReferencedSymbolEntry( + { isDefinition, isWriteAccess, ...rest }: MakeReferenceEntry, + ): ReferencedSymbolEntry { const result = { ...documentSpanFromSubstring(rest), isDefinition, @@ -31,13 +36,25 @@ namespace ts.projectSystem { function checkDeclarationFiles(file: File, session: TestSession, expectedFiles: readonly File[]): void { openFilesForSession([file], session); - const project = Debug.checkDefined(session.getProjectService().getDefaultProjectForFile(file.path as server.NormalizedPath, /*ensureProject*/ false)); + const project = Debug.checkDefined( + session.getProjectService().getDefaultProjectForFile( + file.path as server.NormalizedPath, + /*ensureProject*/ false, + ), + ); const program = project.getCurrentProgram()!; - const output = getFileEmitOutput(program, Debug.checkDefined(program.getSourceFile(file.path)), /*emitOnlyDtsFiles*/ true); + const output = getFileEmitOutput( + program, + Debug.checkDefined(program.getSourceFile(file.path)), + /*emitOnlyDtsFiles*/ true, + ); closeFilesForSession([file], session); Debug.assert(!output.emitSkipped); - assert.deepEqual(output.outputFiles, expectedFiles.map((e): OutputFile => ({ name: e.path, text: e.content, writeByteOrderMark: false }))); + assert.deepEqual( + output.outputFiles, + expectedFiles.map((e): OutputFile => ({ name: e.path, text: e.content, writeByteOrderMark: false })), + ); } describe("unittests:: tsserver:: with declaration file maps:: project references", () => { @@ -69,7 +86,8 @@ namespace ts.projectSystem { const aDts: File = { path: "/a/bin/a.d.ts", // ${""} is needed to mangle the sourceMappingURL part or it breaks the build - content: `export declare function fnA(): void;\nexport interface IfaceA {\n}\nexport declare const instanceA: IfaceA;\n//# source${""}MappingURL=a.d.ts.map`, + content: + `export declare function fnA(): void;\nexport interface IfaceA {\n}\nexport declare const instanceA: IfaceA;\n//# source${""}MappingURL=a.d.ts.map`, }; const bTs: File = { @@ -103,12 +121,14 @@ namespace ts.projectSystem { const userTs: File = { path: "/user/user.ts", - content: 'import * as a from "../a/bin/a";\nimport * as b from "../b/bin/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }', + content: + 'import * as a from "../a/bin/a";\nimport * as b from "../b/bin/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }', }; const userTsForConfigProject: File = { path: "/user/user.ts", - content: 'import * as a from "../a/a";\nimport * as b from "../b/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }', + content: + 'import * as a from "../a/a";\nimport * as b from "../b/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }', }; const userTsconfig: File = { @@ -120,7 +140,18 @@ namespace ts.projectSystem { }; function makeSampleProjects(addUserTsConfig?: boolean, keepAllFiles?: boolean) { - const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, ...(addUserTsConfig ? [userTsForConfigProject, userTsconfig] : [userTs]), dummyFile]); + const host = createServerHost([ + aTs, + aTsconfig, + aDtsMap, + aDts, + bTsconfig, + bTs, + bDtsMap, + bDts, + ...(addUserTsConfig ? [userTsForConfigProject, userTsconfig] : [userTs]), + dummyFile, + ]); const session = createSession(host); checkDeclarationFiles(aTs, session, [aDtsMap, aDts]); @@ -139,7 +170,11 @@ namespace ts.projectSystem { } function verifyInferredProjectUnchanged(session: TestSession) { - checkProjectActualFiles(session.getProjectService().inferredProjects[0], [userTs.path, aDts.path, bDts.path]); + checkProjectActualFiles(session.getProjectService().inferredProjects[0], [ + userTs.path, + aDts.path, + bDts.path, + ]); } function verifyDummyProject(session: TestSession) { @@ -162,7 +197,10 @@ namespace ts.projectSystem { } function verifyATsConfigProject(session: TestSession) { - checkProjectActualFiles(session.getProjectService().configuredProjects.get(aTsconfig.path)!, [aTs.path, aTsconfig.path]); + checkProjectActualFiles(session.getProjectService().configuredProjects.get(aTsconfig.path)!, [ + aTs.path, + aTsconfig.path, + ]); } function verifyATsConfigOriginalProject(session: TestSession) { @@ -187,12 +225,20 @@ namespace ts.projectSystem { } function verifyUserTsConfigProject(session: TestSession) { - checkProjectActualFiles(session.getProjectService().configuredProjects.get(userTsconfig.path)!, [userTs.path, aTs.path, userTsconfig.path]); + checkProjectActualFiles(session.getProjectService().configuredProjects.get(userTsconfig.path)!, [ + userTs.path, + aTs.path, + userTsconfig.path, + ]); } it("goToDefinition", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.Definition, protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.Definition, + protocolFileLocationFromSubstring(userTs, "fnA()"), + ); assert.deepEqual(response, [ protocolFileSpanWithContextFromSubstring({ file: aTs, @@ -205,7 +251,14 @@ namespace ts.projectSystem { it("getDefinitionAndBoundSpan", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest< + protocol.DefinitionAndBoundSpanRequest, + protocol.DefinitionAndBoundSpanResponse + >( + session, + protocol.CommandTypes.DefinitionAndBoundSpan, + protocolFileLocationFromSubstring(userTs, "fnA()"), + ); assert.deepEqual(response, { textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA"), definitions: [ @@ -221,7 +274,14 @@ namespace ts.projectSystem { it("getDefinitionAndBoundSpan with file navigation", () => { const session = makeSampleProjects(/*addUserTsConfig*/ true); - const response = executeSessionRequest(session, protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest< + protocol.DefinitionAndBoundSpanRequest, + protocol.DefinitionAndBoundSpanResponse + >( + session, + protocol.CommandTypes.DefinitionAndBoundSpan, + protocolFileLocationFromSubstring(userTs, "fnA()"), + ); assert.deepEqual(response, { textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA"), definitions: [ @@ -250,7 +310,11 @@ namespace ts.projectSystem { it("goToType", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.TypeDefinition, protocolFileLocationFromSubstring(userTs, "instanceA")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.TypeDefinition, + protocolFileLocationFromSubstring(userTs, "instanceA"), + ); assert.deepEqual(response, [ protocolFileSpanWithContextFromSubstring({ file: aTs, @@ -263,7 +327,11 @@ namespace ts.projectSystem { it("goToImplementation", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.Implementation, protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.Implementation, + protocolFileLocationFromSubstring(userTs, "fnA()"), + ); assert.deepEqual(response, [ protocolFileSpanWithContextFromSubstring({ file: aTs, @@ -276,7 +344,11 @@ namespace ts.projectSystem { it("goToDefinition -- target does not exist", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, CommandNames.Definition, protocolFileLocationFromSubstring(userTs, "fnB()")); + const response = executeSessionRequest( + session, + CommandNames.Definition, + protocolFileLocationFromSubstring(userTs, "fnB()"), + ); // bTs does not exist, so stick with bDts assert.deepEqual(response, [ protocolFileSpanWithContextFromSubstring({ @@ -290,7 +362,11 @@ namespace ts.projectSystem { it("navigateTo", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, CommandNames.Navto, { file: userTs.path, searchValue: "fn" }); + const response = executeSessionRequest( + session, + CommandNames.Navto, + { file: userTs.path, searchValue: "fn" }, + ); assert.deepEqual(response, [ // Keep the .d.ts file since the .ts file no longer exists // (otherwise it would be treated as not in the project) @@ -323,7 +399,11 @@ namespace ts.projectSystem { it("navigateToAll -- when neither file nor project is specified", () => { const session = makeSampleProjects(/*addUserTsConfig*/ true, /*keepAllFiles*/ true); - const response = executeSessionRequest(session, CommandNames.Navto, { file: undefined, searchValue: "fn" }); + const response = executeSessionRequest( + session, + CommandNames.Navto, + { file: undefined, searchValue: "fn" }, + ); assert.deepEqual(response, [ { ...protocolFileSpanFromSubstring({ @@ -363,7 +443,11 @@ namespace ts.projectSystem { it("navigateToAll -- when file is not specified but project is", () => { const session = makeSampleProjects(/*addUserTsConfig*/ true, /*keepAllFiles*/ true); - const response = executeSessionRequest(session, CommandNames.Navto, { projectFileName: bTsconfig.path, file: undefined, searchValue: "fn" }); + const response = executeSessionRequest( + session, + CommandNames.Navto, + { projectFileName: bTsconfig.path, file: undefined, searchValue: "fn" }, + ); assert.deepEqual(response, [ { ...protocolFileSpanFromSubstring({ @@ -388,7 +472,10 @@ namespace ts.projectSystem { contextText: "export function fnA() {}", lineText: "export function fnA() {}", }); - const referencesUserTs = (userTs: File, isDefinition: false | undefined): readonly protocol.ReferencesResponseItem[] => [ + const referencesUserTs = ( + userTs: File, + isDefinition: false | undefined, + ): readonly protocol.ReferencesResponseItem[] => [ makeReferenceItem({ file: userTs, isDefinition, @@ -400,9 +487,16 @@ namespace ts.projectSystem { it("findAllReferences", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.References, + protocolFileLocationFromSubstring(userTs, "fnA()"), + ); assert.deepEqual(response, { - refs: [...referencesUserTs(userTs, /*isDefinition*/ undefined), referenceATs(aTs, /*isDefinition*/ undefined)], + refs: [ + ...referencesUserTs(userTs, /*isDefinition*/ undefined), + referenceATs(aTs, /*isDefinition*/ undefined), + ], symbolName: "fnA", symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnA()").offset, symbolDisplayString: "function fnA(): void", @@ -414,7 +508,11 @@ namespace ts.projectSystem { it("findAllReferences -- starting at definition", () => { const session = makeSampleProjects(); openFilesForSession([aTs], session); // If it's not opened, the reference isn't found. - const response = executeSessionRequest(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(aTs, "fnA")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.References, + protocolFileLocationFromSubstring(aTs, "fnA"), + ); assert.deepEqual(response, { refs: [referenceATs(aTs, /*isDefinition*/ true), ...referencesUserTs(userTs, /*isDefinition*/ false)], symbolName: "fnA", @@ -434,7 +532,11 @@ namespace ts.projectSystem { it("findAllReferencesFull", () => { const session = makeSampleProjects(); - const responseFull = executeSessionRequest(session, protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(userTs, "fnA()")); + const responseFull = executeSessionRequest( + session, + protocol.CommandTypes.ReferencesFull, + protocolFileLocationFromSubstring(userTs, "fnA()"), + ); assert.deepEqual(responseFull, [ { @@ -461,7 +563,12 @@ namespace ts.projectSystem { }, references: [ makeReferencedSymbolEntry({ file: userTs, text: "fnA" }), - makeReferencedSymbolEntry({ file: aTs, text: "fnA", isWriteAccess: true, contextText: "export function fnA() {}" }), + makeReferencedSymbolEntry({ + file: aTs, + text: "fnA", + isWriteAccess: true, + contextText: "export function fnA() {}", + }), ], }, ]); @@ -472,14 +579,29 @@ namespace ts.projectSystem { const aTs: File = { path: "/a/a.ts", content: `function f() {}` }; const aTsconfig: File = { path: "/a/tsconfig.json", - content: JSON.stringify({ compilerOptions: { declaration: true, declarationMap: true, outFile: "../bin/a.js" } }), + content: JSON.stringify({ + compilerOptions: { declaration: true, declarationMap: true, outFile: "../bin/a.js" }, + }), }; const bTs: File = { path: "/b/b.ts", content: `f();` }; - const bTsconfig: File = { path: "/b/tsconfig.json", content: JSON.stringify({ references: [{ path: "../a" }] }) }; - const aDts: File = { path: "/bin/a.d.ts", content: `declare function f(): void;\n//# sourceMappingURL=a.d.ts.map` }; + const bTsconfig: File = { + path: "/b/tsconfig.json", + content: JSON.stringify({ references: [{ path: "../a" }] }), + }; + const aDts: File = { + path: "/bin/a.d.ts", + content: `declare function f(): void;\n//# sourceMappingURL=a.d.ts.map`, + }; const aDtsMap: File = { path: "/bin/a.d.ts.map", - content: JSON.stringify({ version: 3, file: "a.d.ts", sourceRoot: "", sources: ["../a/a.ts"], names: [], mappings: "AAAA,iBAAS,CAAC,SAAK" }), + content: JSON.stringify({ + version: 3, + file: "a.d.ts", + sourceRoot: "", + sources: ["../a/a.ts"], + names: [], + mappings: "AAAA,iBAAS,CAAC,SAAK", + }), }; const session = createSession(createServerHost([aTs, aTsconfig, bTs, bTsconfig, aDts, aDtsMap])); @@ -487,7 +609,11 @@ namespace ts.projectSystem { openFilesForSession([bTs], session); checkNumberOfProjects(session.getProjectService(), { configuredProjects: 2 }); // configured project of b is alive since a references b - const responseFull = executeSessionRequest(session, protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(bTs, "f()")); + const responseFull = executeSessionRequest( + session, + protocol.CommandTypes.ReferencesFull, + protocolFileLocationFromSubstring(bTs, "f()"), + ); assert.deepEqual(responseFull, [ { @@ -535,7 +661,11 @@ namespace ts.projectSystem { it("findAllReferences -- target does not exist", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnB()")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.References, + protocolFileLocationFromSubstring(userTs, "fnB()"), + ); assert.deepEqual(response, { refs: [ makeReferenceItem({ @@ -580,7 +710,11 @@ namespace ts.projectSystem { it("renameLocations", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(userTs, "fnA()"), + ); assert.deepEqual(response, { info: { canRename: true, @@ -588,7 +722,10 @@ namespace ts.projectSystem { fileToRename: undefined, fullDisplayName: '"/a/bin/a".fnA', // Ideally this would use the original source's path instead of the declaration file's path. kind: ScriptElementKind.functionElement, - kindModifiers: [ScriptElementKindModifier.exportedModifier, ScriptElementKindModifier.ambientModifier].join(","), + kindModifiers: [ + ScriptElementKindModifier.exportedModifier, + ScriptElementKindModifier.ambientModifier, + ].join(","), triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnA"), }, locs: [renameUserTs(userTs), renameATs(aTs)], @@ -599,7 +736,11 @@ namespace ts.projectSystem { it("renameLocations -- starting at definition", () => { const session = makeSampleProjects(); openFilesForSession([aTs], session); // If it's not opened, the reference isn't found. - const response = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "fnA")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(aTs, "fnA"), + ); assert.deepEqual(response, { info: { canRename: true, @@ -617,7 +758,11 @@ namespace ts.projectSystem { it("renameLocationsFull", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.RenameLocationsFull, protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.RenameLocationsFull, + protocolFileLocationFromSubstring(userTs, "fnA()"), + ); assert.deepEqual(response, [ renameLocation({ file: userTs, text: "fnA" }), renameLocation({ file: aTs, text: "fnA", contextText: "export function fnA() {}" }), @@ -627,7 +772,11 @@ namespace ts.projectSystem { it("renameLocations -- target does not exist", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnB()")); + const response = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(userTs, "fnB()"), + ); assert.deepEqual(response, { info: { canRename: true, @@ -635,7 +784,10 @@ namespace ts.projectSystem { fileToRename: undefined, fullDisplayName: '"/b/bin/b".fnB', kind: ScriptElementKind.functionElement, - kindModifiers: [ScriptElementKindModifier.exportedModifier, ScriptElementKindModifier.ambientModifier].join(","), + kindModifiers: [ + ScriptElementKindModifier.exportedModifier, + ScriptElementKindModifier.ambientModifier, + ].join(","), triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnB"), }, locs: [ @@ -665,7 +817,10 @@ namespace ts.projectSystem { it("getEditsForFileRename", () => { const session = makeSampleProjects(); - const response = executeSessionRequest(session, protocol.CommandTypes.GetEditsForFileRename, { + const response = executeSessionRequest< + protocol.GetEditsForFileRenameRequest, + protocol.GetEditsForFileRenameResponse + >(session, protocol.CommandTypes.GetEditsForFileRename, { oldFilePath: aTs.path, newFilePath: "/a/aNew.ts", }); @@ -709,7 +864,10 @@ namespace ts.projectSystem { const host = createServerHost([aTs, aTsconfig, bTs, bTsconfig]); const session = createSession(host); openFilesForSession([aTs, bTs], session); - const response = executeSessionRequest(session, CommandNames.GetEditsForFileRename, { + const response = executeSessionRequest< + protocol.GetEditsForFileRenameRequest, + protocol.GetEditsForFileRenameResponse + >(session, CommandNames.GetEditsForFileRename, { oldFilePath: aTs.path, newFilePath: "/a/src/a1.ts", }); diff --git a/src/testRunner/unittests/tsserver/documentRegistry.ts b/src/testRunner/unittests/tsserver/documentRegistry.ts index 59661f02a55de..372274d9d66df 100644 --- a/src/testRunner/unittests/tsserver/documentRegistry.ts +++ b/src/testRunner/unittests/tsserver/documentRegistry.ts @@ -22,12 +22,20 @@ namespace ts.projectSystem { // Update the project const project = getProject(service); project.getLanguageService(); - checkProjectActualFiles(project, [file.path, libFile.path, configFile.path, ...(moduleIsOrphan ? [] : [moduleFile.path])]); + checkProjectActualFiles(project, [ + file.path, + libFile.path, + configFile.path, + ...(moduleIsOrphan ? [] : [moduleFile.path]), + ]); const moduleInfo = service.getScriptInfo(moduleFile.path)!; assert.isDefined(moduleInfo); assert.equal(moduleInfo.isOrphan(), moduleIsOrphan); const key = service.documentRegistry.getKeyForCompilationSettings(project.getCompilationSettings()); - assert.deepEqual(service.documentRegistry.getLanguageServiceRefCounts(moduleInfo.path, moduleInfo.scriptKind), [[key, moduleIsOrphan ? undefined : 1]]); + assert.deepEqual( + service.documentRegistry.getLanguageServiceRefCounts(moduleInfo.path, moduleInfo.scriptKind), + [[key, moduleIsOrphan ? undefined : 1]], + ); } function createServiceAndHost() { @@ -40,13 +48,19 @@ namespace ts.projectSystem { function changeFileToNotImportModule(service: TestProjectService) { const info = service.getScriptInfo(file.path)!; - service.applyChangesToFile(info, singleIterator({ span: { start: 0, length: importModuleContent.length }, newText: "" })); + service.applyChangesToFile( + info, + singleIterator({ span: { start: 0, length: importModuleContent.length }, newText: "" }), + ); checkProject(service, /*moduleIsOrphan*/ true); } function changeFileToImportModule(service: TestProjectService) { const info = service.getScriptInfo(file.path)!; - service.applyChangesToFile(info, singleIterator({ span: { start: 0, length: 0 }, newText: importModuleContent })); + service.applyChangesToFile( + info, + singleIterator({ span: { start: 0, length: 0 }, newText: importModuleContent }), + ); checkProject(service, /*moduleIsOrphan*/ false); } diff --git a/src/testRunner/unittests/tsserver/duplicatePackages.ts b/src/testRunner/unittests/tsserver/duplicatePackages.ts index 6cb38cf10c5ca..f5fedf1aa3883 100644 --- a/src/testRunner/unittests/tsserver/duplicatePackages.ts +++ b/src/testRunner/unittests/tsserver/duplicatePackages.ts @@ -23,14 +23,18 @@ namespace ts.projectSystem { openFilesForSession([aUser, bUser], session); for (const user of [aUser, bUser]) { - const response = executeSessionRequest(session, protocol.CommandTypes.GetCodeFixes, { - file: user.path, - startLine: 2, - startOffset: 1, - endLine: 2, - endOffset: 4, - errorCodes: [Diagnostics.Cannot_find_name_0.code], - }); + const response = executeSessionRequest( + session, + protocol.CommandTypes.GetCodeFixes, + { + file: user.path, + startLine: 2, + startOffset: 1, + endLine: 2, + endOffset: 4, + errorCodes: [Diagnostics.Cannot_find_name_0.code], + }, + ); assert.deepEqual(response, [ { description: `Add import from "foo"`, diff --git a/src/testRunner/unittests/tsserver/dynamicFiles.ts b/src/testRunner/unittests/tsserver/dynamicFiles.ts index d100922fdb939..22e59e4cb6fc4 100644 --- a/src/testRunner/unittests/tsserver/dynamicFiles.ts +++ b/src/testRunner/unittests/tsserver/dynamicFiles.ts @@ -1,6 +1,16 @@ namespace ts.projectSystem { export function verifyDynamic(service: server.ProjectService, path: string) { - const info = Debug.checkDefined(service.filenameToScriptInfo.get(path), `Expected ${path} in :: ${JSON.stringify(arrayFrom(service.filenameToScriptInfo.entries(), ([key, f]) => ({ key, fileName: f.fileName, path: f.path })))}`); + const info = Debug.checkDefined( + service.filenameToScriptInfo.get(path), + `Expected ${path} in :: ${ + JSON.stringify( + arrayFrom( + service.filenameToScriptInfo.entries(), + ([key, f]) => ({ key, fileName: f.fileName, path: f.path }), + ), + ) + }`, + ); assert.isTrue(info.isDynamic); } @@ -27,25 +37,32 @@ var x = 10;`, it("Can convert positions to locations", () => { const aTs: File = { path: "/proj/a.ts", content: "" }; const tsconfig: File = { path: "/proj/tsconfig.json", content: "{}" }; - const session = createSession(createServerHost([aTs, tsconfig]), { useInferredProjectPerProjectRoot: true }); + const session = createSession(createServerHost([aTs, tsconfig]), { + useInferredProjectPerProjectRoot: true, + }); openFilesForSession([aTs], session); executeSessionRequestNoResponse(session, protocol.CommandTypes.Open, { file: untitledFile, - fileContent: `/// \nlet foo = 1;\nfooo/**/`, + fileContent: + `/// \nlet foo = 1;\nfooo/**/`, scriptKindName: "TS", projectRootPath: "/proj", }); verifyDynamic(session.getProjectService(), `/proj/untitled:^untitled-1`); - const response = executeSessionRequest(session, protocol.CommandTypes.GetCodeFixes, { - file: untitledFile, - startLine: 3, - startOffset: 1, - endLine: 3, - endOffset: 5, - errorCodes: [Diagnostics.Cannot_find_name_0_Did_you_mean_1.code], - }); + const response = executeSessionRequest( + session, + protocol.CommandTypes.GetCodeFixes, + { + file: untitledFile, + startLine: 3, + startOffset: 1, + endLine: 3, + endOffset: 5, + errorCodes: [Diagnostics.Cannot_find_name_0_Did_you_mean_1.code], + }, + ); assert.deepEqual(response, [ { description: "Change spelling to 'foo'", @@ -70,7 +87,10 @@ var x = 10;`, path: `${tscWatch.projectRoot}/tsconfig.json`, content: "{}", }; - const host = createServerHost([config, libFile], { useCaseSensitiveFileNames: true, currentDirectory: tscWatch.projectRoot }); + const host = createServerHost([config, libFile], { + useCaseSensitiveFileNames: true, + currentDirectory: tscWatch.projectRoot, + }); const service = createProjectService(host); service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, tscWatch.projectRoot); checkNumberOfProjects(service, { inferredProjects: 1 }); @@ -85,16 +105,28 @@ var x = 10;`, host.checkTimeoutQueueLength(0); service.openClientFile(untitled.path, untitled.content, /*scriptKind*/ undefined, tscWatch.projectRoot); checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 }); - checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, libFile.path, config.path]); + checkProjectActualFiles(service.configuredProjects.get(config.path)!, [ + untitled.path, + libFile.path, + config.path, + ]); checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]); service.closeClientFile(untitledFile); - checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, libFile.path, config.path]); + checkProjectActualFiles(service.configuredProjects.get(config.path)!, [ + untitled.path, + libFile.path, + config.path, + ]); checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]); service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, tscWatch.projectRoot); verifyDynamic(service, `${tscWatch.projectRoot}/${untitledFile}`); - checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, libFile.path, config.path]); + checkProjectActualFiles(service.configuredProjects.get(config.path)!, [ + untitled.path, + libFile.path, + config.path, + ]); checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]); }); @@ -169,21 +201,24 @@ var x = 10;`, assert.strictEqual(projectService.ensureDefaultProjectForFile(server.toNormalizedPath(file.path)), project); const indexOfX = file.content.indexOf("x"); - assert.deepEqual(project.getLanguageService(/*ensureSynchronized*/ true).getQuickInfoAtPosition(file.path, indexOfX), { - kind: ScriptElementKind.variableElement, - kindModifiers: "", - textSpan: { start: indexOfX, length: 1 }, - displayParts: [ - { text: "var", kind: "keyword" }, - { text: " ", kind: "space" }, - { text: "x", kind: "localName" }, - { text: ":", kind: "punctuation" }, - { text: " ", kind: "space" }, - { text: "number", kind: "keyword" }, - ], - documentation: [], - tags: undefined, - }); + assert.deepEqual( + project.getLanguageService(/*ensureSynchronized*/ true).getQuickInfoAtPosition(file.path, indexOfX), + { + kind: ScriptElementKind.variableElement, + kindModifiers: "", + textSpan: { start: indexOfX, length: 1 }, + displayParts: [ + { text: "var", kind: "keyword" }, + { text: " ", kind: "space" }, + { text: "x", kind: "localName" }, + { text: ":", kind: "punctuation" }, + { text: " ", kind: "space" }, + { text: "number", kind: "keyword" }, + ], + documentation: [], + tags: undefined, + }, + ); }); it("dynamic file with reference paths without external project", () => { @@ -204,7 +239,9 @@ var x = 10;`, content: "let y = 10;", }; it("with useInferredProjectPerProjectRoot", () => { - const host = createServerHost([libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true }); + const host = createServerHost([libFile, configFile, configProjectFile], { + useCaseSensitiveFileNames: true, + }); const session = createSession(host, { useInferredProjectPerProjectRoot: true }); openFilesForSession([{ file: file.path, projectRootPath: tscWatch.projectRoot }], session); @@ -229,10 +266,17 @@ var x = 10;`, }); it("fails when useInferredProjectPerProjectRoot is false", () => { - const host = createServerHost([libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true }); + const host = createServerHost([libFile, configFile, configProjectFile], { + useCaseSensitiveFileNames: true, + }); const projectService = createProjectService(host); try { - projectService.openClientFile(file.path, file.content, /*scriptKind*/ undefined, tscWatch.projectRoot); + projectService.openClientFile( + file.path, + file.content, + /*scriptKind*/ undefined, + tscWatch.projectRoot, + ); } catch (e) { assert.strictEqual( @@ -249,7 +293,9 @@ var x = 10;`, describe("verify accepts known schemas as dynamic file", () => { it("walkThroughSnippet", () => { - verifyPathRecognizedAsDynamic("walkThroughSnippet:/usr/share/code/resources/app/out/vs/workbench/contrib/welcome/walkThrough/browser/editor/^vs_code_editor_walkthrough.md#1.ts"); + verifyPathRecognizedAsDynamic( + "walkThroughSnippet:/usr/share/code/resources/app/out/vs/workbench/contrib/welcome/walkThrough/browser/editor/^vs_code_editor_walkthrough.md#1.ts", + ); }); it("untitled", () => { diff --git a/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts b/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts index 4f1a928dc9a0c..2ca3b4abd8d72 100644 --- a/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts +++ b/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts @@ -12,7 +12,9 @@ namespace ts.projectSystem { }; files.push(largeFile); const host = createServerHost(files); - const { session, events: largeFileReferencedEvents } = createSessionWithEventTracking(host, server.LargeFileReferencedEvent); + const { session, events: largeFileReferencedEvents } = createSessionWithEventTracking< + server.LargeFileReferencedEvent + >(host, server.LargeFileReferencedEvent); return { session, verifyLargeFile }; @@ -42,7 +44,10 @@ namespace ts.projectSystem { }; const tsconfig: File = { path: `${tscWatch.projectRoot}/tsconfig.json`, - content: JSON.stringify({ files: ["src/file.ts", getLargeFile(useLargeTsFile)], compilerOptions: { target: 1, allowJs: true } }), + content: JSON.stringify({ + files: ["src/file.ts", getLargeFile(useLargeTsFile)], + compilerOptions: { target: 1, allowJs: true }, + }), }; const files = [file, libFile, tsconfig]; const { session, verifyLargeFile } = createSessionWithEventHandler(files, useLargeTsFile); diff --git a/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts b/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts index 86ed9dc1ff737..e19a5d6089622 100644 --- a/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts +++ b/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts @@ -19,9 +19,14 @@ namespace ts.projectSystem { }; const host = createServerHost([f1, f2, config]); const originalGetFileSize = host.getFileSize; - host.getFileSize = (filePath: string) => filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath); + host.getFileSize = (filePath: string) => + filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 + : originalGetFileSize.call(host, filePath); - const { session, events } = createSessionWithEventTracking(host, server.ProjectLanguageServiceStateEvent); + const { session, events } = createSessionWithEventTracking( + host, + server.ProjectLanguageServiceStateEvent, + ); session.executeCommand({ seq: 0, type: "request", @@ -72,7 +77,11 @@ namespace ts.projectSystem { const project = service.configuredProjects.get(config.path)!; service.logger.info(`languageServiceEnabled: ${project.languageServiceEnabled}`); service.logger.info(`lastFileExceededProgramSize: ${project.lastFileExceededProgramSize}`); - baselineTsserverLogs("projectLanguageServiceStateEvent", "large file size is determined correctly", service); + baselineTsserverLogs( + "projectLanguageServiceStateEvent", + "large file size is determined correctly", + service, + ); }); }); } diff --git a/src/testRunner/unittests/tsserver/events/projectLoading.ts b/src/testRunner/unittests/tsserver/events/projectLoading.ts index 51a9a9ea74f43..9d3b745ac90a3 100644 --- a/src/testRunner/unittests/tsserver/events/projectLoading.ts +++ b/src/testRunner/unittests/tsserver/events/projectLoading.ts @@ -17,7 +17,9 @@ namespace ts.projectSystem { session: TestSession; getNumberOfEvents: () => number; clearEvents: () => void; - verifyProjectLoadEvents: (expected: [server.ProjectLoadingStartEvent, server.ProjectLoadingFinishEvent]) => void; + verifyProjectLoadEvents: ( + expected: [server.ProjectLoadingStartEvent, server.ProjectLoadingFinishEvent], + ) => void; }, ) { function createSessionToVerifyEvent(files: readonly File[]) { @@ -85,7 +87,9 @@ namespace ts.projectSystem { extends: "../a/tsconfig.json", }), }; - const { host, verifyEvent, verifyEventWithOpenTs, service } = createSessionToVerifyEvent(files.concat(bTs, configB)); + const { host, verifyEvent, verifyEventWithOpenTs, service } = createSessionToVerifyEvent( + files.concat(bTs, configB), + ); verifyEventWithOpenTs(bTs, configB.path, 1); host.writeFile(configA.path, configA.content); @@ -113,7 +117,8 @@ namespace ts.projectSystem { }; const aDTsMap: File = { path: `${tscWatch.projects}/a/a.d.ts.map`, - content: `{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["./a.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;CAAI"}`, + content: + `{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["./a.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;CAAI"}`, }; const bTs: File = { path: bTsPath, @@ -131,7 +136,9 @@ namespace ts.projectSystem { }), }; - const { service, session, verifyEventWithOpenTs, verifyEvent } = createSessionToVerifyEvent(files.concat(aDTs, aDTsMap, bTs, configB)); + const { service, session, verifyEventWithOpenTs, verifyEvent } = createSessionToVerifyEvent( + files.concat(aDTs, aDTsMap, bTs, configB), + ); verifyEventWithOpenTs(bTs, configB.path, 1); session.executeCommandSeq({ @@ -147,9 +154,9 @@ namespace ts.projectSystem { assert.isDefined(project); verifyEvent( project, - disableSourceOfProjectReferenceRedirect ? - `Creating project for original file: ${aTs.path} for location: ${aDTs.path}` : - `Creating project for original file: ${aTs.path}`, + disableSourceOfProjectReferenceRedirect + ? `Creating project for original file: ${aTs.path} for location: ${aDTs.path}` + : `Creating project for original file: ${aTs.path}`, ); } }); @@ -158,7 +165,8 @@ namespace ts.projectSystem { const projectFileName = `${tscWatch.projects}/a/project.csproj`; function createSession(lazyConfiguredProjectsFromExternalProject: boolean) { - const { session, service, verifyEvent: verifyEventWorker, getNumberOfEvents } = createSessionToVerifyEvent(files); + const { session, service, verifyEvent: verifyEventWorker, getNumberOfEvents } = + createSessionToVerifyEvent(files); service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } }); service.openExternalProject({ projectFileName, @@ -171,7 +179,10 @@ namespace ts.projectSystem { function verifyEvent() { const projectA = service.configuredProjects.get(configA.path)!; assert.isDefined(projectA); - verifyEventWorker(projectA, `Creating configured project in external project: ${projectFileName}`); + verifyEventWorker( + projectA, + `Creating configured project in external project: ${projectFileName}`, + ); } } @@ -181,7 +192,9 @@ namespace ts.projectSystem { }); it("when lazyConfiguredProjectsFromExternalProject is true and file is opened", () => { - const { verifyEvent, getNumberOfEvents, session } = createSession(/*lazyConfiguredProjectsFromExternalProject*/ true); + const { verifyEvent, getNumberOfEvents, session } = createSession( + /*lazyConfiguredProjectsFromExternalProject*/ true, + ); assert.equal(getNumberOfEvents(), 0); openFilesForSession([aTs], session); @@ -189,7 +202,9 @@ namespace ts.projectSystem { }); it("when lazyConfiguredProjectsFromExternalProject is disabled", () => { - const { verifyEvent, getNumberOfEvents, service } = createSession(/*lazyConfiguredProjectsFromExternalProject*/ true); + const { verifyEvent, getNumberOfEvents, service } = createSession( + /*lazyConfiguredProjectsFromExternalProject*/ true, + ); assert.equal(getNumberOfEvents(), 0); service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: false } }); @@ -200,7 +215,9 @@ namespace ts.projectSystem { describe("when using event handler", () => { verifyProjectLoadingStartAndFinish(host => { - const { session, events } = createSessionWithEventTracking(host, [server.ProjectLoadingStartEvent, server.ProjectLoadingFinishEvent]); + const { session, events } = createSessionWithEventTracking< + server.ProjectLoadingStartEvent | server.ProjectLoadingFinishEvent + >(host, [server.ProjectLoadingStartEvent, server.ProjectLoadingFinishEvent]); return { session, getNumberOfEvents: () => events.length, @@ -212,7 +229,9 @@ namespace ts.projectSystem { describe("when using default event handler", () => { verifyProjectLoadingStartAndFinish(host => { - const { session, getEvents, clearEvents } = createSessionWithDefaultEventHandler(host, [server.ProjectLoadingStartEvent, server.ProjectLoadingFinishEvent]); + const { session, getEvents, clearEvents } = createSessionWithDefaultEventHandler< + protocol.ProjectLoadingStartEvent | protocol.ProjectLoadingFinishEvent + >(host, [server.ProjectLoadingStartEvent, server.ProjectLoadingFinishEvent]); return { session, getNumberOfEvents: () => getEvents().length, @@ -220,7 +239,9 @@ namespace ts.projectSystem { verifyProjectLoadEvents, }; - function verifyProjectLoadEvents(expected: [server.ProjectLoadingStartEvent, server.ProjectLoadingFinishEvent]) { + function verifyProjectLoadEvents( + expected: [server.ProjectLoadingStartEvent, server.ProjectLoadingFinishEvent], + ) { const actual = getEvents().map(e => ({ eventName: e.event, data: e.body })); const mappedExpected = expected.map(e => { const { project, ...rest } = e.data; diff --git a/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts b/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts index 819af9996c6c6..4fe34388df38e 100644 --- a/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts +++ b/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts @@ -1,16 +1,29 @@ namespace ts.projectSystem { describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { function verifyFiles(caption: string, actual: readonly string[], expected: readonly string[]) { - assert.equal(actual.length, expected.length, `Incorrect number of ${caption}. Actual: ${actual} Expected: ${expected}`); + assert.equal( + actual.length, + expected.length, + `Incorrect number of ${caption}. Actual: ${actual} Expected: ${expected}`, + ); const seen = new Map(); forEach(actual, f => { - assert.isFalse(seen.has(f), `${caption}: Found duplicate ${f}. Actual: ${actual} Expected: ${expected}`); + assert.isFalse( + seen.has(f), + `${caption}: Found duplicate ${f}. Actual: ${actual} Expected: ${expected}`, + ); seen.set(f, true); - assert.isTrue(contains(expected, f), `${caption}: Expected not to contain ${f}. Actual: ${actual} Expected: ${expected}`); + assert.isTrue( + contains(expected, f), + `${caption}: Expected not to contain ${f}. Actual: ${actual} Expected: ${expected}`, + ); }); } - function createVerifyInitialOpen(session: TestSession, verifyProjectsUpdatedInBackgroundEventHandler: (events: server.ProjectsUpdatedInBackgroundEvent[]) => void) { + function createVerifyInitialOpen( + session: TestSession, + verifyProjectsUpdatedInBackgroundEventHandler: (events: server.ProjectsUpdatedInBackgroundEvent[]) => void, + ) { return (file: File) => { session.executeCommandSeq({ command: server.CommandNames.Open, @@ -28,7 +41,10 @@ namespace ts.projectSystem { verifyInitialOpen(file: File): void; } - function verifyProjectsUpdatedInBackgroundEvent(scenario: string, createSession: (host: TestServerHost, logger?: Logger) => ProjectsUpdatedInBackgroundEventVerifier) { + function verifyProjectsUpdatedInBackgroundEvent( + scenario: string, + createSession: (host: TestServerHost, logger?: Logger) => ProjectsUpdatedInBackgroundEventVerifier, + ) { it("when adding new file", () => { const commonFile1: File = { path: "/a/b/file1.ts", @@ -141,7 +157,9 @@ namespace ts.projectSystem { /** initial list of files to reload in fs and first file in this list being the file to open */ firstReloadFileList?: string[]; } - function getInitialState({ configObj = {}, getAdditionalFileOrFolder, firstReloadFileList }: InitialStateParams = {}) { + function getInitialState( + { configObj = {}, getAdditionalFileOrFolder, firstReloadFileList }: InitialStateParams = {}, + ) { const moduleFile1: File = { path: moduleFile1Path, content: "export function Foo() { };", @@ -173,13 +191,24 @@ namespace ts.projectSystem { content: JSON.stringify(configObj || { compilerOptions: {} }), }; - const files: File[] = [file1Consumer1, moduleFile1, file1Consumer2, moduleFile2, ...additionalFiles, globalFile3, libFile, configFile]; + const files: File[] = [ + file1Consumer1, + moduleFile1, + file1Consumer2, + moduleFile2, + ...additionalFiles, + globalFile3, + libFile, + configFile, + ]; const filesToReload = firstReloadFileList && getFiles(firstReloadFileList) || files; const host = createServerHost([filesToReload[0], configFile]); // Initial project creation - const { session, verifyProjectsUpdatedInBackgroundEventHandler, verifyInitialOpen } = createSession(host); + const { session, verifyProjectsUpdatedInBackgroundEventHandler, verifyInitialOpen } = createSession( + host, + ); const openFiles = [filesToReload[0].path]; verifyInitialOpen(filesToReload[0]); @@ -248,12 +277,22 @@ namespace ts.projectSystem { verifyProjectsUpdatedInBackgroundEvent(); // Change the content of moduleFile1 to `export var T: number;export function Foo() { console.log('hi'); };` - host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { console.log('hi'); };`); + host.writeFile( + moduleFile1.path, + `export var T: number;export function Foo() { console.log('hi'); };`, + ); verifyProjectsUpdatedInBackgroundEvent(); }); it("should be up-to-date with the reference map changes", () => { - const { host, moduleFile1, file1Consumer1, updateContentOfOpenFile, verifyProjectsUpdatedInBackgroundEvent, verifyNoProjectsUpdatedInBackgroundEvent } = getInitialState(); + const { + host, + moduleFile1, + file1Consumer1, + updateContentOfOpenFile, + verifyProjectsUpdatedInBackgroundEvent, + verifyNoProjectsUpdatedInBackgroundEvent, + } = getInitialState(); // Change file1Consumer1 content to `export let y = Foo();` updateContentOfOpenFile(file1Consumer1, "export let y = Foo();"); @@ -268,7 +307,10 @@ namespace ts.projectSystem { verifyNoProjectsUpdatedInBackgroundEvent(); // Change the content of moduleFile1 to `export var T: number;export var T2: string;export function Foo() { };` - host.writeFile(moduleFile1.path, `export var T: number;export var T2: string;export function Foo() { };`); + host.writeFile( + moduleFile1.path, + `export var T: number;export var T2: string;export function Foo() { };`, + ); verifyProjectsUpdatedInBackgroundEvent(); // Multiple file edits in one go: @@ -281,7 +323,8 @@ namespace ts.projectSystem { }); it("should be up-to-date with deleted files", () => { - const { host, moduleFile1, file1Consumer2, verifyProjectsUpdatedInBackgroundEvent } = getInitialState(); + const { host, moduleFile1, file1Consumer2, verifyProjectsUpdatedInBackgroundEvent } = + getInitialState(); // Change the content of moduleFile1 to `export var T: number;export function Foo() { };` host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); @@ -343,7 +386,14 @@ namespace ts.projectSystem { path: "/a/b/file1Consumer1Consumer1.ts", content: `import {y} from "./file1Consumer1";`, }; - const { host, moduleFile1, file1Consumer1, updateContentOfOpenFile, verifyNoProjectsUpdatedInBackgroundEvent, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ + const { + host, + moduleFile1, + file1Consumer1, + updateContentOfOpenFile, + verifyNoProjectsUpdatedInBackgroundEvent, + verifyProjectsUpdatedInBackgroundEvent, + } = getInitialState({ getAdditionalFileOrFolder: () => [file1Consumer1Consumer1], }); @@ -405,7 +455,13 @@ namespace ts.projectSystem { /// export var x = Foo();`, }; - const { host, moduleFile2, updateContentOfOpenFile, verifyNoProjectsUpdatedInBackgroundEvent, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ + const { + host, + moduleFile2, + updateContentOfOpenFile, + verifyNoProjectsUpdatedInBackgroundEvent, + verifyProjectsUpdatedInBackgroundEvent, + } = getInitialState({ getAdditionalFileOrFolder: () => [referenceFile1], firstReloadFileList: [referenceFile1.path, libFile.path, configFilePath], }); @@ -420,9 +476,13 @@ namespace ts.projectSystem { }); describe("resolution when resolution cache size", () => { - function verifyWithMaxCacheLimit(subScenario: string, useSlashRootAsSomeNotRootFolderInUserDirectory: boolean) { + function verifyWithMaxCacheLimit( + subScenario: string, + useSlashRootAsSomeNotRootFolderInUserDirectory: boolean, + ) { it(subScenario, () => { - const rootFolder = useSlashRootAsSomeNotRootFolderInUserDirectory ? "/user/username/rootfolder/otherfolder/" : "/"; + const rootFolder = useSlashRootAsSomeNotRootFolderInUserDirectory + ? "/user/username/rootfolder/otherfolder/" : "/"; const file1: File = { path: rootFolder + "a/b/project/file1.ts", content: 'import a from "file2"', @@ -442,7 +502,8 @@ namespace ts.projectSystem { const openFiles = [file1.path]; const host = createServerHost([file1, file3, libFile, configFile]); - const { session, verifyInitialOpen, verifyProjectsUpdatedInBackgroundEventHandler } = createSession(host, createLoggerWithInMemoryLogs(host)); + const { session, verifyInitialOpen, verifyProjectsUpdatedInBackgroundEventHandler } = + createSession(host, createLoggerWithInMemoryLogs(host)); verifyInitialOpen(file1); file3.content += "export class d {}"; @@ -472,16 +533,30 @@ namespace ts.projectSystem { baselineTsserverLogs("projectUpdatedInBackground", `${scenario} and ${subScenario}`, session); }); } - verifyWithMaxCacheLimit("project is not at root level", /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ true); - verifyWithMaxCacheLimit("project is at root level", /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ false); + verifyWithMaxCacheLimit( + "project is not at root level", + /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ true, + ); + verifyWithMaxCacheLimit( + "project is at root level", + /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ false, + ); }); } describe("when event handler is set in the session", () => { - verifyProjectsUpdatedInBackgroundEvent("when event handler is set in the session", createSessionWithProjectChangedEventHandler); - - function createSessionWithProjectChangedEventHandler(host: TestServerHost, logger: Logger | undefined): ProjectsUpdatedInBackgroundEventVerifier { - const { session, events: projectChangedEvents } = createSessionWithEventTracking( + verifyProjectsUpdatedInBackgroundEvent( + "when event handler is set in the session", + createSessionWithProjectChangedEventHandler, + ); + + function createSessionWithProjectChangedEventHandler( + host: TestServerHost, + logger: Logger | undefined, + ): ProjectsUpdatedInBackgroundEventVerifier { + const { session, events: projectChangedEvents } = createSessionWithEventTracking< + server.ProjectsUpdatedInBackgroundEvent + >( host, server.ProjectsUpdatedInBackgroundEvent, logger && { logger }, @@ -500,8 +575,16 @@ namespace ts.projectSystem { return "[" + map(events, eventToString).join(",") + "]"; } - function verifyProjectsUpdatedInBackgroundEventHandler(expectedEvents: readonly server.ProjectsUpdatedInBackgroundEvent[]) { - assert.equal(projectChangedEvents.length, expectedEvents.length, `Incorrect number of events Actual: ${eventsToString(projectChangedEvents)} Expected: ${eventsToString(expectedEvents)}`); + function verifyProjectsUpdatedInBackgroundEventHandler( + expectedEvents: readonly server.ProjectsUpdatedInBackgroundEvent[], + ) { + assert.equal( + projectChangedEvents.length, + expectedEvents.length, + `Incorrect number of events Actual: ${eventsToString(projectChangedEvents)} Expected: ${ + eventsToString(expectedEvents) + }`, + ); forEach(projectChangedEvents, (actualEvent, i) => { const expectedEvent = expectedEvents[i]; assert.strictEqual(actualEvent.eventName, expectedEvent.eventName); @@ -516,15 +599,27 @@ namespace ts.projectSystem { describe("when event handler is not set but session is created with canUseEvents = true", () => { describe("without noGetErrOnBackgroundUpdate, diagnostics for open files are queued", () => { - verifyProjectsUpdatedInBackgroundEvent("without noGetErrOnBackgroundUpdate", createSessionThatUsesEvents); + verifyProjectsUpdatedInBackgroundEvent( + "without noGetErrOnBackgroundUpdate", + createSessionThatUsesEvents, + ); }); describe("with noGetErrOnBackgroundUpdate, diagnostics for open file are not queued", () => { - verifyProjectsUpdatedInBackgroundEvent("with noGetErrOnBackgroundUpdate", (host, logger) => createSessionThatUsesEvents(host, logger, /*noGetErrOnBackgroundUpdate*/ true)); + verifyProjectsUpdatedInBackgroundEvent( + "with noGetErrOnBackgroundUpdate", + (host, logger) => createSessionThatUsesEvents(host, logger, /*noGetErrOnBackgroundUpdate*/ true), + ); }); - function createSessionThatUsesEvents(host: TestServerHost, logger: Logger | undefined, noGetErrOnBackgroundUpdate?: boolean): ProjectsUpdatedInBackgroundEventVerifier { - const { session, getEvents, clearEvents } = createSessionWithDefaultEventHandler( + function createSessionThatUsesEvents( + host: TestServerHost, + logger: Logger | undefined, + noGetErrOnBackgroundUpdate?: boolean, + ): ProjectsUpdatedInBackgroundEventVerifier { + const { session, getEvents, clearEvents } = createSessionWithDefaultEventHandler< + protocol.ProjectsUpdatedInBackgroundEvent + >( host, server.ProjectsUpdatedInBackgroundEvent, { noGetErrOnBackgroundUpdate, logger: logger || createHasErrorMessageLogger() }, @@ -536,14 +631,20 @@ namespace ts.projectSystem { verifyInitialOpen: createVerifyInitialOpen(session, verifyProjectsUpdatedInBackgroundEventHandler), }; - function verifyProjectsUpdatedInBackgroundEventHandler(expected: readonly server.ProjectsUpdatedInBackgroundEvent[]) { + function verifyProjectsUpdatedInBackgroundEventHandler( + expected: readonly server.ProjectsUpdatedInBackgroundEvent[], + ) { const expectedEvents: protocol.ProjectsUpdatedInBackgroundEventBody[] = map(expected, e => { return { openFiles: e.data.openFiles, }; }); const events = getEvents(); - assert.equal(events.length, expectedEvents.length, `Incorrect number of events Actual: ${map(events, e => e.body)} Expected: ${expectedEvents}`); + assert.equal( + events.length, + expectedEvents.length, + `Incorrect number of events Actual: ${map(events, e => e.body)} Expected: ${expectedEvents}`, + ); forEach(events, (actualEvent, i) => { const expectedEvent = expectedEvents[i]; verifyFiles("openFiles", actualEvent.body.openFiles, expectedEvent.openFiles); diff --git a/src/testRunner/unittests/tsserver/exportMapCache.ts b/src/testRunner/unittests/tsserver/exportMapCache.ts index 6ceb967ecd139..c0a8a5212cc06 100644 --- a/src/testRunner/unittests/tsserver/exportMapCache.ts +++ b/src/testRunner/unittests/tsserver/exportMapCache.ts @@ -122,14 +122,31 @@ namespace ts.projectSystem { }); function setup() { - const host = createServerHost([aTs, bTs, ambientDeclaration, tsconfig, packageJson, mobxPackageJson, mobxDts, exportEqualsMappedType]); + const host = createServerHost([ + aTs, + bTs, + ambientDeclaration, + tsconfig, + packageJson, + mobxPackageJson, + mobxDts, + exportEqualsMappedType, + ]); const session = createSession(host); openFilesForSession([aTs, bTs], session); const projectService = session.getProjectService(); const project = configuredProjectAt(projectService, 0); triggerCompletions(); const checker = project.getLanguageService().getProgram()!.getTypeChecker(); - return { host, project, projectService, session, exportMapCache: project.getCachedExportInfoMap(), checker, triggerCompletions }; + return { + host, + project, + projectService, + session, + exportMapCache: project.getCachedExportInfoMap(), + checker, + triggerCompletions, + }; function triggerCompletions() { const requestLocation: protocol.FileLocationRequestArgs = { @@ -137,11 +154,15 @@ namespace ts.projectSystem { line: 1, offset: 3, }; - executeSessionRequest(session, protocol.CommandTypes.CompletionInfo, { - ...requestLocation, - includeExternalModuleExports: true, - prefix: "foo", - }); + executeSessionRequest( + session, + protocol.CommandTypes.CompletionInfo, + { + ...requestLocation, + includeExternalModuleExports: true, + prefix: "foo", + }, + ); } } } diff --git a/src/testRunner/unittests/tsserver/externalProjects.ts b/src/testRunner/unittests/tsserver/externalProjects.ts index e1be9a6f34795..5681189292d77 100644 --- a/src/testRunner/unittests/tsserver/externalProjects.ts +++ b/src/testRunner/unittests/tsserver/externalProjects.ts @@ -16,7 +16,10 @@ namespace ts.projectSystem { const host = createServerHost([f1, config], { useCaseSensitiveFileNames: false }); const service = createProjectService(host); service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } }); - const upperCaseConfigFilePath = combinePaths(getDirectoryPath(config.path).toUpperCase(), getBaseFileName(config.path)); + const upperCaseConfigFilePath = combinePaths( + getDirectoryPath(config.path).toUpperCase(), + getBaseFileName(config.path), + ); service.openExternalProject({ projectFileName: "/a/b/project.csproj", rootFiles: toExternalFiles([f1.path, upperCaseConfigFilePath]), @@ -66,7 +69,13 @@ namespace ts.projectSystem { const proxy = Harness.LanguageService.makeDefaultProxy(info); proxy.getSemanticDiagnostics = filename => { const prev = info.languageService.getSemanticDiagnostics(filename); - const sourceFile: SourceFile = info.project.getSourceFile(toPath(filename, /*basePath*/ undefined, createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames)))!; + const sourceFile: SourceFile = info.project.getSourceFile( + toPath( + filename, + /*basePath*/ undefined, + createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames), + ), + )!; prev.push({ category: DiagnosticCategory.Warning, file: sourceFile, @@ -125,7 +134,11 @@ namespace ts.projectSystem { path: "/c/app.ts", content: "let x = 1", }; - const makeProject = (f: File) => ({ projectFileName: f.path + ".csproj", rootFiles: [toExternalFile(f.path)], options: {} }); + const makeProject = (f: File) => ({ + projectFileName: f.path + ".csproj", + rootFiles: [toExternalFile(f.path)], + options: {}, + }); const p1 = makeProject(f1); const p2 = makeProject(f2); const p3 = makeProject(f3); @@ -417,11 +430,19 @@ namespace ts.projectSystem { const host = createServerHost([file1, file2]); const projectService = createProjectService(host); - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path]) }); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles([file1.path]), + }); checkNumberOfProjects(projectService, { externalProjects: 1 }); checkProjectActualFiles(projectService.externalProjects[0], [file1.path]); - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, file2.path]) }); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles([file1.path, file2.path]), + }); checkNumberOfProjects(projectService, { externalProjects: 1 }); checkProjectRootFiles(projectService.externalProjects[0], [file1.path, file2.path]); }); @@ -443,12 +464,20 @@ namespace ts.projectSystem { const host = createServerHost([file1, file2, file3]); const projectService = createProjectService(host); - projectService.openExternalProject({ projectFileName: "project", options: { moduleResolution: ModuleResolutionKind.NodeJs }, rootFiles: toExternalFiles([file1.path, file2.path]) }); + projectService.openExternalProject({ + projectFileName: "project", + options: { moduleResolution: ModuleResolutionKind.NodeJs }, + rootFiles: toExternalFiles([file1.path, file2.path]), + }); checkNumberOfProjects(projectService, { externalProjects: 1 }); checkProjectRootFiles(projectService.externalProjects[0], [file1.path, file2.path]); checkProjectActualFiles(projectService.externalProjects[0], [file1.path, file2.path]); - projectService.openExternalProject({ projectFileName: "project", options: { moduleResolution: ModuleResolutionKind.Classic }, rootFiles: toExternalFiles([file1.path, file2.path]) }); + projectService.openExternalProject({ + projectFileName: "project", + options: { moduleResolution: ModuleResolutionKind.Classic }, + rootFiles: toExternalFiles([file1.path, file2.path]), + }); checkNumberOfProjects(projectService, { externalProjects: 1 }); checkProjectRootFiles(projectService.externalProjects[0], [file1.path, file2.path]); checkProjectActualFiles(projectService.externalProjects[0], [file1.path, file2.path, file3.path]); @@ -465,7 +494,9 @@ namespace ts.projectSystem { }; const host = createServerHost([f1, f2]); const originalGetFileSize = host.getFileSize; - host.getFileSize = (filePath: string) => filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath); + host.getFileSize = (filePath: string) => + filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 + : originalGetFileSize.call(host, filePath); const service = createProjectService(host); const projectFileName = "/a/proj.csproj"; @@ -476,7 +507,10 @@ namespace ts.projectSystem { options: {}, }); service.checkNumberOfProjects({ externalProjects: 1 }); - assert.isFalse(service.externalProjects[0].languageServiceEnabled, "language service should be disabled - 1"); + assert.isFalse( + service.externalProjects[0].languageServiceEnabled, + "language service should be disabled - 1", + ); service.openExternalProject({ projectFileName, @@ -492,7 +526,10 @@ namespace ts.projectSystem { options: {}, }); service.checkNumberOfProjects({ externalProjects: 1 }); - assert.isFalse(service.externalProjects[0].languageServiceEnabled, "language service should be disabled - 2"); + assert.isFalse( + service.externalProjects[0].languageServiceEnabled, + "language service should be disabled - 2", + ); }); describe("deleting config file opened from the external project works", () => { @@ -520,25 +557,37 @@ namespace ts.projectSystem { projectService.openExternalProjects([externalProject]); let knownProjects = projectService.synchronizeProjectList([]); - checkNumberOfProjects(projectService, { configuredProjects: 1, externalProjects: 0, inferredProjects: 0 }); + checkNumberOfProjects(projectService, { + configuredProjects: 1, + externalProjects: 0, + inferredProjects: 0, + }); const configProject = configuredProjectAt(projectService, 0); checkProjectActualFiles( configProject, - lazyConfiguredProjectsFromExternalProject ? - emptyArray : // Since no files opened from this project, its not loaded - [configFile.path], + lazyConfiguredProjectsFromExternalProject + ? emptyArray // Since no files opened from this project, its not loaded + : [configFile.path], ); host.deleteFile(configFile.path); knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info!)); // TODO: GH#18217 GH#20039 - checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 }); + checkNumberOfProjects(projectService, { + configuredProjects: 0, + externalProjects: 0, + inferredProjects: 0, + }); externalProject.rootFiles.length = 1; projectService.openExternalProjects([externalProject]); - checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 1, inferredProjects: 0 }); + checkNumberOfProjects(projectService, { + configuredProjects: 0, + externalProjects: 1, + inferredProjects: 0, + }); checkProjectActualFiles(projectService.externalProjects[0], [site.path, libFile.path]); } it("when lazyConfiguredProjectsFromExternalProject not set", () => { @@ -758,7 +807,9 @@ namespace ts.projectSystem { }, ), }; - const host = createServerHost([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" }); + const host = createServerHost([libES5, libES2015Promise, app, config1], { + executingFilePath: "/compiler/tsc.js", + }); const projectService = createProjectService(host); projectService.openClientFile(app.path); @@ -769,7 +820,12 @@ namespace ts.projectSystem { host.checkTimeoutQueueLengthAndRun(2); projectService.checkNumberOfProjects({ configuredProjects: 1 }); - checkProjectActualFiles(configuredProjectAt(projectService, 0), [libES5.path, libES2015Promise.path, app.path, config2.path]); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [ + libES5.path, + libES2015Promise.path, + app.path, + config2.path, + ]); }); it("should handle non-existing directories in config file", () => { @@ -876,7 +932,9 @@ namespace ts.projectSystem { rootFiles: [{ fileName: tsconfig.path }, { fileName: jsFilePath }], options: { allowJs: false }, }]); - service.applyChangesInOpenFiles(singleIterator({ fileName: jsFilePath, scriptKind: ScriptKind.JS, content: "" })); + service.applyChangesInOpenFiles( + singleIterator({ fileName: jsFilePath, scriptKind: ScriptKind.JS, content: "" }), + ); checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 }); checkProjectActualFiles(configProject, [tsconfig.path]); const inferredProject = service.inferredProjects[0]; diff --git a/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts b/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts index 633f409aed459..ac6b2d3a2f9a7 100644 --- a/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts +++ b/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts @@ -30,7 +30,9 @@ namespace ts.projectSystem { content: JSON.stringify({ extends: "./tsconfig.all.json" }), }; - const host = createServerHost([file1, file2, file2Dts, libFile, tsconfig, tsconfigAll], { useCaseSensitiveFileNames: false }); + const host = createServerHost([file1, file2, file2Dts, libFile, tsconfig, tsconfigAll], { + useCaseSensitiveFileNames: false, + }); const session = createSession(host); openFilesForSession([file1], session); @@ -38,7 +40,8 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1 }); - const diagnostics = configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); + const diagnostics = configuredProjectAt(projectService, 0).getLanguageService() + .getCompilerOptionsDiagnostics(); assert.deepEqual(diagnostics, []); }); @@ -66,7 +69,11 @@ namespace ts.projectSystem { const newLoggerPath = loggerFile.path.toLowerCase(); host.renameFile(loggerFile.path, newLoggerPath); closeFilesForSession([loggerFile], session); - openFilesForSession([{ file: newLoggerPath, content: loggerFile.content, projectRootPath: tscWatch.projectRoot }], session); + openFilesForSession([{ + file: newLoggerPath, + content: loggerFile.content, + projectRootPath: tscWatch.projectRoot, + }], session); // Apply edits for rename openFilesForSession([{ file: anotherFile, projectRootPath: tscWatch.projectRoot }], session); @@ -88,7 +95,11 @@ namespace ts.projectSystem { // Check errors in both files verifyGetErrRequest({ session, host, files: [newLoggerPath, anotherFile] }); - baselineTsserverLogs("forceConsistentCasingInFileNames", "works when renaming file with different casing", session); + baselineTsserverLogs( + "forceConsistentCasingInFileNames", + "works when renaming file with different casing", + session, + ); }); it("when changing module name with different casing", () => { @@ -130,7 +141,11 @@ namespace ts.projectSystem { // Check errors in both files verifyGetErrRequest({ host, session, files: [anotherFile] }); - baselineTsserverLogs("forceConsistentCasingInFileNames", "when changing module name with different casing", session); + baselineTsserverLogs( + "forceConsistentCasingInFileNames", + "when changing module name with different casing", + session, + ); }); }); } diff --git a/src/testRunner/unittests/tsserver/formatSettings.ts b/src/testRunner/unittests/tsserver/formatSettings.ts index b3d61a2cb7b36..4524f89d57020 100644 --- a/src/testRunner/unittests/tsserver/formatSettings.ts +++ b/src/testRunner/unittests/tsserver/formatSettings.ts @@ -12,7 +12,10 @@ namespace ts.projectSystem { const defaultSettings = projectService.getFormatCodeOptions(f1.path as server.NormalizedPath); // set global settings - const newGlobalSettings1 = { ...defaultSettings, placeOpenBraceOnNewLineForControlBlocks: !defaultSettings.placeOpenBraceOnNewLineForControlBlocks }; + const newGlobalSettings1 = { + ...defaultSettings, + placeOpenBraceOnNewLineForControlBlocks: !defaultSettings.placeOpenBraceOnNewLineForControlBlocks, + }; projectService.setHostConfiguration({ formatOptions: newGlobalSettings1 }); // get format options for file - should be equal to new global settings @@ -20,7 +23,10 @@ namespace ts.projectSystem { assert.deepEqual(s1, newGlobalSettings1, "file settings should be the same with global settings"); // set per file format options - const newPerFileSettings = { ...defaultSettings, insertSpaceAfterCommaDelimiter: !defaultSettings.insertSpaceAfterCommaDelimiter }; + const newPerFileSettings = { + ...defaultSettings, + insertSpaceAfterCommaDelimiter: !defaultSettings.insertSpaceAfterCommaDelimiter, + }; projectService.setHostConfiguration({ formatOptions: newPerFileSettings, file: f1.path }); // get format options for file - should be equal to new per-file settings @@ -28,7 +34,10 @@ namespace ts.projectSystem { assert.deepEqual(s2, newPerFileSettings, "file settings should be the same with per-file settings"); // set new global settings - they should not affect ones that were set per-file - const newGlobalSettings2 = { ...defaultSettings, insertSpaceAfterSemicolonInForStatements: !defaultSettings.insertSpaceAfterSemicolonInForStatements }; + const newGlobalSettings2 = { + ...defaultSettings, + insertSpaceAfterSemicolonInForStatements: !defaultSettings.insertSpaceAfterSemicolonInForStatements, + }; projectService.setHostConfiguration({ formatOptions: newGlobalSettings2 }); // get format options for file - should be equal to new per-file settings diff --git a/src/testRunner/unittests/tsserver/getApplicableRefactors.ts b/src/testRunner/unittests/tsserver/getApplicableRefactors.ts index 6ac7d88652462..11205fb47efe0 100644 --- a/src/testRunner/unittests/tsserver/getApplicableRefactors.ts +++ b/src/testRunner/unittests/tsserver/getApplicableRefactors.ts @@ -4,7 +4,10 @@ namespace ts.projectSystem { const aTs: File = { path: "/a.ts", content: "" }; const session = createSession(createServerHost([aTs])); openFilesForSession([aTs], session); - const response = executeSessionRequest( + const response = executeSessionRequest< + protocol.GetApplicableRefactorsRequest, + protocol.GetApplicableRefactorsResponse + >( session, protocol.CommandTypes.GetApplicableRefactors, { file: aTs.path, line: 1, offset: 1 }, diff --git a/src/testRunner/unittests/tsserver/getEditsForFileRename.ts b/src/testRunner/unittests/tsserver/getEditsForFileRename.ts index 5dcd3e96fdb1d..baa5b51e39d53 100644 --- a/src/testRunner/unittests/tsserver/getEditsForFileRename.ts +++ b/src/testRunner/unittests/tsserver/getEditsForFileRename.ts @@ -21,7 +21,12 @@ namespace ts.projectSystem { Debug.assert(!!project.resolveModuleNames); - const edits = project.getLanguageService().getEditsForFileRename("/old.ts", "/new.ts", testFormatSettings, emptyOptions); + const edits = project.getLanguageService().getEditsForFileRename( + "/old.ts", + "/new.ts", + testFormatSettings, + emptyOptions, + ); assert.deepEqual(edits, [{ fileName: "/user.ts", textChanges: [{ @@ -57,14 +62,20 @@ namespace ts.projectSystem { const session = createSession(host); openFilesForSession([aUserTs, bUserTs], session); - const response = executeSessionRequest(session, CommandNames.GetEditsForFileRename, { + const response = executeSessionRequest< + protocol.GetEditsForFileRenameRequest, + protocol.GetEditsForFileRenameResponse + >(session, CommandNames.GetEditsForFileRename, { oldFilePath: aOldTs.path, newFilePath: "/a/new.ts", }); assert.deepEqual(response, [ { fileName: aTsconfig.path, - textChanges: [{ ...protocolTextSpanFromSubstring(aTsconfig.content, "./old.ts"), newText: "new.ts" }], + textChanges: [{ + ...protocolTextSpanFromSubstring(aTsconfig.content, "./old.ts"), + newText: "new.ts", + }], }, { fileName: aUserTs.path, @@ -72,7 +83,10 @@ namespace ts.projectSystem { }, { fileName: bUserTs.path, - textChanges: [{ ...protocolTextSpanFromSubstring(bUserTs.content, "../a/old"), newText: "../a/new" }], + textChanges: [{ + ...protocolTextSpanFromSubstring(bUserTs.content, "../a/old"), + newText: "../a/new", + }], }, ]); }); @@ -86,7 +100,10 @@ namespace ts.projectSystem { const session = createSession(host); openFilesForSession([aTs, cTs], session); - const response = executeSessionRequest(session, CommandNames.GetEditsForFileRename, { + const response = executeSessionRequest< + protocol.GetEditsForFileRenameRequest, + protocol.GetEditsForFileRenameResponse + >(session, CommandNames.GetEditsForFileRename, { oldFilePath: "/b.ts", newFilePath: cTs.path, }); diff --git a/src/testRunner/unittests/tsserver/getFileReferences.ts b/src/testRunner/unittests/tsserver/getFileReferences.ts index 0048a8aad3909..776cdb6f17fb0 100644 --- a/src/testRunner/unittests/tsserver/getFileReferences.ts +++ b/src/testRunner/unittests/tsserver/getFileReferences.ts @@ -44,10 +44,34 @@ namespace ts.projectSystem { const expectResponse: protocol.FileReferencesResponseBody = { refs: [ - makeReferenceItem({ file: bTs, text: "./a", lineText: importA, contextText: importA, isWriteAccess: false }), - makeReferenceItem({ file: cTs, text: "./a", lineText: importCurlyFromA, contextText: importCurlyFromA, isWriteAccess: false }), - makeReferenceItem({ file: dTs, text: "/project/a", lineText: importAFromA, contextText: importAFromA, isWriteAccess: false }), - makeReferenceItem({ file: dTs, text: "./a", lineText: typeofImportA, contextText: typeofImportA, isWriteAccess: false }), + makeReferenceItem({ + file: bTs, + text: "./a", + lineText: importA, + contextText: importA, + isWriteAccess: false, + }), + makeReferenceItem({ + file: cTs, + text: "./a", + lineText: importCurlyFromA, + contextText: importCurlyFromA, + isWriteAccess: false, + }), + makeReferenceItem({ + file: dTs, + text: "/project/a", + lineText: importAFromA, + contextText: importAFromA, + isWriteAccess: false, + }), + makeReferenceItem({ + file: dTs, + text: "./a", + lineText: typeofImportA, + contextText: typeofImportA, + isWriteAccess: false, + }), ], symbolName: `"${aTs.path}"`, }; @@ -67,10 +91,34 @@ namespace ts.projectSystem { const expectResponse: protocol.FileReferencesResponseBody = { refs: [ - makeReferenceItem({ file: bTs, text: "./a", lineText: undefined, contextText: importA, isWriteAccess: false }), - makeReferenceItem({ file: cTs, text: "./a", lineText: undefined, contextText: importCurlyFromA, isWriteAccess: false }), - makeReferenceItem({ file: dTs, text: "/project/a", lineText: undefined, contextText: importAFromA, isWriteAccess: false }), - makeReferenceItem({ file: dTs, text: "./a", lineText: undefined, contextText: typeofImportA, isWriteAccess: false }), + makeReferenceItem({ + file: bTs, + text: "./a", + lineText: undefined, + contextText: importA, + isWriteAccess: false, + }), + makeReferenceItem({ + file: cTs, + text: "./a", + lineText: undefined, + contextText: importCurlyFromA, + isWriteAccess: false, + }), + makeReferenceItem({ + file: dTs, + text: "/project/a", + lineText: undefined, + contextText: importAFromA, + isWriteAccess: false, + }), + makeReferenceItem({ + file: dTs, + text: "./a", + lineText: undefined, + contextText: typeofImportA, + isWriteAccess: false, + }), ], symbolName: `"${aTs.path}"`, }; diff --git a/src/testRunner/unittests/tsserver/helpers.ts b/src/testRunner/unittests/tsserver/helpers.ts index bd01933034844..29637b829d229 100644 --- a/src/testRunner/unittests/tsserver/helpers.ts +++ b/src/testRunner/unittests/tsserver/helpers.ts @@ -107,7 +107,9 @@ namespace ts.projectSystem { function nowString() { // E.g. "12:34:56.789" const d = logger.host!.now(); - return `${padLeft(d.getUTCHours().toString(), 2, "0")}:${padLeft(d.getUTCMinutes().toString(), 2, "0")}:${padLeft(d.getUTCSeconds().toString(), 2, "0")}.${padLeft(d.getUTCMilliseconds().toString(), 3, "0")}`; + return `${padLeft(d.getUTCHours().toString(), 2, "0")}:${padLeft(d.getUTCMinutes().toString(), 2, "0")}:${ + padLeft(d.getUTCSeconds().toString(), 2, "0") + }.${padLeft(d.getUTCMilliseconds().toString(), 3, "0")}`; } } @@ -132,26 +134,56 @@ namespace ts.projectSystem { logger.logs.push( s.replace(/Elapsed::?\s*\d+(?:\.\d+)?ms/g, "Elapsed:: *ms") .replace(/\"updateGraphDurationMs\"\:\d+(?:\.\d+)?/g, `"updateGraphDurationMs":*`) - .replace(/\"createAutoImportProviderProgramDurationMs\"\:\d+(?:\.\d+)?/g, `"createAutoImportProviderProgramDurationMs":*`) + .replace( + /\"createAutoImportProviderProgramDurationMs\"\:\d+(?:\.\d+)?/g, + `"createAutoImportProviderProgramDurationMs":*`, + ) .replace(`"version":"${version}"`, `"version":"FakeVersion"`) - .replace(/getCompletionData: Get current token: \d+(?:\.\d+)?/g, `getCompletionData: Get current token: *`) - .replace(/getCompletionData: Is inside comment: \d+(?:\.\d+)?/g, `getCompletionData: Is inside comment: *`) - .replace(/getCompletionData: Get previous token: \d+(?:\.\d+)?/g, `getCompletionData: Get previous token: *`) - .replace(/getCompletionsAtPosition: isCompletionListBlocker: \d+(?:\.\d+)?/g, `getCompletionsAtPosition: isCompletionListBlocker: *`) - .replace(/getCompletionData: Semantic work: \d+(?:\.\d+)?/g, `getCompletionData: Semantic work: *`) - .replace(/getCompletionsAtPosition: getCompletionEntriesFromSymbols: \d+(?:\.\d+)?/g, `getCompletionsAtPosition: getCompletionEntriesFromSymbols: *`) - .replace(/forEachExternalModuleToImportFrom autoImportProvider: \d+(?:\.\d+)?/g, `forEachExternalModuleToImportFrom autoImportProvider: *`) + .replace( + /getCompletionData: Get current token: \d+(?:\.\d+)?/g, + `getCompletionData: Get current token: *`, + ) + .replace( + /getCompletionData: Is inside comment: \d+(?:\.\d+)?/g, + `getCompletionData: Is inside comment: *`, + ) + .replace( + /getCompletionData: Get previous token: \d+(?:\.\d+)?/g, + `getCompletionData: Get previous token: *`, + ) + .replace( + /getCompletionsAtPosition: isCompletionListBlocker: \d+(?:\.\d+)?/g, + `getCompletionsAtPosition: isCompletionListBlocker: *`, + ) + .replace( + /getCompletionData: Semantic work: \d+(?:\.\d+)?/g, + `getCompletionData: Semantic work: *`, + ) + .replace( + /getCompletionsAtPosition: getCompletionEntriesFromSymbols: \d+(?:\.\d+)?/g, + `getCompletionsAtPosition: getCompletionEntriesFromSymbols: *`, + ) + .replace( + /forEachExternalModuleToImportFrom autoImportProvider: \d+(?:\.\d+)?/g, + `forEachExternalModuleToImportFrom autoImportProvider: *`, + ) .replace(/getExportInfoMap: done in \d+(?:\.\d+)?/g, `getExportInfoMap: done in *`) .replace(/collectAutoImports: \d+(?:\.\d+)?/g, `collectAutoImports: *`) .replace(/dependencies in \d+(?:\.\d+)?/g, `dependencies in *`) - .replace(/\"exportMapKey\"\:\s*\"[_$a-zA-Z][_$_$a-zA-Z0-9]*\|\d+\|/g, match => match.replace(/\|\d+\|/, `|*|`)), + .replace( + /\"exportMapKey\"\:\s*\"[_$a-zA-Z][_$_$a-zA-Z0-9]*\|\d+\|/g, + match => match.replace(/\|\d+\|/, `|*|`), + ), ), }, host); } export function baselineTsserverLogs(scenario: string, subScenario: string, sessionOrService: { logger: Logger; }) { Debug.assert(sessionOrService.logger.logs.length); // Ensure caller used in memory logger - Harness.Baseline.runBaseline(`tsserver/${scenario}/${subScenario.split(" ").join("-")}.js`, sessionOrService.logger.logs.join("\r\n")); + Harness.Baseline.runBaseline( + `tsserver/${scenario}/${subScenario.split(" ").join("-")}.js`, + sessionOrService.logger.logs.join("\r\n"), + ); } export function appendAllScriptInfos(service: server.ProjectService, logs: string[]) { @@ -181,7 +213,14 @@ namespace ts.projectSystem { readonly typesRegistry = new Map>(), log?: TI.Log, ) { - super(installTypingHost, globalTypingsCacheLocation, "/safeList.json" as Path, customTypesMap.path, throttleLimit, log); + super( + installTypingHost, + globalTypingsCacheLocation, + "/safeList.json" as Path, + customTypesMap.path, + throttleLimit, + log, + ); } protected postExecActions: PostExecAction[] = []; @@ -220,8 +259,17 @@ namespace ts.projectSystem { this.projectService.updateTypingsForProject(response); } - enqueueInstallTypingsRequest(project: server.Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray) { - const request = server.createInstallTypingsRequest(project, typeAcquisition, unresolvedImports, this.globalTypingsCacheLocation); + enqueueInstallTypingsRequest( + project: server.Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + ) { + const request = server.createInstallTypingsRequest( + project, + typeAcquisition, + unresolvedImports, + this.globalTypingsCacheLocation, + ); this.install(request); } @@ -271,7 +319,21 @@ namespace ts.projectSystem { } export function fileStats(nonZeroStats: Partial): server.FileStats { - return { ts: 0, tsSize: 0, tsx: 0, tsxSize: 0, dts: 0, dtsSize: 0, js: 0, jsSize: 0, jsx: 0, jsxSize: 0, deferred: 0, deferredSize: 0, ...nonZeroStats }; + return { + ts: 0, + tsSize: 0, + tsx: 0, + tsxSize: 0, + dts: 0, + dtsSize: 0, + js: 0, + jsSize: 0, + jsx: 0, + jsxSize: 0, + deferred: 0, + deferredSize: 0, + ...nonZeroStats, + }; } export class TestServerEventManager { @@ -314,31 +376,40 @@ namespace ts.projectSystem { this.events.forEach(event => assert.notEqual(event.eventName, eventName)); } - assertProjectInfoTelemetryEvent(partial: Partial, configFile = "/tsconfig.json"): void { - assert.deepEqual(this.getEvent(server.ProjectInfoTelemetryEvent), { - projectId: sys.createSHA256Hash!(configFile), - fileStats: fileStats({ ts: 1 }), - compilerOptions: {}, - extends: false, - files: false, - include: false, - exclude: false, - compileOnSave: false, - typeAcquisition: { - enable: false, - exclude: false, + assertProjectInfoTelemetryEvent( + partial: Partial, + configFile = "/tsconfig.json", + ): void { + assert.deepEqual( + this.getEvent(server.ProjectInfoTelemetryEvent), + { + projectId: sys.createSHA256Hash!(configFile), + fileStats: fileStats({ ts: 1 }), + compilerOptions: {}, + extends: false, + files: false, include: false, + exclude: false, + compileOnSave: false, + typeAcquisition: { + enable: false, + exclude: false, + include: false, + }, + configFileName: "tsconfig.json", + projectType: "configured", + languageServiceEnabled: true, + version: ts.version, // eslint-disable-line @typescript-eslint/no-unnecessary-qualifier + ...partial, }, - configFileName: "tsconfig.json", - projectType: "configured", - languageServiceEnabled: true, - version: ts.version, // eslint-disable-line @typescript-eslint/no-unnecessary-qualifier - ...partial, - }); + ); } assertOpenFileTelemetryEvent(info: server.OpenFileInfo): void { - assert.deepEqual(this.getEvent(server.OpenFileInfoTelemetryEvent), { info }); + assert.deepEqual( + this.getEvent(server.OpenFileInfoTelemetryEvent), + { info }, + ); } assertNoOpenFilesTelemetryEvent(): void { this.hasZeroEvent(server.OpenFileInfoTelemetryEvent); @@ -384,9 +455,17 @@ namespace ts.projectSystem { } function runQueuedImmediateCallbacks(checkCount?: number) { - host.baselineHost(`Before running immediate callbacks${checkCount === undefined ? "" : ` and checking length (${checkCount})`}`); + host.baselineHost( + `Before running immediate callbacks${ + checkCount === undefined ? "" : ` and checking length (${checkCount})` + }`, + ); originalRunQueuedImmediateCallbacks.call(host, checkCount); - host.baselineHost(`Before running immediate callbacks${checkCount === undefined ? "" : ` and checking length (${checkCount})`}`); + host.baselineHost( + `Before running immediate callbacks${ + checkCount === undefined ? "" : ` and checking length (${checkCount})` + }`, + ); } function baselineHost(title: string) { @@ -451,11 +530,18 @@ namespace ts.projectSystem { this.testhost.clearOutput(); } - private baseline(type: "request" | "response", requestOrResult: T): T { + private baseline( + type: "request" | "response", + requestOrResult: T, + ): T { if (!this.logger.hasLevel(server.LogLevel.verbose)) return requestOrResult; - if (type === "request") this.logger.info(`request:${server.indent(JSON.stringify(requestOrResult, undefined, 2))}`); + if (type === "request") { + this.logger.info(`request:${server.indent(JSON.stringify(requestOrResult, undefined, 2))}`); + } this.testhost.baselineHost(type === "request" ? "Before request" : "After request"); - if (type === "response") this.logger.info(`response:${server.indent(JSON.stringify(requestOrResult, undefined, 2))}`); + if (type === "response") { + this.logger.info(`response:${server.indent(JSON.stringify(requestOrResult, undefined, 2))}`); + } return requestOrResult; } } @@ -484,11 +570,18 @@ namespace ts.projectSystem { return new TestSession({ ...sessionOptions, ...opts }); } - export function createSessionWithEventTracking(host: server.ServerHost, eventNames: T["eventName"] | T["eventName"][], opts: Partial = {}) { + export function createSessionWithEventTracking( + host: server.ServerHost, + eventNames: T["eventName"] | T["eventName"][], + opts: Partial = {}, + ) { const events: T[] = []; const session = createSession(host, { eventHandler: e => { - if (isArray(eventNames) ? eventNames.some(eventName => e.eventName === eventName) : eventNames === e.eventName) { + if ( + isArray(eventNames) ? eventNames.some(eventName => e.eventName === eventName) + : eventNames === e.eventName + ) { events.push(e as T); } }, @@ -498,7 +591,11 @@ namespace ts.projectSystem { return { session, events }; } - export function createSessionWithDefaultEventHandler(host: TestServerHost, eventNames: T["event"] | T["event"][], opts: Partial = {}) { + export function createSessionWithDefaultEventHandler( + host: TestServerHost, + eventNames: T["event"] | T["event"][], + opts: Partial = {}, + ) { const session = createSession(host, { canUseEvents: true, ...opts }); return { @@ -510,7 +607,8 @@ namespace ts.projectSystem { function getEvents() { return mapDefined(host.getOutput(), s => { const e = mapOutputToJson(s); - return (isArray(eventNames) ? eventNames.some(eventName => e.event === eventName) : e.event === eventNames) ? e as T : undefined; + return (isArray(eventNames) ? eventNames.some(eventName => e.event === eventName) + : e.event === eventNames) ? e as T : undefined; }); } @@ -525,7 +623,14 @@ namespace ts.projectSystem { export class TestProjectService extends server.ProjectService { public testhost: TestSessionAndServiceHost; - constructor(host: TestServerHost, public logger: Logger, cancellationToken: HostCancellationToken, useSingleInferredProject: boolean, typingsInstaller: server.ITypingsInstaller, opts: Partial = {}) { + constructor( + host: TestServerHost, + public logger: Logger, + cancellationToken: HostCancellationToken, + useSingleInferredProject: boolean, + typingsInstaller: server.ITypingsInstaller, + opts: Partial = {}, + ) { super({ host, logger, @@ -544,7 +649,9 @@ namespace ts.projectSystem { this.testhost.baselineHost("Creating project service"); } - checkNumberOfProjects(count: { inferredProjects?: number; configuredProjects?: number; externalProjects?: number; }) { + checkNumberOfProjects( + count: { inferredProjects?: number; configuredProjects?: number; externalProjects?: number; }, + ) { checkNumberOfProjects(this, count); } } @@ -552,8 +659,16 @@ namespace ts.projectSystem { export function createProjectService(host: TestServerHost, options?: Partial) { const cancellationToken = options?.cancellationToken || server.nullCancellationToken; const logger = options?.logger || createHasErrorMessageLogger(); - const useSingleInferredProject = options?.useSingleInferredProject !== undefined ? options.useSingleInferredProject : false; - return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, options?.typingsInstaller || server.nullTypingsInstaller, options); + const useSingleInferredProject = options?.useSingleInferredProject !== undefined + ? options.useSingleInferredProject : false; + return new TestProjectService( + host, + logger, + cancellationToken, + useSingleInferredProject, + options?.typingsInstaller || server.nullTypingsInstaller, + options, + ); } export function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) { @@ -568,7 +683,10 @@ namespace ts.projectSystem { assert.equal(projectService.inferredProjects.length, expected, `expected ${expected} inferred project(s)`); } - export function checkNumberOfProjects(projectService: server.ProjectService, count: { inferredProjects?: number; configuredProjects?: number; externalProjects?: number; }) { + export function checkNumberOfProjects( + projectService: server.ProjectService, + count: { inferredProjects?: number; configuredProjects?: number; externalProjects?: number; }, + ) { checkNumberOfConfiguredProjects(projectService, count.configuredProjects || 0); checkNumberOfExternalProjects(projectService, count.externalProjects || 0); checkNumberOfInferredProjects(projectService, count.inferredProjects || 0); @@ -587,11 +705,19 @@ namespace ts.projectSystem { } export function checkProjectActualFiles(project: server.Project, expectedFiles: readonly string[]) { - checkArray(`${server.ProjectKind[project.projectKind]} project: ${project.getProjectName()}:: actual files`, project.getFileNames(), expectedFiles); + checkArray( + `${server.ProjectKind[project.projectKind]} project: ${project.getProjectName()}:: actual files`, + project.getFileNames(), + expectedFiles, + ); } export function checkProjectRootFiles(project: server.Project, expectedFiles: readonly string[]) { - checkArray(`${server.ProjectKind[project.projectKind]} project: ${project.getProjectName()}::, rootFileNames`, project.getRootFiles(), expectedFiles); + checkArray( + `${server.ProjectKind[project.projectKind]} project: ${project.getProjectName()}::, rootFileNames`, + project.getRootFiles(), + expectedFiles, + ); } export function mapCombinedPathsInAncestor(dir: string, path2: string, mapAncestor: (ancestor: string) => boolean) { @@ -626,7 +752,11 @@ namespace ts.projectSystem { ]; } - export function protocolLocationFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): protocol.Location { + export function protocolLocationFromSubstring( + str: string, + substring: string, + options?: SpanFromSubstringOptions, + ): protocol.Location { const start = nthIndexOf(str, substring, options ? options.index : 0); Debug.assert(start !== -1); return protocolToLocation(str)(start); @@ -640,7 +770,11 @@ namespace ts.projectSystem { }; } - export function protocolTextSpanFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): protocol.TextSpan { + export function protocolTextSpanFromSubstring( + str: string, + substring: string, + options?: SpanFromSubstringOptions, + ): protocol.TextSpan { const span = textSpanFromSubstring(str, substring, options); const toLocation = protocolToLocation(str); return { start: toLocation(span.start), end: toLocation(textSpanEnd(span)) }; @@ -653,7 +787,9 @@ namespace ts.projectSystem { contextText?: string; contextOptions?: SpanFromSubstringOptions; } - export function protocolFileSpanFromSubstring({ file, text, options }: DocumentSpanFromSubstring): protocol.FileSpan { + export function protocolFileSpanFromSubstring( + { file, text, options }: DocumentSpanFromSubstring, + ): protocol.FileSpan { return { file: file.path, ...protocolTextSpanFromSubstring(file.content, text, options) }; } @@ -664,18 +800,20 @@ namespace ts.projectSystem { contextText?: string; contextOptions?: SpanFromSubstringOptions; } - export function protocolFileSpanWithContextFromSubstring({ contextText, contextOptions, ...rest }: FileSpanWithContextFromSubString): protocol.FileSpanWithContext { + export function protocolFileSpanWithContextFromSubstring( + { contextText, contextOptions, ...rest }: FileSpanWithContextFromSubString, + ): protocol.FileSpanWithContext { const result = protocolFileSpanFromSubstring(rest); - const contextSpan = contextText !== undefined ? - protocolFileSpanFromSubstring({ file: rest.file, text: contextText, options: contextOptions }) : - undefined; - return contextSpan ? - { + const contextSpan = contextText !== undefined + ? protocolFileSpanFromSubstring({ file: rest.file, text: contextText, options: contextOptions }) + : undefined; + return contextSpan + ? { ...result, contextStart: contextSpan.start, contextEnd: contextSpan.end, - } : - result; + } + : result; } export interface ProtocolTextSpanWithContextFromString { @@ -685,10 +823,13 @@ namespace ts.projectSystem { contextText?: string; contextOptions?: SpanFromSubstringOptions; } - export function protocolTextSpanWithContextFromSubstring({ fileText, text, options, contextText, contextOptions }: ProtocolTextSpanWithContextFromString): protocol.TextSpanWithContext { + export function protocolTextSpanWithContextFromSubstring( + { fileText, text, options, contextText, contextOptions }: ProtocolTextSpanWithContextFromString, + ): protocol.TextSpanWithContext { const span = textSpanFromSubstring(fileText, text, options); const toLocation = protocolToLocation(fileText); - const contextSpan = contextText !== undefined ? textSpanFromSubstring(fileText, contextText, contextOptions) : undefined; + const contextSpan = contextText !== undefined ? textSpanFromSubstring(fileText, contextText, contextOptions) + : undefined; return { start: toLocation(span.start), end: toLocation(textSpanEnd(span)), @@ -705,20 +846,30 @@ namespace ts.projectSystem { readonly suffixText?: string; }; } - export function protocolRenameSpanFromSubstring({ prefixSuffixText, ...rest }: ProtocolRenameSpanFromSubstring): protocol.RenameTextSpan { + export function protocolRenameSpanFromSubstring( + { prefixSuffixText, ...rest }: ProtocolRenameSpanFromSubstring, + ): protocol.RenameTextSpan { return { ...protocolTextSpanWithContextFromSubstring(rest), ...prefixSuffixText, }; } - export function textSpanFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): TextSpan { + export function textSpanFromSubstring( + str: string, + substring: string, + options?: SpanFromSubstringOptions, + ): TextSpan { const start = nthIndexOf(str, substring, options ? options.index : 0); Debug.assert(start !== -1); return createTextSpan(start, substring.length); } - export function protocolFileLocationFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): protocol.FileLocationRequestArgs { + export function protocolFileLocationFromSubstring( + file: File, + substring: string, + options?: SpanFromSubstringOptions, + ): protocol.FileLocationRequestArgs { return { file: file.path, ...protocolLocationFromSubstring(file.content, substring, options) }; } @@ -768,7 +919,8 @@ namespace ts.projectSystem { // If the request id is the request to cancel and isCancellationRequestedCount // has been met then cancel the request. Ex: cancel the request if it is a // nav bar request & isCancellationRequested() has already been called three times. - return this.requestToCancel === this.currentId && this.isCancellationRequestedCount >= this.cancelAfterRequest; + return this.requestToCancel === this.currentId + && this.isCancellationRequestedCount >= this.cancelAfterRequest; } resetToken() { @@ -787,23 +939,46 @@ namespace ts.projectSystem { }; } - export function executeSessionRequest(session: server.Session, command: TRequest["command"], args: TRequest["arguments"]): TResponse["body"] { + export function executeSessionRequest( + session: server.Session, + command: TRequest["command"], + args: TRequest["arguments"], + ): TResponse["body"] { return session.executeCommand(makeSessionRequest(command, args)).response as TResponse["body"]; } - export function executeSessionRequestNoResponse(session: server.Session, command: TRequest["command"], args: TRequest["arguments"]): void { + export function executeSessionRequestNoResponse( + session: server.Session, + command: TRequest["command"], + args: TRequest["arguments"], + ): void { session.executeCommand(makeSessionRequest(command, args)); } - export function openFilesForSession(files: readonly (File | { readonly file: File | string; readonly projectRootPath: string; content?: string; })[], session: server.Session): void { + export function openFilesForSession( + files: + readonly (File | { readonly file: File | string; readonly projectRootPath: string; content?: string; })[], + session: server.Session, + ): void { for (const file of files) { - session.executeCommand(makeSessionRequest(CommandNames.Open, "projectRootPath" in file ? { file: typeof file.file === "string" ? file.file : file.file.path, projectRootPath: file.projectRootPath } : { file: file.path })); // eslint-disable-line local/no-in-operator + session.executeCommand( + makeSessionRequest( + CommandNames.Open, + "projectRootPath" in file + ? { + file: typeof file.file === "string" ? file.file : file.file.path, + projectRootPath: file.projectRootPath, + } : { file: file.path }, + ), + ); // eslint-disable-line local/no-in-operator } } export function closeFilesForSession(files: readonly File[], session: server.Session): void { for (const file of files) { - session.executeCommand(makeSessionRequest(CommandNames.Close, { file: file.path })); + session.executeCommand( + makeSessionRequest(CommandNames.Close, { file: file.path }), + ); } } @@ -813,7 +988,9 @@ namespace ts.projectSystem { lineText?: string; } - export function makeReferenceItem({ isDefinition, isWriteAccess, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem { + export function makeReferenceItem( + { isDefinition, isWriteAccess, lineText, ...rest }: MakeReferenceItem, + ): protocol.ReferencesResponseItem { return { ...protocolFileSpanWithContextFromSubstring(rest), isDefinition, @@ -867,7 +1044,9 @@ namespace ts.projectSystem { return isString(file) ? file : file.path; } - function verifyErrorsUsingGeterr({ scenario, subScenario, allFiles, openFiles, getErrRequest }: VerifyGetErrScenario) { + function verifyErrorsUsingGeterr( + { scenario, subScenario, allFiles, openFiles, getErrRequest }: VerifyGetErrScenario, + ) { it("verifies the errors in open file", () => { const host = createServerHost([...allFiles(), libFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -878,7 +1057,9 @@ namespace ts.projectSystem { }); } - function verifyErrorsUsingGeterrForProject({ scenario, subScenario, allFiles, openFiles, getErrForProjectRequest }: VerifyGetErrScenario) { + function verifyErrorsUsingGeterrForProject( + { scenario, subScenario, allFiles, openFiles, getErrForProjectRequest }: VerifyGetErrScenario, + ) { it("verifies the errors in projects", () => { const host = createServerHost([...allFiles(), libFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -895,7 +1076,9 @@ namespace ts.projectSystem { }); } - function verifyErrorsUsingSyncMethods({ scenario, subScenario, allFiles, openFiles, syncDiagnostics }: VerifyGetErrScenario) { + function verifyErrorsUsingSyncMethods( + { scenario, subScenario, allFiles, openFiles, syncDiagnostics }: VerifyGetErrScenario, + ) { it("verifies the errors using sync commands", () => { const host = createServerHost([...allFiles(), libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); diff --git a/src/testRunner/unittests/tsserver/importHelpers.ts b/src/testRunner/unittests/tsserver/importHelpers.ts index 93363ff4ee8c1..a1d57869f55ad 100644 --- a/src/testRunner/unittests/tsserver/importHelpers.ts +++ b/src/testRunner/unittests/tsserver/importHelpers.ts @@ -11,7 +11,11 @@ namespace ts.projectSystem { }; const host = createServerHost([f1, tslib]); const service = createProjectService(host); - service.openExternalProject({ projectFileName: "p", rootFiles: [toExternalFile(f1.path)], options: { importHelpers: true } }); + service.openExternalProject({ + projectFileName: "p", + rootFiles: [toExternalFile(f1.path)], + options: { importHelpers: true }, + }); service.checkNumberOfProjects({ externalProjects: 1 }); }); }); diff --git a/src/testRunner/unittests/tsserver/inferredProjects.ts b/src/testRunner/unittests/tsserver/inferredProjects.ts index 218350d321048..9aa45e038de04 100644 --- a/src/testRunner/unittests/tsserver/inferredProjects.ts +++ b/src/testRunner/unittests/tsserver/inferredProjects.ts @@ -51,7 +51,12 @@ namespace ts.projectSystem { checkNumberOfConfiguredProjects(projectService, 0); checkNumberOfInferredProjects(projectService, 1); - checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path, libFile.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [ + file1.path, + file2.path, + file3.path, + libFile.path, + ]); host.writeFile(configFile.path, configFile.content); host.checkTimeoutQueueLengthAndRun(2); // load configured project from disk + ensureProjectsForOpenFiles @@ -226,7 +231,11 @@ namespace ts.projectSystem { assert.equal(projectService.inferredProjects[2].getCompilationSettings().target, ScriptTarget.ES2015); }); - function checkInferredProject(inferredProject: server.InferredProject, actualFiles: File[], target: ScriptTarget) { + function checkInferredProject( + inferredProject: server.InferredProject, + actualFiles: File[], + target: ScriptTarget, + ) { checkProjectActualFiles(inferredProject, actualFiles.map(f => f.path)); assert.equal(inferredProject.getCompilationSettings().target, target); } @@ -239,7 +248,10 @@ namespace ts.projectSystem { { path: "/c/file3.ts", content: "let z = 4;" }, ]; const host = createServerHost(files, { useCaseSensitiveFileNames }); - const projectService = createProjectService(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + useInferredProjectPerProjectRoot: true, + }); projectService.setCompilerOptionsForInferredProjects({ allowJs: true, target: ScriptTarget.ESNext, @@ -306,7 +318,9 @@ namespace ts.projectSystem { } closeClientFiles(); - function openClientFiles(projectRoots: [string | undefined, string | undefined, string | undefined, string | undefined]) { + function openClientFiles( + projectRoots: [string | undefined, string | undefined, string | undefined, string | undefined], + ) { files.forEach((file, index) => { projectService.openClientFile(file.path, file.content, ScriptKind.JS, projectRoots[index]); }); @@ -437,7 +451,11 @@ namespace ts.projectSystem { include: [], exclude: [], }; - assert.deepEqual(inferredProject.getTypeAcquisition(), expected, "typeAcquisition should be inferred for inferred projects"); + assert.deepEqual( + inferredProject.getTypeAcquisition(), + expected, + "typeAcquisition should be inferred for inferred projects", + ); }); it("Setting compiler options for inferred projects when there are no open files should not schedule any refresh", () => { diff --git a/src/testRunner/unittests/tsserver/inlayHints.ts b/src/testRunner/unittests/tsserver/inlayHints.ts index c5b7471fe557b..fb28f69370f17 100644 --- a/src/testRunner/unittests/tsserver/inlayHints.ts +++ b/src/testRunner/unittests/tsserver/inlayHints.ts @@ -28,14 +28,20 @@ namespace ts.projectSystem { session.executeCommandSeq({ command: protocol.CommandTypes.UpdateOpen, arguments: { - changedFiles: [{ fileName: app.path, textChanges: [{ start: { line: 1, offset: 39 }, end: { line: 1, offset: 39 }, newText: "//" }] }], + changedFiles: [{ + fileName: app.path, + textChanges: [{ start: { line: 1, offset: 39 }, end: { line: 1, offset: 39 }, newText: "//" }], + }], }, }); verifyInlayHintResponse(session); session.executeCommandSeq({ command: protocol.CommandTypes.UpdateOpen, arguments: { - changedFiles: [{ fileName: app.path, textChanges: [{ start: { line: 1, offset: 41 }, end: { line: 1, offset: 41 }, newText: "c" }] }], + changedFiles: [{ + fileName: app.path, + textChanges: [{ start: { line: 1, offset: 41 }, end: { line: 1, offset: 41 }, newText: "c" }], + }], }, }); verifyInlayHintResponse(session); diff --git a/src/testRunner/unittests/tsserver/languageService.ts b/src/testRunner/unittests/tsserver/languageService.ts index 2aeaad6f8f16c..58a814d4a5853 100644 --- a/src/testRunner/unittests/tsserver/languageService.ts +++ b/src/testRunner/unittests/tsserver/languageService.ts @@ -9,7 +9,10 @@ namespace ts.projectSystem { path: "/a/b/app.ts", content: "let x = 1;", }; - const host = createServerHost([lib, f], { executingFilePath: "/a/Lib/tsc.js", useCaseSensitiveFileNames: true }); + const host = createServerHost([lib, f], { + executingFilePath: "/a/Lib/tsc.js", + useCaseSensitiveFileNames: true, + }); const projectService = createProjectService(host); projectService.openClientFile(f.path); projectService.checkNumberOfProjects({ inferredProjects: 1 }); @@ -26,7 +29,8 @@ namespace ts.projectSystem { }, { path: `/project/a/tsconfig.json`, - content: `{ "compilerOptions": { "paths": { "foo": ["./foo.d.ts"] } }, "files": ["./index.ts", "./foo.d.ts"] }`, + content: + `{ "compilerOptions": { "paths": { "foo": ["./foo.d.ts"] } }, "files": ["./index.ts", "./foo.d.ts"] }`, }, { path: `/project/a/foo.d.ts`, @@ -40,7 +44,8 @@ namespace ts.projectSystem { }, { path: `/project/b/tsconfig.json`, - content: `{ "compilerOptions": { "paths": { "foo": ["./foo.d.ts"] } }, "files": ["./index.ts", "./foo.d.ts"] }`, + content: + `{ "compilerOptions": { "paths": { "foo": ["./foo.d.ts"] } }, "files": ["./index.ts", "./foo.d.ts"] }`, }, { path: `/project/b/foo.d.ts`, @@ -54,14 +59,19 @@ namespace ts.projectSystem { }, ]; - const host = createServerHost(files, { executingFilePath: "/project/tsc.js", useCaseSensitiveFileNames: true }); + const host = createServerHost(files, { + executingFilePath: "/project/tsc.js", + useCaseSensitiveFileNames: true, + }); const projectService = createProjectService(host); projectService.openClientFile(files[3].path); projectService.openClientFile(files[6].path); projectService.checkNumberOfProjects({ configuredProjects: 2 }); - const proj1Diags = projectService.configuredProjects.get(files[1].path)!.getLanguageService().getProgram()!.getSemanticDiagnostics(); + const proj1Diags = projectService.configuredProjects.get(files[1].path)!.getLanguageService().getProgram()! + .getSemanticDiagnostics(); Debug.assertEqual(proj1Diags.length, 0); - const proj2Diags = projectService.configuredProjects.get(files[4].path)!.getLanguageService().getProgram()!.getSemanticDiagnostics(); + const proj2Diags = projectService.configuredProjects.get(files[4].path)!.getLanguageService().getProgram()! + .getSemanticDiagnostics(); Debug.assertEqual(proj2Diags.length, 1); }); }); diff --git a/src/testRunner/unittests/tsserver/metadataInResponse.ts b/src/testRunner/unittests/tsserver/metadataInResponse.ts index 8ffeff9c011e1..2f8a6c0c9e640 100644 --- a/src/testRunner/unittests/tsserver/metadataInResponse.ts +++ b/src/testRunner/unittests/tsserver/metadataInResponse.ts @@ -7,15 +7,35 @@ namespace ts.projectSystem { host.clearOutput(); } - function verifyCommandWithMetadata(session: TestSession, host: TestServerHost, command: Partial, expectedResponseBody: U) { + function verifyCommandWithMetadata( + session: TestSession, + host: TestServerHost, + command: Partial, + expectedResponseBody: U, + ) { command.seq = session.getSeq(); command.type = "request"; session.onMessage(JSON.stringify(command)); verifyOutput( host, - expectedResponseBody ? - { seq: 0, type: "response", command: command.command!, request_seq: command.seq, success: true, body: expectedResponseBody, metadata } : - { seq: 0, type: "response", command: command.command!, request_seq: command.seq, success: false, message: "No content available." }, + expectedResponseBody + ? { + seq: 0, + type: "response", + command: command.command!, + request_seq: command.seq, + success: true, + body: expectedResponseBody, + metadata, + } + : { + seq: 0, + type: "response", + command: command.command!, + request_seq: command.seq, + success: false, + message: "No content available.", + }, ); } @@ -35,7 +55,11 @@ namespace ts.projectSystem { create(info: server.PluginCreateInfo) { const proxy = Harness.LanguageService.makeDefaultProxy(info); proxy.getCompletionsAtPosition = (filename, position, options) => { - const result = info.languageService.getCompletionsAtPosition(filename, position, options); + const result = info.languageService.getCompletionsAtPosition( + filename, + position, + options, + ); if (result) { result.metadata = metadata; } @@ -57,18 +81,33 @@ namespace ts.projectSystem { offset: aTs.content.indexOf("this.") + 1 + "this.".length, }; const expectedCompletionEntries: readonly protocol.CompletionEntry[] = [ - { name: "foo", kind: ScriptElementKind.memberFunctionElement, kindModifiers: "", sortText: Completions.SortText.LocationPriority }, - { name: "prop", kind: ScriptElementKind.memberVariableElement, kindModifiers: "", sortText: Completions.SortText.LocationPriority }, + { + name: "foo", + kind: ScriptElementKind.memberFunctionElement, + kindModifiers: "", + sortText: Completions.SortText.LocationPriority, + }, + { + name: "prop", + kind: ScriptElementKind.memberVariableElement, + kindModifiers: "", + sortText: Completions.SortText.LocationPriority, + }, ]; it("can pass through metadata when the command returns array", () => { const host = createHostWithPlugin([aTs, tsconfig]); const session = createSession(host); openFilesForSession([aTs], session); - verifyCommandWithMetadata(session, host, { - command: protocol.CommandTypes.Completions, - arguments: completionRequestArgs, - }, expectedCompletionEntries); + verifyCommandWithMetadata( + session, + host, + { + command: protocol.CommandTypes.Completions, + arguments: completionRequestArgs, + }, + expectedCompletionEntries, + ); }); it("can pass through metadata when the command returns object", () => { diff --git a/src/testRunner/unittests/tsserver/moduleResolution.ts b/src/testRunner/unittests/tsserver/moduleResolution.ts index c1c113e71340b..dcbc8654e339b 100644 --- a/src/testRunner/unittests/tsserver/moduleResolution.ts +++ b/src/testRunner/unittests/tsserver/moduleResolution.ts @@ -31,7 +31,10 @@ namespace ts.projectSystem { } `, }; - const host = createServerHost([configFile, fileA, fileB, packageFile, { ...libFile, path: "/a/lib/lib.es2016.full.d.ts" }]); + const host = createServerHost([configFile, fileA, fileB, packageFile, { + ...libFile, + path: "/a/lib/lib.es2016.full.d.ts", + }]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([fileA], session); return { @@ -42,7 +45,9 @@ namespace ts.projectSystem { }; } it("package json file is edited", () => { - const { host, session, packageFile, verifyErr } = setup(JSON.stringify({ name: "app", version: "1.0.0" })); + const { host, session, packageFile, verifyErr } = setup( + JSON.stringify({ name: "app", version: "1.0.0" }), + ); session.logger.info("Modify package json file to add type module"); host.writeFile( @@ -128,7 +133,11 @@ namespace ts.projectSystem { host.runQueuedTimeoutCallbacks(); // Actual update verifyErr(); - baselineTsserverLogs("moduleResolution", "package json file is edited when package json with type module exists", session); + baselineTsserverLogs( + "moduleResolution", + "package json file is edited when package json with type module exists", + session, + ); }); }); }); diff --git a/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts b/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts index 4b028f42b429f..e210bb360855a 100644 --- a/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts +++ b/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts @@ -39,7 +39,10 @@ namespace ts.projectSystem { describe("unittests:: tsserver:: moduleSpecifierCache", () => { it("caches importability within a file", () => { const { moduleSpecifierCache } = setup(); - assert.isFalse(moduleSpecifierCache.get(bTs.path as Path, aTs.path as Path, {}, {})?.isBlockedByPackageJsonDependencies); + assert.isFalse( + moduleSpecifierCache.get(bTs.path as Path, aTs.path as Path, {}, {}) + ?.isBlockedByPackageJsonDependencies, + ); }); it("caches module specifiers within a file", () => { @@ -59,20 +62,29 @@ namespace ts.projectSystem { }); it("invalidates module specifiers when changes happen in contained node_modules directories", () => { - const { host, session, moduleSpecifierCache, triggerCompletions } = setup(host => createLoggerWithInMemoryLogs(host)); + const { host, session, moduleSpecifierCache, triggerCompletions } = setup(host => + createLoggerWithInMemoryLogs(host) + ); // Completion at an import statement will calculate and cache module specifiers triggerCompletions({ file: cTs.path, line: 1, offset: cTs.content.length + 1 }); host.writeFile("/node_modules/.staging/mobx-12345678/package.json", "{}"); host.runQueuedTimeoutCallbacks(); assert.equal(moduleSpecifierCache.count(), 0); - baselineTsserverLogs("moduleSpecifierCache", "invalidates module specifiers when changes happen in contained node_modules directories", session); + baselineTsserverLogs( + "moduleSpecifierCache", + "invalidates module specifiers when changes happen in contained node_modules directories", + session, + ); }); it("does not invalidate the cache when new files are added", () => { const { host, moduleSpecifierCache } = setup(); host.writeFile("/src/a2.ts", aTs.content); host.runQueuedTimeoutCallbacks(); - assert.isFalse(moduleSpecifierCache.get(bTs.path as Path, aTs.path as Path, {}, {})?.isBlockedByPackageJsonDependencies); + assert.isFalse( + moduleSpecifierCache.get(bTs.path as Path, aTs.path as Path, {}, {}) + ?.isBlockedByPackageJsonDependencies, + ); }); it("invalidates the cache when symlinks are added or removed", () => { @@ -91,7 +103,10 @@ namespace ts.projectSystem { it("invalidates the cache when module resolution settings change", () => { const { host, moduleSpecifierCache } = setup(); - host.writeFile(tsconfig.path, `{ "compilerOptions": { "moduleResolution": "classic" }, "include": ["src"] }`); + host.writeFile( + tsconfig.path, + `{ "compilerOptions": { "moduleResolution": "classic" }, "include": ["src"] }`, + ); host.runQueuedTimeoutCallbacks(); assert.equal(moduleSpecifierCache.count(), 0); }); @@ -101,7 +116,11 @@ namespace ts.projectSystem { const preferences: UserPreferences = { importModuleSpecifierPreference: "project-relative" }; assert.ok(getWithPreferences({})); - executeSessionRequest(session, protocol.CommandTypes.Configure, { preferences }); + executeSessionRequest( + session, + protocol.CommandTypes.Configure, + { preferences }, + ); // Nothing changes yet assert.ok(getWithPreferences({})); assert.isUndefined(getWithPreferences(preferences)); @@ -111,9 +130,13 @@ namespace ts.projectSystem { assert.ok(getWithPreferences(preferences)); // Test other affecting preference - executeSessionRequest(session, protocol.CommandTypes.Configure, { - preferences: { importModuleSpecifierEnding: "js" }, - }); + executeSessionRequest( + session, + protocol.CommandTypes.Configure, + { + preferences: { importModuleSpecifierEnding: "js" }, + }, + ); triggerCompletions({ file: bTs.path, line: 1, offset: 3 }); assert.isUndefined(getWithPreferences(preferences)); @@ -124,27 +147,52 @@ namespace ts.projectSystem { }); function setup(createLogger?: (host: TestServerHost) => Logger) { - const host = createServerHost([aTs, bTs, cTs, bSymlink, ambientDeclaration, tsconfig, packageJson, mobxPackageJson, mobxDts]); + const host = createServerHost([ + aTs, + bTs, + cTs, + bSymlink, + ambientDeclaration, + tsconfig, + packageJson, + mobxPackageJson, + mobxDts, + ]); const session = createSession(host, createLogger && { logger: createLogger(host) }); openFilesForSession([aTs, bTs, cTs], session); const projectService = session.getProjectService(); const project = configuredProjectAt(projectService, 0); - executeSessionRequest(session, protocol.CommandTypes.Configure, { - preferences: { - includeCompletionsForImportStatements: true, - includeCompletionsForModuleExports: true, - includeCompletionsWithInsertText: true, - includeCompletionsWithSnippetText: true, + executeSessionRequest( + session, + protocol.CommandTypes.Configure, + { + preferences: { + includeCompletionsForImportStatements: true, + includeCompletionsForModuleExports: true, + includeCompletionsWithInsertText: true, + includeCompletionsWithSnippetText: true, + }, }, - }); + ); triggerCompletions({ file: bTs.path, line: 1, offset: 3 }); - return { host, project, projectService, session, moduleSpecifierCache: project.getModuleSpecifierCache(), triggerCompletions }; + return { + host, + project, + projectService, + session, + moduleSpecifierCache: project.getModuleSpecifierCache(), + triggerCompletions, + }; function triggerCompletions(requestLocation: protocol.FileLocationRequestArgs) { - executeSessionRequest(session, protocol.CommandTypes.CompletionInfo, { - ...requestLocation, - }); + executeSessionRequest( + session, + protocol.CommandTypes.CompletionInfo, + { + ...requestLocation, + }, + ); } } } diff --git a/src/testRunner/unittests/tsserver/navTo.ts b/src/testRunner/unittests/tsserver/navTo.ts index 443c083cce1d9..0c616af9f798e 100644 --- a/src/testRunner/unittests/tsserver/navTo.ts +++ b/src/testRunner/unittests/tsserver/navTo.ts @@ -22,11 +22,22 @@ namespace ts.projectSystem { openFilesForSession([file1], session); // Try to find some interface type defined in lib.d.ts - const libTypeNavToRequest = makeSessionRequest(CommandNames.Navto, { searchValue: "Document", file: file1.path, projectFileName: configFile.path }); + const libTypeNavToRequest = makeSessionRequest(CommandNames.Navto, { + searchValue: "Document", + file: file1.path, + projectFileName: configFile.path, + }); const items = session.executeCommand(libTypeNavToRequest).response as protocol.NavtoItem[]; - assert.isFalse(containsNavToItem(items, "Document", "interface"), `Found lib.d.ts symbol in JavaScript project nav to request result.`); + assert.isFalse( + containsNavToItem(items, "Document", "interface"), + `Found lib.d.ts symbol in JavaScript project nav to request result.`, + ); - const localFunctionNavToRequst = makeSessionRequest(CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path }); + const localFunctionNavToRequst = makeSessionRequest(CommandNames.Navto, { + searchValue: "foo", + file: file1.path, + projectFileName: configFile.path, + }); const items2 = session.executeCommand(localFunctionNavToRequst).response as protocol.NavtoItem[]; assert.isTrue(containsNavToItem(items2, "foo", "function"), `Cannot find function symbol "foo".`); }); @@ -64,7 +75,10 @@ export const ghijkl = a.abcdef;`, const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file1, file2], session); - const request = makeSessionRequest(CommandNames.Navto, { searchValue: "abcdef", file: file1.path }); + const request = makeSessionRequest(CommandNames.Navto, { + searchValue: "abcdef", + file: file1.path, + }); session.executeCommand(request).response as protocol.NavtoItem[]; baselineTsserverLogs("navTo", "should de-duplicate symbols", session); @@ -110,7 +124,9 @@ export const ghijkl = a.abcdef;`, const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file1], session); - const request = makeSessionRequest(CommandNames.Navto, { searchValue: "abcdef" }); + const request = makeSessionRequest(CommandNames.Navto, { + searchValue: "abcdef", + }); session.executeCommand(request).response as protocol.NavtoItem[]; baselineTsserverLogs("navTo", "should de-duplicate symbols when searching all projects", session); }); @@ -129,7 +145,11 @@ export const ghijkl = a.abcdef;`, openFilesForSession([file1], session); // Try to find some interface type defined in lib.d.ts - const libTypeNavToRequest = makeSessionRequest(CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path }); + const libTypeNavToRequest = makeSessionRequest(CommandNames.Navto, { + searchValue: "foo", + file: file1.path, + projectFileName: configFile.path, + }); const items = session.executeCommand(libTypeNavToRequest).response as protocol.NavtoItem[]; const fooItem = findNavToItem(items, "foo", "function"); assert.isNotNull(fooItem, `Cannot find function symbol "foo".`); diff --git a/src/testRunner/unittests/tsserver/occurences.ts b/src/testRunner/unittests/tsserver/occurences.ts index 0955edafcdb51..84d23661f59fb 100644 --- a/src/testRunner/unittests/tsserver/occurences.ts +++ b/src/testRunner/unittests/tsserver/occurences.ts @@ -16,7 +16,8 @@ namespace ts.projectSystem { CommandNames.Occurrences, { file: file1.path, line: 1, offset: 11 }, ); - const highlightResponse = session.executeCommand(highlightRequest).response as protocol.OccurrencesResponseItem[]; + const highlightResponse = session.executeCommand(highlightRequest) + .response as protocol.OccurrencesResponseItem[]; const firstOccurence = highlightResponse[0]; assert.isTrue(firstOccurence.isInString, "Highlights should be marked with isInString"); } @@ -26,10 +27,14 @@ namespace ts.projectSystem { CommandNames.Occurrences, { file: file1.path, line: 3, offset: 13 }, ); - const highlightResponse = session.executeCommand(highlightRequest).response as protocol.OccurrencesResponseItem[]; + const highlightResponse = session.executeCommand(highlightRequest) + .response as protocol.OccurrencesResponseItem[]; assert.isTrue(highlightResponse.length === 2); const firstOccurence = highlightResponse[0]; - assert.isUndefined(firstOccurence.isInString, "Highlights should not be marked with isInString if on property name"); + assert.isUndefined( + firstOccurence.isInString, + "Highlights should not be marked with isInString if on property name", + ); } { @@ -37,10 +42,14 @@ namespace ts.projectSystem { CommandNames.Occurrences, { file: file1.path, line: 4, offset: 14 }, ); - const highlightResponse = session.executeCommand(highlightRequest).response as protocol.OccurrencesResponseItem[]; + const highlightResponse = session.executeCommand(highlightRequest) + .response as protocol.OccurrencesResponseItem[]; assert.isTrue(highlightResponse.length === 2); const firstOccurence = highlightResponse[0]; - assert.isUndefined(firstOccurence.isInString, "Highlights should not be marked with isInString if on indexer"); + assert.isUndefined( + firstOccurence.isInString, + "Highlights should not be marked with isInString if on indexer", + ); } }); }); diff --git a/src/testRunner/unittests/tsserver/openFile.ts b/src/testRunner/unittests/tsserver/openFile.ts index 4865e713ecdcb..35e3b06ba2c0a 100644 --- a/src/testRunner/unittests/tsserver/openFile.ts +++ b/src/testRunner/unittests/tsserver/openFile.ts @@ -60,7 +60,12 @@ namespace ts.projectSystem { verifyConfigFileName(file2, "/a/B", useCaseSensitiveFileNames ? undefined : configFile); function verifyConfigFileName(file: File, projectRoot: string, expectedConfigFile: File | undefined) { - const { configFileName } = service.openClientFile(file.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectRoot); + const { configFileName } = service.openClientFile( + file.path, + /*fileContent*/ undefined, + /*scriptKind*/ undefined, + projectRoot, + ); assert.equal(configFileName, expectedConfigFile && expectedConfigFile.path); service.closeClientFile(file.path); } @@ -181,7 +186,11 @@ bar();`, }, }); verifyGetErrRequest({ session, host, files: [file] }); - baselineTsserverLogs("openfile", "when file makes edits to add/remove comment directives, they are handled correcrly", session); + baselineTsserverLogs( + "openfile", + "when file makes edits to add/remove comment directives, they are handled correcrly", + session, + ); }); }); } diff --git a/src/testRunner/unittests/tsserver/partialSemanticServer.ts b/src/testRunner/unittests/tsserver/partialSemanticServer.ts index bdfd2ba994981..37ab88615e5cd 100644 --- a/src/testRunner/unittests/tsserver/partialSemanticServer.ts +++ b/src/testRunner/unittests/tsserver/partialSemanticServer.ts @@ -109,7 +109,8 @@ import { something } from "something"; command: protocol.CommandTypes.SyntacticDiagnosticsSync, arguments: { file: file1.path }, }; - const response = session.executeCommandSeq(request).response as protocol.SyntacticDiagnosticsSyncResponse["body"]; + const response = session.executeCommandSeq(request) + .response as protocol.SyntacticDiagnosticsSyncResponse["body"]; assert.isDefined(response); assert.equal(response!.length, 1); assert.equal((response![0] as protocol.Diagnostic).text, expectedErrorMessage); @@ -166,7 +167,11 @@ function fooB() { }`, logger: createLoggerWithInMemoryLogs(host), }); openFilesForSession([file1], session); - baselineTsserverLogs("partialSemanticServer", "should not include referenced files from unopened files", session); + baselineTsserverLogs( + "partialSemanticServer", + "should not include referenced files from unopened files", + session, + ); }); it("should not crash when external module name resolution is reused", () => { @@ -179,7 +184,11 @@ function fooB() { }`, // Open file with non relative external module name openFilesForSession([file2], session); - baselineTsserverLogs("partialSemanticServer", "should not crash when external module name resolution is reused", session); + baselineTsserverLogs( + "partialSemanticServer", + "should not crash when external module name resolution is reused", + session, + ); }); it("should not create autoImportProvider or handle package jsons", () => { @@ -203,8 +212,18 @@ function fooB() { }`, path: "/index.ts", content: "", }; - const host = createServerHost([angularFormsDts, angularFormsPackageJson, tsconfig, packageJson, indexTs, libFile]); - const session = createSession(host, { serverMode: LanguageServiceMode.PartialSemantic, useSingleInferredProject: true }); + const host = createServerHost([ + angularFormsDts, + angularFormsPackageJson, + tsconfig, + packageJson, + indexTs, + libFile, + ]); + const session = createSession(host, { + serverMode: LanguageServiceMode.PartialSemantic, + useSingleInferredProject: true, + }); const service = session.getProjectService(); openFilesForSession([indexTs], session); const project = service.inferredProjects[0]; @@ -220,7 +239,11 @@ function fooB() { }`, command: protocol.CommandTypes.DefinitionAndBoundSpan, arguments: protocolFileLocationFromSubstring(file1, `"./b"`), }); - baselineTsserverLogs("partialSemanticServer", "should support go-to-definition on module specifiers", session); + baselineTsserverLogs( + "partialSemanticServer", + "should support go-to-definition on module specifiers", + session, + ); }); }); } diff --git a/src/testRunner/unittests/tsserver/plugins.ts b/src/testRunner/unittests/tsserver/plugins.ts index 24ba436a48860..54e2842233fce 100644 --- a/src/testRunner/unittests/tsserver/plugins.ts +++ b/src/testRunner/unittests/tsserver/plugins.ts @@ -133,7 +133,13 @@ namespace ts.projectSystem { }; const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([aTs], session); - session.logger.logs.push(`ExternalFiles:: ${JSON.stringify(session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles())}`); + session.logger.logs.push( + `ExternalFiles:: ${ + JSON.stringify( + session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles(), + ) + }`, + ); host.writeFile( tsconfig.path, @@ -144,7 +150,13 @@ namespace ts.projectSystem { }), ); host.runQueuedTimeoutCallbacks(); - session.logger.logs.push(`ExternalFiles:: ${JSON.stringify(session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles())}`); + session.logger.logs.push( + `ExternalFiles:: ${ + JSON.stringify( + session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles(), + ) + }`, + ); baselineTsserverLogs("plugins", "gets external files with config file reload", session); }); diff --git a/src/testRunner/unittests/tsserver/projectErrors.ts b/src/testRunner/unittests/tsserver/projectErrors.ts index 22fff624a8215..a0ae1884a3ffc 100644 --- a/src/testRunner/unittests/tsserver/projectErrors.ts +++ b/src/testRunner/unittests/tsserver/projectErrors.ts @@ -1,26 +1,46 @@ namespace ts.projectSystem { describe("unittests:: tsserver:: Project Errors", () => { - function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: readonly string[]): void { + function checkProjectErrors( + projectFiles: server.ProjectFilesWithTSDiagnostics, + expectedErrors: readonly string[], + ): void { assert.isTrue(projectFiles !== undefined, "missing project files"); checkProjectErrorsWorker(projectFiles.projectErrors, expectedErrors); } function checkProjectErrorsWorker(errors: readonly Diagnostic[], expectedErrors: readonly string[]): void { - assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`); + assert.equal( + errors ? errors.length : 0, + expectedErrors.length, + `expected ${expectedErrors.length} error in the list`, + ); if (expectedErrors.length) { for (let i = 0; i < errors.length; i++) { const actualMessage = flattenDiagnosticMessageText(errors[i].messageText, "\n"); const expectedMessage = expectedErrors[i]; - assert.isTrue(actualMessage.indexOf(expectedMessage) === 0, `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`); + assert.isTrue( + actualMessage.indexOf(expectedMessage) === 0, + `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`, + ); } } } - function checkDiagnosticsWithLinePos(errors: server.protocol.DiagnosticWithLinePosition[], expectedErrors: string[]) { - assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`); + function checkDiagnosticsWithLinePos( + errors: server.protocol.DiagnosticWithLinePosition[], + expectedErrors: string[], + ) { + assert.equal( + errors ? errors.length : 0, + expectedErrors.length, + `expected ${expectedErrors.length} error in the list`, + ); if (expectedErrors.length) { zipWith(errors, expectedErrors, ({ message: actualMessage }, expectedMessage) => { - assert.isTrue(startsWith(actualMessage, actualMessage), `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`); + assert.isTrue( + startsWith(actualMessage, actualMessage), + `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`, + ); }); } } @@ -53,7 +73,8 @@ namespace ts.projectSystem { }); checkNumberOfProjects(projectService, { externalProjects: 1 }); - const diags = session.executeCommand(compilerOptionsRequest).response as server.protocol.DiagnosticWithLinePosition[]; + const diags = session.executeCommand(compilerOptionsRequest) + .response as server.protocol.DiagnosticWithLinePosition[]; // only file1 exists - expect error checkDiagnosticsWithLinePos(diags, ["File '/a/b/applib.ts' not found."]); } @@ -61,7 +82,8 @@ namespace ts.projectSystem { { // only file2 exists - expect error checkNumberOfProjects(projectService, { externalProjects: 1 }); - const diags = session.executeCommand(compilerOptionsRequest).response as server.protocol.DiagnosticWithLinePosition[]; + const diags = session.executeCommand(compilerOptionsRequest) + .response as server.protocol.DiagnosticWithLinePosition[]; checkDiagnosticsWithLinePos(diags, ["File '/a/b/app.ts' not found."]); } @@ -69,7 +91,8 @@ namespace ts.projectSystem { { // both files exist - expect no errors checkNumberOfProjects(projectService, { externalProjects: 1 }); - const diags = session.executeCommand(compilerOptionsRequest).response as server.protocol.DiagnosticWithLinePosition[]; + const diags = session.executeCommand(compilerOptionsRequest) + .response as server.protocol.DiagnosticWithLinePosition[]; checkDiagnosticsWithLinePos(diags, []); } }); @@ -99,13 +122,15 @@ namespace ts.projectSystem { seq: 2, arguments: { projectFileName: project.getProjectName() }, }; - let diags = session.executeCommand(compilerOptionsRequest).response as server.protocol.DiagnosticWithLinePosition[]; + let diags = session.executeCommand(compilerOptionsRequest) + .response as server.protocol.DiagnosticWithLinePosition[]; checkDiagnosticsWithLinePos(diags, ["File '/a/b/applib.ts' not found."]); host.writeFile(file2.path, file2.content); checkNumberOfProjects(projectService, { configuredProjects: 1 }); - diags = session.executeCommand(compilerOptionsRequest).response as server.protocol.DiagnosticWithLinePosition[]; + diags = session.executeCommand(compilerOptionsRequest) + .response as server.protocol.DiagnosticWithLinePosition[]; checkDiagnosticsWithLinePos(diags, []); }); @@ -132,7 +157,10 @@ namespace ts.projectSystem { projectService.openClientFile(file1.path); { projectService.checkNumberOfProjects({ configuredProjects: 1 }); - const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; + const configuredProject = find( + projectService.synchronizeProjectList([]), + f => f.info!.projectName === corruptedConfig.path, + )!; assert.isTrue(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); @@ -146,7 +174,10 @@ namespace ts.projectSystem { host.writeFile(correctConfig.path, correctConfig.content); { projectService.checkNumberOfProjects({ configuredProjects: 1 }); - const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; + const configuredProject = find( + projectService.synchronizeProjectList([]), + f => f.info!.projectName === corruptedConfig.path, + )!; assert.isTrue(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); @@ -177,7 +208,10 @@ namespace ts.projectSystem { projectService.openClientFile(file1.path); { projectService.checkNumberOfProjects({ configuredProjects: 1 }); - const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; + const configuredProject = find( + projectService.synchronizeProjectList([]), + f => f.info!.projectName === corruptedConfig.path, + )!; assert.isTrue(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); @@ -187,7 +221,10 @@ namespace ts.projectSystem { host.writeFile(corruptedConfig.path, corruptedConfig.content); { projectService.checkNumberOfProjects({ configuredProjects: 1 }); - const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; + const configuredProject = find( + projectService.synchronizeProjectList([]), + f => f.info!.projectName === corruptedConfig.path, + )!; assert.isTrue(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); @@ -232,7 +269,11 @@ namespace ts.projectSystem { content: "class c { }", }; const host = createServerHost([libFile, fileInRoot, fileInProjectRoot]); - const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host), useInferredProjectPerProjectRoot: true }); + const session = createSession(host, { + canUseEvents: true, + logger: createLoggerWithInMemoryLogs(host), + useInferredProjectPerProjectRoot: true, + }); const untitledFile = "untitled:Untitled-1"; const refPathNotFound1 = "../../../../../../typings/@epic/Core.d.ts"; @@ -253,7 +294,13 @@ namespace ts.projectSystem { // Since this is not js project so no typings are queued host.checkTimeoutQueueLength(0); verifyGetErrRequest({ session, host, files: [untitledFile] }); - baselineTsserverLogs("projectErrors", `when opening new file that doesnt exist on disk yet ${useProjectRoot ? "with projectRoot" : "without projectRoot"}`, session); + baselineTsserverLogs( + "projectErrors", + `when opening new file that doesnt exist on disk yet ${ + useProjectRoot ? "with projectRoot" : "without projectRoot" + }`, + session, + ); } it("has projectRoot", () => { @@ -277,7 +324,10 @@ namespace ts.projectSystem { }; const configFile: File = { path: `${projectDir}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { module: "none", targer: "es5" }, exclude: ["node_modules"] }), + content: JSON.stringify({ + compilerOptions: { module: "none", targer: "es5" }, + exclude: ["node_modules"], + }), }; const host = createServerHost([app, foo, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -292,7 +342,11 @@ namespace ts.projectSystem { host.runQueuedTimeoutCallbacks(); host.runQueuedTimeoutCallbacks(); verifyGetErrRequest({ session, host, files: [app] }); - baselineTsserverLogs("projectErrors", `folder rename updates project structure and reports no errors`, session); + baselineTsserverLogs( + "projectErrors", + `folder rename updates project structure and reports no errors`, + session, + ); }); it("Getting errors before opening file", () => { @@ -329,14 +383,22 @@ namespace ts.projectSystem { }; const files = [libFile, app, serverUtilities, backendTest]; const host = createServerHost(files); - const session = createSession(host, { useInferredProjectPerProjectRoot: true, canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + useInferredProjectPerProjectRoot: true, + canUseEvents: true, + logger: createLoggerWithInMemoryLogs(host), + }); openFilesForSession([{ file: app, projectRootPath: tscWatch.projectRoot }], session); openFilesForSession([{ file: backendTest, projectRootPath: tscWatch.projectRoot }], session); verifyGetErrRequest({ session, host, files: [backendTest.path, app.path] }); closeFilesForSession([backendTest], session); openFilesForSession([{ file: serverUtilities.path, projectRootPath: tscWatch.projectRoot }], session); verifyGetErrRequest({ session, host, files: [serverUtilities.path, app.path] }); - baselineTsserverLogs("projectErrors", `reports errors correctly when file referenced by inferred project root, is opened right after closing the root file`, session); + baselineTsserverLogs( + "projectErrors", + `reports errors correctly when file referenced by inferred project root, is opened right after closing the root file`, + session, + ); }); it("Correct errors when resolution resolves to file that has same ambient module and is also module", () => { @@ -384,7 +446,11 @@ declare module '@custom/plugin' { }, }); checkErrors(); - baselineTsserverLogs("projectErrors", `correct errors when resolution resolves to file that has same ambient module and is also module`, session); + baselineTsserverLogs( + "projectErrors", + `correct errors when resolution resolves to file that has same ambient module and is also module`, + session, + ); function checkErrors() { host.checkTimeoutQueueLength(0); @@ -432,7 +498,11 @@ declare module '@custom/plugin' { const host = createServerHost([file, libFile, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file has errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are generated when the config file has errors", + session, + ); }); it("are generated when the config file doesn't have errors", () => { @@ -449,7 +519,11 @@ declare module '@custom/plugin' { const host = createServerHost([file, libFile, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file doesnt have errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are generated when the config file doesnt have errors", + session, + ); }); it("are generated when the config file changes", () => { @@ -481,7 +555,11 @@ declare module '@custom/plugin' { }`; host.writeFile(configFile.path, configFile.content); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file changes", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are generated when the config file changes", + session, + ); }); it("are not generated when the config file does not include file opened and config file has errors", () => { @@ -513,7 +591,11 @@ declare module '@custom/plugin' { openFilesForSession([file], session); // We generate only if project is created when opening file from the project openFilesForSession([file3], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file does not include file opened and config file has errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are not generated when the config file does not include file opened and config file has errors", + session, + ); }); it("are not generated when the config file has errors but suppressDiagnosticEvents is true", () => { @@ -531,9 +613,17 @@ declare module '@custom/plugin' { }`, }; const host = createServerHost([file, libFile, configFile]); - const session = createSession(host, { canUseEvents: true, suppressDiagnosticEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + canUseEvents: true, + suppressDiagnosticEvents: true, + logger: createLoggerWithInMemoryLogs(host), + }); openFilesForSession([file], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file has errors but suppressDiagnosticEvents is true", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are not generated when the config file has errors but suppressDiagnosticEvents is true", + session, + ); }); it("are not generated when the config file does not include file opened and doesnt contain any errors", () => { @@ -562,7 +652,11 @@ declare module '@custom/plugin' { openFilesForSession([file], session); // We generate only if project is created when opening file from the project openFilesForSession([file3], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file does not include file opened and doesnt contain any errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are not generated when the config file does not include file opened and doesnt contain any errors", + session, + ); }); it("contains the project reference errors", () => { @@ -582,7 +676,11 @@ declare module '@custom/plugin' { const host = createServerHost([file, libFile, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events contains the project reference errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events contains the project reference errors", + session, + ); }); }); @@ -605,7 +703,8 @@ declare module '@custom/plugin' { command: server.CommandNames.CompilerOptionsDiagnosticsFull, seq: 2, arguments: { projectFileName: projectName }, - } as server.protocol.CompilerOptionsDiagnosticsRequest).response as readonly protocol.DiagnosticWithLinePosition[]; + } as server.protocol.CompilerOptionsDiagnosticsRequest) + .response as readonly protocol.DiagnosticWithLinePosition[]; assert.isTrue(diags.length === 0); session.executeCommand({ @@ -619,7 +718,8 @@ declare module '@custom/plugin' { command: server.CommandNames.CompilerOptionsDiagnosticsFull, seq: 4, arguments: { projectFileName: projectName }, - } as server.protocol.CompilerOptionsDiagnosticsRequest).response as readonly protocol.DiagnosticWithLinePosition[]; + } as server.protocol.CompilerOptionsDiagnosticsRequest) + .response as readonly protocol.DiagnosticWithLinePosition[]; assert.isTrue(diagsAfterUpdate.length === 0); }); @@ -646,7 +746,8 @@ declare module '@custom/plugin' { command: server.CommandNames.CompilerOptionsDiagnosticsFull, seq: 2, arguments: { projectFileName }, - } as server.protocol.CompilerOptionsDiagnosticsRequest).response as readonly server.protocol.DiagnosticWithLinePosition[]; + } as server.protocol.CompilerOptionsDiagnosticsRequest) + .response as readonly server.protocol.DiagnosticWithLinePosition[]; assert.isTrue(diags.length === 0); session.executeCommand({ @@ -664,7 +765,8 @@ declare module '@custom/plugin' { command: server.CommandNames.CompilerOptionsDiagnosticsFull, seq: 4, arguments: { projectFileName }, - } as server.protocol.CompilerOptionsDiagnosticsRequest).response as readonly server.protocol.DiagnosticWithLinePosition[]; + } as server.protocol.CompilerOptionsDiagnosticsRequest) + .response as readonly server.protocol.DiagnosticWithLinePosition[]; assert.isTrue(diagsAfterUpdate.length === 0); }); }); @@ -684,7 +786,8 @@ declare module '@custom/plugin' { "mapRoot": "./" } }`; - const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + configFileContentAfterComment; + const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + + configFileContentAfterComment; const configFileContentWithoutCommentLine = configFileContentBeforeComment + configFileContentAfterComment; const configFile = { @@ -704,7 +807,8 @@ declare module '@custom/plugin' { command: server.CommandNames.SemanticDiagnosticsSync, seq: 2, arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true }, - } as server.protocol.SemanticDiagnosticsSyncRequest).response as readonly server.protocol.DiagnosticWithLinePosition[]; + } as server.protocol.SemanticDiagnosticsSyncRequest) + .response as readonly server.protocol.DiagnosticWithLinePosition[]; assert.isTrue(diags.length === 3); configFile.content = configFileContentWithoutCommentLine; @@ -715,14 +819,18 @@ declare module '@custom/plugin' { command: server.CommandNames.SemanticDiagnosticsSync, seq: 2, arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true }, - } as server.protocol.SemanticDiagnosticsSyncRequest).response as readonly server.protocol.DiagnosticWithLinePosition[]; + } as server.protocol.SemanticDiagnosticsSyncRequest) + .response as readonly server.protocol.DiagnosticWithLinePosition[]; assert.isTrue(diagsAfterEdit.length === 3); verifyDiagnostic(diags[0], diagsAfterEdit[0]); verifyDiagnostic(diags[1], diagsAfterEdit[1]); verifyDiagnostic(diags[2], diagsAfterEdit[2]); - function verifyDiagnostic(beforeEditDiag: server.protocol.DiagnosticWithLinePosition, afterEditDiag: server.protocol.DiagnosticWithLinePosition) { + function verifyDiagnostic( + beforeEditDiag: server.protocol.DiagnosticWithLinePosition, + afterEditDiag: server.protocol.DiagnosticWithLinePosition, + ) { assert.equal(beforeEditDiag.message, afterEditDiag.message); assert.equal(beforeEditDiag.code, afterEditDiag.code); assert.equal(beforeEditDiag.category, afterEditDiag.category); @@ -737,7 +845,8 @@ declare module '@custom/plugin' { describe("unittests:: tsserver:: Project Errors with config file change", () => { it("Updates diagnostics when '--noUnusedLabels' changes", () => { const aTs: File = { path: "/a.ts", content: "label: while (1) {}" }; - const options = (allowUnusedLabels: boolean) => `{ "compilerOptions": { "allowUnusedLabels": ${allowUnusedLabels} } }`; + const options = (allowUnusedLabels: boolean) => + `{ "compilerOptions": { "allowUnusedLabels": ${allowUnusedLabels} } }`; const tsconfig: File = { path: "/tsconfig.json", content: options(/*allowUnusedLabels*/ true) }; const host = createServerHost([aTs, tsconfig]); @@ -747,7 +856,12 @@ declare module '@custom/plugin' { host.modifyFile(tsconfig.path, options(/*allowUnusedLabels*/ false)); host.runQueuedTimeoutCallbacks(); - const response = executeSessionRequest(session, protocol.CommandTypes.SemanticDiagnosticsSync, { file: aTs.path }) as protocol.Diagnostic[] | undefined; + const response = executeSessionRequest< + protocol.SemanticDiagnosticsSyncRequest, + protocol.SemanticDiagnosticsSyncResponse + >(session, protocol.CommandTypes.SemanticDiagnosticsSync, { file: aTs.path }) as + | protocol.Diagnostic[] + | undefined; assert.deepEqual(response, [ { start: { line: 1, offset: 1 }, @@ -798,7 +912,11 @@ console.log(blabla);`, include: ["./src/*.ts", "./src/*.json"], }); verifyGetErrRequest({ session, host, files: [test] }); - baselineTsserverLogs("projectErrors", `should not report incorrect error when json is root file found by tsconfig`, session); + baselineTsserverLogs( + "projectErrors", + `should not report incorrect error when json is root file found by tsconfig`, + session, + ); }); it("should report error when json is not root file found by tsconfig", () => { @@ -806,7 +924,11 @@ console.log(blabla);`, include: ["./src/*.ts"], }); verifyGetErrRequest({ session, host, files: [test] }); - baselineTsserverLogs("projectErrors", `should report error when json is not root file found by tsconfig`, session); + baselineTsserverLogs( + "projectErrors", + `should report error when json is not root file found by tsconfig`, + session, + ); }); }); @@ -845,14 +967,24 @@ console.log(blabla);`, filesAndFoldersToAdd = [ { path: `${tscWatch.projectRoot}/node_modules/.staging/@angular/platform-browser-dynamic-5efaaa1a` }, - { path: `${tscWatch.projectRoot}/node_modules/.staging/@angular/cli-c1e44b05/models/analytics.d.ts`, content: `export const x = 10;` }, - { path: `${tscWatch.projectRoot}/node_modules/.staging/@angular/core-0963aebf/index.d.ts`, content: `export const y = 10;` }, + { + path: `${tscWatch.projectRoot}/node_modules/.staging/@angular/cli-c1e44b05/models/analytics.d.ts`, + content: `export const x = 10;`, + }, + { + path: `${tscWatch.projectRoot}/node_modules/.staging/@angular/core-0963aebf/index.d.ts`, + content: `export const y = 10;`, + }, ]; // Since we added/removed in .staging no timeout verifyWhileNpmInstall(0); filesAndFoldersToAdd = []; - host.ensureFileOrFolder(moduleFile, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true, /*ignoreParentWatch*/ true); + host.ensureFileOrFolder( + moduleFile, + /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true, + /*ignoreParentWatch*/ true, + ); // Since we added/removed in .staging no timeout verifyWhileNpmInstall(0); @@ -863,7 +995,13 @@ console.log(blabla);`, // Additional watch for watching script infos from node_modules verifyWhileNpmInstall(3); - baselineTsserverLogs("projectErrors", `npm install when timeout occurs ${timeoutDuringPartialInstallation ? "inbetween" : "after"} installation`, session); + baselineTsserverLogs( + "projectErrors", + `npm install when timeout occurs ${ + timeoutDuringPartialInstallation ? "inbetween" : "after" + } installation`, + session, + ); function verifyWhileNpmInstall(timeouts: number) { filesAndFoldersToAdd.forEach(f => host.ensureFileOrFolder(f)); @@ -876,7 +1014,13 @@ console.log(blabla);`, else { host.checkTimeoutQueueLength(timeouts ? 3 : 2); } - verifyGetErrRequest({ session, host, files: [main], existingTimeouts: !npmInstallComplete && !timeoutDuringPartialInstallation ? timeouts ? 3 : 2 : undefined }); + verifyGetErrRequest({ + session, + host, + files: [main], + existingTimeouts: !npmInstallComplete && !timeoutDuringPartialInstallation ? timeouts ? 3 : 2 + : undefined, + }); } } diff --git a/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts b/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts index 59acdb403fdbe..1266c96780eae 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts @@ -60,7 +60,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage", + session, + ); }); it("with initial file open, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -84,7 +88,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project", + session, + ); }); it("with local change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -114,7 +122,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage and local change to dependency", + session, + ); }); it("with local change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -144,7 +156,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project and local change to dependency", + session, + ); }); it("with local change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -185,7 +201,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage and local change to usage", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -226,7 +246,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project and local change to usage", + session, + ); }); it("with change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -256,7 +280,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and change to depenedency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage and change to depenedency", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -286,7 +314,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and change to depenedency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project and change to depenedency", + session, + ); }); it("with change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -327,7 +359,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage and change to usage", + session, + ); }); it("with change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -368,7 +404,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project and change to usage", + session, + ); }); }); @@ -395,7 +435,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency", + session, + ); }); it("with initial file open, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -419,7 +463,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project", + session, + ); }); it("with local change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -449,7 +497,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency and local change to dependency", + session, + ); }); it("with local change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -479,7 +531,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project and local change to dependency", + session, + ); }); it("with local change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -520,7 +576,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency and local change to usage", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -561,7 +621,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project and local change to usage", + session, + ); }); it("with change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -591,7 +655,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency and change to dependency", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -621,7 +689,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project and change to dependency", + session, + ); }); it("with change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -662,7 +734,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency and change to usage", + session, + ); }); it("with change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -703,7 +779,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project and change to usage", + session, + ); }); }); }); @@ -797,7 +877,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and local change to dependency", + session, + ); }); it("with local change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -838,7 +922,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to dependency with file", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and local change to dependency with file", + session, + ); }); it("with local change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -879,7 +967,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and local change to usage", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -920,7 +1012,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to usage with project", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and local change to usage with project", + session, + ); }); it("with change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -961,7 +1057,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and change to dependency", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1002,7 +1102,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage with project and change to dependency", + session, + ); }); it("with change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1083,7 +1187,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage with project and change to usage", + session, + ); }); }); @@ -1110,7 +1218,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with usage project", + session, + ); }); it("with local change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1151,7 +1263,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with usage project and local change to dependency", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1192,7 +1308,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with usage project and local change to usage", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1233,7 +1353,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with usage project and change to dependency", + session, + ); }); it("with change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1274,7 +1398,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with usage project and change to usage", + session, + ); }); }); @@ -1366,7 +1494,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency and local change to dependency", + session, + ); }); it("with local change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1407,7 +1539,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with project and local change to dependency", + session, + ); }); it("with local change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1448,7 +1584,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency and local change to usage", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1489,7 +1629,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with project and local change to usage", + session, + ); }); it("with change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1530,7 +1674,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency and change to dependency", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1571,7 +1719,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with project and change to dependency", + session, + ); }); it("with change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1612,7 +1764,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency and change to usage", + session, + ); }); it("with change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1653,7 +1809,11 @@ fn2(); command: protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with project and change to usage", + session, + ); }); }); }); @@ -1715,7 +1875,14 @@ fn2(); } }`, }; - const host = createServerHost([libFile, tsbaseJson, buttonConfig, buttonSource, siblingConfig, siblingSource], { useCaseSensitiveFileNames: true }); + const host = createServerHost([ + libFile, + tsbaseJson, + buttonConfig, + buttonSource, + siblingConfig, + siblingSource, + ], { useCaseSensitiveFileNames: true }); // ts build should succeed tscWatch.ensureErrorFreeBuild(host, [siblingConfig.path]); @@ -1730,7 +1897,11 @@ fn2(); projectFileName: siblingConfig.path, }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "compile on save emits same output as project build with external project", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "compile on save emits same output as project build with external project", + session, + ); }); }); } diff --git a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts index 2bc8f56176eb6..422d6f1b2008f 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts @@ -3,7 +3,13 @@ namespace ts.projectSystem { const dependecyLocation = `${tscWatch.projectRoot}/dependency`; const usageLocation = `${tscWatch.projectRoot}/usage`; - function verifyUsageAndDependency(scenario: string, dependencyTs: File, dependencyConfig: File, usageTs: File, usageConfig: File) { + function verifyUsageAndDependency( + scenario: string, + dependencyTs: File, + dependencyConfig: File, + usageTs: File, + usageConfig: File, + ) { function usageProjectDiagnostics(): GetErrForProjectDiagnostics { return { project: usageTs, files: [usageTs, dependencyTs] }; } diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index 00c9681635be1..b53cf051d2b43 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -1,5 +1,8 @@ namespace ts.projectSystem { - export function createHostWithSolutionBuild(files: readonly TestFSWithWatch.FileOrFolderOrSymLink[], rootNames: readonly string[]) { + export function createHostWithSolutionBuild( + files: readonly TestFSWithWatch.FileOrFolderOrSymLink[], + rootNames: readonly string[], + ) { const host = createServerHost(files); // ts build should succeed tscWatch.ensureErrorFreeBuild(host, rootNames); @@ -217,7 +220,13 @@ function foo() { symbolStartOffset: protocolLocationFromSubstring(keyboardTs.content, searchStr).offset, symbolDisplayString: "function evaluateKeyboardEvent(): void", }); - baselineTsserverLogs("projectReferences", `root file is file from referenced project${disableSourceOfProjectReferenceRedirect ? " and using declaration maps" : ""}`, session); + baselineTsserverLogs( + "projectReferences", + `root file is file from referenced project${ + disableSourceOfProjectReferenceRedirect ? " and using declaration maps" : "" + }`, + session, + ); } it(`when using declaration file maps to navigate between projects`, () => { @@ -332,13 +341,18 @@ function foo() { }); } - function verifySession(scenario: string, { bPackageJson, aTest, bFoo, bBar, bSymlink }: Packages, alreadyBuilt: boolean, extraOptions: CompilerOptions) { + function verifySession( + scenario: string, + { bPackageJson, aTest, bFoo, bBar, bSymlink }: Packages, + alreadyBuilt: boolean, + extraOptions: CompilerOptions, + ) { const aConfig = config("A", extraOptions, ["../B"]); const bConfig = config("B", extraOptions); const files = [libFile, bPackageJson, aConfig, bConfig, aTest, bFoo, bBar, bSymlink]; - const host = alreadyBuilt ? - createHostWithSolutionBuild(files, [aConfig.path]) : - createServerHost(files); + const host = alreadyBuilt + ? createHostWithSolutionBuild(files, [aConfig.path]) + : createServerHost(files); // Create symlink in node module const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -358,7 +372,13 @@ function foo() { }, }); verifyGetErrRequest({ session, host, files: [aTest] }); - baselineTsserverLogs("projectReferences", `monorepo like with symlinks ${scenario} and solution is ${alreadyBuilt ? "built" : "not built"}${extraOptions.preserveSymlinks ? " with preserveSymlinks" : ""}`, session); + baselineTsserverLogs( + "projectReferences", + `monorepo like with symlinks ${scenario} and solution is ${alreadyBuilt ? "built" : "not built"}${ + extraOptions.preserveSymlinks ? " with preserveSymlinks" : "" + }`, + session, + ); } function config(packageName: string, extraOptions: CompilerOptions, references?: string[]): File { @@ -385,52 +405,58 @@ function foo() { } function verifyMonoRepoLike(scope = "") { - verifySymlinkScenario(`when packageJson has types field and has index.ts${scope ? " with scoped package" : ""}`, () => ({ - bPackageJson: { - path: `${tscWatch.projectRoot}/packages/B/package.json`, - content: JSON.stringify({ - main: "lib/index.js", - types: "lib/index.d.ts", - }), - }, - aTest: file( - "A", - "index.ts", - `import { foo } from '${scope}b'; + verifySymlinkScenario( + `when packageJson has types field and has index.ts${scope ? " with scoped package" : ""}`, + () => ({ + bPackageJson: { + path: `${tscWatch.projectRoot}/packages/B/package.json`, + content: JSON.stringify({ + main: "lib/index.js", + types: "lib/index.d.ts", + }), + }, + aTest: file( + "A", + "index.ts", + `import { foo } from '${scope}b'; import { bar } from '${scope}b/lib/bar'; foo(); bar(); `, - ), - bFoo: file("B", "index.ts", `export function foo() { }`), - bBar: file("B", "bar.ts", `export function bar() { }`), - bSymlink: { - path: `${tscWatch.projectRoot}/node_modules/${scope}b`, - symLink: `${tscWatch.projectRoot}/packages/B`, - }, - })); + ), + bFoo: file("B", "index.ts", `export function foo() { }`), + bBar: file("B", "bar.ts", `export function bar() { }`), + bSymlink: { + path: `${tscWatch.projectRoot}/node_modules/${scope}b`, + symLink: `${tscWatch.projectRoot}/packages/B`, + }, + }), + ); - verifySymlinkScenario(`when referencing file from subFolder${scope ? " with scoped package" : ""}`, () => ({ - bPackageJson: { - path: `${tscWatch.projectRoot}/packages/B/package.json`, - content: "{}", - }, - aTest: file( - "A", - "test.ts", - `import { foo } from '${scope}b/lib/foo'; + verifySymlinkScenario( + `when referencing file from subFolder${scope ? " with scoped package" : ""}`, + () => ({ + bPackageJson: { + path: `${tscWatch.projectRoot}/packages/B/package.json`, + content: "{}", + }, + aTest: file( + "A", + "test.ts", + `import { foo } from '${scope}b/lib/foo'; import { bar } from '${scope}b/lib/bar/foo'; foo(); bar(); `, - ), - bFoo: file("B", "foo.ts", `export function foo() { }`), - bBar: file("B", "bar/foo.ts", `export function bar() { }`), - bSymlink: { - path: `${tscWatch.projectRoot}/node_modules/${scope}b`, - symLink: `${tscWatch.projectRoot}/packages/B`, - }, - })); + ), + bFoo: file("B", "foo.ts", `export function foo() { }`), + bBar: file("B", "bar/foo.ts", `export function bar() { }`), + bSymlink: { + path: `${tscWatch.projectRoot}/node_modules/${scope}b`, + symLink: `${tscWatch.projectRoot}/packages/B`, + }, + }), + ); } describe("when package is not scoped", () => { @@ -499,11 +525,24 @@ testCompositeFunction('why hello there', 42);`, path: `${tscWatch.projectRoot}/node_modules/emit-composite`, symLink: `${tscWatch.projectRoot}/packages/emit-composite`, }; - const host = createServerHost([libFile, compositeConfig, compositePackageJson, compositeIndex, compositeTestModule, consumerConfig, consumerIndex, symlink], { useCaseSensitiveFileNames: true }); + const host = createServerHost([ + libFile, + compositeConfig, + compositePackageJson, + compositeIndex, + compositeTestModule, + consumerConfig, + consumerIndex, + symlink, + ], { useCaseSensitiveFileNames: true }); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([consumerIndex], session); verifyGetErrRequest({ host, session, files: [consumerIndex] }); - baselineTsserverLogs("projectReferences", `when the referenced projects have allowJs and emitDeclarationOnly`, session); + baselineTsserverLogs( + "projectReferences", + `when the referenced projects have allowJs and emitDeclarationOnly`, + session, + ); }); it("when finding local reference doesnt load ancestor/sibling projects", () => { @@ -568,7 +607,16 @@ testCompositeFunction('why hello there', 42);`, }`, }; - const files = [libFile, solution, compilerConfig, typesFile, programFile, servicesConfig, servicesFile, libFile]; + const files = [ + libFile, + solution, + compilerConfig, + typesFile, + programFile, + servicesConfig, + servicesFile, + libFile, + ]; const host = createServerHost(files); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([programFile], session); @@ -586,7 +634,11 @@ testCompositeFunction('why hello there', 42);`, command: protocol.CommandTypes.References, arguments: protocolFileLocationFromSubstring(programFile, "getSourceFiles"), }); - baselineTsserverLogs("projectReferences", `finding local reference doesnt load ancestor/sibling projects`, session); + baselineTsserverLogs( + "projectReferences", + `finding local reference doesnt load ancestor/sibling projects`, + session, + ); }); it("when finding references in overlapping projects", () => { @@ -688,7 +740,19 @@ testCompositeFunction('why hello there', 42);`, `, }; - const files = [libFile, solutionConfig, aConfig, aFile, bConfig, bFile, cConfig, cFile, dConfig, dFile, libFile]; + const files = [ + libFile, + solutionConfig, + aConfig, + aFile, + bConfig, + bFile, + cConfig, + cFile, + dConfig, + dFile, + libFile, + ]; const host = createServerHost(files); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([bFile], session); @@ -763,7 +827,17 @@ ${usage}`, path: `${solutionLocation}/shared/src/index.ts`, content: definition, }; - const host = createServerHost([libFile, solution, libFile, apiConfig, apiFile, appConfig, appFile, sharedConfig, sharedFile]); + const host = createServerHost([ + libFile, + solution, + libFile, + apiConfig, + apiFile, + appConfig, + appFile, + sharedConfig, + sharedFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([apiFile], session); @@ -879,7 +953,16 @@ export const foo = local;`, }`, }; - const files = [libFile, solution, compilerConfig, typesFile, programFile, servicesConfig, servicesFile, libFile]; + const files = [ + libFile, + solution, + compilerConfig, + typesFile, + programFile, + servicesConfig, + servicesFile, + libFile, + ]; const host = createServerHost(files); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([programFile], session); @@ -890,7 +973,11 @@ export const foo = local;`, command: protocol.CommandTypes.References, arguments: protocolFileLocationFromSubstring(programFile, "getSourceFiles"), }); - baselineTsserverLogs("projectReferences", `with disableSolutionSearching solution and siblings are not loaded`, session); + baselineTsserverLogs( + "projectReferences", + `with disableSolutionSearching solution and siblings are not loaded`, + session, + ); }); describe("when default project is solution project", () => { @@ -918,7 +1005,8 @@ export { foo }; }; const mainDtsMap: File = { path: `${tscWatch.projectRoot}/target/src/main.d.ts.map`, - content: `{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAExC,OAAO,EAAC,GAAG,EAAC,CAAC"}`, + content: + `{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAExC,OAAO,EAAC,GAAG,EAAC,CAAC"}`, }; const helperDts: File = { path: `${tscWatch.projectRoot}/target/src/helpers/functions.d.ts`, @@ -927,7 +1015,8 @@ export { foo }; }; const helperDtsMap: File = { path: `${tscWatch.projectRoot}/target/src/helpers/functions.d.ts.map`, - content: `{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../src/helpers/functions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,GAAG,IAAI,CAAC"}`, + content: + `{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../src/helpers/functions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,GAAG,IAAI,CAAC"}`, }; const tsconfigIndirect3: File = { path: `${tscWatch.projectRoot}/indirect3/tsconfig.json`, @@ -997,7 +1086,11 @@ export function bar() {}`, const info = service.getScriptInfoForPath(main.path as Path)!; session.logger.startGroup(); session.logger.info(`getDefaultProject for ${main.path}: ${info.getDefaultProject().projectName}`); - session.logger.info(`findDefaultConfiguredProject for ${main.path}: ${service.findDefaultConfiguredProject(info)!.projectName}`); + session.logger.info( + `findDefaultConfiguredProject for ${main.path}: ${ + service.findDefaultConfiguredProject(info)!.projectName + }`, + ); session.logger.endGroup(); // Verify errors @@ -1064,7 +1157,10 @@ export function bar() {}`, const info = service.getScriptInfoForPath(main.path as Path)!; session.logger.startGroup(); session.logger.info(`getDefaultProject for ${main.path}: ${info.getDefaultProject().projectName}`); - session.logger.info(`findDefaultConfiguredProject for ${main.path}: ${service.findDefaultConfiguredProject(info)?.projectName}`); + session.logger.info( + `findDefaultConfiguredProject for ${main.path}: ${service.findDefaultConfiguredProject(info) + ?.projectName}`, + ); session.logger.endGroup(); // Verify collection of script infos @@ -1111,7 +1207,8 @@ export function bar() {}`, it("disables looking into the child project if disableReferencedProjectLoad is set in indirect project", () => { const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true }); verifyDisableReferencedProjectLoad({ - scenario: "disables looking into the child project if disableReferencedProjectLoad is set in indirect project", + scenario: + "disables looking into the child project if disableReferencedProjectLoad is set in indirect project", configRefs: ["./tsconfig-indirect1.json"], additionalFiles: [tsconfigIndirect, indirect], }); @@ -1121,7 +1218,8 @@ export function bar() {}`, const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true }); const { tsconfigIndirect: tsconfigIndirect2, indirect: indirect2 } = getIndirectProject("2"); verifyDisableReferencedProjectLoad({ - scenario: "disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", + scenario: + "disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", configRefs: ["./tsconfig-indirect1.json", "./tsconfig-indirect2.json"], additionalFiles: [tsconfigIndirect, indirect, tsconfigIndirect2, indirect2], }); @@ -1134,7 +1232,8 @@ export function bar() {}`, content: fileResolvingToMainDts.content, }; verifySolutionScenario({ - scenario: "solution with its own files and project found is not solution but references open file through project reference", + scenario: + "solution with its own files and project found is not solution but references open file through project reference", solutionFiles: [`./own/main.ts`], solutionOptions: { outDir: "./target/", @@ -1171,7 +1270,8 @@ bar;`, content: fileResolvingToMainDts.content, }; verifyDisableReferencedProjectLoad({ - scenario: "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set", + scenario: + "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set", solutionFiles: [`./own/main.ts`], solutionOptions: { outDir: "./target/", @@ -1189,9 +1289,12 @@ bar;`, content: `import { bar } from 'main'; bar;`, }; - const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true }); + const { tsconfigIndirect, indirect } = getIndirectProject("1", { + disableReferencedProjectLoad: true, + }); verifyDisableReferencedProjectLoad({ - scenario: "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set in indirect project", + scenario: + "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set in indirect project", solutionFiles: [`./own/main.ts`], solutionOptions: { outDir: "./target/", @@ -1208,10 +1311,13 @@ bar;`, content: `import { bar } from 'main'; bar;`, }; - const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true }); + const { tsconfigIndirect, indirect } = getIndirectProject("1", { + disableReferencedProjectLoad: true, + }); const { tsconfigIndirect: tsconfigIndirect2, indirect: indirect2 } = getIndirectProject("2"); verifyDisableReferencedProjectLoad({ - scenario: "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", + scenario: + "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", solutionFiles: [`./own/main.ts`], solutionOptions: { outDir: "./target/", @@ -1276,14 +1382,21 @@ bar;`, host.checkTimeoutQueueLengthAndRun(2); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ + path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); host.checkTimeoutQueueLengthAndRun(0); // Add output from new class to referenced project const class3Dts = `${tscWatch.projectRoot}/projects/project1/class3.d.ts`; host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(0); - baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is not open`, session); + baselineTsserverLogs( + "projectReferences", + `new file is added to the referenced project when referenced project is not open`, + session, + ); }); it("when referenced project is open", () => { @@ -1295,13 +1408,20 @@ bar;`, host.writeFile(class3, `class class3 {}`); host.checkTimeoutQueueLengthAndRun(3); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ + path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); host.checkTimeoutQueueLengthAndRun(0); // Add output from new class to referenced project const class3Dts = `${tscWatch.projectRoot}/projects/project1/class3.d.ts`; host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(0); - baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is open`, session); + baselineTsserverLogs( + "projectReferences", + `new file is added to the referenced project when referenced project is open`, + session, + ); }); it("when referenced project is not open with disableSourceOfProjectReferenceRedirect", () => { @@ -1316,7 +1436,10 @@ bar;`, host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ + path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); host.checkTimeoutQueueLengthAndRun(0); // Delete output from new class to referenced project host.deleteFile(class3Dts); @@ -1324,7 +1447,11 @@ bar;`, // Write back output of new class to referenced project host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); - baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is not open with disableSourceOfProjectReferenceRedirect`, session); + baselineTsserverLogs( + "projectReferences", + `new file is added to the referenced project when referenced project is not open with disableSourceOfProjectReferenceRedirect`, + session, + ); }); it("when referenced project is open with disableSourceOfProjectReferenceRedirect", () => { @@ -1340,7 +1467,10 @@ bar;`, host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ + path: `${tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); host.checkTimeoutQueueLengthAndRun(0); // Delete output from new class to referenced project host.deleteFile(class3Dts); @@ -1348,7 +1478,11 @@ bar;`, // Write back output of new class to referenced project host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); - baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is open with disableSourceOfProjectReferenceRedirect`, session); + baselineTsserverLogs( + "projectReferences", + `new file is added to the referenced project when referenced project is open with disableSourceOfProjectReferenceRedirect`, + session, + ); }); }); @@ -1411,7 +1545,17 @@ bar;`, path: `${tscWatch.projectRoot}/node_modules/shared`, symLink: `${tscWatch.projectRoot}/shared`, }; - const files = [solnConfig, sharedConfig, sharedIndex, sharedPackage, appConfig, appBar, appIndex, sharedSymlink, libFile]; + const files = [ + solnConfig, + sharedConfig, + sharedIndex, + sharedPackage, + appConfig, + appBar, + appIndex, + sharedSymlink, + libFile, + ]; const host = createServerHost(files); if (built) { tscWatch.solutionBuildWithBaseline(host, [solnConfig.path]); @@ -1430,7 +1574,13 @@ bar;`, errorCodes: [Diagnostics.Cannot_find_name_0.code], }, }); - baselineTsserverLogs("projectReferences", `auto import with referenced project${built ? " when built" : ""}${disableSourceOfProjectReferenceRedirect ? " with disableSourceOfProjectReferenceRedirect" : ""}`, session); + baselineTsserverLogs( + "projectReferences", + `auto import with referenced project${built ? " when built" : ""}${ + disableSourceOfProjectReferenceRedirect ? " with disableSourceOfProjectReferenceRedirect" : "" + }`, + session, + ); } it("when project is built", () => { @@ -1445,7 +1595,11 @@ bar;`, }); it("when files from two projects are open and one project references", () => { - function getPackageAndFile(packageName: string, references?: string[], optionsToExtend?: CompilerOptions): [file: File, config: File] { + function getPackageAndFile( + packageName: string, + references?: string[], + optionsToExtend?: CompilerOptions, + ): [file: File, config: File] { const file: File = { path: `${tscWatch.projectRoot}/${packageName}/src/file1.ts`, content: `export const ${packageName}Const = 10;`, @@ -1459,17 +1613,35 @@ bar;`, }; return [file, config]; } - const [mainFile, mainConfig] = getPackageAndFile("main", ["core", "indirect", "noCoreRef1", "indirectDisabledChildLoad1", "indirectDisabledChildLoad2", "refToCoreRef3", "indirectNoCoreRef"]); + const [mainFile, mainConfig] = getPackageAndFile("main", [ + "core", + "indirect", + "noCoreRef1", + "indirectDisabledChildLoad1", + "indirectDisabledChildLoad2", + "refToCoreRef3", + "indirectNoCoreRef", + ]); const [coreFile, coreConfig] = getPackageAndFile("core"); const [noCoreRef1File, noCoreRef1Config] = getPackageAndFile("noCoreRef1"); const [indirectFile, indirectConfig] = getPackageAndFile("indirect", ["coreRef1"]); const [coreRef1File, coreRef1Config] = getPackageAndFile("coreRef1", ["core"]); - const [indirectDisabledChildLoad1File, indirectDisabledChildLoad1Config] = getPackageAndFile("indirectDisabledChildLoad1", ["coreRef2"], { disableReferencedProjectLoad: true }); + const [indirectDisabledChildLoad1File, indirectDisabledChildLoad1Config] = getPackageAndFile( + "indirectDisabledChildLoad1", + ["coreRef2"], + { disableReferencedProjectLoad: true }, + ); const [coreRef2File, coreRef2Config] = getPackageAndFile("coreRef2", ["core"]); - const [indirectDisabledChildLoad2File, indirectDisabledChildLoad2Config] = getPackageAndFile("indirectDisabledChildLoad2", ["coreRef3"], { disableReferencedProjectLoad: true }); + const [indirectDisabledChildLoad2File, indirectDisabledChildLoad2Config] = getPackageAndFile( + "indirectDisabledChildLoad2", + ["coreRef3"], + { disableReferencedProjectLoad: true }, + ); const [coreRef3File, coreRef3Config] = getPackageAndFile("coreRef3", ["core"]); const [refToCoreRef3File, refToCoreRef3Config] = getPackageAndFile("refToCoreRef3", ["coreRef3"]); - const [indirectNoCoreRefFile, indirectNoCoreRefConfig] = getPackageAndFile("indirectNoCoreRef", ["noCoreRef2"]); + const [indirectNoCoreRefFile, indirectNoCoreRefConfig] = getPackageAndFile("indirectNoCoreRef", [ + "noCoreRef2", + ]); const [noCoreRef2File, noCoreRef2Config] = getPackageAndFile("noCoreRef2"); const host = createServerHost([ @@ -1507,7 +1679,11 @@ bar;`, command: protocol.CommandTypes.References, arguments: protocolFileLocationFromSubstring(coreFile, `coreConst`), }); - baselineTsserverLogs("projectReferences", `when files from two projects are open and one project references`, session); + baselineTsserverLogs( + "projectReferences", + `when files from two projects are open and one project references`, + session, + ); }); describe("find refs to decl in other proj", () => { @@ -1553,7 +1729,8 @@ const b: B = new B();`, const dtsMapB: File = { path: `${tscWatch.projectRoot}/b/lib/index.d.ts.map`, - content: `{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;IACV,CAAC;CACJ"}`, + content: + `{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;IACV,CAAC;CACJ"}`, }; function baselineDisableReferencedProjectLoad( @@ -1563,10 +1740,10 @@ const b: B = new B();`, dtsMapPresent: boolean, ) { // Mangled to stay under windows path length limit - const subScenario = `when proj ${projectAlreadyLoaded ? "is" : "is not"} loaded` + - ` and refd proj loading is ${disableReferencedProjectLoad ? "disabled" : "enabled"}` + - ` and proj ref redirects are ${disableSourceOfProjectReferenceRedirect ? "disabled" : "enabled"}` + - ` and a decl map is ${dtsMapPresent ? "present" : "missing"}`; + const subScenario = `when proj ${projectAlreadyLoaded ? "is" : "is not"} loaded` + + ` and refd proj loading is ${disableReferencedProjectLoad ? "disabled" : "enabled"}` + + ` and proj ref redirects are ${disableSourceOfProjectReferenceRedirect ? "disabled" : "enabled"}` + + ` and a decl map is ${dtsMapPresent ? "present" : "missing"}`; const compilerOptions: CompilerOptions = { disableReferencedProjectLoad, disableSourceOfProjectReferenceRedirect, @@ -1582,7 +1759,15 @@ const b: B = new B();`, }`, }; - const host = createServerHost([configA, indexA, configB, indexB, helperB, dtsB, ...(dtsMapPresent ? [dtsMapB] : [])]); + const host = createServerHost([ + configA, + indexA, + configB, + indexB, + helperB, + dtsB, + ...(dtsMapPresent ? [dtsMapB] : []), + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([indexA, ...(projectAlreadyLoaded ? [helperB] : [])], session); @@ -1590,7 +1775,11 @@ const b: B = new B();`, command: protocol.CommandTypes.References, arguments: protocolFileLocationFromSubstring(indexA, `B`, { index: 1 }), }); - baselineTsserverLogs("projectReferences", `find refs to decl in other proj ${subScenario}`, session); + baselineTsserverLogs( + "projectReferences", + `find refs to decl in other proj ${subScenario}`, + session, + ); }); } diff --git a/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts b/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts index 82f943be3fa48..95e8112939217 100644 --- a/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts +++ b/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts @@ -14,7 +14,9 @@ export function fn5() { } }; const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true, declarationDir: "../decls" } }), + content: JSON.stringify({ + compilerOptions: { composite: true, declarationMap: true, declarationDir: "../decls" }, + }), }; const mainTs: File = { @@ -100,9 +102,18 @@ fn5(); equal: boolean, debugInfo?: string, ) { - assert.strictEqual(session.getProjectService().filenameToScriptInfo.get(dtsMapPath), dependencyMap, `${debugInfo} dependencyMap`); + assert.strictEqual( + session.getProjectService().filenameToScriptInfo.get(dtsMapPath), + dependencyMap, + `${debugInfo} dependencyMap`, + ); if (dependencyMap) { - verifyEquality(dependencyMap.documentPositionMapper, documentPositionMapper, equal, `${debugInfo} DocumentPositionMapper`); + verifyEquality( + dependencyMap.documentPositionMapper, + documentPositionMapper, + equal, + `${debugInfo} DocumentPositionMapper`, + ); } } @@ -157,7 +168,12 @@ fn5(); } } verifyEquality(dtsMapInfo, existingDependencyMap, existingMapEqual, `${debugInfo} dependencyMap`); - verifyEquality(existingDocumentPositionMapper, dtsMapInfo?.documentPositionMapper, existingDocumentPositionMapperEqual, `${debugInfo} DocumentPositionMapper`); + verifyEquality( + existingDocumentPositionMapper, + dtsMapInfo?.documentPositionMapper, + existingDocumentPositionMapperEqual, + `${debugInfo} DocumentPositionMapper`, + ); sourceMapPath = dtsInfo?.sourceMapFilePath; dependencyMap = dtsMapInfo; documentPositionMapper = dependencyMap?.documentPositionMapper; @@ -191,7 +207,11 @@ fn5(); type OnHostCreate = (host: TestServerHost) => void; type CreateSessionFn = (onHostCreate?: OnHostCreate) => { host: TestServerHost; session: TestSession; }; - function setupWith(createSession: CreateSessionFn, openFiles: readonly File[], onHostCreate: OnHostCreate | undefined) { + function setupWith( + createSession: CreateSessionFn, + openFiles: readonly File[], + onHostCreate: OnHostCreate | undefined, + ) { const result = createSession(onHostCreate); openFilesForSession(openFiles, result.session); return result; @@ -205,7 +225,10 @@ fn5(); return setupWith(createSession, [dependencyTs, randomFile], onHostCreate); } - function setupWithMainTsAndDependencyTs(createSession: CreateSessionFn, onHostCreate: OnHostCreate | undefined) { + function setupWithMainTsAndDependencyTs( + createSession: CreateSessionFn, + onHostCreate: OnHostCreate | undefined, + ) { return setupWith(createSession, [mainTs, dependencyTs, randomFile], onHostCreate); } @@ -284,7 +307,10 @@ fn5(); } describe("from project that uses dependency: goToDef", () => { - function setupWithActionWith(setup: (onHostCreate?: OnHostCreate) => ReturnType, onHostCreate: OnHostCreate | undefined) { + function setupWithActionWith( + setup: (onHostCreate?: OnHostCreate) => ReturnType, + onHostCreate: OnHostCreate | undefined, + ) { const result = setup(onHostCreate); result.session.executeCommandSeq(goToDefFromMainTs(1)); return { ...result, ...getDocumentPositionMapper(result.session) }; @@ -310,7 +336,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/can go to definition correctly", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/can go to definition correctly", + session, + ); }); // Edit @@ -332,7 +362,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/usage file changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/usage file changes with timeout before request", + session, + ); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -350,7 +384,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/usage file changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/usage file changes", + session, + ); }); // Edit dts to add new fn @@ -372,7 +410,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts changes with timeout before request", + session, + ); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -390,7 +432,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts changes", + session, + ); }); // Edit map file to represent added new line @@ -412,7 +458,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap changes with timeout before request", + session, + ); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -430,7 +480,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap changes", + session, + ); }); it(`with depedency files map file, when file is not present`, () => { @@ -445,7 +499,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -464,7 +522,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -480,7 +542,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -495,7 +561,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -514,7 +584,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -530,7 +604,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts deleted", + session, + ); }); }); describe("when main tsconfig has project reference", () => { @@ -553,7 +631,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/can go to definition correctly", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/can go to definition correctly", + session, + ); }); // Edit @@ -575,7 +657,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/usage file changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/usage file changes with timeout before request", + session, + ); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -593,7 +679,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/usage file changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/usage file changes", + session, + ); }); // Edit dts to add new fn @@ -615,7 +705,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts changes with timeout before request", + session, + ); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -633,7 +727,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts changes", + session, + ); }); // Edit map file to represent added new line @@ -655,7 +753,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap changes with timeout before request", + session, + ); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -673,7 +775,11 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap changes", + session, + ); }); it(`with depedency files map file, when file is not present`, () => { @@ -688,7 +794,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -707,7 +817,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -723,7 +837,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -738,7 +856,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -757,7 +879,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -773,7 +899,11 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts deleted", + session, + ); }); it(`when defining project source changes, when timeout occurs before request`, () => { // Create DocumentPositionMapper @@ -798,7 +928,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency source changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency source changes with timeout before request", + session, + ); }); it(`when defining project source changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -821,7 +955,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency source changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency source changes", + session, + ); }); it("when projects are not built", () => { @@ -837,7 +975,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/when projects are not built", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/when projects are not built", + session, + ); }); }); describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => { @@ -860,7 +1002,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/can go to definition correctly", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/can go to definition correctly", + session, + ); }); // Edit @@ -882,7 +1028,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/usage file changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/usage file changes with timeout before request", + session, + ); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -900,7 +1050,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/usage file changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/usage file changes", + session, + ); }); // Edit dts to add new fn @@ -922,7 +1076,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts changes with timeout before request", + session, + ); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -940,7 +1098,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts changes", + session, + ); }); // Edit map file to represent added new line @@ -962,7 +1124,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap changes with timeout before request", + session, + ); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -980,7 +1146,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap changes", + session, + ); }); it(`with depedency files map file, when file is not present`, () => { @@ -995,7 +1165,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1014,7 +1188,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1030,7 +1208,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1045,7 +1227,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1064,7 +1250,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1080,13 +1270,20 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts deleted", + session, + ); }); }); }); describe("from defining project: rename", () => { - function setupWithActionWith(setup: (onHostCreate?: OnHostCreate) => ReturnType, onHostCreate: OnHostCreate | undefined) { + function setupWithActionWith( + setup: (onHostCreate?: OnHostCreate) => ReturnType, + onHostCreate: OnHostCreate | undefined, + ) { const result = setup(onHostCreate); result.session.executeCommandSeq(renameFromDependencyTs(1)); return { ...result, ...getDocumentPositionMapper(result.session) }; @@ -1112,7 +1309,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/rename locations", + session, + ); }); // Edit @@ -1134,7 +1335,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/usage file changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/usage file changes with timeout before request", + session, + ); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1152,7 +1357,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/usage file changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/usage file changes", + session, + ); }); // Edit dts to add new fn @@ -1174,7 +1383,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts changes with timeout before request", + session, + ); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1192,7 +1405,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts changes", + session, + ); }); // Edit map file to represent added new line @@ -1214,7 +1431,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap changes with timeout before request", + session, + ); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1232,7 +1453,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap changes", + session, + ); }); it(`with depedency files map file, when file is not present`, () => { @@ -1247,7 +1472,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1266,7 +1495,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1282,7 +1515,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1297,7 +1534,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1316,7 +1557,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1332,7 +1577,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts deleted", + session, + ); }); }); describe("when main tsconfig has project reference", () => { @@ -1355,7 +1604,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/rename locations", + session, + ); }); // Edit @@ -1377,7 +1630,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/usage file changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/usage file changes with timeout before request", + session, + ); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1395,7 +1652,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/usage file changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/usage file changes", + session, + ); }); // Edit dts to add new fn @@ -1417,7 +1678,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts changes with timeout before request", + session, + ); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1435,7 +1700,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts changes", + session, + ); }); // Edit map file to represent added new line @@ -1457,7 +1726,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap changes with timeout before request", + session, + ); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1475,7 +1748,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap changes", + session, + ); }); it(`with depedency files map file, when file is not present`, () => { @@ -1490,7 +1767,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1509,7 +1790,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1525,7 +1810,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1540,7 +1829,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1559,7 +1852,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1575,7 +1872,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts deleted", + session, + ); }); it(`when defining project source changes, when timeout occurs before request`, () => { // Create DocumentPositionMapper @@ -1607,7 +1908,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency source changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency source changes with timeout before request", + session, + ); }); it(`when defining project source changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1637,7 +1942,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency source changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency source changes", + session, + ); }); it("when projects are not built", () => { @@ -1653,7 +1962,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/when projects are not built", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/when projects are not built", + session, + ); }); }); describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => { @@ -1676,7 +1989,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/rename locations", + session, + ); }); // Edit @@ -1698,7 +2015,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/usage file changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/usage file changes with timeout before request", + session, + ); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1716,7 +2037,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/usage file changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/usage file changes", + session, + ); }); // Edit dts to add new fn @@ -1738,7 +2063,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts changes with timeout before request", + session, + ); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1756,7 +2085,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts changes", + session, + ); }); // Edit map file to represent added new line @@ -1778,7 +2111,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap changes with timeout before request", + session, + ); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1796,7 +2133,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap changes", + session, + ); }); it(`with depedency files map file, when file is not present`, () => { @@ -1811,7 +2152,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1830,7 +2175,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1846,7 +2195,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1861,7 +2214,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1880,7 +2237,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1896,13 +2257,20 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts deleted", + session, + ); }); }); }); describe("when opening depedency and usage project: goToDef and rename", () => { - function setupWithActionWith(setup: (onHostCreate?: OnHostCreate) => ReturnType, onHostCreate: OnHostCreate | undefined) { + function setupWithActionWith( + setup: (onHostCreate?: OnHostCreate) => ReturnType, + onHostCreate: OnHostCreate | undefined, + ) { const result = setup(onHostCreate); result.session.executeCommandSeq(goToDefFromMainTs(1)); result.session.executeCommandSeq(renameFromDependencyTs(1)); @@ -1938,7 +2306,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/goToDef and rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/goToDef and rename locations", + session, + ); }); // Edit @@ -1969,7 +2341,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/usage file changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/usage file changes with timeout before request", + session, + ); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1996,7 +2372,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/usage file changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/usage file changes", + session, + ); }); // Edit dts to add new fn @@ -2026,7 +2406,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts changes with timeout before request", + session, + ); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2052,7 +2436,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts changes", + session, + ); }); // Edit map file to represent added new line @@ -2083,7 +2471,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap changes with timeout before request", + session, + ); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2110,7 +2502,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap changes", + session, + ); }); it(`with depedency files map file, when file is not present`, () => { @@ -2133,7 +2529,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2151,7 +2551,8 @@ ${dependencyTs.content}`, /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, @@ -2161,7 +2562,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2176,7 +2581,8 @@ ${dependencyTs.content}`, /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, @@ -2186,7 +2592,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -2208,7 +2618,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2226,7 +2640,8 @@ ${dependencyTs.content}`, /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, @@ -2236,7 +2651,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2260,7 +2679,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts deleted", + session, + ); }); }); describe("when main tsconfig has project reference", () => { @@ -2291,7 +2714,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/gotoDef and rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/gotoDef and rename locations", + session, + ); }); // Edit @@ -2322,7 +2749,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/usage file changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/usage file changes with timeout before request", + session, + ); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2349,7 +2780,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/usage file changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/usage file changes", + session, + ); }); // Edit dts to add new fn @@ -2379,7 +2814,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts changes with timeout before request", + session, + ); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2405,7 +2844,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts changes", + session, + ); }); // Edit map file to represent added new line @@ -2435,7 +2878,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap changes with timeout before request", + session, + ); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2461,7 +2908,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap changes", + session, + ); }); it(`with depedency files map file, when file is not present`, () => { @@ -2484,7 +2935,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2512,7 +2967,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2537,7 +2996,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -2560,7 +3023,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2587,7 +3054,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2611,7 +3082,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts deleted", + session, + ); }); it(`when defining project source changes, when timeout occurs before request`, () => { // Create DocumentPositionMapper @@ -2651,7 +3126,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency source changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency source changes with timeout before request", + session, + ); }); it(`when defining project source changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2689,7 +3168,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency source changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency source changes", + session, + ); }); it("when projects are not built", () => { @@ -2713,7 +3196,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/when projects are not built", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/when projects are not built", + session, + ); }); }); describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => { @@ -2745,7 +3232,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/gotoDef and rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/gotoDef and rename locations", + session, + ); }); // Edit @@ -2776,7 +3267,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/usage file changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/usage file changes with timeout before request", + session, + ); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2803,7 +3298,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/usage file changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/usage file changes", + session, + ); }); // Edit dts to add new fn @@ -2833,7 +3332,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts changes with timeout before request", + session, + ); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2859,7 +3362,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts changes", + session, + ); }); // Edit map file to represent added new line @@ -2890,7 +3397,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes with timeout before request", + session, + ); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2917,7 +3428,11 @@ ${dependencyTs.content}`, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes", + session, + ); }); it(`with depedency files map file, when file is not present`, () => { @@ -2940,7 +3455,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2958,7 +3477,8 @@ ${dependencyTs.content}`, /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, @@ -2968,7 +3488,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2983,7 +3507,8 @@ ${dependencyTs.content}`, /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, @@ -2993,7 +3518,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -3016,7 +3545,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -3034,7 +3567,8 @@ ${dependencyTs.content}`, /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, @@ -3044,7 +3578,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -3068,7 +3606,11 @@ ${dependencyTs.content}`, /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts deleted", + session, + ); }); }); }); diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index 822e2a793c912..d7f66c291ce47 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -77,15 +77,27 @@ namespace ts.projectSystem { const host = createServerHost([file1, file2, file3]); const projectService = createProjectService(host); - projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path]), options: {}, projectFileName: proj1name }); + projectService.openExternalProject({ + rootFiles: toExternalFiles([file1.path]), + options: {}, + projectFileName: proj1name, + }); const proj1 = projectService.findProject(proj1name)!; assert.isTrue(proj1.languageServiceEnabled); - projectService.openExternalProject({ rootFiles: toExternalFiles([file2.path]), options: {}, projectFileName: proj2name }); + projectService.openExternalProject({ + rootFiles: toExternalFiles([file2.path]), + options: {}, + projectFileName: proj2name, + }); const proj2 = projectService.findProject(proj2name)!; assert.isTrue(proj2.languageServiceEnabled); - projectService.openExternalProject({ rootFiles: toExternalFiles([file3.path]), options: {}, projectFileName: proj3name }); + projectService.openExternalProject({ + rootFiles: toExternalFiles([file3.path]), + options: {}, + projectFileName: proj3name, + }); const proj3 = projectService.findProject(proj3name)!; assert.isFalse(proj3.languageServiceEnabled); }); @@ -107,7 +119,11 @@ namespace ts.projectSystem { const host = createServerHost([file1, file2]); const projectService = createProjectService(host, { useSingleInferredProject: true, eventHandler: noop }); - projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path, file2.path]), options: {}, projectFileName: projName }); + projectService.openExternalProject({ + rootFiles: toExternalFiles([file1.path, file2.path]), + options: {}, + projectFileName: projName, + }); const proj1 = projectService.findProject(projName)!; assert.isFalse(proj1.languageServiceEnabled); @@ -189,7 +205,9 @@ namespace ts.projectSystem { const host = createServerHost([file1, config1]); const projectService = createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true }); - projectService.applyChangesInOpenFiles(singleIterator({ fileName: file1.path, content: file1.content })); + projectService.applyChangesInOpenFiles( + singleIterator({ fileName: file1.path, content: file1.content }), + ); checkNumberOfProjects(projectService, { inferredProjects: 1 }); const proj = projectService.inferredProjects[0]; @@ -211,7 +229,11 @@ namespace ts.projectSystem { const host = createServerHost([f1, f2, libFile]); const service = createProjectService(host); - service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: toExternalFiles([f1.path, f2.path]), options: {} }); + service.openExternalProject({ + projectFileName: "/a/b/project", + rootFiles: toExternalFiles([f1.path, f2.path]), + options: {}, + }); service.openClientFile(f1.path); service.openClientFile(f2.path, "let x: string"); @@ -219,13 +241,24 @@ namespace ts.projectSystem { service.checkNumberOfProjects({ externalProjects: 1 }); checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]); - const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, emptyOptions)!; + const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition( + f1.path, + 2, + emptyOptions, + )!; // should contain completions for string assert.isTrue(completions1.entries.some(e => e.name === "charAt"), "should contain 'charAt'"); - assert.isFalse(completions1.entries.some(e => e.name === "toExponential"), "should not contain 'toExponential'"); + assert.isFalse( + completions1.entries.some(e => e.name === "toExponential"), + "should not contain 'toExponential'", + ); service.closeClientFile(f2.path); - const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, emptyOptions)!; + const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition( + f1.path, + 2, + emptyOptions, + )!; // should contain completions for string assert.isFalse(completions2.entries.some(e => e.name === "charAt"), "should not contain 'charAt'"); assert.isTrue(completions2.entries.some(e => e.name === "toExponential"), "should contain 'toExponential'"); @@ -243,7 +276,11 @@ namespace ts.projectSystem { const host = createServerHost([f1, f2, libFile]); const service = createProjectService(host); - service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: [{ fileName: f1.path }, { fileName: f2.path, hasMixedContent: true }], options: {} }); + service.openExternalProject({ + projectFileName: "/a/b/project", + rootFiles: [{ fileName: f1.path }, { fileName: f2.path, hasMixedContent: true }], + options: {}, + }); service.openClientFile(f1.path); service.openClientFile(f2.path, "let somelongname: string"); @@ -251,12 +288,23 @@ namespace ts.projectSystem { service.checkNumberOfProjects({ externalProjects: 1 }); checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]); - const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, emptyOptions)!; + const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition( + f1.path, + 0, + emptyOptions, + )!; assert.isTrue(completions1.entries.some(e => e.name === "somelongname"), "should contain 'somelongname'"); service.closeClientFile(f2.path); - const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, emptyOptions)!; - assert.isFalse(completions2.entries.some(e => e.name === "somelongname"), "should not contain 'somelongname'"); + const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition( + f1.path, + 0, + emptyOptions, + )!; + assert.isFalse( + completions2.entries.some(e => e.name === "somelongname"), + "should not contain 'somelongname'", + ); const sf2 = service.externalProjects[0].getLanguageService().getProgram()!.getSourceFile(f2.path)!; assert.equal(sf2.text, ""); }); @@ -344,7 +392,11 @@ namespace ts.projectSystem { const host = createServerHost([file1, office, customTypesMap]); const projectService = createProjectService(host); try { - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, office.path]) }); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles([file1.path, office.path]), + }); const proj = projectService.externalProjects[0]; assert.deepEqual(proj.getFileNames(/*excludeFilesFromExternalLibraries*/ true), [file1.path]); assert.deepEqual(proj.getTypeAcquisition().include, ["duck-types"]); @@ -375,7 +427,14 @@ namespace ts.projectSystem { installPackage: notImplemented, enqueueInstallTypingsRequest: (proj, typeAcquisition, unresolvedImports) => { assert.isUndefined(request); - request = JSON.stringify(server.createInstallTypingsRequest(proj, typeAcquisition, unresolvedImports || server.emptyArray, cachePath)); + request = JSON.stringify( + server.createInstallTypingsRequest( + proj, + typeAcquisition, + unresolvedImports || server.emptyArray, + cachePath, + ), + ); }, attach: noop, onProjectClosed: noop, @@ -384,7 +443,11 @@ namespace ts.projectSystem { const projectName = "project"; const projectService = createProjectService(host, { typingsInstaller }); - projectService.openExternalProject({ projectFileName: projectName, options: {}, rootFiles: toExternalFiles([file1.path, constructorFile.path, bliss.path]) }); + projectService.openExternalProject({ + projectFileName: projectName, + options: {}, + rootFiles: toExternalFiles([file1.path, constructorFile.path, bliss.path]), + }); assert.equal( request, JSON.stringify({ @@ -446,7 +509,11 @@ namespace ts.projectSystem { const host = createServerHost(files); const projectService = createProjectService(host); try { - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles(files.map(f => f.path)) }); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles(files.map(f => f.path)), + }); const proj = projectService.externalProjects[0]; assert.deepEqual(proj.getFileNames(/*excludeFilesFromExternalLibraries*/ true), [file1.path]); assert.deepEqual(proj.getTypeAcquisition().include, ["kendo-ui", "office"]); @@ -488,7 +555,12 @@ namespace ts.projectSystem { const host = createServerHost([file1, file2, file3, customTypesMap]); const projectService = createProjectService(host); try { - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, file2.path]), typeAcquisition: { enable: true } }); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles([file1.path, file2.path]), + typeAcquisition: { enable: true }, + }); const proj = projectService.externalProjects[0]; assert.deepEqual(proj.getFileNames(), [file2.path]); } @@ -577,7 +649,9 @@ namespace ts.projectSystem { const projectService = createProjectService(host); projectService.applyChangesInOpenFiles(singleIterator(tsFile)); const projs = projectService.synchronizeProjectList([]); - projectService.findProject(projs[0].info!.projectName)!.getLanguageService().getNavigationBarItems(tsFile.fileName); + projectService.findProject(projs[0].info!.projectName)!.getLanguageService().getNavigationBarItems( + tsFile.fileName, + ); projectService.synchronizeProjectList([projs[0].info!]); projectService.applyChangesInOpenFiles(singleIterator(jsFile)); }); @@ -684,12 +758,19 @@ namespace ts.projectSystem { // Specify .html extension as mixed content const extraFileExtensions = [{ extension: ".html", scriptKind: ScriptKind.JS, isMixedContent: true }]; - const configureHostRequest = makeSessionRequest(CommandNames.Configure, { extraFileExtensions }); + const configureHostRequest = makeSessionRequest( + CommandNames.Configure, + { extraFileExtensions }, + ); session.executeCommand(configureHostRequest); // The configured project should now be updated to include html file checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(configuredProjectAt(projectService, 0), configuredProj, "Same configured project should be updated"); + assert.strictEqual( + configuredProjectAt(projectService, 0), + configuredProj, + "Same configured project should be updated", + ); checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); // Open HTML file @@ -706,7 +787,10 @@ namespace ts.projectSystem { // Check identifiers defined in HTML content are available in .ts file const project = configuredProjectAt(projectService, 0); let completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 1, emptyOptions); - assert(completions && some(completions.entries, e => e.name === "hello"), `expected entry hello to be in completion list`); + assert( + completions && some(completions.entries, e => e.name === "hello"), + `expected entry hello to be in completion list`, + ); // Close HTML file projectService.applyChangesInOpenFiles( @@ -739,12 +823,17 @@ namespace ts.projectSystem { content: JSON.stringify({ compilerOptions: { allowJs: true } }), }; - let host = createServerHost([file1, file2, config1, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + let host = createServerHost([file1, file2, config1, libFile], { + executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js"), + }); let session = createSession(host); // Specify .html extension as mixed content in a configure host request const extraFileExtensions = [{ extension: ".html", scriptKind: ScriptKind.JS, isMixedContent: true }]; - const configureHostRequest = makeSessionRequest(CommandNames.Configure, { extraFileExtensions }); + const configureHostRequest = makeSessionRequest( + CommandNames.Configure, + { extraFileExtensions }, + ); session.executeCommand(configureHostRequest); openFilesForSession([file1], session); @@ -752,7 +841,8 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1 }); - let diagnostics = configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); + let diagnostics = configuredProjectAt(projectService, 0).getLanguageService() + .getCompilerOptionsDiagnostics(); assert.deepEqual(diagnostics, []); // #2. Ensure no errors when allowJs is false @@ -761,7 +851,9 @@ namespace ts.projectSystem { content: JSON.stringify({ compilerOptions: { allowJs: false } }), }; - host = createServerHost([file1, file2, config2, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + host = createServerHost([file1, file2, config2, libFile], { + executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js"), + }); session = createSession(host); session.executeCommand(configureHostRequest); @@ -780,7 +872,9 @@ namespace ts.projectSystem { content: JSON.stringify({}), }; - host = createServerHost([file1, file2, config3, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + host = createServerHost([file1, file2, config3, libFile], { + executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js"), + }); session = createSession(host); session.executeCommand(configureHostRequest); @@ -799,7 +893,9 @@ namespace ts.projectSystem { content: JSON.stringify({ compilerOptions: { allowJs: true }, files: [file1.path, file2.path] }), }; - host = createServerHost([file1, file2, config4, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + host = createServerHost([file1, file2, config4, libFile], { + executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js"), + }); session = createSession(host); session.executeCommand(configureHostRequest); @@ -818,7 +914,9 @@ namespace ts.projectSystem { content: JSON.stringify({ compilerOptions: { allowJs: true }, exclude: [file2.path] }), }; - host = createServerHost([file1, file2, config5, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + host = createServerHost([file1, file2, config5, libFile], { + executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js"), + }); session = createSession(host); session.executeCommand(configureHostRequest); @@ -850,7 +948,10 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { inferredProjects: 1 }); projectService.applyChangesInOpenFiles( /*openFiles*/ undefined, - /*changedFiles*/ singleIterator({ fileName: file1.path, changes: singleIterator({ span: createTextSpan(0, file1.path.length), newText: "let y = 1" }) }), + /*changedFiles*/ singleIterator({ + fileName: file1.path, + changes: singleIterator({ span: createTextSpan(0, file1.path.length), newText: "let y = 1" }), + }), /*closedFiles*/ undefined, ); @@ -867,7 +968,11 @@ namespace ts.projectSystem { const host = createServerHost([file1]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); const projectFileName = "projectFileName"; - projectService.openExternalProject({ projectFileName, options: {}, rootFiles: [{ fileName: file1.path, scriptKind: ScriptKind.JS, hasMixedContent: true }] }); + projectService.openExternalProject({ + projectFileName, + options: {}, + rootFiles: [{ fileName: file1.path, scriptKind: ScriptKind.JS, hasMixedContent: true }], + }); const project = projectService.externalProjects[0]; @@ -899,10 +1004,14 @@ namespace ts.projectSystem { const projectService = createProjectService(host, { useSingleInferredProject: true }); projectService.setCompilerOptionsForInferredProjects({ target: ScriptTarget.ES5, allowJs: false }); projectService.openClientFile(file1.path); - projectService.inferredProjects[0].getLanguageService(/*ensureSynchronized*/ false).getOutliningSpans(file1.path); + projectService.inferredProjects[0].getLanguageService(/*ensureSynchronized*/ false).getOutliningSpans( + file1.path, + ); projectService.setCompilerOptionsForInferredProjects({ target: ScriptTarget.ES5, allowJs: true }); projectService.getScriptInfo(file1.path)!.editContent(0, 0, " "); - projectService.inferredProjects[0].getLanguageService(/*ensureSynchronized*/ false).getOutliningSpans(file1.path); + projectService.inferredProjects[0].getLanguageService(/*ensureSynchronized*/ false).getOutliningSpans( + file1.path, + ); projectService.closeClientFile(file1.path); }); @@ -943,8 +1052,16 @@ namespace ts.projectSystem { assert.isTrue(project2.hasOpenRef(), "Has open ref count in project2 - 2"); // file1 assert.isFalse(project2.isClosed()); - assert.equal(project1.getScriptInfo(file1.path)!.containingProjects.length, 2, `${file1.path} containing projects count`); - assert.equal(project1.getScriptInfo(file2.path)!.containingProjects.length, 1, `${file2.path} containing projects count`); + assert.equal( + project1.getScriptInfo(file1.path)!.containingProjects.length, + 2, + `${file1.path} containing projects count`, + ); + assert.equal( + project1.getScriptInfo(file2.path)!.containingProjects.length, + 1, + `${file2.path} containing projects count`, + ); projectService.closeClientFile(file2.path); checkNumberOfProjects(projectService, { configuredProjects: 2 }); @@ -989,12 +1106,15 @@ namespace ts.projectSystem { projectService.openClientFile(f1.path, "let x = 1;\nlet y = 2;"); projectService.checkNumberOfProjects({ externalProjects: 1 }); - projectService.externalProjects[0].getLanguageService(/*ensureSynchronized*/ false).getNavigationBarItems(f1.path); + projectService.externalProjects[0].getLanguageService(/*ensureSynchronized*/ false).getNavigationBarItems( + f1.path, + ); projectService.closeClientFile(f1.path); projectService.openClientFile(f1.path); projectService.checkNumberOfProjects({ externalProjects: 1 }); - const navbar = projectService.externalProjects[0].getLanguageService(/*ensureSynchronized*/ false).getNavigationBarItems(f1.path); + const navbar = projectService.externalProjects[0].getLanguageService(/*ensureSynchronized*/ false) + .getNavigationBarItems(f1.path); assert.equal(navbar[0].spans[0].length, f1.content.length); }); @@ -1028,7 +1148,11 @@ namespace ts.projectSystem { files: [f1.path], }, } as protocol.GeterrRequest); - baselineTsserverLogs("projects", "getting errors from closed script info does not throw exception because of getting project from orphan script info", session); + baselineTsserverLogs( + "projects", + "getting errors from closed script info does not throw exception because of getting project from orphan script info", + session, + ); }); it("Properly handle Windows-style outDir", () => { @@ -1187,8 +1311,15 @@ namespace ts.projectSystem { }); // Configure the deferred extension. - const extraFileExtensions = [{ extension: ".deferred", scriptKind: ScriptKind.Deferred, isMixedContent: true }]; - const configureHostRequest = makeSessionRequest(CommandNames.Configure, { extraFileExtensions }); + const extraFileExtensions = [{ + extension: ".deferred", + scriptKind: ScriptKind.Deferred, + isMixedContent: true, + }]; + const configureHostRequest = makeSessionRequest( + CommandNames.Configure, + { extraFileExtensions }, + ); session.executeCommand(configureHostRequest); // Open external project @@ -1242,7 +1373,12 @@ namespace ts.projectSystem { const host = createServerHost(files); const service = createProjectService(host); service.openClientFile(file1.path); - checkProjectActualFiles(service.configuredProjects.get(config.path)!, [file1.path, file2.path, libFile.path, config.path]); + checkProjectActualFiles(service.configuredProjects.get(config.path)!, [ + file1.path, + file2.path, + libFile.path, + config.path, + ]); const configContent2 = JSON.stringify({ files: ["src/file1.ts"], @@ -1251,14 +1387,22 @@ namespace ts.projectSystem { host.writeFile(config.path, config.content); host.runQueuedTimeoutCallbacks(); - checkProjectActualFiles(service.configuredProjects.get(config.path)!, [file1.path, libFile.path, config.path]); + checkProjectActualFiles(service.configuredProjects.get(config.path)!, [ + file1.path, + libFile.path, + config.path, + ]); verifyFile2InfoIsOrphan(); file2.content += "export let z = 10;"; host.writeFile(file2.path, file2.content); host.runQueuedTimeoutCallbacks(); - checkProjectActualFiles(service.configuredProjects.get(config.path)!, [file1.path, libFile.path, config.path]); + checkProjectActualFiles(service.configuredProjects.get(config.path)!, [ + file1.path, + libFile.path, + config.path, + ]); verifyFile2InfoIsOrphan(); function verifyFile2InfoIsOrphan() { @@ -1323,7 +1467,10 @@ namespace ts.projectSystem { const projectService = createProjectService(host); projectService.openClientFile(fileA.path); projectService.openClientFile(fileB.path); - const knownProjects = projectService.synchronizeProjectList([], /*includeProjectReferenceRedirectInfo*/ true); + const knownProjects = projectService.synchronizeProjectList( + [], + /*includeProjectReferenceRedirectInfo*/ true, + ); assert.deepEqual(knownProjects[0].files, [ { fileName: libFile.path, @@ -1398,7 +1545,10 @@ namespace ts.projectSystem { const projectService = createProjectService(host); projectService.openClientFile(fileA.path); projectService.openClientFile(fileB.path); - const knownProjects = projectService.synchronizeProjectList([], /*includeProjectReferenceRedirectInfo*/ true); + const knownProjects = projectService.synchronizeProjectList( + [], + /*includeProjectReferenceRedirectInfo*/ true, + ); assert.deepEqual(knownProjects[0].files, [ { fileName: libFile.path, @@ -1445,7 +1595,10 @@ namespace ts.projectSystem { ] }`, ); - const newKnownProjects = projectService.synchronizeProjectList(knownProjects.map(proj => proj.info!), /*includeProjectReferenceRedirectInfo*/ true); + const newKnownProjects = projectService.synchronizeProjectList( + knownProjects.map(proj => proj.info!), + /*includeProjectReferenceRedirectInfo*/ true, + ); assert.deepEqual(newKnownProjects[0].changes?.added, [ { fileName: fileB2.path, @@ -1472,7 +1625,10 @@ namespace ts.projectSystem { const host = createServerHost([file, config, libFile]); const projectService = createProjectService(host); projectService.openClientFile(file.path); - const knownProjects = projectService.synchronizeProjectList([], /*includeProjectReferenceRedirectInfo*/ false); + const knownProjects = projectService.synchronizeProjectList( + [], + /*includeProjectReferenceRedirectInfo*/ false, + ); assert.deepEqual(knownProjects[0].files, [ libFile.path, file.path, @@ -1493,7 +1649,10 @@ namespace ts.projectSystem { const host = createServerHost([file, config, libFile]); const projectService = createProjectService(host); projectService.openClientFile(file.path); - const knownProjects = projectService.synchronizeProjectList([], /*includeProjectReferenceRedirectInfo*/ true); + const knownProjects = projectService.synchronizeProjectList( + [], + /*includeProjectReferenceRedirectInfo*/ true, + ); assert.deepEqual(knownProjects[0].files, [ { fileName: libFile.path, isSourceOfProjectReferenceRedirect: false }, { fileName: file.path, isSourceOfProjectReferenceRedirect: false }, @@ -1522,7 +1681,11 @@ namespace ts.projectSystem { }; const files = [fileSubA, fileB, config, libFile]; const host = createServerHost(files); - const session = createSession(host, { canUseEvents: true, noGetErrOnBackgroundUpdate: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + canUseEvents: true, + noGetErrOnBackgroundUpdate: true, + logger: createLoggerWithInMemoryLogs(host), + }); openFile(fileB); openFile(fileSubA); @@ -1577,13 +1740,21 @@ namespace ts.projectSystem { const project = service.inferredProjects[0]; checkProjectActualFiles(project, [commonFile1.path, libFile.path]); // Intentionally create scriptinfo and attach it to project - const info = service.getOrCreateScriptInfoForNormalizedPath(commonFile2.path as server.NormalizedPath, /*openedByClient*/ false)!; + const info = service.getOrCreateScriptInfoForNormalizedPath( + commonFile2.path as server.NormalizedPath, + /*openedByClient*/ false, + )!; info.attachToProject(project); try { - service.applyChangesInOpenFiles(/*openFiles*/ undefined, /*changedFiles*/ undefined, [commonFile1.path]); + service.applyChangesInOpenFiles(/*openFiles*/ undefined, /*changedFiles*/ undefined, [ + commonFile1.path, + ]); } catch (e) { - assert.isTrue(e.message.indexOf("Debug Failure. False expression: Found script Info still attached to project") === 0); + assert.isTrue( + e.message.indexOf("Debug Failure. False expression: Found script Info still attached to project") + === 0, + ); } }); it("does not look beyond node_modules folders for default configured projects", () => { @@ -1611,13 +1782,21 @@ namespace ts.projectSystem { assert.isUndefined(openNodeModulesFileResult2.configFileName); const rootProject = projectService.findProject(rootProjectPath)!; - checkProjectActualFiles(rootProject, [rootProjectPath, rootFilePath, nodeModulesFilePath1, nodeModulesFilePath2]); + checkProjectActualFiles(rootProject, [ + rootProjectPath, + rootFilePath, + nodeModulesFilePath1, + nodeModulesFilePath2, + ]); checkNumberOfInferredProjects(projectService, 0); }); describe("file opened is in configured project that will be removed", () => { - function runOnTs(scenario: string, getRequest: (innerFile: File) => Partial) { + function runOnTs( + scenario: string, + getRequest: (innerFile: File) => Partial, + ) { it(scenario, () => { const testsConfig: File = { path: `${tscWatch.projectRoot}/playground/tsconfig.json`, @@ -1641,7 +1820,14 @@ namespace ts.projectSystem { path: `${tscWatch.projectRoot}/playground/tsconfig-json/src/src.ts`, content: `export function foobar() { }`, }; - const host = createServerHost([testsConfig, testsFile, innerFile, innerConfig, innerSrcFile, libFile]); + const host = createServerHost([ + testsConfig, + testsFile, + innerFile, + innerConfig, + innerSrcFile, + libFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([testsFile], session); closeFilesForSession([testsFile], session); @@ -1695,7 +1881,11 @@ namespace ts.projectSystem { openFilesForSession([mocksFile], session); closeFilesForSession([mocksFile], session); openFilesForSession([innerFile], session); - baselineTsserverLogs("projects", "js file opened is in configured project that will be removed", session); + baselineTsserverLogs( + "projects", + "js file opened is in configured project that will be removed", + session, + ); }); }); }); diff --git a/src/testRunner/unittests/tsserver/projectsWithReferences.ts b/src/testRunner/unittests/tsserver/projectsWithReferences.ts index fac602bf93090..f569fe6b3815a 100644 --- a/src/testRunner/unittests/tsserver/projectsWithReferences.ts +++ b/src/testRunner/unittests/tsserver/projectsWithReferences.ts @@ -9,7 +9,17 @@ namespace ts.projectSystem { const logicIndex = TestFSWithWatch.getTsBuildProjectFile("sample1", "logic/index.ts"); const testsConfig = TestFSWithWatch.getTsBuildProjectFile("sample1", "tests/tsconfig.json"); const testsIndex = TestFSWithWatch.getTsBuildProjectFile("sample1", "tests/index.ts"); - const host = createServerHost([libFile, coreConfig, coreIndex, coreAnotherModule, coreSomeDecl, logicConfig, logicIndex, testsConfig, testsIndex]); + const host = createServerHost([ + libFile, + coreConfig, + coreIndex, + coreAnotherModule, + coreSomeDecl, + logicConfig, + logicIndex, + testsConfig, + testsIndex, + ]); const logger = createLoggerWithInMemoryLogs(host); const service = createProjectService(host, { logger }); service.openClientFile(testsIndex.path); @@ -111,7 +121,11 @@ export class A {}`, // revert the edit on config file host.writeFile(cConfig.path, cConfig.content); host.checkTimeoutQueueLengthAndRun(2); - baselineTsserverLogs("projectsWithReferences", "transitive references with edit on config file", service); + baselineTsserverLogs( + "projectsWithReferences", + "transitive references with edit on config file", + service, + ); }); it("edit in referenced config file", () => { @@ -129,7 +143,11 @@ export class A {}`, // revert the edit on config file host.writeFile(bConfig.path, bConfig.content); host.checkTimeoutQueueLengthAndRun(2); - baselineTsserverLogs("projectsWithReferences", "transitive references with edit in referenced config file", service); + baselineTsserverLogs( + "projectsWithReferences", + "transitive references with edit in referenced config file", + service, + ); }); it("deleting referenced config file", () => { @@ -140,7 +158,11 @@ export class A {}`, // revert host.writeFile(bConfig.path, bConfig.content); host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation - baselineTsserverLogs("projectsWithReferences", "transitive references with deleting referenced config file", service); + baselineTsserverLogs( + "projectsWithReferences", + "transitive references with deleting referenced config file", + service, + ); }); it("deleting transitively referenced config file", () => { @@ -151,7 +173,11 @@ export class A {}`, // revert host.writeFile(aConfig.path, aConfig.content); host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation - baselineTsserverLogs("projectsWithReferences", "transitive references with deleting transitively referenced config file", service); + baselineTsserverLogs( + "projectsWithReferences", + "transitive references with deleting transitively referenced config file", + service, + ); }); }); @@ -208,7 +234,11 @@ export class A {}`, // non local edit host.appendFile(bTs.path, `export function gFoo() { }`); host.checkTimeoutQueueLengthAndRun(2); - baselineTsserverLogs("projectsWithReferences", "trasitive references without files with non local edit", service); + baselineTsserverLogs( + "projectsWithReferences", + "trasitive references without files with non local edit", + service, + ); }); it("edit on config file", () => { @@ -226,7 +256,11 @@ export class A {}`, // revert the edit on config file host.writeFile(cConfig.path, cConfig.content); host.checkTimeoutQueueLengthAndRun(2); - baselineTsserverLogs("projectsWithReferences", "trasitive references without files with edit on config file", service); + baselineTsserverLogs( + "projectsWithReferences", + "trasitive references without files with edit on config file", + service, + ); }); it("edit in referenced config file", () => { @@ -244,7 +278,11 @@ export class A {}`, // revert the edit on config file host.writeFile(bConfig.path, bConfig.content); host.checkTimeoutQueueLengthAndRun(2); - baselineTsserverLogs("projectsWithReferences", "trasitive references without files with edit in referenced config file", service); + baselineTsserverLogs( + "projectsWithReferences", + "trasitive references without files with edit in referenced config file", + service, + ); }); it("deleting referenced config file", () => { @@ -255,7 +293,11 @@ export class A {}`, // revert host.writeFile(bConfig.path, bConfig.content); host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation - baselineTsserverLogs("projectsWithReferences", "trasitive references without files with deleting referenced config file", service); + baselineTsserverLogs( + "projectsWithReferences", + "trasitive references without files with deleting referenced config file", + service, + ); }); it("deleting transitively referenced config file", () => { @@ -266,7 +308,11 @@ export class A {}`, // revert host.writeFile(aConfig.path, aConfig.content); host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation - baselineTsserverLogs("projectsWithReferences", "trasitive references without files with deleting transitively referenced config file", service); + baselineTsserverLogs( + "projectsWithReferences", + "trasitive references without files with deleting transitively referenced config file", + service, + ); }); }); }); diff --git a/src/testRunner/unittests/tsserver/refactors.ts b/src/testRunner/unittests/tsserver/refactors.ts index 63e044873895a..fb214084f1f93 100644 --- a/src/testRunner/unittests/tsserver/refactors.ts +++ b/src/testRunner/unittests/tsserver/refactors.ts @@ -123,7 +123,10 @@ namespace ts.projectSystem { const session = createSession(createServerHost([aTs, tsconfig])); openFilesForSession([aTs], session); - const result = executeSessionRequest(session, protocol.CommandTypes.GetEditsForRefactor, { + const result = executeSessionRequest< + protocol.GetEditsForRefactorRequest, + protocol.GetEditsForRefactorResponse + >(session, protocol.CommandTypes.GetEditsForRefactor, { file: aTs.path, startLine: 1, startOffset: 1, @@ -136,15 +139,27 @@ namespace ts.projectSystem { edits: [ { fileName: aTs.path, - textChanges: [{ start: { line: 1, offset: 1 }, end: { line: 1, offset: aTs.content.length + 1 }, newText: "" }], + textChanges: [{ + start: { line: 1, offset: 1 }, + end: { line: 1, offset: aTs.content.length + 1 }, + newText: "", + }], }, { fileName: tsconfig.path, - textChanges: [{ start: { line: 1, offset: 21 }, end: { line: 1, offset: 21 }, newText: ', "./x.ts"' }], + textChanges: [{ + start: { line: 1, offset: 21 }, + end: { line: 1, offset: 21 }, + newText: ', "./x.ts"', + }], }, { fileName: "/Foo/x.ts", - textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: "const x = 0;\n" }], + textChanges: [{ + start: { line: 0, offset: 0 }, + end: { line: 0, offset: 0 }, + newText: "const x = 0;\n", + }], }, ], renameFilename: undefined, diff --git a/src/testRunner/unittests/tsserver/reloadProjects.ts b/src/testRunner/unittests/tsserver/reloadProjects.ts index 1e28a05fcb271..ae2c660b33975 100644 --- a/src/testRunner/unittests/tsserver/reloadProjects.ts +++ b/src/testRunner/unittests/tsserver/reloadProjects.ts @@ -65,9 +65,17 @@ namespace ts.projectSystem { const service = createProjectService(host, { useInferredProjectPerProjectRoot: true }); service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } }); const timeoutId = host.getNextTimeoutId(); - service.setCompilerOptionsForInferredProjects({ excludeDirectories: ["node_modules"] }, tscWatch.projectRoot); + service.setCompilerOptionsForInferredProjects( + { excludeDirectories: ["node_modules"] }, + tscWatch.projectRoot, + ); host.clearTimeout(timeoutId); - service.openClientFile(file1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, tscWatch.projectRoot); + service.openClientFile( + file1.path, + /*fileContent*/ undefined, + /*scriptKind*/ undefined, + tscWatch.projectRoot, + ); checkNumberOfProjects(service, { inferredProjects: 1 }); const project = service.inferredProjects[0]; checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]); diff --git a/src/testRunner/unittests/tsserver/rename.ts b/src/testRunner/unittests/tsserver/rename.ts index fc508cb7c3304..f87e2fee7b60c 100644 --- a/src/testRunner/unittests/tsserver/rename.ts +++ b/src/testRunner/unittests/tsserver/rename.ts @@ -8,7 +8,11 @@ namespace ts.projectSystem { openFilesForSession([bTs], session); // rename fails with allowRenameOfImportPath disabled - const response1 = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";')); + const response1 = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(bTs, 'a";'), + ); assert.deepEqual(response1, { info: { canRename: false, @@ -19,7 +23,11 @@ namespace ts.projectSystem { // rename succeeds with allowRenameOfImportPath enabled in host session.getProjectService().setHostConfiguration({ preferences: { allowRenameOfImportPath: true } }); - const response2 = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";')); + const response2 = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(bTs, 'a";'), + ); assert.deepEqual(response2, { info: { canRename: true, @@ -44,8 +52,16 @@ namespace ts.projectSystem { // rename succeeds with allowRenameOfImportPath enabled in file session.getProjectService().setHostConfiguration({ preferences: { allowRenameOfImportPath: false } }); - session.getProjectService().setHostConfiguration({ file: "/b.ts", formatOptions: {}, preferences: { allowRenameOfImportPath: true } }); - const response3 = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";')); + session.getProjectService().setHostConfiguration({ + file: "/b.ts", + formatOptions: {}, + preferences: { allowRenameOfImportPath: true }, + }); + const response3 = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(bTs, 'a";'), + ); assert.deepEqual(response3, { info: { canRename: true, @@ -76,7 +92,11 @@ namespace ts.projectSystem { openFilesForSession([aTs], session); // rename with prefixText and suffixText disabled - const response1 = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x")); + const response1 = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(aTs, "x"), + ); assert.deepEqual(response1, { info: { canRename: true, @@ -107,8 +127,14 @@ namespace ts.projectSystem { }); // rename with prefixText and suffixText enabled in host - session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: true } }); - const response2 = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x")); + session.getProjectService().setHostConfiguration({ + preferences: { providePrefixAndSuffixTextForRename: true }, + }); + const response2 = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(aTs, "x"), + ); assert.deepEqual(response2, { info: { canRename: true, @@ -140,9 +166,19 @@ namespace ts.projectSystem { }); // rename with prefixText and suffixText enabled for file - session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: false } }); - session.getProjectService().setHostConfiguration({ file: "/a.ts", formatOptions: {}, preferences: { providePrefixAndSuffixTextForRename: true } }); - const response3 = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x")); + session.getProjectService().setHostConfiguration({ + preferences: { providePrefixAndSuffixTextForRename: false }, + }); + session.getProjectService().setHostConfiguration({ + file: "/a.ts", + formatOptions: {}, + preferences: { providePrefixAndSuffixTextForRename: true }, + }); + const response3 = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(aTs, "x"), + ); assert.deepEqual(response3, { info: { canRename: true, @@ -176,13 +212,22 @@ namespace ts.projectSystem { it("export default anonymous function works with prefixText and suffixText when disabled", () => { const aTs: File = { path: "/a.ts", content: "export default function() {}" }; - const bTs: File = { path: "/b.ts", content: `import aTest from "./a"; function test() { return aTest(); }` }; + const bTs: File = { + path: "/b.ts", + content: `import aTest from "./a"; function test() { return aTest(); }`, + }; const session = createSession(createServerHost([aTs, bTs])); openFilesForSession([bTs], session); - session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: false } }); - const response1 = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, "aTest(")); + session.getProjectService().setHostConfiguration({ + preferences: { providePrefixAndSuffixTextForRename: false }, + }); + const response1 = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(bTs, "aTest("), + ); assert.deepEqual(response1, { info: { canRename: true, @@ -219,8 +264,16 @@ namespace ts.projectSystem { openFilesForSession([aTs, bTs], session); // rename from file with prefixText and suffixText enabled - session.getProjectService().setHostConfiguration({ file: "/a.ts", formatOptions: {}, preferences: { providePrefixAndSuffixTextForRename: true } }); - const response1 = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x")); + session.getProjectService().setHostConfiguration({ + file: "/a.ts", + formatOptions: {}, + preferences: { providePrefixAndSuffixTextForRename: true }, + }); + const response1 = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(aTs, "x"), + ); assert.deepEqual(response1, { info: { canRename: true, @@ -253,7 +306,11 @@ namespace ts.projectSystem { }); // rename from file with prefixText and suffixText disabled - const response2 = executeSessionRequest(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, "x")); + const response2 = executeSessionRequest( + session, + protocol.CommandTypes.Rename, + protocolFileLocationFromSubstring(bTs, "x"), + ); assert.deepEqual(response2, { info: { canRename: true, diff --git a/src/testRunner/unittests/tsserver/resolutionCache.ts b/src/testRunner/unittests/tsserver/resolutionCache.ts index 8639095c31e51..039f3fae2036c 100644 --- a/src/testRunner/unittests/tsserver/resolutionCache.ts +++ b/src/testRunner/unittests/tsserver/resolutionCache.ts @@ -185,7 +185,11 @@ namespace ts.projectSystem { }; const host = createServerHost([file]); - const session = createSession(host, { canUseEvents: true, suppressDiagnosticEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + canUseEvents: true, + suppressDiagnosticEvents: true, + logger: createLoggerWithInMemoryLogs(host), + }); session.executeCommandSeq({ command: server.CommandNames.Open, @@ -252,7 +256,11 @@ namespace ts.projectSystem { host.runQueuedTimeoutCallbacks(); session.executeCommand(getErrRequest); - baselineTsserverLogs("resolutionCache", "renaming module should restore the states for inferred projects", session); + baselineTsserverLogs( + "resolutionCache", + "renaming module should restore the states for inferred projects", + session, + ); }); it("should restore the states for configured projects", () => { @@ -286,7 +294,11 @@ namespace ts.projectSystem { host.renameFile(moduleFileNewPath, moduleFile.path); host.runQueuedTimeoutCallbacks(); session.executeCommand(getErrRequest); - baselineTsserverLogs("resolutionCache", "renaming module should restore the states for configured projects", session); + baselineTsserverLogs( + "resolutionCache", + "renaming module should restore the states for configured projects", + session, + ); }); it("should property handle missing config files", () => { @@ -301,13 +313,21 @@ namespace ts.projectSystem { const projectName = "project1"; const host = createServerHost([f1]); const projectService = createProjectService(host); - projectService.openExternalProject({ rootFiles: toExternalFiles([f1.path, config.path]), options: {}, projectFileName: projectName }); + projectService.openExternalProject({ + rootFiles: toExternalFiles([f1.path, config.path]), + options: {}, + projectFileName: projectName, + }); // should have one external project since config file is missing projectService.checkNumberOfProjects({ externalProjects: 1 }); host.writeFile(config.path, config.content); - projectService.openExternalProject({ rootFiles: toExternalFiles([f1.path, config.path]), options: {}, projectFileName: projectName }); + projectService.openExternalProject({ + rootFiles: toExternalFiles([f1.path, config.path]), + options: {}, + projectFileName: projectName, + }); projectService.checkNumberOfProjects({ configuredProjects: 1 }); }); @@ -369,7 +389,10 @@ namespace ts.projectSystem { it("relative module name", () => { const fileContent = `import { module1 } from "./module1";import { module2 } from "../module2";`; const { file1, file2 } = getFiles(fileContent); - const { module1, module2 } = getModules(`${tscWatch.projectRoot}/src/module1.ts`, `${tscWatch.projectRoot}/module2.ts`); + const { module1, module2 } = getModules( + `${tscWatch.projectRoot}/src/module1.ts`, + `${tscWatch.projectRoot}/module2.ts`, + ); const files = [module1, module2, file1, file2, configFile, libFile]; const host = createServerHost(files); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -385,7 +408,10 @@ namespace ts.projectSystem { it("non relative module name", () => { const fileContent = `import { module1 } from "module1";import { module2 } from "module2";`; const { file1, file2 } = getFiles(fileContent); - const { module1, module2 } = getModules(`${tscWatch.projectRoot}/src/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`); + const { module1, module2 } = getModules( + `${tscWatch.projectRoot}/src/node_modules/module1/index.ts`, + `${tscWatch.projectRoot}/node_modules/module2/index.ts`, + ); const files = [module1, module2, file1, file2, configFile, libFile]; const host = createServerHost(files); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -399,7 +425,12 @@ namespace ts.projectSystem { }); describe("from files in different folders", () => { - function getFiles(fileContent1: string, fileContent2 = fileContent1, fileContent3 = fileContent1, fileContent4 = fileContent1) { + function getFiles( + fileContent1: string, + fileContent2 = fileContent1, + fileContent3 = fileContent1, + fileContent4 = fileContent1, + ) { const file1: File = { path: `${tscWatch.projectRoot}/product/src/file1.ts`, content: fileContent1, @@ -422,10 +453,14 @@ namespace ts.projectSystem { it("relative module name", () => { const fileContent1 = `import { module1 } from "./module1";import { module2 } from "../module2";`; const fileContent2 = `import { module1 } from "../module1";import { module2 } from "../../module2";`; - const fileContent3 = `import { module1 } from "../../src/module1";import { module2 } from "../../module2";`; + const fileContent3 = + `import { module1 } from "../../src/module1";import { module2 } from "../../module2";`; const fileContent4 = `import { module1 } from "../src/module1}";import { module2 } from "../module2";`; const { file1, file2, file3, file4 } = getFiles(fileContent1, fileContent2, fileContent3, fileContent4); - const { module1, module2 } = getModules(`${tscWatch.projectRoot}/product/src/module1.ts`, `${tscWatch.projectRoot}/product/module2.ts`); + const { module1, module2 } = getModules( + `${tscWatch.projectRoot}/product/src/module1.ts`, + `${tscWatch.projectRoot}/product/module2.ts`, + ); const files = [module1, module2, file1, file2, file3, file4, configFile, libFile]; const host = createServerHost(files); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -436,13 +471,20 @@ namespace ts.projectSystem { host.writeFile(file3.path, file3.content + fileContent3); host.writeFile(file4.path, file4.content + fileContent4); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("resolutionCache", "relative module name from files in different folders", service); + baselineTsserverLogs( + "resolutionCache", + "relative module name from files in different folders", + service, + ); }); it("non relative module name", () => { const fileContent = `import { module1 } from "module1";import { module2 } from "module2";`; const { file1, file2, file3, file4 } = getFiles(fileContent); - const { module1, module2 } = getModules(`${tscWatch.projectRoot}/product/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`); + const { module1, module2 } = getModules( + `${tscWatch.projectRoot}/product/node_modules/module1/index.ts`, + `${tscWatch.projectRoot}/node_modules/module2/index.ts`, + ); const files = [module1, module2, file1, file2, file3, file4, configFile, libFile]; const host = createServerHost(files); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -453,7 +495,11 @@ namespace ts.projectSystem { host.writeFile(file3.path, file3.content + fileContent); host.writeFile(file4.path, file4.content + fileContent); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("resolutionCache", "non relative module name from files in different folders", service); + baselineTsserverLogs( + "resolutionCache", + "non relative module name from files in different folders", + service, + ); }); it("non relative module name from inferred project", () => { @@ -462,9 +508,18 @@ namespace ts.projectSystem { const file2Name = "./feature/file2"; const file3Name = "../test/src/file3"; const file4Name = "../test/file4"; - const importModuleContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`; - const { file1, file2, file3, file4 } = getFiles(`import "${file2Name}"; import "${file4Name}"; import "${file3Name}"; ${importModuleContent}`, importModuleContent, importModuleContent, importModuleContent); - const { module1, module2 } = getModules(`${tscWatch.projectRoot}/product/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`); + const importModuleContent = + `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`; + const { file1, file2, file3, file4 } = getFiles( + `import "${file2Name}"; import "${file4Name}"; import "${file3Name}"; ${importModuleContent}`, + importModuleContent, + importModuleContent, + importModuleContent, + ); + const { module1, module2 } = getModules( + `${tscWatch.projectRoot}/product/node_modules/module1/index.ts`, + `${tscWatch.projectRoot}/node_modules/module2/index.ts`, + ); const files = [module1, module2, file1, file2, file3, file4, libFile]; const host = createServerHost(files); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -524,7 +579,14 @@ export const x = 10;`, }), }; - const files = [...(useNodeFile ? [nodeFile] : []), electronFile, srcFile, moduleFile, configFile, libFile]; + const files = [ + ...(useNodeFile ? [nodeFile] : []), + electronFile, + srcFile, + moduleFile, + configFile, + libFile, + ]; const host = createServerHost(files); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, tscWatch.projectRoot); @@ -587,7 +649,10 @@ export const x = 10;`, path: `${tscWatch.projectRoot}/src/file1.ts`, content: fileContent, }; - const { module1, module2 } = getModules(`${tscWatch.projectRoot}/src/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`); + const { module1, module2 } = getModules( + `${tscWatch.projectRoot}/src/node_modules/module1/index.ts`, + `${tscWatch.projectRoot}/node_modules/module2/index.ts`, + ); const files = [module1, module2, file1, configFile, libFile]; const host = createServerHost(files); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); diff --git a/src/testRunner/unittests/tsserver/session.ts b/src/testRunner/unittests/tsserver/session.ts index 3d0b8242e2481..6706076ec20f1 100644 --- a/src/testRunner/unittests/tsserver/session.ts +++ b/src/testRunner/unittests/tsserver/session.ts @@ -159,7 +159,10 @@ namespace ts.server { session.onMessage(JSON.stringify(configureRequest)); - assert.equal(session.getProjectService().getFormatCodeOptions("" as NormalizedPath).indentStyle, IndentStyle.Block); + assert.equal( + session.getProjectService().getFormatCodeOptions("" as NormalizedPath).indentStyle, + IndentStyle.Block, + ); const setOptionsRequest: protocol.SetCompilerOptionsForInferredProjectsRequest = { command: CommandNames.CompilerOptionsForInferredProjects, @@ -467,7 +470,9 @@ namespace ts.server { const command = "testhandler"; class TestSession extends Session { lastSent: protocol.Message | undefined; - private exceptionRaisingHandler(_request: protocol.Request): { response?: any; responseRequired: boolean; } { + private exceptionRaisingHandler( + _request: protocol.Request, + ): { response?: any; responseRequired: boolean; } { f1(); return Debug.fail(); // unreachable, throw to make compiler happy function f1() { diff --git a/src/testRunner/unittests/tsserver/skipLibCheck.ts b/src/testRunner/unittests/tsserver/skipLibCheck.ts index f703df58b8ad4..24699a368ad9d 100644 --- a/src/testRunner/unittests/tsserver/skipLibCheck.ts +++ b/src/testRunner/unittests/tsserver/skipLibCheck.ts @@ -28,7 +28,9 @@ namespace ts.projectSystem { let errorResult = session.executeCommand(file2GetErrRequest).response as protocol.Diagnostic[]; assert.isTrue(errorResult.length === 0); - const closeFileRequest = makeSessionRequest(CommandNames.Close, { file: file1.path }); + const closeFileRequest = makeSessionRequest(CommandNames.Close, { + file: file1.path, + }); session.executeCommand(closeFileRequest); errorResult = session.executeCommand(file2GetErrRequest).response as protocol.Diagnostic[]; assert.isTrue(errorResult.length !== 0); @@ -167,7 +169,10 @@ namespace ts.projectSystem { ); const errorResult = session.executeCommand(getErrRequest).response as protocol.Diagnostic[]; assert.isTrue(errorResult.length === 1); - assert.equal(errorResult[0].code, Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap.code); + assert.equal( + errorResult[0].code, + Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap.code, + ); }); it("should report semantic errors for configured js project with '// @ts-check' and skipLibCheck=true", () => { @@ -194,7 +199,10 @@ namespace ts.projectSystem { ); const errorResult = session.executeCommand(getErrRequest).response as protocol.Diagnostic[]; assert.isTrue(errorResult.length === 1); - assert.equal(errorResult[0].code, Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap.code); + assert.equal( + errorResult[0].code, + Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap.code, + ); }); it("should report semantic errors for configured js project with checkJs=true and skipLibCheck=true", () => { @@ -223,7 +231,10 @@ namespace ts.projectSystem { ); const errorResult = session.executeCommand(getErrRequest).response as protocol.Diagnostic[]; assert.isTrue(errorResult.length === 1); - assert.equal(errorResult[0].code, Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap.code); + assert.equal( + errorResult[0].code, + Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap.code, + ); }); }); } diff --git a/src/testRunner/unittests/tsserver/symLinks.ts b/src/testRunner/unittests/tsserver/symLinks.ts index bb819c94480d5..a10bdbe748a5e 100644 --- a/src/testRunner/unittests/tsserver/symLinks.ts +++ b/src/testRunner/unittests/tsserver/symLinks.ts @@ -50,7 +50,11 @@ namespace ts.projectSystem { ], session, ); - executeSessionRequest(session, protocol.CommandTypes.Rename, { file: aFc, ...protocolLocationFromSubstring(cFile.content, "C") }); + executeSessionRequest( + session, + protocol.CommandTypes.Rename, + { file: aFc, ...protocolLocationFromSubstring(cFile.content, "C") }, + ); baselineTsserverLogs("symLinks", "rename in common file renames all project", session); }); @@ -119,68 +123,101 @@ new C();`, } function verifyModuleResolution(withPathMapping: boolean) { - describe(withPathMapping ? "when tsconfig file contains path mapping" : "when tsconfig does not contain path mapping", () => { - const filesWithSources = [libFile, recognizersDateTimeSrcFile, withPathMapping ? recognizerDateTimeTsconfigWithPathMapping : recognizerDateTimeTsconfigWithoutPathMapping, recognizerTextSrcFile, recongnizerTextPackageJson]; - it("when project compiles from sources", () => { - const host = createServerHost(filesWithSources); - const session = createSessionAndOpenFile(host); - verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); - - host.ensureFileOrFolder(nodeModulesRecorgnizersText); - host.writeFile(recongnizerTextDistTypingFile.path, recongnizerTextDistTypingFile.content); - host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions - host.runQueuedTimeoutCallbacks(); // Actual update - - verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); - - // Change config file's module resolution affecting option - const config = JSON.parse(host.readFile(recognizerDateTimeTsconfigPath)!); - host.writeFile( - recognizerDateTimeTsconfigPath, - JSON.stringify({ - ...config, - compilerOptions: { ...config.compilerOptions, resolveJsonModule: true }, - }), - ); - host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions - host.runQueuedTimeoutCallbacks(); // Actual update - - baselineTsserverLogs("symLinks", `module resolution${withPathMapping ? " with path mapping" : ""} when project compiles from sources`, session); - }); - - it("when project has node_modules setup but doesnt have modules in typings folder and then recompiles", () => { - const host = createServerHost([...filesWithSources, nodeModulesRecorgnizersText]); - const session = createSessionAndOpenFile(host); - verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); - - host.writeFile(recongnizerTextDistTypingFile.path, recongnizerTextDistTypingFile.content); - host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions - host.runQueuedTimeoutCallbacks(); // Actual update - - verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); - baselineTsserverLogs("symLinks", `module resolution${withPathMapping ? " with path mapping" : ""} when project has node_modules setup but doesnt have modules in typings folder and then recompiles`, session); - }); - - it("when project recompiles after deleting generated folders", () => { - const host = createServerHost([...filesWithSources, nodeModulesRecorgnizersText, recongnizerTextDistTypingFile]); - const session = createSessionAndOpenFile(host); - - verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); - - host.deleteFolder(recognizersTextDist, /*recursive*/ true); - host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions - host.runQueuedTimeoutCallbacks(); // Actual update - - verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); - - host.ensureFileOrFolder(recongnizerTextDistTypingFile); - host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions - host.runQueuedTimeoutCallbacks(); // Actual update - - verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); - baselineTsserverLogs("symLinks", `module resolution${withPathMapping ? " with path mapping" : ""} when project recompiles after deleting generated folders`, session); - }); - }); + describe( + withPathMapping ? "when tsconfig file contains path mapping" + : "when tsconfig does not contain path mapping", + () => { + const filesWithSources = [ + libFile, + recognizersDateTimeSrcFile, + withPathMapping ? recognizerDateTimeTsconfigWithPathMapping + : recognizerDateTimeTsconfigWithoutPathMapping, + recognizerTextSrcFile, + recongnizerTextPackageJson, + ]; + it("when project compiles from sources", () => { + const host = createServerHost(filesWithSources); + const session = createSessionAndOpenFile(host); + verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); + + host.ensureFileOrFolder(nodeModulesRecorgnizersText); + host.writeFile(recongnizerTextDistTypingFile.path, recongnizerTextDistTypingFile.content); + host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions + host.runQueuedTimeoutCallbacks(); // Actual update + + verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); + + // Change config file's module resolution affecting option + const config = JSON.parse(host.readFile(recognizerDateTimeTsconfigPath)!); + host.writeFile( + recognizerDateTimeTsconfigPath, + JSON.stringify({ + ...config, + compilerOptions: { ...config.compilerOptions, resolveJsonModule: true }, + }), + ); + host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions + host.runQueuedTimeoutCallbacks(); // Actual update + + baselineTsserverLogs( + "symLinks", + `module resolution${ + withPathMapping ? " with path mapping" : "" + } when project compiles from sources`, + session, + ); + }); + + it("when project has node_modules setup but doesnt have modules in typings folder and then recompiles", () => { + const host = createServerHost([...filesWithSources, nodeModulesRecorgnizersText]); + const session = createSessionAndOpenFile(host); + verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); + + host.writeFile(recongnizerTextDistTypingFile.path, recongnizerTextDistTypingFile.content); + host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions + host.runQueuedTimeoutCallbacks(); // Actual update + + verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); + baselineTsserverLogs( + "symLinks", + `module resolution${ + withPathMapping ? " with path mapping" : "" + } when project has node_modules setup but doesnt have modules in typings folder and then recompiles`, + session, + ); + }); + + it("when project recompiles after deleting generated folders", () => { + const host = createServerHost([ + ...filesWithSources, + nodeModulesRecorgnizersText, + recongnizerTextDistTypingFile, + ]); + const session = createSessionAndOpenFile(host); + + verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); + + host.deleteFolder(recognizersTextDist, /*recursive*/ true); + host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions + host.runQueuedTimeoutCallbacks(); // Actual update + + verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); + + host.ensureFileOrFolder(recongnizerTextDistTypingFile); + host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions + host.runQueuedTimeoutCallbacks(); // Actual update + + verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] }); + baselineTsserverLogs( + "symLinks", + `module resolution${ + withPathMapping ? " with path mapping" : "" + } when project recompiles after deleting generated folders`, + session, + ); + }); + }, + ); } verifyModuleResolution(/*withPathMapping*/ false); diff --git a/src/testRunner/unittests/tsserver/syntacticServer.ts b/src/testRunner/unittests/tsserver/syntacticServer.ts index a989f44dea449..0253c73899e5f 100644 --- a/src/testRunner/unittests/tsserver/syntacticServer.ts +++ b/src/testRunner/unittests/tsserver/syntacticServer.ts @@ -26,7 +26,11 @@ import { something } from "something"; content: "{}", }; const host = createServerHost([file1, file2, file3, something, libFile, configFile]); - const session = createSession(host, { syntaxOnly: true, useSingleInferredProject: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + syntaxOnly: true, + useSingleInferredProject: true, + logger: createLoggerWithInMemoryLogs(host), + }); return { host, session, file1, file2, file3, something, configFile }; } @@ -57,7 +61,11 @@ import { something } from "something"; closeFilesForSession([file3], session); closeFilesForSession([file2], session); - baselineTsserverLogs("syntacticServer", "files go to inferred project and semantic operations fail", session); + baselineTsserverLogs( + "syntacticServer", + "files go to inferred project and semantic operations fail", + session, + ); function verifyCompletions() { verifySessionException(session, { diff --git a/src/testRunner/unittests/tsserver/syntaxOperations.ts b/src/testRunner/unittests/tsserver/syntaxOperations.ts index 343ee80256a61..10d7393dccdde 100644 --- a/src/testRunner/unittests/tsserver/syntaxOperations.ts +++ b/src/testRunner/unittests/tsserver/syntaxOperations.ts @@ -94,7 +94,11 @@ export function Test2() { assert.strictEqual(sourceFile.text, unitTest1WithChangedContent.content); const navBarResultUnitTest1WithChangedContent = navBarFull(session, unitTest1WithChangedContent); - assert.notStrictEqual(navBarResultUnitTest1WithChangedContent, navBarResultUnitTest1, "With changes in contents of unitTest file, we should see changed naviagation bar item result"); + assert.notStrictEqual( + navBarResultUnitTest1WithChangedContent, + navBarResultUnitTest1, + "With changes in contents of unitTest file, we should see changed naviagation bar item result", + ); }); }); } diff --git a/src/testRunner/unittests/tsserver/telemetry.ts b/src/testRunner/unittests/tsserver/telemetry.ts index b795811e66b63..501dec99d6ca4 100644 --- a/src/testRunner/unittests/tsserver/telemetry.ts +++ b/src/testRunner/unittests/tsserver/telemetry.ts @@ -31,7 +31,8 @@ namespace ts.projectSystem { }); it("counts files by extension", () => { - const files = ["ts.ts", "tsx.tsx", "moo.ts", "dts.d.ts", "jsx.jsx", "js.js", "badExtension.badExtension"].map(f => makeFile(`/src/${f}`)); + const files = ["ts.ts", "tsx.tsx", "moo.ts", "dts.d.ts", "jsx.jsx", "js.js", "badExtension.badExtension"] + .map(f => makeFile(`/src/${f}`)); const notIncludedFile = makeFile("/bin/ts.js"); const compilerOptions: CompilerOptions = { allowJs: true }; const tsconfig = makeFile("/tsconfig.json", { compilerOptions, include: ["src"] }); diff --git a/src/testRunner/unittests/tsserver/textStorage.ts b/src/testRunner/unittests/tsserver/textStorage.ts index ac8f4d5debc4f..40bce7c8fe242 100644 --- a/src/testRunner/unittests/tsserver/textStorage.ts +++ b/src/testRunner/unittests/tsserver/textStorage.ts @@ -32,20 +32,40 @@ namespace ts.textStorage { for (let offset = 0; offset < end - start; offset++) { const pos1 = ts1.lineOffsetToPosition(line + 1, offset + 1); const pos2 = ts2.lineOffsetToPosition(line + 1, offset + 1); - assert.strictEqual(pos1, pos2, `lineOffsetToPosition ${line + 1}-${offset + 1}: expected ${pos1} to equal ${pos2}`); + assert.strictEqual( + pos1, + pos2, + `lineOffsetToPosition ${line + 1}-${offset + 1}: expected ${pos1} to equal ${pos2}`, + ); } const { start: start1, length: length1 } = ts1.lineToTextSpan(line); const { start: start2, length: length2 } = ts2.lineToTextSpan(line); - assert.strictEqual(start1, start2, `lineToTextSpan ${line}::start:: expected ${start1} to equal ${start2}`); - assert.strictEqual(length1, length2, `lineToTextSpan ${line}::length:: expected ${length1} to equal ${length2}`); + assert.strictEqual( + start1, + start2, + `lineToTextSpan ${line}::start:: expected ${start1} to equal ${start2}`, + ); + assert.strictEqual( + length1, + length2, + `lineToTextSpan ${line}::length:: expected ${length1} to equal ${length2}`, + ); } for (let pos = 0; pos < f.content.length; pos++) { const { line: line1, offset: offset1 } = ts1.positionToLineOffset(pos); const { line: line2, offset: offset2 } = ts2.positionToLineOffset(pos); - assert.strictEqual(line1, line2, `positionToLineOffset ${pos}::line:: expected ${line1} to equal ${line2}`); - assert.strictEqual(offset1, offset2, `positionToLineOffset ${pos}::offset:: expected ${offset1} to equal ${offset2}`); + assert.strictEqual( + line1, + line2, + `positionToLineOffset ${pos}::line:: expected ${line1} to equal ${line2}`, + ); + assert.strictEqual( + offset1, + offset2, + `positionToLineOffset ${pos}::offset:: expected ${offset1} to equal ${offset2}`, + ); } }); diff --git a/src/testRunner/unittests/tsserver/typeAquisition.ts b/src/testRunner/unittests/tsserver/typeAquisition.ts index ebf75303a75d3..3d15486eb0937 100644 --- a/src/testRunner/unittests/tsserver/typeAquisition.ts +++ b/src/testRunner/unittests/tsserver/typeAquisition.ts @@ -13,7 +13,11 @@ namespace ts.projectSystem { const projectService = createProjectService(host); projectService.openExternalProject({ projectFileName: "/a/b/proj.csproj", - rootFiles: [toExternalFile(file2.path), { fileName: file1.path, hasMixedContent: true, scriptKind: ScriptKind.JS }], + rootFiles: [toExternalFile(file2.path), { + fileName: file1.path, + hasMixedContent: true, + scriptKind: ScriptKind.JS, + }], options: {}, }); projectService.checkNumberOfProjects({ externalProjects: 1 }); @@ -42,7 +46,9 @@ namespace ts.projectSystem { content: JSON.stringify({ compilerOptions: { allowJs: true }, exclude: ["node_modules"] }), }; const host = createServerHost([f1, barjs, barTypings, config]); - const projectService = createProjectService(host, { typingsInstaller: new TestTypingsInstaller(typingsCacheLocation, /*throttleLimit*/ 5, host) }); + const projectService = createProjectService(host, { + typingsInstaller: new TestTypingsInstaller(typingsCacheLocation, /*throttleLimit*/ 5, host), + }); projectService.openClientFile(f1.path); projectService.checkNumberOfProjects({ configuredProjects: 1 }); diff --git a/src/testRunner/unittests/tsserver/typeOnlyImportChains.ts b/src/testRunner/unittests/tsserver/typeOnlyImportChains.ts index 2f7356d6708b4..3879fbe38d8b7 100644 --- a/src/testRunner/unittests/tsserver/typeOnlyImportChains.ts +++ b/src/testRunner/unittests/tsserver/typeOnlyImportChains.ts @@ -14,7 +14,11 @@ namespace ts.projectSystem { content: "import { a } from './b'; new a.A();", }; - assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type); + assertUsageError( + [a, b, c], + c, + Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type, + ); }); it("named export -> type-only named import -> named export -> named import", () => { @@ -31,7 +35,11 @@ namespace ts.projectSystem { content: "import { A } from './b'; new A();", }; - assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type); + assertUsageError( + [a, b, c], + c, + Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type, + ); }); it("named export -> type-only namespace import -> export equals -> import equals", () => { @@ -48,7 +56,11 @@ namespace ts.projectSystem { content: "import a = require('./b'); new a.A();", }; - assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type); + assertUsageError( + [a, b, c], + c, + Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type, + ); }); it("named export -> type-only namespace import -> export default -> import default", () => { @@ -65,7 +77,11 @@ namespace ts.projectSystem { content: "import a from './b'; new a.A();", }; - assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type); + assertUsageError( + [a, b, c], + c, + Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type, + ); }); it("export default -> type-only import default -> export default -> import default", () => { @@ -82,7 +98,11 @@ namespace ts.projectSystem { content: "import A from './b'; new A();", }; - assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type); + assertUsageError( + [a, b, c], + c, + Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type, + ); }); it("named export -> type-only export from -> export star from -> named import", () => { @@ -103,7 +123,11 @@ namespace ts.projectSystem { content: "import { A } from './c'; new A();", }; - assertUsageError([a, b, c, d], d, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type); + assertUsageError( + [a, b, c, d], + d, + Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type, + ); }); it("named export -> export namespace from -> type-only named import -> named export -> named import", () => { @@ -124,7 +148,11 @@ namespace ts.projectSystem { content: "import { a } from './c'; new a.A();", }; - assertUsageError([a, b, c, d], d, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type); + assertUsageError( + [a, b, c, d], + d, + Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type, + ); }); it("named export -> type-only export from -> export namespace from -> named import", () => { @@ -149,7 +177,11 @@ namespace ts.projectSystem { }); }); - function assertUsageError(files: readonly TestFSWithWatch.File[], openFile: TestFSWithWatch.File, diagnostic: DiagnosticMessage) { + function assertUsageError( + files: readonly TestFSWithWatch.File[], + openFile: TestFSWithWatch.File, + diagnostic: DiagnosticMessage, + ) { const host = createServerHost(files); const session = createSession(host); openFilesForSession([openFile], session); diff --git a/src/testRunner/unittests/tsserver/typingsInstaller.ts b/src/testRunner/unittests/tsserver/typingsInstaller.ts index 46bf841fdd8a5..b458008083459 100644 --- a/src/testRunner/unittests/tsserver/typingsInstaller.ts +++ b/src/testRunner/unittests/tsserver/typingsInstaller.ts @@ -25,7 +25,13 @@ namespace ts.projectSystem { } } - function executeCommand(self: Installer, host: TestServerHost, installedTypings: string[] | string, typingFiles: File[], cb: TI.RequestCompletedAction): void { + function executeCommand( + self: Installer, + host: TestServerHost, + installedTypings: string[] | string, + typingFiles: File[], + cb: TI.RequestCompletedAction, + ): void { self.addPostExecAction(installedTypings, success => { for (const file of typingFiles) { host.ensureFileOrFolder(file); @@ -73,7 +79,10 @@ namespace ts.projectSystem { const host = createServerHost([f1, f2, config, typesConfig]); const installer = new (class extends Installer { constructor() { - super(host, { typesRegistry: createTypesRegistry("config"), globalTypingsCacheLocation: typesCache }); + super(host, { + typesRegistry: createTypesRegistry("config"), + globalTypingsCacheLocation: typesCache, + }); } installWorker(_requestId: number, _args: string[], _cwd: string, _cb: TI.RequestCompletedAction) { assert(false, "should not be called"); @@ -174,7 +183,10 @@ namespace ts.projectSystem { } })(); - const projectService = createProjectService(host, { useSingleInferredProject: true, typingsInstaller: installer }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + typingsInstaller: installer, + }); projectService.openClientFile(file1.path); checkNumberOfProjects(projectService, { inferredProjects: 1 }); @@ -199,9 +211,16 @@ namespace ts.projectSystem { const host = createServerHost([jqueryJs]); const installer = new (class extends Installer { constructor() { - super(host, { typesRegistry: createTypesRegistry("jquery") }, { isEnabled: () => true, writeLine: msg => messages.push(msg) }); - } - enqueueInstallTypingsRequest(project: server.Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray) { + super(host, { typesRegistry: createTypesRegistry("jquery") }, { + isEnabled: () => true, + writeLine: msg => messages.push(msg), + }); + } + enqueueInstallTypingsRequest( + project: server.Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + ) { super.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void { @@ -228,7 +247,10 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { inferredProjects: 1 }); // files should not be removed from project if ATA is skipped checkProjectActualFiles(p, [jqueryJs.path]); - assert.isTrue(messages.indexOf("No new typings were requested as a result of typings discovery") > 0, "Should not request filename-based typings"); + assert.isTrue( + messages.indexOf("No new typings were requested as a result of typings discovery") > 0, + "Should not request filename-based typings", + ); }); it("external project - no type acquisition, no .d.ts/js files", () => { @@ -334,7 +356,11 @@ namespace ts.projectSystem { constructor() { super(host, { typesRegistry: createTypesRegistry("jquery") }); } - enqueueInstallTypingsRequest(project: server.Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray) { + enqueueInstallTypingsRequest( + project: server.Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + ) { enqueueIsCalled = true; super.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports); } @@ -404,7 +430,11 @@ namespace ts.projectSystem { projectService.openExternalProject({ projectFileName, options: { allowJS: true, moduleResolution: ModuleResolutionKind.NodeJs }, - rootFiles: [toExternalFile(lodashJs.path), toExternalFile(file2Jsx.path), toExternalFile(file3dts.path)], + rootFiles: [ + toExternalFile(lodashJs.path), + toExternalFile(file2Jsx.path), + toExternalFile(file3dts.path), + ], typeAcquisition: {}, }); @@ -433,7 +463,11 @@ namespace ts.projectSystem { constructor() { super(host, { typesRegistry: createTypesRegistry("jquery") }); } - enqueueInstallTypingsRequest(project: server.Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray) { + enqueueInstallTypingsRequest( + project: server.Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + ) { super.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void { @@ -471,9 +505,16 @@ namespace ts.projectSystem { const host = createServerHost([jqueryJs]); const installer = new (class extends Installer { constructor() { - super(host, { typesRegistry: createTypesRegistry("jquery") }, { isEnabled: () => true, writeLine: msg => messages.push(msg) }); - } - enqueueInstallTypingsRequest(project: server.Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray) { + super(host, { typesRegistry: createTypesRegistry("jquery") }, { + isEnabled: () => true, + writeLine: msg => messages.push(msg), + }); + } + enqueueInstallTypingsRequest( + project: server.Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + ) { super.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void { @@ -500,7 +541,10 @@ namespace ts.projectSystem { projectService.checkNumberOfProjects({ externalProjects: 1 }); // files should not be removed from project if ATA is skipped checkProjectActualFiles(p, [jqueryJs.path]); - assert.isTrue(messages.indexOf("No new typings were requested as a result of typings discovery") > 0, "Should not request filename-based typings"); + assert.isTrue( + messages.indexOf("No new typings were requested as a result of typings discovery") > 0, + "Should not request filename-based typings", + ); }); it("external project - no type acquisition, with js & ts files", () => { @@ -520,7 +564,11 @@ namespace ts.projectSystem { constructor() { super(host, { typesRegistry: createTypesRegistry("jquery") }); } - enqueueInstallTypingsRequest(project: server.Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray) { + enqueueInstallTypingsRequest( + project: server.Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + ) { super.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void { @@ -611,7 +659,11 @@ namespace ts.projectSystem { projectService.openExternalProject({ projectFileName, options: { allowJS: true, moduleResolution: ModuleResolutionKind.NodeJs }, - rootFiles: [toExternalFile(lodashJs.path), toExternalFile(commanderJs.path), toExternalFile(file3dts.path)], + rootFiles: [ + toExternalFile(lodashJs.path), + toExternalFile(commanderJs.path), + toExternalFile(file3dts.path), + ], typeAcquisition: { enable: true, include: ["jquery", "moment"], exclude: ["lodash"] }, }); @@ -680,10 +732,19 @@ namespace ts.projectSystem { const host = createServerHost([lodashJs, commanderJs, file3, packageJson, customTypesMap]); const installer = new (class extends Installer { constructor() { - super(host, { throttleLimit: 3, typesRegistry: createTypesRegistry("commander", "express", "jquery", "moment", "lodash") }); + super(host, { + throttleLimit: 3, + typesRegistry: createTypesRegistry("commander", "express", "jquery", "moment", "lodash"), + }); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void { - const installedTypings = ["@types/commander", "@types/express", "@types/jquery", "@types/moment", "@types/lodash"]; + const installedTypings = [ + "@types/commander", + "@types/express", + "@types/jquery", + "@types/moment", + "@types/lodash", + ]; executeCommand(this, host, installedTypings, typingFiles, cb); } })(); @@ -693,7 +754,11 @@ namespace ts.projectSystem { projectService.openExternalProject({ projectFileName, options: { allowJS: true, moduleResolution: ModuleResolutionKind.NodeJs }, - rootFiles: [toExternalFile(lodashJs.path), toExternalFile(commanderJs.path), toExternalFile(file3.path)], + rootFiles: [ + toExternalFile(lodashJs.path), + toExternalFile(commanderJs.path), + toExternalFile(file3.path), + ], typeAcquisition: { include: ["jquery", "moment"] }, }); @@ -708,7 +773,14 @@ namespace ts.projectSystem { } host.checkTimeoutQueueLengthAndRun(1); checkNumberOfProjects(projectService, { externalProjects: 1 }); - checkProjectActualFiles(p, [file3.path, commander.path, express.path, jquery.path, moment.path, lodash.path]); + checkProjectActualFiles(p, [ + file3.path, + commander.path, + express.path, + jquery.path, + moment.path, + lodash.path, + ]); }); it("Throttle - delayed run install requests", () => { @@ -759,7 +831,10 @@ namespace ts.projectSystem { const host = createServerHost([lodashJs, commanderJs, file3, customTypesMap]); const installer = new (class extends Installer { constructor() { - super(host, { throttleLimit: 1, typesRegistry: createTypesRegistry("commander", "jquery", "lodash", "cordova", "gulp", "grunt") }); + super(host, { + throttleLimit: 1, + typesRegistry: createTypesRegistry("commander", "jquery", "lodash", "cordova", "gulp", "grunt"), + }); } installWorker(_requestId: number, args: string[], _cwd: string, cb: TI.RequestCompletedAction): void { let typingFiles: (File & { typings: string; })[] = []; @@ -779,7 +854,11 @@ namespace ts.projectSystem { projectService.openExternalProject({ projectFileName: projectFileName1, options: { allowJS: true, moduleResolution: ModuleResolutionKind.NodeJs }, - rootFiles: [toExternalFile(lodashJs.path), toExternalFile(commanderJs.path), toExternalFile(file3.path)], + rootFiles: [ + toExternalFile(lodashJs.path), + toExternalFile(commanderJs.path), + toExternalFile(file3.path), + ], typeAcquisition: { include: ["jquery", "cordova"] }, }); @@ -854,10 +933,21 @@ namespace ts.projectSystem { path: "/tmp/node_modules/@types/zkat__cacache/index.d.ts", content: "", }; - const host = createServerHost([app, jsconfig, pkgJson, commander, commanderPackage, cacache, cacachePackage]); + const host = createServerHost([ + app, + jsconfig, + pkgJson, + commander, + commanderPackage, + cacache, + cacachePackage, + ]); const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: "/tmp", typesRegistry: createTypesRegistry("zkat__cacache", "nested", "commander") }); + super(host, { + globalTypingsCacheLocation: "/tmp", + typesRegistry: createTypesRegistry("zkat__cacache", "nested", "commander"), + }); } installWorker(_requestId: number, args: string[], _cwd: string, cb: TI.RequestCompletedAction) { assert.deepEqual(args, [`@types/zkat__cacache@ts${versionMajorMinor}`]); @@ -867,7 +957,10 @@ namespace ts.projectSystem { } })(); - const projectService = createProjectService(host, { useSingleInferredProject: true, typingsInstaller: installer }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + typingsInstaller: installer, + }); projectService.openClientFile(app.path); checkNumberOfProjects(projectService, { configuredProjects: 1 }); @@ -881,12 +974,14 @@ namespace ts.projectSystem { checkProjectActualFiles(p, [app.path, cacacheDTS.path, jsconfig.path]); }); - function testConfiguredProjectNodeModules({ jsconfigContent, appJsContent, jQueryJsInProjectBeforeInstall, jQueryDtsInProjectAfterInstall }: { - jsconfigContent?: object; - appJsContent?: string; - jQueryJsInProjectBeforeInstall?: boolean; - jQueryDtsInProjectAfterInstall?: boolean; - } = {}) { + function testConfiguredProjectNodeModules( + { jsconfigContent, appJsContent, jQueryJsInProjectBeforeInstall, jQueryDtsInProjectAfterInstall }: { + jsconfigContent?: object; + appJsContent?: string; + jQueryJsInProjectBeforeInstall?: boolean; + jQueryDtsInProjectAfterInstall?: boolean; + } = {}, + ) { const app = { path: "/app.js", content: appJsContent || "", @@ -931,10 +1026,22 @@ namespace ts.projectSystem { path: "/tmp/node_modules/@types/jquery/index.d.ts", content: "", }; - const host = createServerHost([app, jsconfig, pkgJson, commander, commanderPackage, jquery, jqueryPackage, nestedPackage]); + const host = createServerHost([ + app, + jsconfig, + pkgJson, + commander, + commanderPackage, + jquery, + jqueryPackage, + nestedPackage, + ]); const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: "/tmp", typesRegistry: createTypesRegistry("jquery", "nested", "commander") }); + super(host, { + globalTypingsCacheLocation: "/tmp", + typesRegistry: createTypesRegistry("jquery", "nested", "commander"), + }); } installWorker(_requestId: number, args: string[], _cwd: string, cb: TI.RequestCompletedAction) { assert.deepEqual(args, [`@types/jquery@ts${versionMajorMinor}`]); @@ -944,19 +1051,26 @@ namespace ts.projectSystem { } })(); - const projectService = createProjectService(host, { useSingleInferredProject: true, typingsInstaller: installer }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + typingsInstaller: installer, + }); projectService.openClientFile(app.path); checkNumberOfProjects(projectService, { configuredProjects: 1 }); const p = configuredProjectAt(projectService, 0); - const filesBeforeInstall = jQueryJsInProjectBeforeInstall ? [app.path, jquery.path, jsconfig.path] : [app.path, jsconfig.path]; + const filesBeforeInstall = jQueryJsInProjectBeforeInstall ? [app.path, jquery.path, jsconfig.path] + : [app.path, jsconfig.path]; checkProjectActualFiles(p, filesBeforeInstall); installer.installAll(jQueryDtsInProjectAfterInstall ? 1 : 0); checkNumberOfProjects(projectService, { configuredProjects: 1 }); host.checkTimeoutQueueLengthAndRun(jQueryDtsInProjectAfterInstall ? 2 : 0); - checkProjectActualFiles(p, jQueryDtsInProjectAfterInstall ? [app.path, jqueryDTS.path, jsconfig.path] : filesBeforeInstall); + checkProjectActualFiles( + p, + jQueryDtsInProjectAfterInstall ? [app.path, jqueryDTS.path, jsconfig.path] : filesBeforeInstall, + ); } it("configured projects discover from node_modules", () => { @@ -1037,7 +1151,11 @@ namespace ts.projectSystem { installer.installAll(/*expectedCount*/ 1); host.checkTimeoutQueueLengthAndRun(2); - baselineTsserverLogs("typingsInstaller", "configured projects discover from bower_components", projectService); + baselineTsserverLogs( + "typingsInstaller", + "configured projects discover from bower_components", + projectService, + ); }); it("configured projects discover from bower.json", () => { @@ -1073,7 +1191,10 @@ namespace ts.projectSystem { } })(); - const projectService = createProjectService(host, { useSingleInferredProject: true, typingsInstaller: installer }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + typingsInstaller: installer, + }); projectService.openClientFile(app.path); checkNumberOfProjects(projectService, { configuredProjects: 1 }); @@ -1108,7 +1229,10 @@ namespace ts.projectSystem { const host = createServerHost([f, brokenPackageJson]); const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") }); + super(host, { + globalTypingsCacheLocation: cachePath, + typesRegistry: createTypesRegistry("commander"), + }); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) { const installedTypings = ["@types/commander"]; @@ -1154,7 +1278,10 @@ namespace ts.projectSystem { const host = createServerHost([file]); const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("node", "commander") }); + super(host, { + globalTypingsCacheLocation: cachePath, + typesRegistry: createTypesRegistry("node", "commander"), + }); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) { const installedTypings = ["@types/node", "@types/commander", `@types/${emberComponentDirectory}`]; @@ -1175,7 +1302,12 @@ namespace ts.projectSystem { assert.isTrue(host.fileExists(emberComponent.path), "typings for 'commander' should be created"); host.checkTimeoutQueueLengthAndRun(2); - checkProjectActualFiles(service.inferredProjects[0], [file.path, node.path, commander.path, emberComponent.path]); + checkProjectActualFiles(service.inferredProjects[0], [ + file.path, + node.path, + commander.path, + emberComponent.path, + ]); }); it("should redo resolution that resolved to '.js' file after typings are installed", () => { @@ -1195,11 +1327,17 @@ namespace ts.projectSystem { const host = createServerHost([file, commanderJS]); const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry(...typeNames) }); + super(host, { + globalTypingsCacheLocation: cachePath, + typesRegistry: createTypesRegistry(...typeNames), + }); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) { const installedTypings = typeNames.map(name => `@types/${name}`); - const typingFiles = typeNames.map((name): TestFSWithWatch.File => ({ path: typePath(name), content: "" })); + const typingFiles = typeNames.map((name): TestFSWithWatch.File => ({ + path: typePath(name), + content: "", + })); executeCommand(this, host, installedTypings, typingFiles, cb); } })(); @@ -1352,7 +1490,10 @@ namespace ts.projectSystem { } })(); - const projectService = createProjectService(host, { useSingleInferredProject: true, typingsInstaller: installer }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + typingsInstaller: installer, + }); projectService.openClientFile(file1.path); checkNumberOfProjects(projectService, { inferredProjects: 1 }); @@ -1424,7 +1565,10 @@ namespace ts.projectSystem { } })(); - const projectService = createProjectService(host, { useSingleInferredProject: true, typingsInstaller: installer }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + typingsInstaller: installer, + }); projectService.openClientFile(file1.path); checkNumberOfProjects(projectService, { inferredProjects: 1 }); @@ -1454,34 +1598,81 @@ namespace ts.projectSystem { }); it("package non URI safe characters are not supported", () => { assert.equal(validatePackageName(" scope "), NameValidationResult.NameContainsNonURISafeCharacters); - assert.equal(validatePackageName("; say ‘Hello from TypeScript!’ #"), NameValidationResult.NameContainsNonURISafeCharacters); + assert.equal( + validatePackageName("; say ‘Hello from TypeScript!’ #"), + NameValidationResult.NameContainsNonURISafeCharacters, + ); assert.equal(validatePackageName("a/b/c"), NameValidationResult.NameContainsNonURISafeCharacters); }); it("scoped package name is supported", () => { assert.equal(validatePackageName("@scope/bar"), NameValidationResult.Ok); }); it("scoped name in scoped package name cannot start with dot", () => { - assert.deepEqual(validatePackageName("@.scope/bar"), { name: ".scope", isScopeName: true, result: NameValidationResult.NameStartsWithDot }); - assert.deepEqual(validatePackageName("@.scope/.bar"), { name: ".scope", isScopeName: true, result: NameValidationResult.NameStartsWithDot }); + assert.deepEqual(validatePackageName("@.scope/bar"), { + name: ".scope", + isScopeName: true, + result: NameValidationResult.NameStartsWithDot, + }); + assert.deepEqual(validatePackageName("@.scope/.bar"), { + name: ".scope", + isScopeName: true, + result: NameValidationResult.NameStartsWithDot, + }); }); it("scope name in scoped package name cannot start with underscore", () => { - assert.deepEqual(validatePackageName("@_scope/bar"), { name: "_scope", isScopeName: true, result: NameValidationResult.NameStartsWithUnderscore }); - assert.deepEqual(validatePackageName("@_scope/_bar"), { name: "_scope", isScopeName: true, result: NameValidationResult.NameStartsWithUnderscore }); + assert.deepEqual(validatePackageName("@_scope/bar"), { + name: "_scope", + isScopeName: true, + result: NameValidationResult.NameStartsWithUnderscore, + }); + assert.deepEqual(validatePackageName("@_scope/_bar"), { + name: "_scope", + isScopeName: true, + result: NameValidationResult.NameStartsWithUnderscore, + }); }); it("scope name in scoped package name with non URI safe characters are not supported", () => { - assert.deepEqual(validatePackageName("@ scope /bar"), { name: " scope ", isScopeName: true, result: NameValidationResult.NameContainsNonURISafeCharacters }); - assert.deepEqual(validatePackageName("@; say ‘Hello from TypeScript!’ #/bar"), { name: "; say ‘Hello from TypeScript!’ #", isScopeName: true, result: NameValidationResult.NameContainsNonURISafeCharacters }); - assert.deepEqual(validatePackageName("@ scope / bar "), { name: " scope ", isScopeName: true, result: NameValidationResult.NameContainsNonURISafeCharacters }); + assert.deepEqual(validatePackageName("@ scope /bar"), { + name: " scope ", + isScopeName: true, + result: NameValidationResult.NameContainsNonURISafeCharacters, + }); + assert.deepEqual(validatePackageName("@; say ‘Hello from TypeScript!’ #/bar"), { + name: "; say ‘Hello from TypeScript!’ #", + isScopeName: true, + result: NameValidationResult.NameContainsNonURISafeCharacters, + }); + assert.deepEqual(validatePackageName("@ scope / bar "), { + name: " scope ", + isScopeName: true, + result: NameValidationResult.NameContainsNonURISafeCharacters, + }); }); it("package name in scoped package name cannot start with dot", () => { - assert.deepEqual(validatePackageName("@scope/.bar"), { name: ".bar", isScopeName: false, result: NameValidationResult.NameStartsWithDot }); + assert.deepEqual(validatePackageName("@scope/.bar"), { + name: ".bar", + isScopeName: false, + result: NameValidationResult.NameStartsWithDot, + }); }); it("package name in scoped package name cannot start with underscore", () => { - assert.deepEqual(validatePackageName("@scope/_bar"), { name: "_bar", isScopeName: false, result: NameValidationResult.NameStartsWithUnderscore }); + assert.deepEqual(validatePackageName("@scope/_bar"), { + name: "_bar", + isScopeName: false, + result: NameValidationResult.NameStartsWithUnderscore, + }); }); it("package name in scoped package name with non URI safe characters are not supported", () => { - assert.deepEqual(validatePackageName("@scope/ bar "), { name: " bar ", isScopeName: false, result: NameValidationResult.NameContainsNonURISafeCharacters }); - assert.deepEqual(validatePackageName("@scope/; say ‘Hello from TypeScript!’ #"), { name: "; say ‘Hello from TypeScript!’ #", isScopeName: false, result: NameValidationResult.NameContainsNonURISafeCharacters }); + assert.deepEqual(validatePackageName("@scope/ bar "), { + name: " bar ", + isScopeName: false, + result: NameValidationResult.NameContainsNonURISafeCharacters, + }); + assert.deepEqual(validatePackageName("@scope/; say ‘Hello from TypeScript!’ #"), { + name: "; say ‘Hello from TypeScript!’ #", + isScopeName: false, + result: NameValidationResult.NameContainsNonURISafeCharacters, + }); }); }); @@ -1503,7 +1694,10 @@ namespace ts.projectSystem { const host = createServerHost([f1, packageJson]); const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: "/tmp" }, { isEnabled: () => true, writeLine: msg => messages.push(msg) }); + super(host, { globalTypingsCacheLocation: "/tmp" }, { + isEnabled: () => true, + writeLine: msg => messages.push(msg), + }); } installWorker(_requestId: number, _args: string[], _cwd: string, _cb: TI.RequestCompletedAction) { assert(false, "runCommand should not be invoked"); @@ -1513,7 +1707,12 @@ namespace ts.projectSystem { projectService.openClientFile(f1.path); installer.checkPendingCommands(/*expectedCount*/ 0); - assert.isTrue(messages.indexOf("'; say ‘Hello from TypeScript!’ #':: Package name '; say ‘Hello from TypeScript!’ #' contains non URI safe characters") > 0, "should find package with invalid name"); + assert.isTrue( + messages.indexOf( + "'; say ‘Hello from TypeScript!’ #':: Package name '; say ‘Hello from TypeScript!’ #' contains non URI safe characters", + ) > 0, + "should find package with invalid name", + ); }); }); @@ -1538,7 +1737,18 @@ namespace ts.projectSystem { const host = createServerHost([app, jquery, chroma]); const logger = trackingLogger(); - const result = JsTyping.discoverTypings(host, logger.log, [app.path, jquery.path, chroma.path], getDirectoryPath(app.path as Path), safeList, emptyMap, { enable: true }, emptyArray, emptyMap, emptyOptions); + const result = JsTyping.discoverTypings( + host, + logger.log, + [app.path, jquery.path, chroma.path], + getDirectoryPath(app.path as Path), + safeList, + emptyMap, + { enable: true }, + emptyArray, + emptyMap, + emptyOptions, + ); const finish = logger.finish(); assert.deepEqual(finish, [ 'Inferred typings from file names: ["jquery","chroma-js"]', @@ -1558,7 +1768,18 @@ namespace ts.projectSystem { for (const name of JsTyping.nodeCoreModuleList) { const logger = trackingLogger(); - const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(f.path as Path), emptySafeList, cache, { enable: true }, [name, "somename"], emptyMap, emptyOptions); + const result = JsTyping.discoverTypings( + host, + logger.log, + [f.path], + getDirectoryPath(f.path as Path), + emptySafeList, + cache, + { enable: true }, + [name, "somename"], + emptyMap, + emptyOptions, + ); assert.deepEqual(logger.finish(), [ 'Inferred typings from unresolved imports: ["node","somename"]', 'Result: {"cachedTypingPaths":[],"newTypingNames":["node","somename"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}', @@ -1577,10 +1798,25 @@ namespace ts.projectSystem { content: "", }; const host = createServerHost([f, node]); - const cache = new Map(getEntries({ node: { typingLocation: node.path, version: new Version("1.3.0") } })); + const cache = new Map( + getEntries({ + node: { typingLocation: node.path, version: new Version("1.3.0") }, + }), + ); const registry = createTypesRegistry("node"); const logger = trackingLogger(); - const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(f.path as Path), emptySafeList, cache, { enable: true }, ["fs", "bar"], registry, emptyOptions); + const result = JsTyping.discoverTypings( + host, + logger.log, + [f.path], + getDirectoryPath(f.path as Path), + emptySafeList, + cache, + { enable: true }, + ["fs", "bar"], + registry, + emptyOptions, + ); assert.deepEqual(logger.finish(), [ 'Inferred typings from unresolved imports: ["node","bar"]', 'Result: {"cachedTypingPaths":["/a/b/node.d.ts"],"newTypingNames":["bar"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}', @@ -1599,9 +1835,24 @@ namespace ts.projectSystem { content: "", }; const host = createServerHost([f, node]); - const cache = new Map(getEntries({ node: { typingLocation: node.path, version: new Version("1.3.0") } })); + const cache = new Map( + getEntries({ + node: { typingLocation: node.path, version: new Version("1.3.0") }, + }), + ); const logger = trackingLogger(); - const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(f.path as Path), emptySafeList, cache, { enable: true }, ["fs", "bar"], emptyMap, emptyOptions); + const result = JsTyping.discoverTypings( + host, + logger.log, + [f.path], + getDirectoryPath(f.path as Path), + emptySafeList, + cache, + { enable: true }, + ["fs", "bar"], + emptyMap, + emptyOptions, + ); assert.deepEqual(logger.finish(), [ 'Inferred typings from unresolved imports: ["node","bar"]', 'Result: {"cachedTypingPaths":[],"newTypingNames":["node","bar"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}', @@ -1626,7 +1877,18 @@ namespace ts.projectSystem { const host = createServerHost([app, a, b]); const cache = new Map(); const logger = trackingLogger(); - const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(app.path as Path), emptySafeList, cache, { enable: true }, /*unresolvedImports*/ [], emptyMap, emptyOptions); + const result = JsTyping.discoverTypings( + host, + logger.log, + [app.path], + getDirectoryPath(app.path as Path), + emptySafeList, + cache, + { enable: true }, + /*unresolvedImports*/ [], + emptyMap, + emptyOptions, + ); assert.deepEqual(logger.finish(), [ 'Searching for typing names in /node_modules; all files: ["/node_modules/a/package.json"]', ' Found package names: ["a"]', @@ -1652,7 +1914,18 @@ namespace ts.projectSystem { const host = createServerHost([app, a]); const cache = new Map(); const logger = trackingLogger(); - const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(app.path as Path), emptySafeList, cache, { enable: true }, /*unresolvedImports*/ [], emptyMap, emptyOptions); + const result = JsTyping.discoverTypings( + host, + logger.log, + [app.path], + getDirectoryPath(app.path as Path), + emptySafeList, + cache, + { enable: true }, + /*unresolvedImports*/ [], + emptyMap, + emptyOptions, + ); assert.deepEqual(logger.finish(), [ 'Searching for typing names in /node_modules; all files: ["/node_modules/@a/b/package.json"]', ' Found package names: ["@a/b"]', @@ -1686,7 +1959,18 @@ namespace ts.projectSystem { })); const registry = createTypesRegistry("node", "commander"); const logger = trackingLogger(); - const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(app.path as Path), emptySafeList, cache, { enable: true }, ["http", "commander"], registry, emptyOptions); + const result = JsTyping.discoverTypings( + host, + logger.log, + [app.path], + getDirectoryPath(app.path as Path), + emptySafeList, + cache, + { enable: true }, + ["http", "commander"], + registry, + emptyOptions, + ); assert.deepEqual(logger.finish(), [ 'Inferred typings from unresolved imports: ["node","commander"]', 'Result: {"cachedTypingPaths":["/a/cache/node_modules/@types/node/index.d.ts"],"newTypingNames":["commander"],"filesToWatch":["/a/bower_components","/a/node_modules"]}', @@ -1712,7 +1996,18 @@ namespace ts.projectSystem { const registry = createTypesRegistry("node"); registry.delete(`ts${versionMajorMinor}`); const logger = trackingLogger(); - const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(app.path as Path), emptySafeList, cache, { enable: true }, ["http"], registry, emptyOptions); + const result = JsTyping.discoverTypings( + host, + logger.log, + [app.path], + getDirectoryPath(app.path as Path), + emptySafeList, + cache, + { enable: true }, + ["http"], + registry, + emptyOptions, + ); assert.deepEqual(logger.finish(), [ 'Inferred typings from unresolved imports: ["node"]', 'Result: {"cachedTypingPaths":[],"newTypingNames":["node"],"filesToWatch":["/a/bower_components","/a/node_modules"]}', @@ -1743,7 +2038,18 @@ namespace ts.projectSystem { const registry = createTypesRegistry("node", "commander"); registry.get("node")![`ts${versionMajorMinor}`] = "1.3.0-next.1"; const logger = trackingLogger(); - const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(app.path as Path), emptySafeList, cache, { enable: true }, ["http", "commander"], registry, emptyOptions); + const result = JsTyping.discoverTypings( + host, + logger.log, + [app.path], + getDirectoryPath(app.path as Path), + emptySafeList, + cache, + { enable: true }, + ["http", "commander"], + registry, + emptyOptions, + ); assert.deepEqual(logger.finish(), [ 'Inferred typings from unresolved imports: ["node","commander"]', 'Result: {"cachedTypingPaths":[],"newTypingNames":["node","commander"],"filesToWatch":["/a/bower_components","/a/node_modules"]}', @@ -1772,14 +2078,23 @@ namespace ts.projectSystem { let seenTelemetryEvent = false; const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") }); + super(host, { + globalTypingsCacheLocation: cachePath, + typesRegistry: createTypesRegistry("commander"), + }); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) { const installedTypings = ["@types/commander"]; const typingFiles = [commander]; executeCommand(this, host, installedTypings, typingFiles, cb); } - sendResponse(response: server.SetTypings | server.InvalidateCachedTypings | server.BeginInstallTypes | server.EndInstallTypes) { + sendResponse( + response: + | server.SetTypings + | server.InvalidateCachedTypings + | server.BeginInstallTypes + | server.EndInstallTypes, + ) { if (response.kind === server.EventBeginInstallTypes) { return; } @@ -1833,14 +2148,23 @@ namespace ts.projectSystem { let endEvent!: server.EndInstallTypes; const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") }); + super(host, { + globalTypingsCacheLocation: cachePath, + typesRegistry: createTypesRegistry("commander"), + }); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) { const installedTypings = ["@types/commander"]; const typingFiles = [commander]; executeCommand(this, host, installedTypings, typingFiles, cb); } - sendResponse(response: server.SetTypings | server.InvalidateCachedTypings | server.BeginInstallTypes | server.EndInstallTypes) { + sendResponse( + response: + | server.SetTypings + | server.InvalidateCachedTypings + | server.BeginInstallTypes + | server.EndInstallTypes, + ) { if (response.kind === server.EventBeginInstallTypes) { beginEvent = response; return; @@ -1881,12 +2205,21 @@ namespace ts.projectSystem { let endEvent: server.EndInstallTypes | undefined; const installer: Installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") }); + super(host, { + globalTypingsCacheLocation: cachePath, + typesRegistry: createTypesRegistry("commander"), + }); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) { executeCommand(this, host, "", [], cb); } - sendResponse(response: server.SetTypings | server.InvalidateCachedTypings | server.BeginInstallTypes | server.EndInstallTypes) { + sendResponse( + response: + | server.SetTypings + | server.InvalidateCachedTypings + | server.BeginInstallTypes + | server.EndInstallTypes, + ) { if (response.kind === server.EventBeginInstallTypes) { beginEvent = response; return; @@ -2403,7 +2736,12 @@ namespace ts.projectSystem { ]; const expectedCommands = [ TI.getNpmCommandForInstallation(npmPath, tsVersion, packageNames, packageNames.length).command, - TI.getNpmCommandForInstallation(npmPath, tsVersion, packageNames, packageNames.length - Math.ceil(packageNames.length / 2)).command, + TI.getNpmCommandForInstallation( + npmPath, + tsVersion, + packageNames, + packageNames.length - Math.ceil(packageNames.length / 2), + ).command, ]; it("works when the command is too long to install all packages at once", () => { const commands: string[] = []; @@ -2432,7 +2770,8 @@ namespace ts.projectSystem { const foooPath = "/a/b/node_modules/fooo/index.d.ts"; function verifyResolvedModuleOfFooo(project: server.Project) { server.updateProjectIfDirty(project); - const foooResolution = project.getLanguageService().getProgram()!.getSourceFileByPath(appPath)!.resolvedModules!.get("fooo", /*mode*/ undefined)!; + const foooResolution = project.getLanguageService().getProgram()!.getSourceFileByPath(appPath)! + .resolvedModules!.get("fooo", /*mode*/ undefined)!; assert.equal(foooResolution.resolvedFileName, foooPath); return foooResolution; } @@ -2642,7 +2981,14 @@ declare module "stream" { }), }; - const files = [file, packageJsonInCurrentDirectory, packageJsonOfPkgcurrentdirectory, indexOfPkgcurrentdirectory, typingsCachePackageJson, typingsCachePackageLockJson]; + const files = [ + file, + packageJsonInCurrentDirectory, + packageJsonOfPkgcurrentdirectory, + indexOfPkgcurrentdirectory, + typingsCachePackageJson, + typingsCachePackageLockJson, + ]; const host = createServerHost(files, { currentDirectory }); const typesRegistry = createTypesRegistry("pkgcurrentdirectory"); diff --git a/src/testRunner/unittests/tsserver/versionCache.ts b/src/testRunner/unittests/tsserver/versionCache.ts index b807d3455986f..ac00c9cd6f080 100644 --- a/src/testRunner/unittests/tsserver/versionCache.ts +++ b/src/testRunner/unittests/tsserver/versionCache.ts @@ -7,7 +7,13 @@ namespace ts { return lineIndex.absolutePositionOfStartOfLine(line) + (col - 1); } - function validateEdit(lineIndex: server.LineIndex, sourceText: string, position: number, deleteLength: number, insertString: string): void { + function validateEdit( + lineIndex: server.LineIndex, + sourceText: string, + position: number, + deleteLength: number, + insertString: string, + ): void { const checkText = editFlat(position, deleteLength, insertString, sourceText); const snapshot = lineIndex.edit(position, deleteLength, insertString); const editedText = snapshot.getText(0, snapshot.getLength()); @@ -16,7 +22,12 @@ namespace ts { } describe(`unittests:: tsserver:: VersionCache TS code`, () => { - let validateEditAtLineCharIndex: (line: number, char: number, deleteLength: number, insertString: string) => void; + let validateEditAtLineCharIndex: ( + line: number, + char: number, + deleteLength: number, + insertString: string, + ) => void; before(() => { const testContent = `/// @@ -153,7 +164,11 @@ and grew 1cm per day`; }); it(`Insert multiple line breaks`, () => { - validateEditAtPosition(21, 1, "cr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr"); + validateEditAtPosition( + 21, + 1, + "cr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr", + ); }); it(`Insert multiple line breaks`, () => { @@ -313,7 +328,11 @@ and grew 1cm per day`; const lp = lineIndex.positionToLineOffset(rsa[i]); const lac = computeLineAndCharacterOfPosition(lineMap, rsa[i]); assert.equal(lac.line + 1, lp.line, "Line number mismatch " + (lac.line + 1) + " " + lp.line + " " + i); - assert.equal(lac.character, lp.offset - 1, "Character offset mismatch " + lac.character + " " + (lp.offset - 1) + " " + i); + assert.equal( + lac.character, + lp.offset - 1, + "Character offset mismatch " + lac.character + " " + (lp.offset - 1) + " " + i, + ); } }); diff --git a/src/testRunner/unittests/tsserver/watchEnvironment.ts b/src/testRunner/unittests/tsserver/watchEnvironment.ts index 22553afbecc30..d5027eeaa8d4b 100644 --- a/src/testRunner/unittests/tsserver/watchEnvironment.ts +++ b/src/testRunner/unittests/tsserver/watchEnvironment.ts @@ -113,7 +113,9 @@ namespace ts.projectSystem { }; const environmentVariables = new Map(); environmentVariables.set("TSC_WATCHDIRECTORY", Tsc_WatchDirectory.NonRecursiveWatchDirectory); - const host = createServerHost([index, file1, configFile, libFile, nodeModulesExistingUnusedFile], { environmentVariables }); + const host = createServerHost([index, file1, configFile, libFile, nodeModulesExistingUnusedFile], { + environmentVariables, + }); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([index], session); @@ -152,7 +154,11 @@ namespace ts.projectSystem { host.checkTimeoutQueueLength(0); }); - baselineTsserverLogs("watchEnvironment", `recursive directory does not watch files starting with dot in node_modules`, session); + baselineTsserverLogs( + "watchEnvironment", + `recursive directory does not watch files starting with dot in node_modules`, + session, + ); }); it("unittests:: tsserver:: watchEnvironment:: tsserverProjectSystem watching files with network style paths", () => { @@ -227,7 +233,10 @@ namespace ts.projectSystem { content: "{}", }; const files = [libFile, commonFile2, configFile]; - const host = createServerHost(files.concat(commonFile1), { runWithoutRecursiveWatches: true, runWithFallbackPolling: true }); + const host = createServerHost(files.concat(commonFile1), { + runWithoutRecursiveWatches: true, + runWithFallbackPolling: true, + }); const logger = createLoggerWithInMemoryLogs(host); const session = createSession(host, { logger }); session.executeCommandSeq({ @@ -286,7 +295,10 @@ namespace ts.projectSystem { }), }; const files = [libFile, commonFile2, configFile]; - const host = createServerHost(files.concat(commonFile1), { runWithoutRecursiveWatches: true, runWithFallbackPolling: true }); + const host = createServerHost(files.concat(commonFile1), { + runWithoutRecursiveWatches: true, + runWithFallbackPolling: true, + }); const logger = createLoggerWithInMemoryLogs(host); const session = createSession(host, { logger }); session.executeCommandSeq({ @@ -331,7 +343,10 @@ namespace ts.projectSystem { function setup(configureHost?: boolean) { const configFile: File = { path: `${tscWatch.projectRoot}/tsconfig.json`, - content: JSON.stringify({ include: ["src"], watchOptions: { excludeDirectories: ["node_modules"] } }), + content: JSON.stringify({ + include: ["src"], + watchOptions: { excludeDirectories: ["node_modules"] }, + }), }; const { main, bar, foo } = setupFiles(); const files = [libFile, main, bar, foo, configFile]; @@ -377,7 +392,11 @@ namespace ts.projectSystem { it("external project watch options in host configuration", () => { const session = setupExternalProject(/*configureHost*/ true); - baselineTsserverLogs("watchEnvironment", `external project watch options in host configuration`, session); + baselineTsserverLogs( + "watchEnvironment", + `external project watch options in host configuration`, + session, + ); }); it("external project watch options errors", () => { @@ -400,7 +419,10 @@ namespace ts.projectSystem { const { main, bar, foo } = setupFiles(); const files = [libFile, main, bar, foo]; const host = createServerHost(files, { currentDirectory: tscWatch.projectRoot }); - const session = createSession(host, { useInferredProjectPerProjectRoot: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + useInferredProjectPerProjectRoot: true, + logger: createLoggerWithInMemoryLogs(host), + }); setupConfigureHost(session, configureHost); session.executeCommandSeq({ command: protocol.CommandTypes.CompilerOptionsForInferredProjects, @@ -420,15 +442,25 @@ namespace ts.projectSystem { it("inferred project watch options in host configuration", () => { const session = setupInferredProject(/*configureHost*/ true); - baselineTsserverLogs("watchEnvironment", `inferred project watch options in host configuration`, session); + baselineTsserverLogs( + "watchEnvironment", + `inferred project watch options in host configuration`, + session, + ); }); it("inferred project watch options errors", () => { const { main, bar, foo } = setupFiles(); const files = [libFile, main, bar, foo]; const host = createServerHost(files, { currentDirectory: tscWatch.projectRoot }); - const service = createProjectService(host, { useInferredProjectPerProjectRoot: true, logger: createLoggerWithInMemoryLogs(host) }); - service.setCompilerOptionsForInferredProjects({ excludeDirectories: ["**/../*"] }, tscWatch.projectRoot); + const service = createProjectService(host, { + useInferredProjectPerProjectRoot: true, + logger: createLoggerWithInMemoryLogs(host), + }); + service.setCompilerOptionsForInferredProjects( + { excludeDirectories: ["**/../*"] }, + tscWatch.projectRoot, + ); service.openClientFile(main.path, main.content, ScriptKind.TS, tscWatch.projectRoot); const project = service.inferredProjects[0]; service.logger.info(JSON.stringify(project.getAllProjectErrors(), undefined, 2)); diff --git a/src/testRunner/unittests/tsserver/webServer.ts b/src/testRunner/unittests/tsserver/webServer.ts index b8a0cc327eb0e..caca9a8cae8b6 100644 --- a/src/testRunner/unittests/tsserver/webServer.ts +++ b/src/testRunner/unittests/tsserver/webServer.ts @@ -2,7 +2,12 @@ namespace ts.projectSystem { describe("unittests:: tsserver:: webServer", () => { class TestWorkerSession extends server.WorkerSession { - constructor(host: server.ServerHost, webHost: server.HostWithWriteMessage, options: Partial, logger: server.Logger) { + constructor( + host: server.ServerHost, + webHost: server.HostWithWriteMessage, + options: Partial, + logger: server.Logger, + ) { super( host, webHost, @@ -29,7 +34,11 @@ namespace ts.projectSystem { } } - function setup(logLevel: server.LogLevel | undefined, options?: Partial, importPlugin?: server.ServerHost["importPlugin"]) { + function setup( + logLevel: server.LogLevel | undefined, + options?: Partial, + importPlugin?: server.ServerHost["importPlugin"], + ) { const host = createServerHost([libFile], { windowsStyleRoot: "c:/" }); const messages: any[] = []; const webHost: server.WebHost = { @@ -40,7 +49,10 @@ namespace ts.projectSystem { const webSys = server.createWebSystem(webHost, emptyArray, () => host.getExecutingFilePath()); webSys.importPlugin = importPlugin; const logger = logLevel !== undefined ? new server.MainProcessLogger(logLevel, webHost) : nullLogger(); - const session = new TestWorkerSession(webSys, webHost, { serverMode: LanguageServiceMode.PartialSemantic, ...options }, logger); + const session = new TestWorkerSession(webSys, webHost, { + serverMode: LanguageServiceMode.PartialSemantic, + ...options, + }, logger); return { getMessages: () => messages, clearMessages: () => messages.length = 0, session }; } @@ -132,7 +144,11 @@ namespace ts.projectSystem { function verifyLogger() { const messages = getMessages(); - assert.equal(messages.length, logLevel === server.LogLevel.verbose ? 4 : 1, `Expected ${JSON.stringify(messages)}`); + assert.equal( + messages.length, + logLevel === server.LogLevel.verbose ? 4 : 1, + `Expected ${JSON.stringify(messages)}`, + ); if (logLevel === server.LogLevel.verbose) { verifyLogMessages(messages[0], "info"); verifyLogMessages(messages[1], "perf"); @@ -175,7 +191,12 @@ namespace ts.projectSystem { const { session } = setup(/*logLevel*/ undefined, { globalPlugins: ["plugin-a"] }, importPlugin); const projectService = session.getProjectService(); - session.executeCommand({ seq: 1, type: "request", command: protocol.CommandTypes.Open, arguments: { file: "^memfs:/foo.ts", content: "" } }); + session.executeCommand({ + seq: 1, + type: "request", + command: protocol.CommandTypes.Open, + arguments: { file: "^memfs:/foo.ts", content: "" }, + }); // This should be false because `executeCommand` should have already triggered // plugin enablement asynchronously and there are no plugin enablements currently @@ -214,10 +235,19 @@ namespace ts.projectSystem { }; }; - const { session } = setup(/*logLevel*/ undefined, { globalPlugins: ["plugin-a", "plugin-b"] }, importPlugin); + const { session } = setup( + /*logLevel*/ undefined, + { globalPlugins: ["plugin-a", "plugin-b"] }, + importPlugin, + ); const projectService = session.getProjectService(); - session.executeCommand({ seq: 1, type: "request", command: protocol.CommandTypes.Open, arguments: { file: "^memfs:/foo.ts", content: "" } }); + session.executeCommand({ + seq: 1, + type: "request", + command: protocol.CommandTypes.Open, + arguments: { file: "^memfs:/foo.ts", content: "" }, + }); // wait a turn await Promise.resolve(); @@ -248,10 +278,19 @@ namespace ts.projectSystem { }; }; - const { session, getMessages } = setup(/*logLevel*/ undefined, { globalPlugins: ["plugin-a"] }, importPlugin); + const { session, getMessages } = setup( + /*logLevel*/ undefined, + { globalPlugins: ["plugin-a"] }, + importPlugin, + ); const projectService = session.getProjectService(); - session.executeCommand({ seq: 1, type: "request", command: protocol.CommandTypes.Open, arguments: { file: "^memfs:/foo.ts", content: "" } }); + session.executeCommand({ + seq: 1, + type: "request", + command: protocol.CommandTypes.Open, + arguments: { file: "^memfs:/foo.ts", content: "" }, + }); await projectService.waitForPendingPlugins(); @@ -289,7 +328,12 @@ namespace ts.projectSystem { const { session } = setup(/*logLevel*/ undefined, { globalPlugins: ["plugin-a"] }, importPlugin); const projectService = session.getProjectService(); - session.executeCommand({ seq: 1, type: "request", command: protocol.CommandTypes.Open, arguments: { file: "^memfs:/foo.ts", content: "" } }); + session.executeCommand({ + seq: 1, + type: "request", + command: protocol.CommandTypes.Open, + arguments: { file: "^memfs:/foo.ts", content: "" }, + }); const project = projectService.inferredProjects[0]; @@ -327,16 +371,30 @@ namespace ts.projectSystem { }; }; - const { session, getMessages } = setup(/*logLevel*/ undefined, { globalPlugins: ["plugin-a"] }, importPlugin); + const { session, getMessages } = setup( + /*logLevel*/ undefined, + { globalPlugins: ["plugin-a"] }, + importPlugin, + ); const projectService = session.getProjectService(); - session.executeCommand({ seq: 1, type: "request", command: protocol.CommandTypes.Open, arguments: { file: "^memfs:/foo.ts", content: "" } }); + session.executeCommand({ + seq: 1, + type: "request", + command: protocol.CommandTypes.Open, + arguments: { file: "^memfs:/foo.ts", content: "" }, + }); // wait for the plugin to start loading await pluginALoaded.promise; // close the project - session.executeCommand({ seq: 2, type: "request", command: protocol.CommandTypes.Close, arguments: { file: "^memfs:/foo.ts" } }); + session.executeCommand({ + seq: 2, + type: "request", + command: protocol.CommandTypes.Close, + arguments: { file: "^memfs:/foo.ts" }, + }); // continue loading the plugin projectClosed.resolve(); diff --git a/src/tsserver/nodeServer.ts b/src/tsserver/nodeServer.ts index 38ff4a5e29211..5988b60e29b23 100644 --- a/src/tsserver/nodeServer.ts +++ b/src/tsserver/nodeServer.ts @@ -60,8 +60,8 @@ namespace ts.server { let pathStart = args[initialIndex]; let extraPartCounter = 0; if ( - pathStart.charCodeAt(0) === CharacterCodes.doubleQuote && - pathStart.charCodeAt(pathStart.length - 1) !== CharacterCodes.doubleQuote + pathStart.charCodeAt(0) === CharacterCodes.doubleQuote + && pathStart.charCodeAt(pathStart.length - 1) !== CharacterCodes.doubleQuote ) { for (let i = initialIndex + 1; i < args.length; i++) { pathStart += " "; @@ -93,7 +93,11 @@ namespace ts.server { export function initializeNodeSystem(): StartInput { const sys = Debug.checkDefined(ts.sys) as ServerHost; const childProcess: { - execFileSync(file: string, args: string[], options: { stdio: "ignore"; env: MapLike; }): string | Buffer; + execFileSync( + file: string, + args: string[], + options: { stdio: "ignore"; env: MapLike; }, + ): string | Buffer; } = require("child_process"); interface Stats { @@ -200,7 +204,10 @@ namespace ts.server { let canWrite = true; if (useWatchGuard) { - const currentDrive = extractWatchDirectoryCacheKey(sys.resolvePath(sys.getCurrentDirectory()), /*currentDriveKey*/ undefined); + const currentDrive = extractWatchDirectoryCacheKey( + sys.resolvePath(sys.getCurrentDirectory()), + /*currentDriveKey*/ undefined, + ); const statusCache = new Map(); sys.watchDirectory = (path, callback, recursive, options) => { const cacheKey = extractWatchDirectoryCacheKey(path, currentDrive); @@ -214,7 +221,10 @@ namespace ts.server { if (logger.hasLevel(LogLevel.verbose)) { logger.info(`Starting ${process.execPath} with args:${stringifyIndented(args)}`); } - childProcess.execFileSync(process.execPath, args, { stdio: "ignore", env: { ELECTRON_RUN_AS_NODE: "1" } }); + childProcess.execFileSync(process.execPath, args, { + stdio: "ignore", + env: { ELECTRON_RUN_AS_NODE: "1" }, + }); status = true; if (logger.hasLevel(LogLevel.verbose)) { logger.info(`WatchGuard for path ${path} returned: OK`); @@ -369,7 +379,12 @@ namespace ts.server { // This is the function that catches the exceptions when watching directory, and yet lets project service continue to function // Eg. on linux the number of watches are limited and one could easily exhaust watches and the exception ENOSPC is thrown when creating watcher at that point - function watchDirectorySwallowingException(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher { + function watchDirectorySwallowingException( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher { try { return originalWatchDirectory(path, callback, recursive, options); } @@ -385,9 +400,17 @@ namespace ts.server { return eventPort !== undefined && !isNaN(eventPort) ? eventPort : undefined; } - function startNodeSession(options: StartSessionOptions, logger: Logger, cancellationToken: ServerCancellationToken) { + function startNodeSession( + options: StartSessionOptions, + logger: Logger, + cancellationToken: ServerCancellationToken, + ) { const childProcess: { - fork(modulePath: string, args: string[], options?: { execArgv: string[]; env?: MapLike; }): NodeChildProcess; + fork( + modulePath: string, + args: string[], + options?: { execArgv: string[]; env?: MapLike; }, + ): NodeChildProcess; } = require("child_process"); const os: { @@ -431,7 +454,10 @@ namespace ts.server { // buffer, but we have yet to find a way to retrieve that value. private static readonly maxActiveRequestCount = 10; private static readonly requestDelayMillis = 100; - private packageInstalledPromise: { resolve(value: ApplyCodeActionCommandResult): void; reject(reason: unknown): void; } | undefined; + private packageInstalledPromise: { + resolve(value: ApplyCodeActionCommandResult): void; + reject(reason: unknown): void; + } | undefined; constructor( private readonly telemetryEnabled: boolean, @@ -481,7 +507,13 @@ namespace ts.server { args.push(Arguments.EnableTelemetry); } if (this.logger.loggingEnabled() && this.logger.getLogFileName()) { - args.push(Arguments.LogFile, combinePaths(getDirectoryPath(normalizeSlashes(this.logger.getLogFileName()!)), `ti-${process.pid}.log`)); + args.push( + Arguments.LogFile, + combinePaths( + getDirectoryPath(normalizeSlashes(this.logger.getLogFileName()!)), + `ti-${process.pid}.log`, + ), + ); } if (this.typingSafeListLocation) { args.push(Arguments.TypingSafeListLocation, this.typingSafeListLocation); @@ -532,7 +564,11 @@ namespace ts.server { this.installer.send(rq); } - enqueueInstallTypingsRequest(project: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray): void { + enqueueInstallTypingsRequest( + project: Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + ): void { const request = createInstallTypingsRequest(project, typeAcquisition, unresolvedImports); if (this.logger.hasLevel(LogLevel.verbose)) { if (this.logger.hasLevel(LogLevel.verbose)) { @@ -561,7 +597,16 @@ namespace ts.server { } } - private handleMessage(response: TypesRegistryResponse | PackageInstalledResponse | SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse) { + private handleMessage( + response: + | TypesRegistryResponse + | PackageInstalledResponse + | SetTypings + | InvalidateCachedTypings + | BeginInstallTypes + | EndInstallTypes + | InitializationFailedResponse, + ) { if (this.logger.hasLevel(LogLevel.verbose)) { this.logger.info(`Received response:${stringifyIndented(response)}`); } @@ -590,7 +635,8 @@ namespace ts.server { const body: protocol.TypesInstallerInitializationFailedEventBody = { message: response.message, }; - const eventName: protocol.TypesInstallerInitializationFailedEventName = "typesInstallerInitializationFailed"; + const eventName: protocol.TypesInstallerInitializationFailedEventName = + "typesInstallerInitializationFailed"; this.event(body, eventName); break; } @@ -687,7 +733,17 @@ namespace ts.server { const typingsInstaller = disableAutomaticTypingAcquisition ? undefined - : new NodeTypingsInstaller(telemetryEnabled, logger, host, getGlobalTypingsCacheLocation(), typingSafeListLocation, typesMapLocation, npmLocation, validateDefaultNpmLocation, event); + : new NodeTypingsInstaller( + telemetryEnabled, + logger, + host, + getGlobalTypingsCacheLocation(), + typingSafeListLocation, + typesMapLocation, + npmLocation, + validateDefaultNpmLocation, + event, + ); super({ host, @@ -719,7 +775,10 @@ namespace ts.server { } event(body: T, eventName: string): void { - Debug.assert(!!this.constructed, "Should only call `IOSession.prototype.event` on an initialized IOSession"); + Debug.assert( + !!this.constructed, + "Should only call `IOSession.prototype.event` on an initialized IOSession", + ); if (this.canUseEvents && this.eventPort) { if (!this.eventSocket) { @@ -740,7 +799,10 @@ namespace ts.server { } private writeToEventSocket(body: object, eventName: string): void { - this.eventSocket!.write(formatMessage(toEvent(eventName, body), this.logger, this.byteLength, this.host.newLine), "utf8"); + this.eventSocket!.write( + formatMessage(toEvent(eventName, body), this.logger, this.byteLength, this.host.newLine), + "utf8", + ); } exit() { @@ -794,7 +856,8 @@ namespace ts.server { const eventPort: number | undefined = parseEventPort(findArgument("--eventPort")); const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation)!; // TODO: GH#18217 - const typesMapLocation = findArgument(Arguments.TypesMapLocation) || combinePaths(getDirectoryPath(sys.getExecutingFilePath()), "typesMap.json"); + const typesMapLocation = findArgument(Arguments.TypesMapLocation) + || combinePaths(getDirectoryPath(sys.getExecutingFilePath()), "typesMap.json"); const npmLocation = findArgument(Arguments.NpmLocation); const validateDefaultNpmLocation = hasArgument(Arguments.ValidateDefaultNpmLocation); const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition"); @@ -820,13 +883,17 @@ namespace ts.server { function getGlobalTypingsCacheLocation() { switch (process.platform) { case "win32": { - const basePath = process.env.LOCALAPPDATA || - process.env.APPDATA || - (os.homedir && os.homedir()) || - process.env.USERPROFILE || - (process.env.HOMEDRIVE && process.env.HOMEPATH && normalizeSlashes(process.env.HOMEDRIVE + process.env.HOMEPATH)) || - os.tmpdir(); - return combinePaths(combinePaths(normalizeSlashes(basePath), "Microsoft/TypeScript"), versionMajorMinor); + const basePath = process.env.LOCALAPPDATA + || process.env.APPDATA + || (os.homedir && os.homedir()) + || process.env.USERPROFILE + || (process.env.HOMEDRIVE && process.env.HOMEPATH + && normalizeSlashes(process.env.HOMEDRIVE + process.env.HOMEPATH)) + || os.tmpdir(); + return combinePaths( + combinePaths(normalizeSlashes(basePath), "Microsoft/TypeScript"), + versionMajorMinor, + ); } case "openbsd": case "freebsd": @@ -847,10 +914,11 @@ namespace ts.server { return process.env.XDG_CACHE_HOME; } const usersDir = platformIsDarwin ? "Users" : "home"; - const homePath = (os.homedir && os.homedir()) || - process.env.HOME || - ((process.env.LOGNAME || process.env.USER) && `/${usersDir}/${process.env.LOGNAME || process.env.USER}`) || - os.tmpdir(); + const homePath = (os.homedir && os.homedir()) + || process.env.HOME + || ((process.env.LOGNAME || process.env.USER) + && `/${usersDir}/${process.env.LOGNAME || process.env.USER}`) + || os.tmpdir(); const cacheFolder = platformIsDarwin ? "Library/Caches" : ".cache"; diff --git a/src/tsserver/server.ts b/src/tsserver/server.ts index 2aa4afe7921fc..d83c074d40fa8 100644 --- a/src/tsserver/server.ts +++ b/src/tsserver/server.ts @@ -30,13 +30,18 @@ namespace ts.server { unknownServerMode?: string; startSession: (option: StartSessionOptions, logger: Logger, cancellationToken: ServerCancellationToken) => void; } - function start({ args, logger, cancellationToken, serverMode, unknownServerMode, startSession: startServer }: StartInput, platform: string) { + function start( + { args, logger, cancellationToken, serverMode, unknownServerMode, startSession: startServer }: StartInput, + platform: string, + ) { const syntaxOnly = hasArgument("--syntaxOnly"); logger.info(`Starting TS Server`); logger.info(`Version: ${version}`); logger.info(`Arguments: ${args.join(" ")}`); - logger.info(`Platform: ${platform} NodeVersion: ${getNodeMajorVersion()} CaseSensitive: ${sys.useCaseSensitiveFileNames}`); + logger.info( + `Platform: ${platform} NodeVersion: ${getNodeMajorVersion()} CaseSensitive: ${sys.useCaseSensitiveFileNames}`, + ); logger.info(`ServerMode: ${serverMode} syntaxOnly: ${syntaxOnly} hasUnknownServerMode: ${unknownServerMode}`); setStackTraceLimit(); diff --git a/src/typingsInstaller/nodeTypingsInstaller.ts b/src/typingsInstaller/nodeTypingsInstaller.ts index c995903b49054..462a1c1d969d9 100644 --- a/src/typingsInstaller/nodeTypingsInstaller.ts +++ b/src/typingsInstaller/nodeTypingsInstaller.ts @@ -29,7 +29,11 @@ namespace ts.server.typingsInstaller { } /** Used if `--npmLocation` is not passed. */ - function getDefaultNPMLocation(processName: string, validateDefaultNpmLocation: boolean, host: InstallTypingHost): string { + function getDefaultNPMLocation( + processName: string, + validateDefaultNpmLocation: boolean, + host: InstallTypingHost, + ): string { if (path.basename(processName).indexOf("node") === 0) { const npmPath = path.join(path.dirname(process.argv[0]), "npm"); if (!validateDefaultNpmLocation) { @@ -46,7 +50,11 @@ namespace ts.server.typingsInstaller { entries: MapLike>; } - function loadTypesRegistryFile(typesRegistryFilePath: string, host: InstallTypingHost, log: Log): ESMap> { + function loadTypesRegistryFile( + typesRegistryFilePath: string, + host: InstallTypingHost, + log: Log, + ): ESMap> { if (!host.fileExists(typesRegistryFilePath)) { if (log.isEnabled()) { log.writeLine(`Types registry file '${typesRegistryFilePath}' does not exist`); @@ -59,7 +67,11 @@ namespace ts.server.typingsInstaller { } catch (e) { if (log.isEnabled()) { - log.writeLine(`Error when loading types registry file '${typesRegistryFilePath}': ${(e as Error).message}, ${(e as Error).stack}`); + log.writeLine( + `Error when loading types registry file '${typesRegistryFilePath}': ${(e as Error).message}, ${ + (e as Error).stack + }`, + ); } return new Map>(); } @@ -67,7 +79,10 @@ namespace ts.server.typingsInstaller { const typesRegistryPackageName = "types-registry"; function getTypesRegistryFileLocation(globalTypingsCacheLocation: string): string { - return combinePaths(normalizeSlashes(globalTypingsCacheLocation), `node_modules/${typesRegistryPackageName}/index.json`); + return combinePaths( + normalizeSlashes(globalTypingsCacheLocation), + `node_modules/${typesRegistryPackageName}/index.json`, + ); } interface ExecSyncOptions { @@ -83,16 +98,33 @@ namespace ts.server.typingsInstaller { private delayedInitializationError: InitializationFailedResponse | undefined; - constructor(globalTypingsCacheLocation: string, typingSafeListLocation: string, typesMapLocation: string, npmLocation: string | undefined, validateDefaultNpmLocation: boolean, throttleLimit: number, log: Log) { + constructor( + globalTypingsCacheLocation: string, + typingSafeListLocation: string, + typesMapLocation: string, + npmLocation: string | undefined, + validateDefaultNpmLocation: boolean, + throttleLimit: number, + log: Log, + ) { super( sys, globalTypingsCacheLocation, - typingSafeListLocation ? toPath(typingSafeListLocation, "", createGetCanonicalFileName(sys.useCaseSensitiveFileNames)) : toPath("typingSafeList.json", __dirname, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)), - typesMapLocation ? toPath(typesMapLocation, "", createGetCanonicalFileName(sys.useCaseSensitiveFileNames)) : toPath("typesMap.json", __dirname, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)), + typingSafeListLocation + ? toPath(typingSafeListLocation, "", createGetCanonicalFileName(sys.useCaseSensitiveFileNames)) + : toPath( + "typingSafeList.json", + __dirname, + createGetCanonicalFileName(sys.useCaseSensitiveFileNames), + ), + typesMapLocation + ? toPath(typesMapLocation, "", createGetCanonicalFileName(sys.useCaseSensitiveFileNames)) + : toPath("typesMap.json", __dirname, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)), throttleLimit, log, ); - this.npmPath = npmLocation !== undefined ? npmLocation : getDefaultNPMLocation(process.argv[0], validateDefaultNpmLocation, this.installTypingHost); + this.npmPath = npmLocation !== undefined ? npmLocation + : getDefaultNPMLocation(process.argv[0], validateDefaultNpmLocation, this.installTypingHost); // If the NPM path contains spaces and isn't wrapped in quotes, do so. if (stringContains(this.npmPath, " ") && this.npmPath[0] !== `"`) { @@ -100,7 +132,11 @@ namespace ts.server.typingsInstaller { } if (this.log.isEnabled()) { this.log.writeLine(`Process id: ${process.pid}`); - this.log.writeLine(`NPM location: ${this.npmPath} (explicit '${Arguments.NpmLocation}' ${npmLocation === undefined ? "not " : ""} provided)`); + this.log.writeLine( + `NPM location: ${this.npmPath} (explicit '${Arguments.NpmLocation}' ${ + npmLocation === undefined ? "not " : "" + } provided)`, + ); this.log.writeLine(`validateDefaultNpmLocation: ${validateDefaultNpmLocation}`); } ({ execSync: this.nodeExecSync } = require("child_process")); @@ -111,7 +147,10 @@ namespace ts.server.typingsInstaller { if (this.log.isEnabled()) { this.log.writeLine(`Updating ${typesRegistryPackageName} npm package...`); } - this.execSyncAndLog(`${this.npmPath} install --ignore-scripts ${typesRegistryPackageName}@${this.latestDistTag}`, { cwd: globalTypingsCacheLocation }); + this.execSyncAndLog( + `${this.npmPath} install --ignore-scripts ${typesRegistryPackageName}@${this.latestDistTag}`, + { cwd: globalTypingsCacheLocation }, + ); if (this.log.isEnabled()) { this.log.writeLine(`Updated ${typesRegistryPackageName} npm package`); } @@ -128,7 +167,11 @@ namespace ts.server.typingsInstaller { }; } - this.typesRegistry = loadTypesRegistryFile(getTypesRegistryFileLocation(globalTypingsCacheLocation), this.installTypingHost, this.log); + this.typesRegistry = loadTypesRegistryFile( + getTypesRegistryFileLocation(globalTypingsCacheLocation), + this.installTypingHost, + this.log, + ); } listen() { @@ -159,13 +202,24 @@ namespace ts.server.typingsInstaller { const cwd = getDirectoryOfPackageJson(fileName, this.installTypingHost) || projectRootPath; if (cwd) { this.installWorker(-1, [packageName], cwd, success => { - const message = success ? `Package ${packageName} installed.` : `There was an error installing ${packageName}.`; - const response: PackageInstalledResponse = { kind: ActionPackageInstalled, projectName, success, message }; + const message = success ? `Package ${packageName} installed.` + : `There was an error installing ${packageName}.`; + const response: PackageInstalledResponse = { + kind: ActionPackageInstalled, + projectName, + success, + message, + }; this.sendResponse(response); }); } else { - const response: PackageInstalledResponse = { kind: ActionPackageInstalled, projectName, success: false, message: "Could not determine a project root path." }; + const response: PackageInstalledResponse = { + kind: ActionPackageInstalled, + projectName, + success: false, + message: "Could not determine a project root path.", + }; this.sendResponse(response); } break; @@ -186,12 +240,22 @@ namespace ts.server.typingsInstaller { } } - protected installWorker(requestId: number, packageNames: string[], cwd: string, onRequestCompleted: RequestCompletedAction): void { + protected installWorker( + requestId: number, + packageNames: string[], + cwd: string, + onRequestCompleted: RequestCompletedAction, + ): void { if (this.log.isEnabled()) { this.log.writeLine(`#${requestId} with arguments'${JSON.stringify(packageNames)}'.`); } const start = Date.now(); - const hasError = installNpmPackages(this.npmPath, version, packageNames, command => this.execSyncAndLog(command, { cwd })); + const hasError = installNpmPackages( + this.npmPath, + version, + packageNames, + command => this.execSyncAndLog(command, { cwd }), + ); if (this.log.isEnabled()) { this.log.writeLine(`npm install #${requestId} took: ${Date.now() - start} ms`); } @@ -212,7 +276,11 @@ namespace ts.server.typingsInstaller { } catch (error) { const { stdout, stderr } = error; - this.log.writeLine(` Failed. stdout:${indent(sys.newLine, stdout)}${sys.newLine} stderr:${indent(sys.newLine, stderr)}`); + this.log.writeLine( + ` Failed. stdout:${indent(sys.newLine, stdout)}${sys.newLine} stderr:${ + indent(sys.newLine, stderr) + }`, + ); return true; } } @@ -245,7 +313,15 @@ namespace ts.server.typingsInstaller { } process.exit(0); }); - const installer = new NodeTypingsInstaller(globalTypingsCacheLocation!, typingSafeListLocation!, typesMapLocation!, npmLocation, validateDefaultNpmLocation, /*throttleLimit*/ 5, log); // TODO: GH#18217 + const installer = new NodeTypingsInstaller( + globalTypingsCacheLocation!, + typingSafeListLocation!, + typesMapLocation!, + npmLocation, + validateDefaultNpmLocation, + /*throttleLimit*/ 5, + log, + ); // TODO: GH#18217 installer.listen(); function indent(newline: string, str: string | undefined): string { diff --git a/src/typingsInstallerCore/typingsInstaller.ts b/src/typingsInstallerCore/typingsInstaller.ts index 659b9b82d540a..9c0f90ae2560c 100644 --- a/src/typingsInstallerCore/typingsInstaller.ts +++ b/src/typingsInstallerCore/typingsInstaller.ts @@ -17,9 +17,16 @@ namespace ts.server.typingsInstaller { writeLine: noop, }; - function typingToFileName(cachePath: string, packageName: string, installTypingHost: InstallTypingHost, log: Log): string | undefined { + function typingToFileName( + cachePath: string, + packageName: string, + installTypingHost: InstallTypingHost, + log: Log, + ): string | undefined { try { - const result = resolveModuleName(packageName, combinePaths(cachePath, "index.d.ts"), { moduleResolution: ModuleResolutionKind.NodeJs }, installTypingHost); + const result = resolveModuleName(packageName, combinePaths(cachePath, "index.d.ts"), { + moduleResolution: ModuleResolutionKind.NodeJs, + }, installTypingHost); return result.resolvedModule && result.resolvedModule.resolvedFileName; } catch (e) { @@ -31,7 +38,12 @@ namespace ts.server.typingsInstaller { } /*@internal*/ - export function installNpmPackages(npmPath: string, tsVersion: string, packageNames: string[], install: (command: string) => boolean) { + export function installNpmPackages( + npmPath: string, + tsVersion: string, + packageNames: string[], + install: (command: string) => boolean, + ) { let hasError = false; for (let remaining = packageNames.length; remaining > 0;) { const result = getNpmCommandForInstallation(npmPath, tsVersion, packageNames, remaining); @@ -42,11 +54,19 @@ namespace ts.server.typingsInstaller { } /*@internal*/ - export function getNpmCommandForInstallation(npmPath: string, tsVersion: string, packageNames: string[], remaining: number) { + export function getNpmCommandForInstallation( + npmPath: string, + tsVersion: string, + packageNames: string[], + remaining: number, + ) { const sliceStart = packageNames.length - remaining; let command: string, toSlice = remaining; while (true) { - command = `${npmPath} install --ignore-scripts ${(toSlice === packageNames.length ? packageNames : packageNames.slice(sliceStart, sliceStart + toSlice)).join(" ")} --save-dev --user-agent="typesInstaller/${tsVersion}"`; + command = `${npmPath} install --ignore-scripts ${ + (toSlice === packageNames.length ? packageNames : packageNames.slice(sliceStart, sliceStart + toSlice)) + .join(" ") + } --save-dev --user-agent="typesInstaller/${tsVersion}"`; if (command.length < 8000) { break; } @@ -66,9 +86,10 @@ namespace ts.server.typingsInstaller { function endsWith(str: string, suffix: string, caseSensitive: boolean): boolean { const expectedPos = str.length - suffix.length; - return expectedPos >= 0 && - (str.indexOf(suffix, expectedPos) === expectedPos || - (!caseSensitive && compareStringsCaseInsensitive(str.substr(expectedPos), suffix) === Comparison.EqualTo)); + return expectedPos >= 0 + && (str.indexOf(suffix, expectedPos) === expectedPos + || (!caseSensitive + && compareStringsCaseInsensitive(str.substr(expectedPos), suffix) === Comparison.EqualTo)); } function isPackageOrBowerJson(fileName: string, caseSensitive: boolean) { @@ -119,9 +140,16 @@ namespace ts.server.typingsInstaller { this.globalCachePackageJsonPath = combinePaths(globalCachePath, "package.json"); const isLoggingEnabled = this.log.isEnabled(); if (isLoggingEnabled) { - this.log.writeLine(`Global cache location '${globalCachePath}', safe file path '${safeListPath}', types map path ${typesMapLocation}`); + this.log.writeLine( + `Global cache location '${globalCachePath}', safe file path '${safeListPath}', types map path ${typesMapLocation}`, + ); } - this.watchFactory = getWatchFactory(this.installTypingHost as WatchFactoryHost, isLoggingEnabled ? WatchLogLevel.Verbose : WatchLogLevel.None, s => this.log.writeLine(s), getDetailWatchInfo); + this.watchFactory = getWatchFactory( + this.installTypingHost as WatchFactoryHost, + isLoggingEnabled ? WatchLogLevel.Verbose : WatchLogLevel.None, + s => this.log.writeLine(s), + getDetailWatchInfo, + ); this.processCacheLocation(this.globalCachePath); } @@ -156,7 +184,9 @@ namespace ts.server.typingsInstaller { // load existing typing information from the cache if (req.cachePath) { if (this.log.isEnabled()) { - this.log.writeLine(`Request specifies cache path '${req.cachePath}', loading cached information...`); + this.log.writeLine( + `Request specifies cache path '${req.cachePath}', loading cached information...`, + ); } this.processCacheLocation(req.cachePath); } @@ -186,7 +216,12 @@ namespace ts.server.typingsInstaller { // install typings if (discoverTypingsResult.newTypingNames.length) { - this.installTypings(req, req.cachePath || this.globalCachePath, discoverTypingsResult.cachedTypingPaths, discoverTypingsResult.newTypingNames); + this.installTypings( + req, + req.cachePath || this.globalCachePath, + discoverTypingsResult.cachedTypingPaths, + discoverTypingsResult.newTypingNames, + ); } else { this.sendResponse(this.createSetTypings(req, discoverTypingsResult.cachedTypingPaths)); @@ -243,7 +278,12 @@ namespace ts.server.typingsInstaller { if (!packageName) { continue; } - const typingFile = typingToFileName(cacheLocation, packageName, this.installTypingHost, this.log); + const typingFile = typingToFileName( + cacheLocation, + packageName, + this.installTypingHost, + this.log, + ); if (!typingFile) { this.missingTypingsSet.add(packageName); continue; @@ -255,7 +295,9 @@ namespace ts.server.typingsInstaller { } if (this.log.isEnabled()) { - this.log.writeLine(`New typing for package ${packageName} from '${typingFile}' conflicts with existing typing file '${existingTypingFile}'`); + this.log.writeLine( + `New typing for package ${packageName} from '${typingFile}' conflicts with existing typing file '${existingTypingFile}'`, + ); } } if (this.log.isEnabled()) { @@ -267,7 +309,10 @@ namespace ts.server.typingsInstaller { continue; } - const newTyping: JsTyping.CachedTyping = { typingLocation: typingFile, version: new Version(version) }; + const newTyping: JsTyping.CachedTyping = { + typingLocation: typingFile, + version: new Version(version), + }; this.packageNameToTypingLocation.set(packageName, newTyping); } } @@ -282,22 +327,40 @@ namespace ts.server.typingsInstaller { return mapDefined(typingsToInstall, typing => { const typingKey = mangleScopedPackageName(typing); if (this.missingTypingsSet.has(typingKey)) { - if (this.log.isEnabled()) this.log.writeLine(`'${typing}':: '${typingKey}' is in missingTypingsSet - skipping...`); + if (this.log.isEnabled()) { + this.log.writeLine(`'${typing}':: '${typingKey}' is in missingTypingsSet - skipping...`); + } return undefined; } const validationResult = JsTyping.validatePackageName(typing); if (validationResult !== JsTyping.NameValidationResult.Ok) { // add typing name to missing set so we won't process it again this.missingTypingsSet.add(typingKey); - if (this.log.isEnabled()) this.log.writeLine(JsTyping.renderPackageNameValidationFailure(validationResult, typing)); + if (this.log.isEnabled()) { + this.log.writeLine(JsTyping.renderPackageNameValidationFailure(validationResult, typing)); + } return undefined; } if (!this.typesRegistry.has(typingKey)) { - if (this.log.isEnabled()) this.log.writeLine(`'${typing}':: Entry for package '${typingKey}' does not exist in local types registry - skipping...`); + if (this.log.isEnabled()) { + this.log.writeLine( + `'${typing}':: Entry for package '${typingKey}' does not exist in local types registry - skipping...`, + ); + } return undefined; } - if (this.packageNameToTypingLocation.get(typingKey) && JsTyping.isTypingUpToDate(this.packageNameToTypingLocation.get(typingKey)!, this.typesRegistry.get(typingKey)!)) { - if (this.log.isEnabled()) this.log.writeLine(`'${typing}':: '${typingKey}' already has an up-to-date typing - skipping...`); + if ( + this.packageNameToTypingLocation.get(typingKey) + && JsTyping.isTypingUpToDate( + this.packageNameToTypingLocation.get(typingKey)!, + this.typesRegistry.get(typingKey)!, + ) + ) { + if (this.log.isEnabled()) { + this.log.writeLine( + `'${typing}':: '${typingKey}' already has an up-to-date typing - skipping...`, + ); + } return undefined; } return typingKey; @@ -318,14 +381,21 @@ namespace ts.server.typingsInstaller { } } - private installTypings(req: DiscoverTypings, cachePath: string, currentlyCachedTypings: string[], typingsToInstall: string[]) { + private installTypings( + req: DiscoverTypings, + cachePath: string, + currentlyCachedTypings: string[], + typingsToInstall: string[], + ) { if (this.log.isEnabled()) { this.log.writeLine(`Installing typings ${JSON.stringify(typingsToInstall)}`); } const filteredTypings = this.filterTypings(typingsToInstall); if (filteredTypings.length === 0) { if (this.log.isEnabled()) { - this.log.writeLine(`All typings are known to be missing or invalid - no need to install more typings`); + this.log.writeLine( + `All typings are known to be missing or invalid - no need to install more typings`, + ); } this.sendResponse(this.createSetTypings(req, currentlyCachedTypings)); return; @@ -351,7 +421,11 @@ namespace ts.server.typingsInstaller { try { if (!ok) { if (this.log.isEnabled()) { - this.log.writeLine(`install request failed, marking packages as missing to prevent repeated requests: ${JSON.stringify(filteredTypings)}`); + this.log.writeLine( + `install request failed, marking packages as missing to prevent repeated requests: ${ + JSON.stringify(filteredTypings) + }`, + ); } for (const typing of filteredTypings) { this.missingTypingsSet.add(typing); @@ -373,7 +447,9 @@ namespace ts.server.typingsInstaller { // packageName is guaranteed to exist in typesRegistry by filterTypings const distTags = this.typesRegistry.get(packageName)!; - const newVersion = new Version(distTags[`ts${versionMajorMinor}`] || distTags[this.latestDistTag]); + const newVersion = new Version( + distTags[`ts${versionMajorMinor}`] || distTags[this.latestDistTag], + ); const newTyping: JsTyping.CachedTyping = { typingLocation: typingFile, version: newVersion }; this.packageNameToTypingLocation.set(packageName, newTyping); installedTypingFiles.push(typingFile); @@ -410,7 +486,12 @@ namespace ts.server.typingsInstaller { } } - private watchFiles(projectName: string, files: string[], projectRootPath: Path, options: WatchOptions | undefined) { + private watchFiles( + projectName: string, + files: string[], + projectRootPath: Path, + options: WatchOptions | undefined, + ) { if (!files.length) { // shut down existing watchers this.closeWatchers(projectName); @@ -441,8 +522,8 @@ namespace ts.server.typingsInstaller { if (isLoggingEnabled) { this.log.writeLine(`${projectWatcherType}:: Added:: WatchInfo: ${path}`); } - const watcher = projectWatcherType === ProjectWatcherType.FileWatcher ? - this.watchFactory.watchFile( + const watcher = projectWatcherType === ProjectWatcherType.FileWatcher + ? this.watchFactory.watchFile( path, () => { if (!watchers.isInvoked) { @@ -454,8 +535,8 @@ namespace ts.server.typingsInstaller { options, projectName, watchers, - ) : - this.watchFactory.watchDirectory( + ) + : this.watchFactory.watchDirectory( path, f => { if (watchers.isInvoked || !fileExtensionIs(f, Extension.Json)) { @@ -463,8 +544,12 @@ namespace ts.server.typingsInstaller { } if ( - isPackageOrBowerJson(f, this.installTypingHost.useCaseSensitiveFileNames) && - !sameFiles(f, this.globalCachePackageJsonPath, this.installTypingHost.useCaseSensitiveFileNames) + isPackageOrBowerJson(f, this.installTypingHost.useCaseSensitiveFileNames) + && !sameFiles( + f, + this.globalCachePackageJsonPath, + this.installTypingHost.useCaseSensitiveFileNames, + ) ) { watchers.isInvoked = true; this.sendResponse({ projectName, kind: ActionInvalidate }); @@ -496,7 +581,14 @@ namespace ts.server.typingsInstaller { } // path in projectRoot, watch project root - if (containsPath(projectRootPath, file, projectRootPath, !this.installTypingHost.useCaseSensitiveFileNames)) { + if ( + containsPath( + projectRootPath, + file, + projectRootPath, + !this.installTypingHost.useCaseSensitiveFileNames, + ) + ) { const subDirectory = file.indexOf(directorySeparator, projectRootPath.length + 1); if (subDirectory !== -1) { // Watch subDirectory @@ -510,7 +602,14 @@ namespace ts.server.typingsInstaller { } // path in global cache, watch global cache - if (containsPath(this.globalCachePath, file, projectRootPath, !this.installTypingHost.useCaseSensitiveFileNames)) { + if ( + containsPath( + this.globalCachePath, + file, + projectRootPath, + !this.installTypingHost.useCaseSensitiveFileNames, + ) + ) { createProjectWatcher(this.globalCachePath, ProjectWatcherType.DirectoryWatcher); continue; } @@ -537,7 +636,12 @@ namespace ts.server.typingsInstaller { }; } - private installTypingsAsync(requestId: number, packageNames: string[], cwd: string, onRequestCompleted: RequestCompletedAction): void { + private installTypingsAsync( + requestId: number, + packageNames: string[], + cwd: string, + onRequestCompleted: RequestCompletedAction, + ): void { this.pendingRunRequests.unshift({ requestId, packageNames, cwd, onRequestCompleted }); this.executeWithThrottling(); } @@ -554,8 +658,15 @@ namespace ts.server.typingsInstaller { } } - protected abstract installWorker(requestId: number, packageNames: string[], cwd: string, onRequestCompleted: RequestCompletedAction): void; - protected abstract sendResponse(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes): void; + protected abstract installWorker( + requestId: number, + packageNames: string[], + cwd: string, + onRequestCompleted: RequestCompletedAction, + ): void; + protected abstract sendResponse( + response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes, + ): void; protected readonly latestDistTag = "latest"; } diff --git a/src/webServer/webServer.ts b/src/webServer/webServer.ts index 4a68abdad7a47..011e603d4f9ab 100644 --- a/src/webServer/webServer.ts +++ b/src/webServer/webServer.ts @@ -127,9 +127,13 @@ namespace ts.server { export function createWebSystem(host: WebHost, args: string[], getExecutingFilePath: () => string): ServerHost { const returnEmptyString = () => ""; - const getExecutingDirectoryPath = memoize(() => memoize(() => ensureTrailingDirectorySeparator(getDirectoryPath(getExecutingFilePath())))); + const getExecutingDirectoryPath = memoize(() => + memoize(() => ensureTrailingDirectorySeparator(getDirectoryPath(getExecutingFilePath()))) + ); // Later we could map ^memfs:/ to do something special if we want to enable more functionality like module resolution or something like that - const getWebPath = (path: string) => startsWith(path, directorySeparator) ? path.replace(directorySeparator, getExecutingDirectoryPath()) : undefined; + const getWebPath = (path: string) => + startsWith(path, directorySeparator) ? path.replace(directorySeparator, getExecutingDirectoryPath()) + : undefined; const dynamicImport = async (id: string): Promise => { // Use syntactic dynamic import first, if available @@ -171,12 +175,18 @@ namespace ts.server { packageJson = await packageJsonResponse.json(); } catch (e) { - return { module: undefined, error: new Error("Could not load plugin. Could not load 'package.json'.") }; + return { + module: undefined, + error: new Error("Could not load plugin. Could not load 'package.json'."), + }; } const browser = packageJson.browser; if (!browser) { - return { module: undefined, error: new Error("Could not load plugin. No 'browser' field found in package.json.") }; + return { + module: undefined, + error: new Error("Could not load plugin. No 'browser' field found in package.json."), + }; } const scriptPath = combinePaths(packageRoot, browser); @@ -229,7 +239,14 @@ namespace ts.server { serverMode: SessionOptions["serverMode"]; } export class WorkerSession extends Session<{}> { - constructor(host: ServerHost, private webHost: HostWithWriteMessage, options: StartSessionOptions, logger: Logger, cancellationToken: ServerCancellationToken, hrtime: SessionOptions["hrtime"]) { + constructor( + host: ServerHost, + private webHost: HostWithWriteMessage, + options: StartSessionOptions, + logger: Logger, + cancellationToken: ServerCancellationToken, + hrtime: SessionOptions["hrtime"], + ) { super({ host, cancellationToken,